Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 37319 | Accepted: 19662 |
Description
As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8
and has a sum of 15.
Input
Output
Sample Input
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
Sample Output
15
Source
题型:DP
题意:找出矩阵中和最大的子矩阵,只需输出最大和的值。
分析:
首先看一下只有一列数的情况,例如:
求下面这一串数的最大和连续子串,对下面这串数作DP:
a--->2 3 -7 2 -1 8
DP--->2 5 -2 2 1 9
因为是连续若干个自然数的和,所以前面的某个数字取与不取的条件就是:以前面这个数字为结尾的连续数的和最大值是否大于0,如果大于0,那么这个数字必然要会出现在包括数字的序列中,否则无法做到最大。
所以 dp[i]=max(0,dp[i-1])+a[i];
然后将dp[]遍历一遍找出最大值即可。
现在推广到二维数组中:
我们可以将二维压成一维,即枚举一段区间,求出其和,以样例为例:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
我们枚举这些行,假如枚举到第二行到第四行
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
每一列的和sum是 4 11 -10 1;
作dp---------------> 4 15 5 6.
所以在第二行到第四行这一段中和最大的子矩阵的和是15。
即 9 2
-4 1
-1 8
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
int main(){
int a[150][150],sum[150],dp[150];
int n;
while(~scanf("%d",&n)){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%d",&a[i][j]);
}
}
int maxn=-1;
for(int i=0;i<n;i++){
memset(sum,0,sizeof(sum));
for(int j=i;j<n;j++){
for(int k=0;k<n;k++){
sum[k]+=a[j][k];
}
dp[0]=sum[0];
for(int k=1;k<n;k++){
dp[k]=max(0,dp[k-1])+sum[k];
}
for(int k=0;k<n;k++){
maxn=max(dp[k],maxn);
}
}
}
printf("%d\n",maxn);
}
return 0;
}