校oj 题目

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84799559

问题 H: 吃西瓜

时间限制: 1 Sec  内存限制: 256 MB
提交: 9  解决: 7
[提交][状态][讨论版][命题人:外部导入]

题目描述

 

【问题描述】

老胡买了是长方体形的西瓜来犒劳大家....

这块西瓜长m厘米,宽n厘米,高h厘米.他发现如果把这块西瓜平均地分成m*n*h块1立方厘米的小正方体,那么每一小块都会有一个营养值(可能为负,因为西瓜是有可能坏掉的,但是绝对值不超过200)。

现在老胡决定从这m*n*h立方厘米的西瓜中切出mm*nn*hh(0<=mm<=m,0<=nn<=n,0<=hh<=h)立方厘米的一块小西瓜(一定是立方体形,长宽高均为整数),送给该场比赛最高分获得者补充营养。他想知道他最多能获得多少营养值。

换句话说,我们希望从一个m*n*h的三维矩阵中,找出一个三维子矩阵,这个子矩阵的权和最大.

 

一个2*3*4的例子,最优方案为切红色2*3*1部分。

【文件输入】matrix.in

扫描二维码关注公众号,回复: 4491807 查看本文章

首行三个正整数h,m,n(注意顺序),分别表示西瓜的高,长,宽.

以下h部分,每部分是一个m*n的矩阵,第i部分第j行的第k个数表示西瓜第i层,第j行第k列的那块1立方厘米的小正方体的营养值.

【文件输出】matrix.out

老胡所能得到的最大营养值

【输入输出样例】

matrix.in

matrix.out

2 3 4

4 1 2 8

0 5 -48 4

3 0 1 9

2 1 4 9

1 0 1 7

3 1 2 8

45

【数据规模】

对于30%的数据,h=1,1<=m,n<=10

对于全部的数据,1<=h<=32,1<=m,n<=50,保证h<=m,n

[说明]此题中出现的所有数全为整数。

 

 

不清楚老师从哪里找的,但是是道好题。。。问了问学长终于构思出dp方案来了。。。

 

本题是从求最大矩阵权值和的基础上,发展成求最大立方体权值和。。。可以从二维推出三维

首先 我们看一下二维

只需要枚举矩阵的 左上角和右下角 假设 设左上为 a[ sx ] [ sy ]

右下为 a[ ex ] [ ey ](当然构造一下前缀和。。更加优秀一些)

那么根据容斥定理

s[ ex ] [ ey ]  = a[ ex ] [ ey ]  - s[ sx-1 ] [ ey ] - s[ ex ] [ sy - 1 ] + s[ sx-1 ] [ sy -1]

那么拓展到三维空间啊,我们不久只需要 先对二维空间进行一下这种处理,然后再拓展到三维空间

即现在二维里找到一个最大矩阵,之后对空间内相邻的二维矩阵之和进行判断,看一下是否会比原来单独的更大,来更新一下数值,那么这样跑一下大概就可以了 首先求二维 耗时大概 O(n^2 * m^2)

再加上一个 高度 h 的话

耗时就是 O(n^2 * m^2 * h) 本题是可以过得。。。(当然 让 h 去变成 h^2 肯定对于本题更快)

 

以下就是 AC 代码了。

#include<iostream>
#include<cstdio>
using namespace std;
const int INF = 0x3f3f3f3f;
int h,m,n;
int s[51][51][51],a[51][51][51];
int dp[51][51][51][51];
int ans;
int main()
{
    scanf("%d%d%d",&h,&m,&n);
    for (int i=1;i<=h;i++)
        for (int j=1;j<=m;j++)
            for (int k=1;k<=n;k++)
            {
                scanf("%d",&a[i][j][k]);
                s[i][j][k] = s[i][j-1][k] + s[i][j][k-1] - s[i][j-1][k-1] + a[i][j][k];
            }
    ans = -INF;
    for (int sj=1;sj<=m;sj++)
        for (int sk=1;sk<=n;sk++)
            for (int ej=sj;ej<=m;ej++)
                for (int ek=sk;ek<=n;ek++)
                {
                    dp[sj][sk][ej][ek] = -INF; // 构造维护一个矩阵最大权值和 dp 
                    for (int i=1;i<=h;i++)
                    {
                        int tem = s[i][ej][ek] - s[i][sj-1][ek] - s[i][ej][sk-1] + s[i][sj-1][sk-1];
                        dp[sj][sk][ej][ek] = max(dp[sj][sk][ej][ek]+tem, tem);
                        ans = max(ans, dp[sj][sk][ej][ek]);
                    }
                }
    printf("%d\n",ans);
    return 0;
}

看懂了就不太难。。主要是只要明白了如何求最大二维矩阵,这道只要推广一下就好了

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/84799559
今日推荐