HDOJ 1081 POJ 1050 ZOJ 1074 TO THE MAX【dp】
题意一句话:给你一个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;
}