Max Sum Plus Plus (動態規劃) HDU1024

題目來源:http://acm.hdu.edu.cn/showproblem.php?pid=1024

(http://www.fjutacm.com/Problem.jsp?pid=1375)

題意:長度爲n的序列裏,m段不相關區間的最大和

思路:我們先要確定一個東西,就是狀態,這裏我用dp[i][j]表示前j個數在取a[j]情況下分i段的最大和;

那麼我們爲了找規律,可以先來一發Excel,就以樣例爲例子:

然後我們可以發現其實紅圈裏的8是狀態dp[2][6](i=2, j=6),那麼我們可以想想這個位置怎麼推導,很明顯,他可以選擇和分i-1塊的最大值相加,得到的i塊可能是最大,或者他也可以直接和同樣分i塊的j-1的位置相加,這樣就相當於不斷開,得到最大。那麼也就是他只有兩種選擇,第一個是dp[i][j-1],第二個是max(dp[i-1][i-1]~dp[i-1][j-1]),也就是dp[i][i~n]只和dp[i-1][i-1~n]這一行的狀態有關,和別的無關。那麼我們就可以用滾動數組保存;但是如果你找max(dp[i-1][i-1]~dp[i-1][j-1])的時候用的是for查找的話,那就涼涼了,因爲那樣複雜度就是O(n^3),也就是我們要用一個maxn來記住之前的最大值,然後每次更新記錄;具體看代碼。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N= 1001000;
const long long INF=0x3f3f3f3f3f3f3f3f;
long long dp[2][N], maxn;
int a[N];
int main( ){
    int m, n, t;
    while(~scanf("%d%d", &m, &n)){
        t=1;///用來滾動數組
        for(int i=1; i<=n; ++i)
            dp[0][i]=-INF;
        for(int i=1; i<=n; ++i)
            scanf("%d", &a[i]);
        for(int i=1; i<=m; ++i, t=1-t){///t=1-t就是在循環滾動
            dp[t][i]=dp[1-t][i-1]+a[i];///對角線的值其實就是前n項和啦!!
            maxn=dp[1-t][i-1];///別把這個忘了
            for(int j=i+1; j<=n; ++j){
                maxn=max(maxn, dp[1-t][j-1]);///maxn更新記錄max(dp[i-1][i-1]~dp[i-1][j-1])
                dp[t][j]=max(dp[t][j-1], maxn)+a[j];///狀態的轉移步驟
            }
        }
        t=1-t;///最後i>m時的那一個++i, t=1-t的影響要轉過來
        maxn=-INF;
        /**
            注意,dp[i][j]是表示前j個數在取a[j]情況下分i段的最大和;
            也就是dp[m%2][n不一定是最優解,因爲可能不加a[n]還更大;
        **/
        for(int i=m; i<=n; ++i)
            maxn=max(maxn, dp[t][i]);
        printf("%I64d\n", maxn);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章