小白學習動態規劃:0-1揹包(經典例題)

前言

揹包問題只是動態規劃問題下的一個分類,求解0-1揹包問題的思路本質上與求解動態規劃的一般思路是一致的,我們經常遇到新的題目做不出來,並不是因爲沒有掌握動態規劃的思想,而有可能是因爲沒有遇到這類具有顯著特徵的題目,無法將一般動態規劃的解題思路應用在實戰中。

動態規劃的原理:

最優子結構性質:問題的最優解可以轉化爲求子問題的最優解,也就是說問題的最優解可以從子問題的最優解中得出。

子問題重疊性質:問題的解由子問題的解組成,所以先構造子問題的解,才能求出最終問題的解。而求問題的解時,由於已經記錄子問題的解,所以不必重新求子問題的解,只需取出來使用即可。

經典例題

NViCiWi使 有N件物品和一個容量爲V 的揹包。放入第i件物品耗費的空間是Ci,得到 的價值是Wi。 \\求解將哪些物品裝入揹包可使價值總和最大。

N=5V=10 例:N = 5,V=10

物品 A B C D E
Wealth 3 4 5 6 7
Cost 1 2 5 6 8

這是最基礎的0-1揹包問題

先看下圖,是在求出問題的解後整個動態規劃表呈現的結果。下面就來看看這張表是如何一步步填上去並求出最終問題解的。
在這裏插入圖片描述

解題思路

① 確定子問題

求容量爲V的揹包裝入物品的價值總和最大,則考慮第i件物品是否放入揹包,使得揹包的價值保持最大。

② 確定狀態及數組

用一個二維數組F[i][j]表示前i件物品放入容量爲j的揹包中可以獲得的最大價值(注意此處的容量是揹包的總容量,而不是揹包的剩餘容量

③ 確定邊界值

F[0][0…V] = 0:表示不管第0件物品放入任意容量的揹包中其最大價值都是0,因爲不存在第0件物品。

F[0…N][0] = 0:表示任意物品放入容量爲0的揹包中其最大價值都是0,因爲容量爲0的揹包裝不下任何物品。

④ 確定狀態轉移方程

Ⅰ:若第i件物品無法放入容量爲j的揹包中
iji1jF[i][j]=F[i1][j] \\則前i件物品放入容量爲j的揹包中的最大價值等於前i-1件物品放入容量爲j的揹包中的最大價值,\\即:F[i][j] = F[i-1][j]
Ⅱ:若第i件物品可以放入容量爲j的揹包中,則分兩種情況:
ijiF1[i][j]=F[i1][jCi]+WiijiF2[i][j]=F[i1][j]F1F2F[i][j]=max(F1[i][j], F2[i][j]) 第i件物品放入容量爲j的揹包中,得到前i件物品的最大價值:F_1[i][j] = F[i-1][j-C_i] + W_i \\第i件物品不放入容量爲j的揹包中,得到前i件物品的最大價值:F_2[i][j] = F[i-1][j] \\取F_1還是F_2取決於誰的價值更大,即:F[i][j] = max(F_1[i][j],\ F_2[i][j])

例:

第Ⅰ種情況:
情況I

當[i,j] = [2,1]時,物品B的耗費空間Cost=2,而揹包的體積 j=1,很明顯物品B無法放入揹包中,所以
F[2][1]=F[1][1]=3 F[2][1] = F[1][1] = 3
第Ⅱ種情況:
情況II
當[i,j] = [2,3]時,物品B的耗費空間Cost = 2,而揹包的體積 j=3,物品B可以放入揹包中,所以
F[2][3]=max(F[1][3],F[1][32]+4)=max(3,3+4)=max(3,7)=7 F[2][3] = max(F[1][3], F[1][3-2] + 4)=max(3,3+4)=max(3,7)=7


作者在理解Ⅱ時有一個困惑:爲什麼第i件物品可以放入容量爲j的揹包中還需要比較不放入的情況?
圖片2
[ij]=[59]ECost=8j=9>Cost,EEEF1[5][9]=F[51][9CostE]+WealthE=10EEFE[5][9]=F[4][9]=13E 當[i,j] = [5,9]時,物品E需要佔用Cost=8,而揹包容量j=9 > Cost,所以揹包可以放入E這件物品\\ 如果放入E,那麼就要騰出E的空間,所以F_1[5][9] = F[5-1][9-Cost_E] + Wealth_E = 10\\ 如果不放入E,那麼不需要騰出E的空間,所以F_E[5][9] = F[4][9]=13,可以看到不放入E反而讓揹包的總價值更大\\
所以並不是說物品E可以放入就馬上放入,因爲每放入一件物品都要騰出相應的空間
V=Costi V_{騰出的空間} = Cost_i
而騰出的空間可以放入其它物品,而有可能放入其它的物品價值總和大於物品E的價值

⑤ 代碼實現

public class Solution{
    public int dp(int[] wealth, int[] cost, int V, int N){
        //特殊狀態處理
        if(wealth.length != cost.length){return -1;}
        if(wealth.length == 0){return 0;}
        if(wealth.length == 1){
            if(cost[0] > V){
                return 0;
            }else{
                return wealth[0];
            }
        }
        int[][] F = new int[N + 1][V+1];
        //邊界值處理
        for(int i = 1; i < N + 1; i++){
            for(int j = 1; j < V + 1; j++){
                //先假設不能放入容量爲j的揹包
                F[i][j] = F[i-1][j];
                //判斷能不能放入揹包
                if(j >= cost[i-1]){
                    F[i][j] = Math.max(F[i-1][j], F[i-1][j-cost[i-1]] + wealth[i-1]);
                }
            }
        }
        return F[N][V];
    }
}

時間有限,能力有限,若有誤希望能夠指出,樂意與大家交流!

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