【吃西瓜】解题报告

题目描述

[说明]此题中出现的所有数全为整数
[背景]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的三维矩阵中,找出一个三维子矩阵,这个子矩阵的权和最大.

一个2*3*4的例子,最优方案为切红色2*3*1部分
[数据范围]
对于30%的数据,h=1,1<=m,n<=10
对于全部的数据,1<=h<=32,1<=m,n<=50,保证h<=m,n

输入格式

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

输出格式

SubRaY所能得到的最大营养值


这个是一个加强版的最大子矩形和,处理方法和普通的几乎一样。

只是在最外层多加了两层循环,枚举另外两个边界。

同时前缀和变成了三维前缀和。


//#include <iostream>
//using std::cout;
//using std::cin;
#include <cstdio>
const long oo = 0x7fff0000;


long h;long m;long n;
long num[34][52][52];


int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	
	scanf("%ld%ld%ld",&h,&m,&n);
	for (long i=1;i<h+1;i++)
	{
		for (long j=1;j<m+1;j++)
		{
			for (long k=1;k<n+1;k++)
			{
				scanf("%ld",&num[i][j][k]);
			}
		}
	}
	for (long i=1;i<h+1;i++)
	{
		for (long j=1;j<m+1;j++)
		{
			for (long k=1;k<n+1;k++)
			{
				num[i][j][k]+=num[i][j][k-1];
			}
		}
	}
	for (long i=1;i<h+1;i++)
	{
		for (long j=1;j<m+1;j++)
		{
			for (long k=1;k<n+1;k++)
			{
				num[i][j][k]+=num[i][j-1][k];
			}
		}
	}
	
	long ans = -oo;
	for (long i=1;i<m+1;i++)
	{
		for (long j=i;j<m+1;j++)
		{
			for (long k=1;k<n+1;k++)
			{
				for (long l=k;l<n+1;l++)
				{
					long x = num[1][j][l]-num[1][j][k-1]-num[1][i-1][l]+num[1][i-1][k-1];
					long max = x;
					if (ans<max)
					{
						ans = max;
					}
					for (long p=2;p<h+1;p++)
					{
						x = num[p][j][l]-num[p][j][k-1]-num[p][i-1][l]+num[p][i-1][k-1];
						if (max>0)
						{
							max += x;
						}
						else
						{
							max = x;
						}
						if (ans<max)
						{
							ans = max;
						}
					}
				}
			}
		}
	}
	printf("%ld",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值