NOI 2.6 动态规划 1768:最大子矩阵

题目来源:http://noi.openjudge.cn/ch0206/1768/

1768:最大子矩阵

总时间限制1000ms   内存限制65536kB

描述

已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵。

比如,如下4 * 4的矩阵

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


的最大子矩阵是

9 2
-4 1
-1 8


这个子矩阵的大小是15

输入

输入是一个N* N的矩阵。输入的第一行给出N (0 < N <= 100)。再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行)。已知矩阵中整数的范围都在[-127,127]

输出

输出最大子矩阵的大小。

样例输入

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

8  0 -2

样例输出

15

来源

翻译自Greater New York 2001 的试题

-----------------------------------------------------

解题思路

动态规划

是最大子段(连续子列)和的二维推广

把矩阵投影到行,相当于求N*(N+1)/2个最大子段和的最大值

最大子段和dp[j]: arr[j]为结尾的最大子段和

dp[j] =max(dp[j-1]+arr[j], arr[j])

整个数组的最大子段和就是max(dp[j]), j=0,1,...,n-1

解释:如果dp[j-1]<0, 则加上0~j-1中的数反而会减小0~j的子段和,因此dp[j] = arr[j];

如果dp[j-1]>=0, 因为子段要求连续,因此以arr[j]结尾的子段如果要包含arr[0]~arr[j-1]的话必须要包含arr[j-1],而dp[j-1]又是0~j-1的最大子段,因此dp[j] =dp[j-1]+arr[j]

-----------------------------------------------------

代码

// 动态规划
// 向行或列做投影,转化为N*(N+1)/2个一维数组最大子段和问题
// 最大连续子列
// dp[i]: 以a[i]为结尾的最大子段和
// dp[i] = max(dp[i-1]+a[i], a[i])

#include
#include
using namespace std;

const int NMAX = 105, NEG_INF = -(1<<30);
int mat[NMAX][NMAX] = {};			// mat[i][j]: 前i行第j列求和(投影到行)
int arr[NMAX] = {};					// 第i行到第j行之间的行和
int dp[NMAX] = {};					// dp[j]: 第i行到第j行之和对应的一维数列的以arr[j]为结尾的最大子段和

int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0206_1768.txt");
	int n,i,j,k,tmp,mymax;
	fin >> n;
	for (i=0; i> tmp;
			for (k=i+1; k<=n; k++)
			{
				mat[k][j] += tmp;
			}
		}
	}
	fin.close();
	if (n==1)
	{
		cout << mat[1][0];
		return 0;
	}
	mymax = NEG_INF;
	for (i=0; i> n;
	for (i=0; i> tmp;
			for (k=i+1; k<=n; k++)
			{
				mat[k][j] += tmp;
			}
		}
	}
	if (n==1)
	{
		cout << mat[1][0];
		return 0;
	}
	mymax = NEG_INF;
	for (i=0; i

 

 

 

你可能感兴趣的:(NOI)