最长子段和 最大子矩阵

最长字段和   

数组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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值