采油区域-APIO 2009

算法训练 采油区域  
时间限制: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

因为只有三块,所以对于整体的划分可分为六种情况:

|||   -|   =   |-    T    

于是可以进行六次遍历

可以先定义

s[i][j]代表1..i行1..j列数字之和。

然后处理出以(i,j)为右下角的k*k的矩阵元素之和。

然后分别处理出以(i,j)为左上角,左下角,右上角,右下角的最大矩阵中最大的k*k的值。


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define gmax(a,b) ((a)>(b)?(a):(b))
#define fill(a,b) memset(a,b,sizeof(a))
#define MAXN 2000
#define MAXM 2000
using namespace std;
int n, m, k;
int a[MAXN][MAXM];
int s[MAXN][MAXM];
int ak[MAXN][MAXM];
int lu[MAXN][MAXM], ru[MAXN][MAXM], ld[MAXN][MAXM], rd[MAXN][MAXM];
int ans;
int main(){

    int i, j;
    scanf("%d %d %d", &n, &m, &k);
    for (i=1; i<n+1; i++){
        for (j=1; j<m+1; j++){
            scanf("%d", &a[i][j]);
            }
        }
    fill(s, 0);
    for (i=1; i<n+1; i++){
        for (j=1; j<m+1; j++){
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
            }
        }
    fill(ak, 0);
    for (i=k; i<n+1; i++){
        for (j=k; j<m+1; j++){
            ak[i][j] = s[i][j] - s[i - k][j] - s[i][j - k] + s[i - k][j - k];
            }
        }
    fill(lu, 0);
    for (i=k; i<n+1; i++){
        for (j=k; j<m+1; j++){
            lu[i][j] = ak[i][j];
            lu[i][j] = gmax(lu[i][j], lu[i - 1][j]);
            lu[i][j] = gmax(lu[i][j], lu[i][j - 1]);
            }
        }
    fill(ru, 0);
    for (i=k; i<n+1; i++){
        for (j=m-k+1; j; j--){
            ru[i][j] = ak[i][j + k - 1];
            ru[i][j] = gmax(ru[i][j], ru[i - 1][j]);
            ru[i][j] = gmax(ru[i][j], ru[i][j + 1]);
            }
        }
    fill(ld, 0);
    for (i=n-k+1; i; i--){
        for (j=k; j<m+1; j++){
            ld[i][j] = ak[i + k - 1][j];
            ld[i][j] = gmax(ld[i][j], ld[i + 1][j]);
            ld[i][j] = gmax(ld[i][j], ld[i][j - 1]);
            }
        }
    fill(rd, 0);
    for (i=n-k+1; i; i--){
        for (j=m-k+1; j; j--){
            rd[i][j] = ak[i + k - 1][j + k - 1];
            rd[i][j] = gmax(rd[i][j], rd[i + 1][j]);
            rd[i][j] = gmax(rd[i][j], rd[i][j + 1]);
            }
        }
    ans = 0;
    for (j=k; j+(k<<1)<m+1; j++){
        for (i=k; i<n+1; i++){
            int t = lu[n][j] + ak[i][j + k] + ru[n][j + k + 1];
            ans = gmax(ans, t);
            }
        }
    for (i=k; i+(k<<1)<n+1; i++){
        for (j=k; j<m+1; j++){
            int t = lu[i][m] + ak[i + k][j] + ld[i + k + 1][m];
            ans = gmax(ans, t);
            }
        }
    for (j=k; j+k<m+1; j++){
        for (i=k; i+k<n+1; i++){
            int t = lu[n][j] + ru[i][j + 1] + rd[i + 1][j + 1];
            ans = gmax(ans, t);
            }
        }
    for (j=k; j+k<m+1; j++){
        for (i=k; i+k<n+1; i++){
            int t = lu[i][j] + ld[i + 1][j] + rd[1][j + 1];
            ans = gmax(ans, t);
            }
        }
    for (i=k; i+k<n+1; i++){
        for (j=k; j+k<m+1; j++){
            int t = lu[i][n] + ld[i + 1][j] + rd[i + 1][j + 1];
            ans = gmax(ans, t);
            }
        }

    for (i=k; i+k<n+1; i++){
        for (j=k; j+k<m+1; j++){
            int t = lu[i][j] + ru[i][j + 1] + ld[i + 1][m];
            ans = gmax(ans, t);
            }
        }


    printf("%d\n", ans);


    return 0;
    }






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值