最大子段和 最大子矩阵

来源:互联网 发布:网络电视用哪个信号源 编辑:程序博客网 时间:2024/04/27 13:52

最大和

时间限制:1000 ms  |  内存限制:65535 KB
难度:5
描述

给定一个由整数组成二维矩阵(r*c),现在需要找出它的一个子矩阵,使得这个子矩阵内的所有元素之和最大,并把这个子矩阵称为最大子矩阵。 
例子:
0 -2 -7 0 
9 2 -6 2 
-4 1 -4 1 
-1 8 0 -2 
其最大子矩阵为:

9 2 
-4 1 
-1 8 
其元素总和为15。 

输入
第一行输入一个整数n(0<n<=100),表示有n组测试数据;
每组测试数据:
第一行有两个的整数r,c(0<r,c<=100),r、c分别代表矩阵的行和列;
随后有r行,每行有c个整数;
输出
输出矩阵的最大子矩阵的元素之和。
样例输入
14 40 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 
样例输出
15
来源
[苗栋栋]原创


思路:

  首先,这个子矩阵可以是任意大小的,而且起始点也可以在任何地方,所以,要把最大子矩阵找出来,我们要考虑多种情况。

  假定原始矩阵的行数为M,那么对于子矩阵,它的行数可以是1到M的任何一个数,而且,对于一个K行(K < M)的子矩阵,它的第一行可以是原始矩阵的第1行到 M - K + 1 的任意一行。

在讲在一个特殊情况下求最大子矩阵之前,先讲一个事实:

假设这个最大子矩阵的维数是一维,要找出最大子矩阵, 原理与求“最大子段和问题” 是一样的。最大子段和问题的递推公式是 b[j]=max{b[j-1]+a[j], a[j]},b[j] 指的是从0开始到j的最大子段和。


    为了找出在原始矩阵里的最大子矩阵,我们要遍历所有的子矩阵的可能情况,也就是说,我们要考虑这个子矩阵有可能只有1行,2行,。。。到n行。而在每一种情况下,我们都要把它所对应的矩阵部分上下相加才求最大子矩阵(局部)。

比如,假设子矩阵是一个3*k的矩阵,而且,它的一行是原始矩阵的第二行,那么,我们就要在

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

里找最大的子矩阵。

如果把它上下相加,我们就变成了 4, 11, -10,1, 从这个数列里可以看出,在这种情况下,最大子矩阵是一个3*2的矩阵,最大和是15.

为了能够在原始矩阵里很快得到从 i 行到 j 行 的上下值之和,我们这里用到了一个辅助矩阵,它是原始矩阵从上到下加下来的。


#include<cstdio>#include<iostream>#include<cstring>using namespace std;#define N 105int maxsum(int n,int a[N]){int sum=a[0],b=a[0],i;for(i=1;i<n;++i){if(b>0)b+=a[i];elseb=a[i];if(b>sum)sum=b;}return sum;}int maxsum1(int m,int n,int a[N][N]){int sum1=-999999999;int b[N];int i,j,k;for(i=0;i<m;++i){memset(b,0,sizeof(b));for(j=i;j<m;++j){for(k=0;k<n;++k)b[k]+=a[j][k];int max=maxsum(n,b);if(max>sum1)sum1=max;}}return sum1;}int main(){int n,a[N][N];cin>>n;while(n--){int r,c;cin>>r>>c;for(int i=0;i<r;++i)for(int j=0;j<c;++j)cin>>a[i][j];cout<<maxsum1(r,c,a)<<endl;}}


原创粉丝点击