算法训练 采油区域
时间限制:2.0s 内存限制:512.0MB
采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井。被拍卖的整块土地为一个矩形区域,被划分为M×N个小块。
Siruseri地质调查局有关于Navalur土地石油储量的估测数据。这些数据表示为M×N个非负整数,即对每一小块土地石油储量的估计值。
为了避免出现垄断,政府规定每一个承包商只能承包一个由K×K块相连的土地构成的正方形区域。
AoE石油联合公司由三个承包商组成,他们想选择三块互不相交的K×K的区域使得总的收益最大。
例如,假设石油储量的估计值如下:
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
如果K = 2, AoE公司可以承包的区域的石油储量总和为100, 如果K = 3, AoE公司可以承包的区域的石油储量总和为208。
AoE公司雇佣你来写一个程序,帮助计算出他们可以承包的区域的石油储量之和的最大值。
输入格式
输入第一行包含三个整数M, N, K,其中M和N是矩形区域的行数和列数,K是每一个承包商承包的正方形的大小(边长的块数)。接下来M行,每行有N个非负整数表示这一行每一小块土地的石油储量的估计值。
输出格式
输出只包含一个整数,表示AoE公司可以承包的区域的石油储量之和的最大值。
数据规模和约定
数据保证K≤M且K≤N并且至少有三个K×K的互不相交的正方形区域。其中30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的石油储量的估计值是非负整数且≤ 500。
样例输入
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
思路:对于三个区域的分布进行考虑,只存在6种情况:
只要找到6种情况中的三个区域中最大的值即可,然而对于case1的所有情况有 1500*1500,因此要找到三个区域中的最大值的时间维持在常数内。此时可预处理,用前缀和将以左上角和(i,j)为对角的矩形内的值的和保存在(i,j),随后将k*k的区域值的最大值保存在(i,j),再分别求出以右下,右上,左上顶点为最大值即可。而对于case1和case2,可以规定中间的区域的宽度就是k,此时最优的情况依然包含在内。
code:
#include<iostream>
using namespace std;
const int MAX_N=1505;
const int MAX_M=1505;
int n,m,k,ans;
int d[MAX_N][MAX_M];
int a[MAX_N][MAX_M],aa[MAX_N][MAX_M];
int b1[MAX_N][MAX_M],b2[MAX_N][MAX_M],b3[MAX_N][MAX_M],b4[MAX_N][MAX_M];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>k;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
{
cin>>d[i][j];
a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+d[i][j];
aa[i][j]=a[i][j]-a[i][j-k]-a[i-k][j]+a[i-k][j-k];
if(i>=k&&j>=k) b1[i][j]=max(aa[i][j],max(b1[i][j-1],b1[i-1][j]));
}
for(int i=k;i<=n;++i)
for(int j=m-k+1;j>=1;--j)
b2[i][j]=max(aa[i][j+k-1],max(b2[i][j+1],b2[i-1][j]));
for(int i=n-k+1;i>=1;--i)
for(int j=k;j<=m;++j)
b3[i][j]=max(aa[i+k-1][j],max(b3[i][j-1],b3[i+1][j]));
for(int i=n-k+1;i>=1;--i)
for(int j=m-k+1;j>=1;--j)
b4[i][j]=max(aa[i+k-1][j+k-1],max(b4[i][j+1],b4[i+1][j]));
for(int i=k;i+k<=n;++i)
for(int j=k;j+k<=m;++j)
{
int aa=max(b1[n][j]+b2[i][j+1]+b4[i+1][j+1],b1[i][j]+b2[n][j+1]+b3[i+1][j]);
int bb=max(b1[i][j]+b2[i][j+1]+b3[i+1][m],b1[i][m]+b3[i+1][j]+b4[i+1][j+1]);
ans=max(ans,max(aa,bb));
}
for(int i=2*k;i+k<=n;++i)
for(int j=k;j<=m;++j)
ans=max(ans,b1[i-k][m]+b3[i+1][m]+aa[i][j]);
for(int j=2*k;j+k<=m;++j)
for(int i=k;i<=n;++i)
ans=max(ans,b1[n][j-k]+b2[n][j+1]+aa[i][j]);
cout<<ans<<endl;
return 0;
}