题意一句话:给你一个n*n的矩阵,求其中的最大子矩阵和


先考虑1*n的矩阵怎么求:就是一行的数怎么求:

从前往后dp对吧:对于当前第i个数,我们选,是因为加上前面的值仍然大于0,即(5,-3……)这种情况,-3是要选的,因为5-3=2>0

否则的话,把前面那一部分舍弃掉,只取当前的值,因为加起来小于0对求最大值没有意义

每选择一个数,就比较一次最大值就可以了


那么现在来考虑n*n的

我们可以枚举起始行i和起始行j,然后把从第i行的值到第j行的值压缩成一行,那么就是求1*n的矩阵的最大值了

枚举i,j,k是三重循环,在复杂度里面,那么应该怎么压缩呢?!


前缀和!提前把每一列的和存到sum值里就好了


所以这个题的思路出来了:

先用前缀和压缩值,预处理每一列的值放入sum数组

然后枚举行i和j,注意j>=i

然后枚举列k,用1*n的方法来求压缩后的一行的值



代码如下:

#include<iostream>
#include<cstdio>
#include<stdio.h>
#include<cstdlib>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
using namespace std;

const int maxn=150;
const int INF=0x3f3f3f3f;
int sum[maxn][maxn];
int a[maxn][maxn],n;

void debug(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            printf("%d%c",sum[i][j],j==n?'\n':' ');
}

int main(){
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
        for(int j=1;j<=n;j++){
            sum[1][j]=a[1][j];
            for(int i=2;i<=n;i++)
                sum[i][j]=sum[i-1][j]+a[i][j];
        }
        //debug();
        int ans=-INF;
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j++){
                int tmp=0,tmpans=-INF;
                for(int k=1;k<=n;k++){
                    int num=sum[j][k]-sum[i-1][k];
                    if (tmp+num>=0) tmp+=num;
                    else tmp=num;
                    tmpans=max(tmpans,tmp);
                }
                ans=max(ans,tmpans);
            }
        printf("%d\n",ans);
    }
    return 0;
}