1、首先考虑一维的最大子段和问题,给出一个序列a[0],a[1],a[2]...a[n],求出连续的一段,使其总和最大。
a[i]表示第i个元素
dp[i]表示以a[i]结尾的最大子段和
dp[i] = max{a[i], dp[i-1] + a[i]}
解释一下方程:
如果dp[i-1] > 0,则 dp[i] = dp[i-1] + a[i]
如果dp[i-1] < 0,则 dp[i] = a[i]
因为不用记录位置信息,所以dp[]可以用一个变量dp代替:
如果dp > 0,则dp += a[i]
如果dp < 0,则dp = a[i]
2、考虑二维的最大子矩阵问题
我们可以利用矩阵压缩把二维的问题转化为一维的最大子段和问题。因为是矩阵和,所以我们可以把这个矩形的高压缩成1,用加法就行了。
恩,其实这个需要自己画图理解,我的注释里写得很详细了,自己看吧。
a[i]表示第i个元素
dp[i]表示以a[i]结尾的最大子段和
dp[i] = max{a[i], dp[i-1] + a[i]}
解释一下方程:
如果dp[i-1] > 0,则 dp[i] = dp[i-1] + a[i]
如果dp[i-1] < 0,则 dp[i] = a[i]
因为不用记录位置信息,所以dp[]可以用一个变量dp代替:
如果dp > 0,则dp += a[i]
如果dp < 0,则dp = a[i]
2、考虑二维的最大子矩阵问题
我们可以利用矩阵压缩把二维的问题转化为一维的最大子段和问题。因为是矩阵和,所以我们可以把这个矩形的高压缩成1,用加法就行了。
恩,其实这个需要自己画图理解,我的注释里写得很详细了,自己看吧。
#include<iostream>
usingnamespace std;
#include<vector>
int temp[101],n;
int map[101][101];
// 求最大字段的和
int max(int *arr,int n){
int max=0,dp=0;
for(int i=0;i<n;i++)
if(dp<0)dp=arr[i];
else {
dp+=arr[i];
if(dp>max)max=dp;
}
return max;
}
int main(){
int N;cin>>N;
int i,j,k;
for(i=0;i<N;i++)
for(j=0;j<N;j++)cin>>map[i][j];
int maxAll=0,maxOne=0;
//一二层的两个循环用来依次将一个二维图压缩成一维数列
for(i=0;i<N;i++){//自上而下
memset(temp,0,sizeof(temp));
for(j=i;j<N;j++){//自上而下
for(k=0;k<N;k++)temp[k]+=map[j][k];//自左到右
maxOne=max(temp,N);
if(maxOne>maxAll)maxAll=maxOne;
}
}
cout<<maxAll<<endl;
return0;
}