给定一个数组,数组长度为n,数组中每个元素为一个整数(其中有正数,负数,零),求一和最大的子数组

这是一道老生常谈的动态规划问题,也是我大一学算法时遇到的第一道动态规划问题,当时觉得解法非常精妙,从此爱上了算法。

题目的具体解法为是dp[i][0]表示前i项数列不含最后一项(第i项)时的子数列之和的最大值,dp[i][1]表示前i项数列含最后一项的子数列之和最大值

很明显dp[i][0]=max(dp[i-1][1],dp[i-1][1]),dp[i][1]=max(dp[i-1][1]+a[i],a[i]);

但是从上面的状态转移方程可以发现,每一项只与前一项有关,所以状态转移过程中,无需记录多余的状态,只记录该状态的前一种状态即可,所以描述子状态二维数组完全可以使用 dp1 和 dp2 这两个数来代替,从而优化了空间发杂度

最终优化完成的代码如下:

#include<iostream>
#include<string>
using namespace std;
int main(){
    long long dp1,dp2,a[10000],ans;
    int n=1;
    cin>>a[0];
    while(getchar()!='\n'){
        cin>>a[n++];
    }
    dp1=-99999999;ans=dp2=a[0];//为避免全为负数
    for(int i=1;i<n;i++){
        dp1=max(dp1,dp2);
        dp2=max(dp2+a[i],a[i]);    
    }
    ans=max(dp1,dp2);    
    cout<<ans<<endl;
    return 0;
}

 

第二,如果上述数列首尾相接,那样的话,其实和原来的问题依然一样,原来的问题可以看做数列在第一个元素和最后一个元素之间比存在一个断口,现在首尾相接,只要枚举一下断口的位置即可,具体代码如下:

#include<iostream>
#include<string>
using namespace std;
int main(){
    long long dp1,dp2,a[10000],ans;
    int n=1;
    cin>>a[0];
    while(getchar()!='\n'){
        cin>>a[n++];
    }
    for(int j=0;j<n;j++){
        int k=j;
        dp1=-99999999;ans=dp2=a[k];
        for(int i=1;i<n;i++){
            k++;k%=n;        
            dp1=max(dp1,dp2);
            dp2=max(dp2+a[k],a[k]);    
        }
        ans=max(ans,max(dp1,dp2));    
    }
    cout<<ans<<endl;
    return 0;
}

 

 posted on 2016-03-27 19:33  yifan2016  阅读(391)  评论(1编辑  收藏  举报