【DP】吃西瓜

【题目描述】

此题中出现的所有数全为整数
SubRaY有一天得到一块西瓜,是长方体形的....
SubRaY发现这块西瓜长m厘米,宽n厘米,高h厘米.他发现如果把这块西瓜平均地分成m*n*h块1立方厘米的小正方体,那么每一小块都会有一个营养值(可能为负,因为西瓜是有可能坏掉的,但是绝对值不超过200).
现在SubRaY决定从这m*n*h立方厘米的西瓜中切出mm*nn*hh立方厘米的一块小西瓜(一定是立方体形,长宽高均为整数),然后吃掉它.他想知道他最多能获得多少营养值.(0<=mm<=m,0<=nn<=n,0<=hh<=h.mm,nn,hh的值由您来决定).
换句话说,我们希望从一个m*n*h的三维矩阵中,找出一个三维子矩阵,这个子矩阵的权和最大.

【输入格式】

首行三个数h,m,n(注意顺序),分别表示西瓜的高,长,宽.以下h部分,每部分是一个m*n的矩阵,第i部分第j行的第k个数表示西瓜第i层,第j行第k列的那块1立方厘米的小正方体的营养值.

【输出格式】

SubRaY所能得到的最大营养值


三维的最大子长方体问题,先将三维图形枚举上下层数转换为平面最大最大子矩阵,再将平面枚举上下行转化为求最大子段和

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
using namespace std;
int n,h,m,a[34][55][55],sum[34][55][55],f[55],b[55][55],ans,dp[55];
int ask()
{
	int maxx=0;
	memset(dp,0,sizeof(dp));
	maxx=f[1],dp[1]=f[1];
	for(int i=2;i<=m;i++)
	{
		dp[i]=max(dp[i-1]+f[i],f[i]);
		if(dp[i]>maxx) maxx=dp[i];
	}
	return maxx;
}
int dps()
{
	int maxx=0;
	for(int i=1;i<=n;i++)
	{
		memset(f,0,sizeof(f));
		for(int j=i;j<=n;j++)
		{
			for(int k=1;k<=m;k++) f[k]+=b[j][k];
			int sum=ask();
			if(sum>maxx) maxx=sum;
		}
	}
	return maxx;
}
int main()
{
	scanf("%d%d%d",&h,&n,&m);
	for(int i=1;i<=h;i++)
	for(int j=1;j<=n;j++)
	for(int k=1;k<=m;k++) scanf("%d",&a[i][j][k]),sum[i][j][k]=sum[i-1][j][k]+a[i][j][k];
	for(int i=1;i<=h;i++)
	{
		for(int j=i;j<=h;j++)
		{
			for(int up=1;up<=n;up++)
			{
				for(int down=1;down<=m;down++)
				{
					b[up][down]=sum[j][up][down]-sum[i-1][up][down];
				}
			}
			int maxx=dps();
			if(maxx>ans) ans=maxx;
		}
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/Dy_Dream/article/details/82999740