Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 49427 | Accepted: 26194 |
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
题意:题意很容易看懂,就是让你求这个矩阵的一个子矩阵使得它的和最大。
思路:由此我们可以想到一维的序列,如果求一维的子序列,我们可以很容易的得出状态转化方程:
dp[i]=(dp[i-1]>0?dp[i-1]:0)+a[i];
好好理解上边的方程就可以得出下面的代码:一维的:
#include<cstdio>
#include<iostream>
#include<climits>
using namespace std;
const int MAX=1000010;
int a[MAX]={0};
int main()
{
int n,m,maxsum;
scanf("%d",&n);
while(n--)
{
maxsum=-INT_MAX;
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%d",&a[i]);
if(a[i-1]>0) a[i]+=a[i-1];
if(a[i]>maxsum) maxsum=a[i];
}
printf("%d\n",maxsum);
}
}
在这里我们可以解决掉一维的问题了,二维的问题其实就是转化成一维来解决。
不过我这个智商说是说不清楚,来看一下这位大神的解释:
下面扩展到二维的情况:考察下面题目中的例子:
0 -2 -7 0
9 2 -6 2
-4 1 -4 7
-1 8 0 -2
我们分别用i j表示起始行和终止行,遍历所有的可能:
for(i=1;i<=n;i++)
for(j=i;j<=n;j++) {}
我们考察其中一种情况 i=2 j=4,这样就相当与选中了2 3 4三行,求那几列的组合能获得最大值,由于总是 2 3 4行,所以我们可以将这3行”捆绑”起来,变为求 4(9-4-1),11(8+2+1),-10(-6-4+0),7(7+2-2)的最大子段和,ok,问题成功转化为一维的情况!
来,代码贴起来
按大神的思路可以得到以下的代码:(是本题的一个答案)
#include<iostream>
#include<cstring>
using namespace std;
#define N 110
#define inf 0x3f3f3f3f
int a[N][N];
int b[N];
int main(){
int n,r;
cin>>r;
for(int i=1;i<=r;++i)
for(int j=1;j<=r;++j)
{
cin>>a[i][j];
a[i][j]+=a[i-1][j];
}
int max=-1*inf;
for(int i=1;i<=r;++i)
for(int j=i+1;j<=r;++j)
{
memset(b,0,sizeof(b));
for(int k=1;k<=r;++k)
{
if(b[k-1]>=0)
b[k]=b[k-1]+a[j][k]-a[i][k];
else
b[k]=a[j][k]-a[i][k];
if(max<b[k])
max=b[k];
}
}
cout<<max<<endl;
return 0;
}
在这里还有一种写法:
dp[i][j][k]表示在从0到i行,从j到k行的最大和
可以得到dp[i][j][k]=max(dp[i-1][j][k]+sum,sum)的状态转化方程,sum是第i行从j列到k列的和由此我们可以得到以下这种写法。思路和上边的一样
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define N 105
#define inf 0x3f3f3f3f
using namespace std;
int a[N][N],dp[N][N][N];
int n;
int main()
{
int i,j,k;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
int ans=-1*inf;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
int sum=0;
for(k=j;k<=n;k++)
{
sum+=a[i][k];
dp[i][j][k]=max(dp[i-1][j][k]+sum,sum);
if(dp[i][j][k]>ans) ans=dp[i][j][k];
}
}
}
printf("%d\n",ans);
return 0;
}