1. 程式人生 > >DP問題各種模型的狀態轉移方程

DP問題各種模型的狀態轉移方程

1(最長公共子串(注意和最長公共子序列區別))

兩個字串str1和str2,長度分別為(l1,l2)

dp[i][j]表示以兩個字串分別以第i和第j個字元結尾所能達到的公共子序列的長度,由於下面涉及到i-1和j-1,那麼這個時候我們一般從i=1和j=1開始到i<=len1, j<=len2。

       if(str[i-1]=str[j-1])

            dp[i][j]=dp[i-1][j-1]+1;

        if(str[i-1]!=str[j-1])

            dp[i][j]=0;

2.(數塔問題)

給定一個數組s[n][m]構成一個數塔求從最上面走到最低端經過的路徑和最大

我麼採用至底向上的思路求解問題(注意從倒數第二行開始)

dp[i][j]表示走到第i行第j個的最大值

那麼就有dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j];

for(i=n-1;i>=1;i--){

     for(j=1;j<=i;j++){

         dp[i][j]=max{dp[i-1][j-1],dp[i-1][j]}+s[i][j]

     }

}

最後dp[1][1]即為最大值

3.(01揹包問題)

有N件物品和一個容量為V的揹包。第i件物品的體積是v[i],價值是c[i]。求解將哪些物品裝入揹包可使價值總和最大。

我們知道對於沒一件物品我們有兩種可能就是放與不放

dp[i][j]表示第i件物品放入容量為j的揹包所得的最大價值

dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]};

這裡我們從j=V倒推回來的話可以優化成

dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

核心程式碼:

fori=1;i<=n;i++){

       for(j=V;j>=0;j--){

            if(j>=v[i])

              dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

       }

}

dp[v]即為最大的價值

4.(完全揹包問題)

有N種物品和一個容量為V的揹包,每種物品都有無限件可用。第i種物品的體積是v[i],價值是c[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

這時候對於沒見物品就不是放與不放的問題了,而是放0件1件…….

這時候我們可以像01揹包一樣

dp[i][j]表示容量為j的揹包第i件物品是否要再一次放入所以我們要從0-V順序迴圈

dp[i][j]=max{dp[i-1][j-v[i]]+c[i],dp[i-1][j]}(注意這裡和01揹包一樣但是求解的過程不同)

優化後:dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

核心程式碼:

            for(i=1;i<=n;i++){

                      for(j=v[i];j<=v;j++){//注意這裡是從v[i]開始到V

                           if(j>=v[i])

                              dp[j]=max{dp[j],dp[j-v[i]]+c[i]};

                      }

              }

注意這列求出的dp[v]是最大的因為一直疊加

5.(多重揹包問題)

有N種物品和一個容量為V的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

因為對於第i種物品有n[i]+1種策略:取0件,取1件……取n[i]件。

重點:令dp[i][j]表示前i種物品恰放入一個容量為j的揹包的最大價值

狀態轉移方程:dp[i][j]=max{dp[i-1][v-k*v[i]]+k*c[i]|0<=k<=n[i]};(k表示第i種物品放入k件);

核心程式碼:

       for(i=1;i<=n;i++){

                    for(j=v;j>=0;j--){

                         for(k=1;k<=n[i];k++){

                             if(j>=k*v[i])

                                dp[i][j]=max(dp[i-1][v-k*v[i]]+k*c[i])
                         }

                    }

6.
最長公共子序列:

根據最長公共子序列問題的性質,我們可以規定dp[i][j]為字串1的前i個字元和字串2的前j個字元的最長公共子序列的長度, 由於下面涉及到i-1和j-1,那麼這個時候我們一般從i=1和j=1開始到i<=len1, j<=len2。

1.ch1[i-1] = ch2[j-1] ,那麼dp[i][j]= dp[i-1][j-1] + 1;
2. ch1[i-1] != ch2[j-1] ,那麼我們知道ch1[i]和ch2[j]不可能在同一個公共子序列裡出現,那麼這個時候的最長的子序列可能以ch1[i]或ch2[j]結尾,那麼由於dp[i][j]=max {dp[i-1][j] , dp[i][j-1]};

就有

dp = dp[i][j] = dp[i-1][j-1] + 1; i > 0且j> 0 且ch1[i-1]=
ch2[j-1];
dp[i][j]= max {dp[i-1][j] , dp[i][j-1]};i > 0且j> 0且ch1[i-1]!= ch2[j-1];

7.
(最大子段和問題(最大子序列的和不同))

給定一個序列為a1,a2,a3……an;

要求:求出這個序列裡面找到一個子段和最大

dp[i]表示以第i個元素結束,求出所有的“以第i個元素結束的連續陣列最大和dp[i]

就有:

       1如果dp[i-1]>0,無論ai為何值,有dp[i]=dp[i-1]+ai;

       2如果dp[i-1]<=0;捨棄,重新令dp[i]=ai;(因為dp[i-1]為負數無論ai為什麼值加上去都會減少)

       狀態轉移方程:dp[i]=dp[i-1]+ai (dp[i-1]>0)

                               dp[i]=ai(dp[i-1]<=0)

8.
(最大m子段和)

在限制條件增加一維時,可以將狀態也相應的增加一維,來進行狀態轉移

以dp[i][j]表示以第i個元素為結尾,使用j個子段所能達到的最大值(這一維的狀態,正是對應了新的限制條件!)這樣就很容易寫出

狀態轉移方程:

            dp[i][j]= max{ dp[i - 1][j] + a[i], dp[i - k][j - 1] + a[i]}( j - 1 <= k <n - m + j).

            1  dp[i - 1][j] + a[i] (把第i個元素包含在最後一個子段內)

            2  dp[i - k][j - 1] + a[i], j - 1 <= k < n - m + j(第i個元素單獨為一子串)