描述:
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个非负整数表示这一行每一小块土地的石油储量的估计值。
输入样例:
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
输出描述:
输出只包含一个整数,表示AoE公司可以承包的区域的石油储量之和的最大值。
输出样例:
208
提示:
数据保证K≤M且K≤N并且至少有三个K×K的互不相交的正方形区域。其中30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的石油储量的估计值是非负整数且≤ 500。
case1 case2
case3 case4
case5 case6
对于case1-case4:
用前缀和将以左上角和(i,j)为对角的矩形内的值的和保存在(i,j),随后将k*k的区域值的最大值保存在(i,j),再分别求出以右上,左下,右下,顶点为最大值。
对于case5-case6:
可以规定中间的区域的宽度就是k,此时最优的情况依然包含在内。
代码如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #define max(a,b)((a)>(b)?(a):(b)) 5 /** 6 *m:行数 7 *n:列数 8 *max:最大值 9 *case1:左上下 10 *case2:上下右 11 *case3:上左右 12 *case4:左右下 13 *case5:上中下 14 *case6:左中右 15 */ 16 int m,n,k,max,case1,case2,case3,case4,case5,case6; 17 /**石油储量矩阵*/ 18 int matrix[1502][1502]; 19 /**矩形计算前缀和*/ 20 int mRect[1502][1502]; 21 /**为k*k正方形计算前缀和*/ 22 int rect[1502][1502]; 23 /** 24 *计算四块区域中k*k的正方形前缀和最大的一块 25 *rect1:up,left 26 *rect2:up,right 27 *rect3:down,left 28 *rect4:down,right 29 */ 30 int rect1[1502][1502],rect2[1502][1502],rect3[1502][1502],rect4[1502][1502]; 31 32 int main(){ 33 scanf("%d%d%d",&m,&n,&k); 34 for(int i=1;i<=m;++i) 35 for(int j=1;j<=n;++j){ 36 scanf("%d",&matrix[i][j]); 37 mRect[i][j]=mRect[i-1][j]+mRect[i][j-1]-mRect[i-1][j-1]+matrix[i][j]; 38 rect[i][j]=mRect[i][j]-mRect[i-k][j]-mRect[i][j-k]+mRect[i-k][j-k]; 39 if(i>=k&&j>=k) 40 rect1[i][j]=max(rect[i][j],max(rect1[i-1][j],rect1[i][j-1])); 41 } 42 for(int i=k;i<=m;++i) 43 for(int j=n-k+1;j>=1;--j) 44 rect2[i][j]=max(rect[i][j+k-1],max(rect2[i-1][j],rect2[i][j+1])); 45 for(int i=m-k+1;i>=1;--i) 46 for(int j=k;j<=n;++j) 47 rect3[i][j]=max(rect[i+k-1][j],max(rect3[i+1][j],rect3[i][j-1])); 48 for(int i=m-k+1;i>=1;--i) 49 for(int j=n-k+1;j>=1;--j) 50 rect4[i][j]=max(rect[i+k-1][j+k-1],max(rect4[i+1][j],rect4[i][j+1])); 51 /**case1-case4情况中的最大值*/ 52 for(int i=k;i+k<=m;++i) 53 for(int j=k;j+k<=n;++j){ 54 case1=rect1[m][j]+rect2[i][j+1]+rect4[i+1][j+1]; 55 case2=rect1[i][j]+rect2[m][j+1]+rect3[i+1][j]; 56 case3=rect1[i][n]+rect3[i+1][j]+rect4[i+1][j+1]; 57 case4=rect1[i][j]+rect2[i][j+1]+rect3[i+1][n]; 58 max=max(max,max(max(case1,case2),max(case3,case4))); 59 } 60 /**case5情况中的最大值。 61 *规定中间区域宽度为k,最优解包含其内。 62 *中间区域判断最大正方形从左到右每个都要试,故用rect 63 *区域上用rect1紧邻中间区域 64 *区域下用rect3紧邻中间区域 65 */ 66 for(int i=2*k;i+k<=m;++i) 67 for(int j=k;j<=n;++j){ 68 case5=rect1[i-k][n]+rect3[i+1][n]+rect[i][j]; 69 max=max(max,case5); 70 } 71 /**case6情况中的最大值*/ 72 for(int j=2*k;j+k<=n;++j) 73 for(int i=k;i<=m;++i){ 74 case6=rect1[m][j-k]+rect2[m][j+1]+rect[i][j]; 75 max=max(max,case6); 76 } 77 printf("%d ",max); 78 }