易保研机试训练营-基础营|动态规划|D - To the Max

Problem

Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1 x 1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.

As an example, the maximal sub-rectangle of the array:

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2

is in the lower left corner:

9 2
-4 1
-1 8

and has a sum of 15.

Input

The input consists of an N x N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N 2 integers separated by whitespace (spaces and newlines). These are the N 2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].

Output

Output the sum of the maximal sub-rectangle.

Example

Input

4
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2

Output

15

正确代码

	/*很难想到,这居然是一道动态规划题
	1、最大子字段和
	题目可以转化为两个子问题:
	1,给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a+a+…+a[j]的子段和的最大值。
	当所给的整均为负数时定义子段和为0,依此定义,所求的最优值为Max{0,a+a+…+a[j]},1<=i<=j<=n
	我们把b[j]理解为从前面某项开始包含a[j](a[j]为最后一个元素)的连续的段的和最大值,易知,开始的a[i]必定为正数!
    记b[j]=max(a+..+a[j-1]+a[j]),其中1<=i<=j<=n,需要明确的一点是b[j]的值必须包含a[j]。则
	所求的最大子段和为max{b[j]},1<=j<=n。
	由b[j]的定义可易知,当b[j-1]>0时(即前面的段加上a[j]这一段值会更大,自然把a[j]这一段接上)b[j]=b[j-1]+a[j],
	否则(由于前面的段为负值,加上a[j],会使值变小,这样的话,我们将前面的段去掉,a[j]即是最大值)b[j]=a[j]。
	故b[j]的动态规划递归式为 b[j]=Max(b[j-1]+a[j],a[j]),1<=j<=n。
	2、最大子矩阵和
	矩阵是二维的,将其压缩成一维就可以用上面的方法求出最大子矩阵和了
    即将一层层的数相加,压缩成一维的即可,我们遍历所有的压缩可能,就可以通过上面的方法,求出最大值!
	*/ 
#include 
#include 
#include 
using namespace std;
int Map[101][101];
int sum[101], dp[101];
int main()
{
	int i, j, k, p, n;
	while(scanf("%d", &n) != EOF)
	{  
		int Max = -200;
		memset(dp, 0, sizeof(dp));
		for(i = 0; i < n; i++)
			for(j = 0; j < n; j++)
				cin >> Map[i][j];
		for(i = 0; i < n; i++)//确定起始行 
		{
			memset(sum,0,sizeof(sum));
			for(k = i; k < n; k++)//确定终止行 
			{
				for(j = 0; j < n; j++)//确定列数 
					sum[j] = Map[k][j] + sum[j];//在上面若干行压缩后的结果上增加本行 
				// 最大子字段和
				dp[0] = sum[0];
				for(p = 1; p < n; p++)
				{
					if (dp[p-1] > 0) 
						dp[p] = dp[p-1] + sum[p];
                    else 
						dp[p] = sum[p];
                    if (dp[p] > Max) 
						Max = dp[p];
				}	
			}
		}
		cout<<Max<<endl;
	}
	return 0;
}

你可能感兴趣的:(VJudge)