问题:
例如:3*3的矩阵:
-1 3 -1
2 -1 3
-3 1 2
和最大的子矩阵是:
3 -1
-1 3
1 2
第2 - N + 1行:矩阵中的元素,每行M个数,中间用空格隔开。(-10^9 <= M i i <= 10^9)
3 3 -1 3 -1 2 -1 3 -3 1 2
7
思路:
这个题其实是最大子段和的一个拓展,我们把矩阵按行分为若干个子矩阵,例如一个3*3的矩阵,就被分成了第一行,第二行,第三行,第一二行,第二三行...这么多矩阵,这些子矩阵肯定是包含最大子矩阵的,又例如,假设最大子矩阵位于该矩阵的第1行到第二行,第二列到第三列(也就是右上角的四个数),那么前边按行分的子矩阵中第一二行的子矩阵就包含了最大子矩阵,只是比最大子矩阵多了第一列,这样既然二者是包含关系,那么最大子矩阵所在的按行分的子矩阵和肯定也是最大的,最大子矩阵由于行,列都未知,不易列举,但按行划分的矩阵就好列举了。那么怎么求按行分的子矩阵和呢?这就用到了最大子段和的思路:对每一个按行划分的子矩阵,把每一列都加起来,得到一个序列,求这段序列的最大子段和,然后从这几个和中找出最大的,就得到答案了。
代码:
#include <stdio.h>
#include <stdlib.h>
int maxseq(long int a[],long int n)//求最大子段和
{
long int now,max;
int i;
max=now=a[0];
for(i=1; i<n; i++)
{
if(now<=0)
now=a[i];
else
now+=a[i];
if(now>max)
max=now;
}
return max;
}
int main()
{
int i,j,k,m,n;
long int ju[500][500],a[500],max_m,max_s;//a数组记录按列相加后的序列
while(scanf("%d%d",&m,&n)!=EOF)
{
max_m=0;
for(i=0; i<n; i++)
for(j=0; j<m; j++)
scanf("%ld",&ju[i][j]);
for(i=0; i<n; i++)
{
for(k=0; k<m; k++)
a[k]=0;//a数组初始化
for(j=i; j<n; j++)//和上上个循环一起将矩阵按行分开
{
for(k=0; k<m; k++)
a[k]+=ju[j][k];//按列相加
max_s=maxseq(a,m);
if(max_s>max_m)
max_m=max_s;
}
}
if(max_m<0)
max_m=0;
printf("%ld\n",max_m);
}
return 0;
}