思路说明:
简单的说求最大子矩阵和,先将矩阵转化为一维,然后在一维区间上求最大子区间和
详细解释:
子矩阵在列上可以变化,行上也可以变化
先假定只可以在行上变化,那么我们要看的就是所有1*k,2*k,3*k,......k*k的矩阵
1*k的矩阵有k个,2*k的矩阵有k-2个,.....k*K的矩阵有一个,然后对这些子矩阵考虑列的变化,因为
是矩阵,只要你加1列,各个行都要加上去,所以列是整体变化的,可以用子矩阵该列的和来代替子矩阵
这一列的i个元素(1<=i<=k),那么二维矩阵就被压缩成一维,现在要考虑的就是对于一个行数
确定的子矩阵,如何选取列,这就是一维的最大子区间和问题,动态转移方程很简单,可以写成一个子
模块,因为要枚举, 的子矩阵很多,它要被调用很多次,这(1+2+3...+k)个矩阵构造的一维区间的最
大子区间和的最大值就是最大子矩阵的和
易错点:
又该是初始值设为-INF
个人收获:
对dp的理解加深,感觉自己弱爆了,郭老说周练的题目都是水题,为什么还是不会做?跟不上节奏,哎.........
参考代码:
#include<iostream>
#include<cmath>
using namespace std;
int N;
int submax(int a[],int len)
{
int sub[101];
for(int j=1; j<=len; j++)
{
if( j==1)
sub[1]=a[1];
else
sub[j]=(sub[j-1]>0)?(sub[j-1]+a[j]):a[j];
}
int m=-30000;
for( int i=1; i<=len; i++)
{
if(sub[i]>m)
m=sub[i];
}
return m;
}
int main()
{
int num[101][101];
int sum[101][101];
int total[101][101];
int i,j,row,col;
while(cin>>N)
{
for( i=1; i<=N; i++)
{
for(j=1; j<=N; j++)
cin>>num[i][j];
}
// 为了能够在原始矩阵里很快得到从 i 行到 j 行 的上下值之和,
// 我们这里用到了一个辅助矩阵,它是原始矩阵从上到下加下来的。
for( i=1; i<=N; i++)
{
for(j=1; j<=N; j++)
{
if(i==1)
total[i][j]=num[i][j];
else
total[i][j]=total[i-1][j]+num[i][j];
}
}
int max1=-20000;
for( i=1; i<=N; i++)
{
for(row=i; row<=N; row++)
{
int result[101];
for( j=1; j<=N; j++)
{
if(i==1)
result[j]=total[row][j];
else{
result[j]=total[row][j]-total[i-1][j];
}
}
int t=submax(result,N);
if(t>max1)
max1=t;
}
}
cout<<max1<<endl;
}
}