从里面任意截取一个矩阵,使得矩阵所包含的数字的和最大.
首先考察该题的简化版:已知一列数,求任意连续若干个数和的最大值。
因为是连续若干个自然数的和,那前面的某个数字取与不取的条件在于:以前面这个数字为结尾的连续数的和最大值是否大于0。如果大于0,那么这个数字必然要会出现在包括数字的序列中,否则无法做到最大。
处理的原则是maxn[i]=max{0,maxn[i-1]}+a[i];
现在再来看看多列数字,我们可以将多列数字转换成单列数字来做! 可以这样设想,结果是一个长方形,我们把他压扁,使得宽为1。
引入辅助数组st,st[i][j]代表第i列从第1行开始的数字累加到第j行的值。那么,我们每次压扁的时候,就可以用st[i][j]-st[i][k-1]来表示第i列从第k个数字累加到第j个数字的值。达到压缩的效果。然后用上面单列数字的方法来做。算法时间复杂度O (N^3)。
#include "stdio.h"
#include "string.h"
#define N 101
int f[N][N];
int v[N][N];
int main()
{
int n , i , j , k , max_sub , sum , curr_max;
scanf("%d",&n);
for( i = 0 ; i < n ; i++ )
for( j = 0 ; j < n ; j++ )
scanf("%d",&v[i][j]);
memset(f,0,sizeof(f));
max_sub = 0;
for( i = 0 ; i < n ; i++ )
{
for( j = i+1 ; j < n+1 ; j++ )
{
curr_max = 0 ;
sum = 0 ;
for( k = 0 ; k < n ; k++ )
{
f[k][j] = f[k][j-1] + v[k][j-1];
sum += f[k][j] - f[k][i]; //相当于找一列的最大值
if(sum < 0)
sum = 0;
if(sum > curr_max)
curr_max = sum;
}
if(curr_max > max_sub)
max_sub = curr_max;
}
}
printf("%d\n",max_sub);
return 0;
}
另外一个code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(){
int a[105][105];
int b[105];
int i,j,p,q,max=-9999,num,k;
scanf("%d",&num);
for(i=1;i<=num;i++)
for(j=1;j<=num;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=num;i++)
for(j=i;j<=num;j++)
{
memset(b,0,sizeof(b));
for(p=1;p<=num;p++)
for(q=i;q<=j;q++)
b[p]+=a[q][p]; //记录了一列中i到j的值
for(k=1;k<=num;k++)
if(b[k]>0)
b[k+1]+=b[k];
for(k=1;k<=num;k++)
if(b[k]>max)
max=b[k];
}
printf("%d\n",max);
}