zoukankan      html  css  js  c++  java
  • 动态规划:采油区域

    描述:

      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 }
  • 相关阅读:
    JavaScript DOM 编程艺术 公用方法
    JavaScript DOM 编程艺术
    Echart 的formatter及重写line chart
    PHP 导出csv
    Linux 搭建PHP环境
    学习新思路
    fork产生子进程利用pipe管道通信
    进程间通信 管道
    进程间通信(IPC) 简介
    java 多态
  • 原文地址:https://www.cnblogs.com/xiehuazhen/p/12166876.html
Copyright © 2011-2022 走看看