标签:uva
题意:
有一个长方体,有A*B*C(我们算做长宽高吧)小块组成,每块小块有它的价值,正负都行,问找一块子长方体,价值最大;
思路:
首先我们要先预处理价值g[i][j][k],表示从高为k,即第k层长到i,宽到j那一块总价值;
我们可以知道g[i][j][k] += g[i-1][j][k] + g[i][j-1][k] - g[i-1][j-1][k];意思就是这一块的价值,等于长减一那一块,加上宽减一那一块,这时候中间算了两次,所以要减掉中间;
知道这个之后我们就可以枚举A,B的起点和终点;
然后递推计算C的起点和终点去何值是价值最大;
其中sum函数表示以枚举出的长宽,计算出endC这一层的价值,在endC++,计算下一层,叠加;如果叠加后的结果是负的,那么就要从startC那一层开始,一层层往下减,知道变为正的,或者全部都减掉位置(这里和最大连续和是一样的);
这样我们就把三维化为二维,知道每一层的价值,去算最大连续和:
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll INF = (ll)1 << 60; const int N = 25; ll g[N][N][N]; int a,b,c; ll sum(int startA, int endA, int startB, int endB, int C) { return g[endA][endB][C] - g[startA - 1][endB][C] - g[endA][startB - 1][C] + g[startA - 1][startB - 1][C]; } int main() { int t; scanf("%d",&t); while(t--) { memset(g, 0 , sizeof(g)); scanf("%d%d%d",&a,&b,&c); for(int i = 1 ; i <= a ;i++) { for(int j = 1; j <= b ; j++) { for(int k = 1 ; k <= c ;k++) { scanf("%lld",&g[i][j][k]); g[i][j][k] += (g[i - 1][j][k] + g[i][j - 1][k] - g[i - 1][j - 1][k]); } } } ll ans = -INF; for(int startA = 1 ; startA <= a ; startA++) { for(int endA = startA ; endA <= a ;endA++) { for(int startB = 1; startB <= b; startB++) { for(int endB = startB ; endB <= b; endB++) { int startC = 1; int endC = 1; ll m = 0; while(endC <= c) { m += sum(startA, endA, startB, endB, endC); if(m > ans) ans = m; while(m < 0 && startC <= endC) { m -= sum(startA, endA, startB, endB, startC); startC++; if(startC <= endC && m > ans) ans = m; } endC++; } } } } } printf("%lld\n",ans); if(t) printf("\n"); } }
标签:uva
原文地址:http://blog.csdn.net/yeyeyeguoguo/article/details/43676433