HDU 1024 Max Sum Plus Plus 經典 DP


首先申明:這題數據有很大問題

當你輸入都為負數時,程序就會出錯

如 2 3

-1 -2 -3

竟然輸出-3。

數據庫里有都為負數的情況,我用別人AC代碼改了一下測試過了,的確有這情況,但答案貌似是錯的。

又如 2 3

-1 2 -3

竟然輸出1.

這讓我郁悶了很久。

 

設輸入的數組為a[1...n],從中找出m個段,使者幾個段的和為最大

dp[i][j]表示前j個數中取i個段的和的最大值,其中最后一個段包含a[j]。(這很關鍵)

則狀態轉移方程為:

dp[i][j]=max{dp[i][j-1]+a[j],max{dp[i-1][t]}+a[j]}    i-1=<t<j-1

 

因為dp[i][j]中a[j]可能就自身一個數組成最后一段,或者a[j]與a[j-1]等前面的數組成最后一段。

此題n數據太大,二維數組開不下,而且三重循環,想到狀態轉移方程后還是困難重重。

想想,二維數組不行的話,肯定要壓縮成一維數組:

因為dp[i-1][t]的值只在計算dp[i][j]的時候用到,那么沒有必要保存所有的dp[i][j] for i=1 to m,這樣我們可以用一維數組存儲。

用pre[j]表示j之前一個狀態dp[i-1][]中1-j之間,不一定包含a[j]的最大字段和,然后推dp[i][j]狀態時,dp[i][j]=max{pre[j-1],dp[j-1]}+a[j];

褐色的為了方便理解,其實不存在。

AC代碼:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 1000003
#define INF 100000000
int dp[maxn],a[maxn],pre[maxn];
int main()
{
    int n, m, i, j, maxx;
    while(~scanf("%d%d",&m,&n))
    {
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        dp[0]=0;
        memset(pre,0,sizeof(pre));
        for(i=1;i<=m;i++)
        {
            maxx =-INF;
            for(j=i;j<=n;j++)//對於每個i,隨着j的增大,maxx越滾越大
            {
                dp[j]=max(dp[j-1],pre[j-1])+a[j];
                pre[j-1]=maxx;//把前一輪的最大值賦給pre;
                //printf("dp[%d]=%d pre[%d]=%d\n",j,dp[j],j-1,pre[j-1]);
                if(maxx<dp[j])maxx=dp[j];
            }
            //puts("");
        }
        printf("%d\n",maxx);//最后一輪的最大值就是答案。
                            //因為上一個循環中對於每個i,隨着j的增大,maxx越滾越大
    }                       //而且pre也是越滾越大的。
    return 0;
}
//給了一組數據,不理解就把所有DP打出來,自己手動模擬一遍,這樣好理解多了
/* 4 7
1 2 -4 5 6 -8 10
*/

 

 本人覺得正確的代碼,可能有錯誤:

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 1000003
#define INF 100000000
int dp[maxn],a[maxn],pre[maxn];
int main()
{
    int n, m, i, j, maxx,ans;
    while(~scanf("%d%d",&m,&n))
    {
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        dp[0]=0;ans=-INF;
        memset(pre,0,sizeof(pre));
        for(i=1;i<=m;i++)
        {
            maxx =-INF;
            for(j=i;j<=n;j++)//對於每個i( 每組),隨着j的增大,maxx越滾越大 ,但i->i+1后,有些maxx不一定越滾越大
            {
                dp[j]=max(dp[j-1],pre[j-1])+a[j];
                pre[j-1]=maxx;//把前一輪的最大值賦給pre;
                //printf("dp[%d]=%d pre[%d]=%d ",j,dp[j],j-1,pre[j-1]);
                if(maxx<dp[j])maxx=dp[j];
                //printf("maxx=%d\n",maxx);
            }
            if(ans<maxx)ans=maxx;
            //puts("");
        }
        printf("%d\n",ans);
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM