【动态规划】采油区域

原创 2012年03月30日 08:10:06

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
此题考察动态规划算法。
最开始的方法有反例。
状态:用f[k][i][j]表示从(1, 1)到(i, j)这个矩形中
选取k个正方形所能得到的最大价值。

转移方程:f[k][i][j] = max{f[k - 1][i][j - k],
                           f[k - 1][i - k][j])
                     + square(i - k, j - k, i, j),
反例如图:

当k=3的时候显然不成立。

正解:首先预处理出每个点到左上、左下、右上、右下这四个角落所在矩形中选一个小正方形所能达到的最大值,以及以各条横线和竖线为下边界和右边界的正方形中所能达到的最大值。


然后枚举分割线,分6种情况考虑,分别如图所示:

取所有情况中的最大值即可。
Accode:

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <string>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define max3(a, b, c) (max((a), max(b, c)))

const char fi[] = "oil.in";
const char fo[] = "oil.out";
const int maxN = 1510;
const int MAX = 0x3f3f3f3f;
const int MIN = ~MAX;

int sum[maxN][maxN];
int zoxx[maxN][maxN]; // Left and below.
int zouh[maxN][maxN]; // Left and above.
int yzxx[maxN][maxN]; // Right and below.
int yzuh[maxN][maxN]; // Right and above.
int hh[maxN]; // Horizon.
int lp[maxN]; // Vertical.
int n, m, K;

void init_file()
{
    freopen(fi, "r", stdin);
    freopen(fo, "w", stdout);
    return;
}

inline int getint()
{
    int res = 0; char tmp;
    while (!isdigit(tmp = getchar()));
    do res = (res << 3) + (res << 1) + tmp - '0';
    while (isdigit(tmp = getchar()));
    return res;
}

void readdata()
{
    n = getint(); m = getint(); K = getint();
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < m + 1; ++j)
        (sum[i][j] = getint()) += sum[i][j - 1];
    for (int i = 1; i < n + 1; ++i)
    for (int j = 1; j < m + 1; ++j)
        sum[i][j] += sum[i - 1][j];
	//预处理出二维的前缀和。
    for (int i = K; i < n + 1; ++i)
    for (int j = K; j < m + 1; ++j)
    {
        zouh[i][j] = sum[i][j]
                   + sum[i - K][j - K]
                   - sum[i][j - K]
                   - sum[i - K][j];
        hh[i] = max(hh[i], zouh[i][j]); //Horizon.
        lp[j] = max(lp[j], zouh[i][j]); //Vertical.
        zouh[i][j] = max3(zouh[i][j],
                         zouh[i - 1][j],
                         zouh[i][j - 1]);
    } // Left and above.

    for (int i = n - K + 1; i; --i)
    for (int j = m - K + 1; j; --j)
        yzxx[i][j] = max3(sum[i - 1][j - 1]
                          + sum[i + K - 1][j + K - 1]
                          - sum[i - 1][j + K - 1]
                          - sum[i + K - 1][j - 1],
                          yzxx[i + 1][j],
                          yzxx[i][j + 1]);
    //Right and below.

    for (int i = K; i < n + 1; ++i)
    for (int j = m - K + 1; j; --j)
        yzuh[i][j] = max3(sum[i][j + K - 1]
                          + sum[i - K][j - 1]
                          - sum[i][j - 1]
                          - sum[i - K][j + K - 1],
                          yzuh[i - 1][j],
                          yzuh[i][j + 1]);
    //Right and above.

    for (int i = n - K + 1; i; --i)
    for (int j = K; j < m + 1; ++j)
        zoxx[i][j] = max3(sum[i - 1][j - K]
                          + sum[i + K - 1][j]
                          - sum[i - 1][j]
                          - sum[i + K - 1][j - K],
                          zoxx[i + 1][j],
                          zoxx[i][j - 1]);
    //Left and below

    return;
}

void work()
{
    int ans = 0;
    for (int i = K; i < n - (K << 1); ++i)
        ans = max(ans, yzuh[i][1]
                  + hh[i + K]
                  + yzxx[i + K + 1][1]);
	// Case 1.
    for (int j = K; j < m - (K << 1); ++j)
        ans = max(ans, zoxx[1][j]
                  + lp[j + K]
                  + yzxx[1][j + K + 1]);
	// Case 2.
    for (int i = K; i < n - K + 1; ++i)
    for (int j = K; j < m - K + 1; ++j)
    {
        ans = max3(ans, zouh[i][j]
                  + yzuh[i][j + 1]
                  + yzxx[i + 1][1], //Case 3.
                  yzuh[i][1]
                  + zoxx[i + 1][j]
                  + yzxx[i + 1][j + 1]); //Case 4.
        ans = max3(ans, zouh[i][j]
                  + zoxx[i + 1][j]
                  + yzxx[1][j + 1], //Case 5.
                  zoxx[1][j]
                  + yzuh[i][j + 1]
                  + yzxx[i + 1][j + 1]); //Case 6.
    }
    printf("%d\n", ans);
    return;
}

int main()
{
    init_file();
    readdata();
    work();
    return 0;
}

#undef max

采油区域-APIO 2009

算法训练 采油区域   时间限制:2.0s   内存限制:512.0MB   采油区域  Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油...
  • wximo
  • wximo
  • 2014年05月19日 21:30
  • 2077

【动态规划】采油区域

采油区域 Siruseri 政府决定将石油资源丰富的 Navalur 省的土地拍卖给私人承包商以 建立油井。被拍卖的整块土地为一个矩形区域,被划分为M×N 个小块。 Siruseri地质调查...

蓝桥杯练习系统OJ题解目录

基础练习 蓝桥杯 BASIC-27 基础练习 2n皇后问题 蓝桥杯 BASIC-18 基础练习 矩形面积交 蓝桥杯BASIC-28 基础练习 Huffuman树 蓝桥杯 BASIC-21 基础练习 ...
  • liuchuo
  • liuchuo
  • 2016年08月04日 02:05
  • 1508

【APIO2009T1】采油区域-分类讨论+动态规划

【APIO2009T1】采油区域-分类讨论+动态规划

【花样枚举】bzoj 1177 apio2009采油区域

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1177 题目大意:给你一个矩阵,让你选出三个边长为k且互不重叠的正方形使得所有正方形内的数...

采油区域-APIO 2009

算法训练 采油区域   时间限制:2.0s   内存限制:512.0MB   采油区域  Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油...
  • wximo
  • wximo
  • 2014年05月19日 21:30
  • 2077

【花样枚举】bzoj 1177 apio2009采油区域

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1177 题目大意:给你一个矩阵,让你选出三个边长为k且互不重叠的正方形使得所有正方形内的数...

动态规划 源码

  • 2017年10月31日 10:51
  • 12KB
  • 下载

利用动态规划解决实际问题之多次兑换获取最大外汇收益

动态规划问题之多次兑换货币获取最大收益实例
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【动态规划】采油区域
举报原因:
原因补充:

(最多只允许输入30个字)