揹包問題(knapsack problem)是一類經典的動態規劃問題,是一種組合優化的np完全(np-complete, npc)問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價值,在限定的總重量內,如何選擇,才能使得物品的總價值最高。npc問題是沒有多項式時間複雜度的解法的,但利用動態規劃,可以在偽多項式時間複雜度下求解揹包問題。本文討論的是揹包問題中的最基本的0/1揹包問題。
一共有n件物品,第i件物品的重量是w[i],價值是v[i]。在總重量不超過揹包承載上限w的情況下,能夠裝入揹包的最大價值是多少?
如果採用暴力法,對於每件物品都有兩種狀態取或不取,時間複雜度為o(2^n),這是不可接受的。如果採用動態規劃,則可以將複雜度降為o(n·w)。
我們的目標是揹包內物品的總價值,而變數是物品和揹包的當前重量,因此我們可以設狀態dp:dp[i][j]
表示考慮前i件物品且揹包當前重量為j時的揹包物品總價值。
那麼,對於dp[0][0...w]
初始化為0,表明考慮前0個物品後,揹包物品總價值為0。當i>0時,dp[i][j]
會有兩種情況:
不裝入第i件物品,則dp[i][j] = dp[i-1][j]
。
裝入第i件物品,則dp[i][j] = dp[i-1][j - w[i]] + v[i]
。
此時,我們可以得到狀態轉移方程(j>=w[i]):dp[i][j] = max(dp[i-1][j], dp[i-1][j - w[i]] + v[i])
。
我們發現,dp[i][j]
只和dp[i-1][0...j-1]
有關,所以我們可以採用動態規劃常用的方法「滾動陣列」對空間進行優化,即去掉dp的第一維。需要注意的是,為了防止上一層迴圈的狀態dp被覆蓋,迴圈的時候 j只能從尾部開始列舉。於是有了如下**:
int dp[w] = ;
for(int i = 1;i<=n;i++)
}
利用動態規劃解決0/1揹包問題,時間複雜度為o(n·w), 空間複雜度為o(w)。由於w的值是w的位數的冪,所以這個時間複雜度是偽多項式時間。
動態規劃的核心思想避免重複計算在01揹包問題中體現得淋漓盡致。第i件物品裝入或者不裝入而獲得的最大價值完全可以由前面i-1件物品的最大價值決定,暴力列舉忽略了這個事實。
揹包問題 01揹包問題
n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...
揹包問題 01揹包
有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...
揹包問題(01揹包)
1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...