1. 程式人生 > >校oj 題目

校oj 題目

問題 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

首行三個正整數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;
}

看懂了就不太難。。主要是隻要明白瞭如何求最大二維矩陣,這道只要推廣一下就好了