背包九講
參考:AcWing題庫
參考書目:背包九講
1、01背包問題
- 題目描述:有 N 件物品和一個容量是 V的背包。每件物品只能使用一次。第 i件物品的體積是 vi,價值是 wi。求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。
輸出最大價值。
-
思路:動態規划,對於每一件物品遍歷背包容量,當背包可容納值大於等於當前物品,與之前已放進去的物品所得價值進行對比,考慮把是否需要置換。
- 狀態轉移方程:定義dp[i][j]:前i個物品,背包容量j下的最優解
-(1)當前背包容量不夠,為前\(i-1\)個物品最優解:j<w[i]時,有dp[i][j]=dp[i-1][j]
-(2)當前背包容量夠,判斷選還是不選第i個物品:j>=w[i]時,選該物品->dp[i][j]=dp[i-1][j-w[i]]+v[i];不選該物品->dp[i][j]=dp[i-1][j]
- 狀態轉移方程:定義dp[i][j]:前i個物品,背包容量j下的最優解
## 偽代碼:
# for i=1..N
# for v=V..0
# f[v]=max{f[v],f[v-c[i]]+w[i]};
- \(\color{red}{代碼實現-github}\):0-1背包
2、完全背包問題
-
題目描述:有 N 種物品和一個容量是 V的背包,每種物品都有無限件可用。第 i種物品的體積是 vi,價值是 wi。求解將哪些物品裝入背包,可使這些物品的總體積不超過背包容量,且總價值最大。輸出最大價值。
-
思路:
-
思路1:最簡單的想法,就是將完全背包轉化為0-1背包問題,可以將第 i 種物品轉化為W/w[i]件費用及價值均不變的物品,然后求解0-1背包問題。
-
思路2:更高效的轉化方法是第 i 種物品拆成費用為w[i]2^k,價值為v[i]2^k的若干件物品,其中k滿足w[i]*2^k<=W。因為不管最優策略 選幾件第 i 種物品,總可以表示成若干個 2^k 件物品的和(二進制思想)
-
思路3(完全背包優化):若兩件物品i、j滿足c[i]<=c[j]且w[i]>=w[j],則將物品j去掉,不用考慮。c表物品重量,w表示對應物品價值。即將重量大且價值低的物品去掉。
-
思路4(復雜度為O(VN)): 0-1背包問題中要按照 w=W..0 的逆序來循環,而完全背包必須按照從小到大的順序。這是因為 要保證第 i 次循環中的狀態 f[i][w]是由狀態 f[i-1][w-w[i]]遞推而來。換句話 說,這正是為了保證每件物品只選一次,保證在考慮“選入第 i 件物品”這件策 略時,依據的是一個絕無已經選入第 i 件物品的子結果 f[i-1][w-w[i]]。而現 在完全背包的特點恰是每種物品可選無限件,所以在考慮“加選一件第 i 種物 品”這種策略時,卻正需要一個可能已選入第 i 種物品的子結果 f[i][w-w[i]], 所以就可以並且必須采用 w=0..W 的順序循環。
-
## 偽代碼:
# for i=1...N
# for w=0...W
# f[w] = max(f[w], f[w-cost]+weight)
- \(\color{red}{代碼實現-github}\):完全背包