题目描述:
Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井。被拍卖的整块土地为一个矩形区域,被划分为M×N个小块。 Siruseri地质调查局有关于Navalur土地石油储量的估测数据。这些数据表示为M×N个正整数,即对每一小块土地石油储量的估计值。 为了避免出现垄断,政府规定每一个承包商只能承包一个由K×K块相连的土地构成的正方形区域。 AoE石油联合公司由三个承包商组成,他们想选择三块互不相交的K×K的区域使得总的收益最大。 例如,假设石油储量的估计值如下:
如果K = 2, AoE公司可以承包的区域的石油储量总和为100, 如果K = 3, AoE公司可以承包的区域的石油储量总和为208。 AoE公司雇佣你来写一个程序,帮助计算出他们可以承包的区域的石油储量之和的最大值。
数据保证K≤M且K≤N并且至少有三个K×K的互不相交的正方形区域。其中30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的石油储量的估计值是非负整数且≤ 500
输入:
输入第一行包含三个整数M, N, K,其中M和N是矩形区域的行数和列数,K是每一个承包商承包的正方形的大小(边长的块数)。接下来M行,每行有N个正整数表示这一行每一小块土地的石油储量的估计值
输出:
输出只包含一个正整数,表示AoE公司可以承包的区域的石油储量之和的最大值
样例输入:
9 9 3
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 8 8 8 8 8 1 1 1
1 1 1 1 8 8 8 1 1
1 1 1 1 1 1 8 8 8
1 1 1 1 1 1 9 9 9
1 1 1 1 1 1 9 9 9
样例输出:
208
解题思路:动态规划问题,使用递推,先将小问题的解求出来,然后再解决大问题。递推+前缀和
一个矩形,分三块,有六种方法 如图:
分别在三个部分中找的k*k面积最大的,加起来就是答案
那么怎么表示这三个块中面积最大的呢?
就需要记录对于每个点
它左上,右上,左下,右下的四个部分中,最大的K * K块的价值和
这个样子:
int a[2000][2000], b[2000][2000], c[2000][2000], d[2000][2000];
//a表示左上,b表示右上,c表示左下,d表示右下
先将循环用define简化:
#define FI for(int i=1;i<=n;i++)
#define FJ for(int j=1;j<=m;j++)
#define FDI for(int i=n;i>=k;i--)
#define FDJ for(int j=m;j>=k;j--)
#define FUI for(int i=k;i<=n;i++)
#define FUJ for(int j=k;j<=m;j++)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
用数组mp先表示以i,j点为右下角的的矩形(注意不是k*k的矩形)的储油量之和,然后通过循环再计算用mp表示以i,j为右下角的k * k的矩形的储油量之和:
FI FJ{cin>>temp;pos[i][j] = pos[i - 1][j] + pos[i][j - 1] - pos[i - 1][j - 1] + temp;}FDI FDJ pos[i][j] -= pos[i - k][j] + pos[i][j - k] - pos[i - k][j - k];
再通过递推公式计算出左上角,右上角,左下角,右下角的储油量最大值:
FUI FUJ a[i][j] = max(pos[i][j], max(a[i - 1][j], a[i][j - 1]));FUI FDJ b[i][j] = max(pos[i][j], max(b[i - 1][j], b[i][j + 1]));FDI FUJ c[i][j] = max(pos[i][j], max(c[i + 1][j], c[i][j - 1]));FDI FDJ d[i][j] = max(pos[i][j], max(d[i + 1][j], d[i][j + 1]));
在根据上面分析的六种情况,算出最大的储油量res:
rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][j] + b[i][j + k] + c[i + k][m]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][m] + c[i + k][j] + d[i + k][j + k]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][j] + b[n][j + k] + c[i + k][j]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[n][j] + b[i][j + k] + d[i + k][j + k]);rep(i, k, n - k) rep(j, k + k, m - k) res = max(res, a[n][j - k] + b[n][j + k] + pos[i][j]);rep(i, k + k, n - k) rep(j, k, m - k) res = max(res, a[i - k][m] + c[i + k][m] + pos[i][j]);
最终输出res:
cout << res;
完整代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>//定义循环符号
#define FI for(int i=1;i<=n;i++)
#define FJ for(int j=1;j<=m;j++)
#define FDI for(int i=n;i>=k;i--)
#define FDJ for(int j=m;j>=k;j--)
#define FUI for(int i=k;i<=n;i++)
#define FUJ for(int j=k;j<=m;j++)
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
using namespace std;int a[2000][2000], b[2000][2000], c[2000][2000], d[2000][2000];
//a表示左上,b表示右上,c表示左下,d表示右下
int pos[2000][2000];
int n, m, k;int main() {cin>>n>>m>>k;int temp;int res = 0;FI FJ{cin>>temp;pos[i][j] = pos[i - 1][j] + pos[i][j - 1] - pos[i - 1][j - 1] + temp;}FDI FDJ pos[i][j] -= pos[i - k][j] + pos[i][j - k] - pos[i - k][j - k];FUI FUJ a[i][j] = max(pos[i][j], max(a[i - 1][j], a[i][j - 1]));FUI FDJ b[i][j] = max(pos[i][j], max(b[i - 1][j], b[i][j + 1]));FDI FUJ c[i][j] = max(pos[i][j], max(c[i + 1][j], c[i][j - 1]));FDI FDJ d[i][j] = max(pos[i][j], max(d[i + 1][j], d[i][j + 1]));rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][j] + b[i][j + k] + c[i + k][m]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][m] + c[i + k][j] + d[i + k][j + k]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[i][j] + b[n][j + k] + c[i + k][j]);rep(i, k, n - k) rep(j, k, m - k) res = max(res, a[n][j] + b[i][j + k] + d[i + k][j + k]);rep(i, k, n - k) rep(j, k + k, m - k) res = max(res, a[n][j - k] + b[n][j + k] + pos[i][j]);rep(i, k + k, n - k) rep(j, k, m - k) res = max(res, a[i - k][m] + c[i + k][m] + pos[i][j]);cout << res;system("pause");return 0;
}