kuangbin專題十二 DP專題 HDU1024 最大m子序列和

題意:
給你n個數,然後讓你在裏面找到m個子序列,讓這m個子序列的和最大。其中可以不要一些數,但是這些子序列裏面的數必須是連續的。
題解:
這道題是我做kuangbin大神的專題的第一道題,當然就被嚇到不敢去做,今天用了快一天的時間把這道題給理解了,以下是我看的博客:
http://blog.sina.com.cn/s/blog_677a3eb30100jxqa.html
http://blog.csdn.net/u013187393/article/details/42914165
http://blog.csdn.net/u013761036/article/details/39804595
按照順序來看比較好,好了,再在我這裏說一下我的見解吧,
這道題是最大子序列的和的加強版,比最大子序列噁心的多了,我之前的想法還停留在01揹包的層次,就是拿或者不拿的思維層次,發現在這裏行不通。所以學了一整天,然後我說一下公式:
dp[i][j]=max(dp[i][j-1]+a[j],dp[i-1][k]+a[j]),(其中i-1<=k<=j)。dp[i][j]就是把j個數分成i段的最大和,而dp[i][j-1]+a[j]就是把a[j]分配到第i段中,而後面的dp[i-1][k]+a[j]的意思就是把前面的j-1個數分成i-1段,而a[j]變成第i段的第一個數值。有可能說到這裏很多人不明白,這個k到底是怎麼回事吧?我們來看一下例子吧:
例如有一組數據 2 3 3 -7 2
那麼它的最大值是多少呢?答案是5,怎麼得出來的呢?
假如前面的dp值我們都已經計算出了,並且都是正確的,那麼dp[2][3]=max(dp[2][2]+a[3],dp[1][k]+a[3]),我們可以看出dp[2][2]爲-4,那麼這裏k怎麼算呢?因爲限制在i-1<=k<=j-1即是1<=k<=2中了,那麼我們看一下k=1的時候dp[1][1]爲3,而k=2的時候dp[1][2]爲-4,所以我們這時候當然是讓k=1了,帶入式子中就可以得出結果5了。爲什麼k是取i-1<=k<=j-1的範圍呢?因爲有時候a[j-1]可能是非常大的負數,大到使前面的正數值總和(我們位了好理解這裏假設前面的總和算出來是正數)加上該數也爲負,你覺得你還會要它嗎?顯然不能,除非第i段缺少數值,纔會要它,不到萬不得已是不會要它的。
然後這裏的m因爲沒說出範圍所以我們要優化一下空間,即是dp[i][j]變成dp[j]表示的是第j個數時的最大值,以上是我的見解,剩下的例如時間上的優化可以看我發上面的三個博客和我的代碼註釋就好了。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define LL long long int 
#define INF 0x7fffffff
const int MAXN= 1000000+7;
LL dp[MAXN];//因爲不知道m是多少所以優化成了一維的了。 
LL maxk[MAXN];//保存的是分成幾段的最大值。 
LL a[MAXN];
int main()
{
    int n,m;
    while(~scanf("%d%d",&m,&n))
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            dp[i]=0;
            maxk[i]=0;
        }
        LL MAX=-INF;
        for(int i=1;i<=m;i++)
        {
            MAX=-INF; 
            for(int j=i;j<=n;j++)//爲什麼是從i開始呢?因爲你跑過了一遍分成i=1段之後,第i=1段就應該是最優的狀態了,所以不用再跑了,直接當做最優的狀態來參與分成i=2階段的計算。 
            {
                dp[j]=max(dp[j-1]+a[j],maxk[j-1]+a[j]);//這裏就相當於dp[i][j]=max(dp[i][j-1]+a[j],dp[i-1][k]+a[j])。 
                maxk[j-1]=MAX;//這裏保存的是dp[i-1][k]的值,即將k分成i-1段得到的最大值(i-1<=k<j-1). 還有就是不能更新mxk[j],只能更新j-1是因爲更新j就會被當前的這個子序列更新的時候用到。
                MAX=max(dp[j],MAX);//保存最大值。 
            }
        }
        printf("%lld\n",MAX);//還有就是這裏不能寫成dp[n],因爲dp[j]代表的是到第j個的時候的最大和。例如你計算到最後,有可能不要最後一個數比要最後一個數要大。所以這裏要輸出MAX。 
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章