動態規劃之01揹包問題
阿新 • • 發佈:2021-06-10
本文理論內容參考自崔添翼的揹包九講系列。
例項可參考上一篇博物館大盜問題。
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\).
步驟總結:
- 使用一個N*V的二維陣列記錄dp[i][j],初始化:dp = [[0 for _ in range(V+1)] for _ in range(N)]
- 邊界:i=0 或j=0 時,dp[i][j] = 0
- 外層迴圈:i件物品,從1到N迴圈
- 內層迴圈:容量V,從1到V迴圈
- j < vi時,第i件物品放入容量為j的揹包,因此
dp[i][j] = dp[i-1][j]
- 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)
輸出結果: