动态规划:采油区域

描述:

  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

提示:

HINT:时间限制:2.0s 内存限制:512.0MB
  数据保证K≤M且K≤N并且至少有三个K×K的互不相交的正方形区域。其中30%的输入数据,M, N≤ 12。所有的输入数据, M, N≤ 1500。每一小块土地的石油储量的估计值是非负整数且≤ 500。
思路:
  对于三个区域的分布进行考虑,只存在6种情况:

                           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 }
原文地址:https://www.cnblogs.com/xiehuazhen/p/12166876.html