1. 程式人生 > 其它 >動態規劃之01揹包問題

動態規劃之01揹包問題

本文理論內容參考自崔添翼的揹包九講系列
例項可參考上一篇博物館大盜問題

01揹包問題

有N件物品和一個容量為V的揹包,第i件物品的體積為\(v_i\),價值為\(w_i\)。求解將哪些物品放入揹包可以打到總價值最大。

基本思路

這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放
子問題定義狀態:即\(F[i,j]\)表示前i件物品放入容量為j的揹包,可以獲得的最大價值。

狀態轉移方程

\[F[i,j] = max\{F[i-1,j], F[i-1,j-v_i] + w_i\} \]

"將前i件物品放入容量為j的揹包中"這個子問題,若只考慮第i件物品的策略(放或不放),那麼就可以轉化為一個只和前i-1件物品相關的問題。

  • 如果不放第i 件物品,那麼問題就轉化為“前i-1件物品放入容量為j的揹包中”,價值為\(F[i-1, j]\)
  • 如果第i 件物品,那麼問題就轉化為“前i-1件物品放入剩下的容量為\(j-v_i\)的揹包中”,此時能獲得的最大價值就是\(F[i-1,j-v_i]\)再加上通過放入第i 件物品獲得的價值\(w_i\).

步驟總結:

  1. 使用一個N*V的二維陣列記錄dp[i][j],初始化:dp = [[0 for _ in range(V+1)] for _ in range(N)]
  2. 邊界:i=0 或j=0 時,dp[i][j] = 0
  3. 外層迴圈:i件物品,從1到N迴圈
  4. 內層迴圈:容量V,從1到V迴圈
  5. j < vi時,第i件物品放入容量為j的揹包,因此dp[i][j] = dp[i-1][j]
  6. j > vi時,狀態轉移方程:dp[i][j] = max(dp[i-1][j], dp[i-1][j-vi] + wi)

python版程式碼:

# 物品屬性
v = [0, 2, 3, 4, 5]
w = [0, 3, 4, 5, 6]
N = len(v)
max_V = 10
dp = [[0 for _ in range(max_V+1)] for _ in range(N)]
for i in range(1, N):
    for j in range(1, max_V+1):
        if j < v[i]:
            dp[i][j] = dp[i-1][j]
        else:
            dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + w[i])
# 按行輸出
for c in dp:
    print(c)

輸出結果: