NOI 4.6 1768:最大子矩阵(最大字段和,动态规划)

题目来源:http://noi.openjudge.cn/ch0406/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[i]: 子段[i,n)的和

dp[i] = max(dp[i+1] + arr[i], arr[i])

其中在求n*(n+1)/2个数组的时候有技巧:

如果把正常输入矩阵的每个元素,再计算n*(n+1)/2个行和,复杂度为O(n^4),

如果在输入的时候直接计算从第j列上从第0行到第i行的元素的和(mat[i][j]),那么第j列上从第i行到第k行的元素和就等于mat[k][j] – mat[i][j],这样两次计算每次复杂度都是O(n^3).

优化的代码参见博文NOI 2.6 动态规划 1768:最大子矩阵

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

代码

// 最大子段和的二维扩展
// 求n*(n+1)/2个最大子段和求最值
// 最大子段和 dp[i]: 子段[i,n)的和
// dp[i] = max(dp[i+1] + arr[i], arr[i])

#include<iostream>
#include<fstream>
#include<cstring>
using namespace std;

const int NMAX = 105;
int mat[NMAX][NMAX] = {};
int arr[NMAX] = {};
int dp[NMAX] = {};

int max_seg(int *arr, int n)					// 输入长度为n的数组arr,返回最大子段和(DP)
{
	int i,mymax;
	if (n==1)
	{
		return arr[0];
	}
	dp[n-1] = arr[n-1];
	for (i=n-2; i>=0; i--)
	{
		dp[i] = max(dp[i+1]+arr[i], arr[i]);
	}
	mymax = dp[0];
	for (i=1; i<n; i++)
	{
		mymax = max(dp[i], mymax);
	}
	return mymax;
}


int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0406_1768.txt");
	int n,i,j,k,l,ans,mymax;
	fin >> n;
	for (i=0; i<n; i++)
	{
		for (j=0; j<n; j++)
		{
			fin >> mat[i][j];
		}
	}
	fin.close();
	mymax = mat[0][0];
	for (i=0; i<n; i++)
	{
		for (j=i; j<n; j++)
		{
			memset(arr, 0, sizeof(arr));
			for (k=0; k<n; k++)
			{
				for (l=i; l<=j; l++)
				{
					arr[k] += mat[l][k];
				}
			}
			ans = max_seg(arr,n);
			mymax = max(ans,mymax);
		}
	}
	cout << mymax;
	return 0;
#endif
#ifdef ONLINE_JUDGE
	int n,i,j,k,l,ans,mymax;
	cin >> n;
	for (i=0; i<n; i++)
	{
		for (j=0; j<n; j++)
		{
			cin >> mat[i][j];
		}
	}
	mymax = mat[0][0];
	for (i=0; i<n; i++)
	{
		for (j=i; j<n; j++)
		{
			memset(arr, 0, sizeof(arr));
			for (k=0; k<n; k++)
			{
				for (l=i; l<=j; l++)
				{
					arr[k] += mat[l][k];
				}
			}
			ans = max_seg(arr,n);
			mymax = max(ans,mymax);
		}
	}
	cout << mymax;
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80755613
4.6