最长字段和
数组a[0...n],求出max a[i..j]的和
用dp的思想做 dp[i]表示从a[0]到a[i]的最长子段和,并且肯定包含a[i],则原问题转换成求max dp
dp[i] = max(dp[i-1]+a[i],a[i])
故若dp[i-1]>0,则dp[i] = dp[i-1]+a[i];若dp[i-1]<0,则dp[i]=a[i];
int maxSum(int a[],int N){
int resultSum = 0;
int newSum = 0; //newSum代替dp数组
for(int i = 0; i < N; i++){
if(newSum > 0){
newSum += a[i];
}else{
newSum = a[i];
}
if(newSum > resultSum){
resultSum = newSum;
}
}
return resultSum;
}
最大子矩阵
矩阵是二维的,想办法把二维矩阵压缩成一维就可以转换成最长字段和的问题。
首先考虑行数为1的矩阵,对每行采用最长字段和
考虑行数为2的矩阵,并且把同一列的元素相加,将二维转换成一维
....重复
为了避免重复计算,可以引入辅助数组a[i][j][len]表示第j列,从第i行开始,长度为len的元素的和,
a[i][j][len] = a[i][j][len-1]+source[i+len-1][j]
故这里可以去掉最后一维
a[i][j] = a[i][j] + source[i+len-1][j]
#include<iostream>
//思路 最大子段和的动态规划迭代公式 dp[i]表示dp[0..i]的最长子矩阵,其中肯定包含第i个元素
// dp[i] = max(dp[i-1]+a[i],a[i]) 所以 若dp[i-1] > 0 --dp[i] = dp[i-1]+a[i]; 否则 dp[i] = a[i]
//最大字段和即为max dp[i]
//最大子矩阵把二维的矩阵压缩成一维 首先考虑只有一行的子矩阵,在考虑只有两行的(把两行的对应位置相加)
using namespace std;
int source[110][110];
int a[110][110];//辅助数组
int N;
//计算a并且返回最大字段和
int maxSum(int a[],int N){
int resultSum = 0;
int newSum = 0;
for(int i = 0; i < N; i++){
if(newSum > 0){
newSum += a[i];
}else{
newSum = a[i];
}
if(newSum > resultSum){
resultSum = newSum;
}
}
return resultSum;
}
int cala(int len){
int maxsum = 0;
for(int i = 0; i < N-len+1; i++){
for(int j = 0; j < N; j++){
a[i][j] = a[i][j] + source[i+len-1][j]; //更新a数组
}
int tempSum = maxSum(a[i],N);
if(tempSum > maxsum){
maxsum = tempSum;
}
}
return maxsum;
}
int main(){
cin>>N;
int maxsum = 0;
for(int i = 0; i < N; i++){
for(int j = 0; j < N;j ++)
{
cin>>source[i][j];
}
}
for(int len = 1; len <= N;len++){//有len行的子矩阵
int temp = cala(len);
if(temp > maxsum){
maxsum = temp;
}
}
cout<<maxsum<<endl;
}