有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是w[i],價值是v[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
貪心 y or n ?
因為每件物品都可以選取任意件,你也許會想到貪心演算法:選取價值最高的就好了~~~ 看上去沒什麼毛病,但是有乙個問題,就是往往無法填滿揹包,還有剩餘空間。當然,你也許會想:用價值第二高的填充,如果還是放不下,就選第
三、四高的填充。聽起來似乎可行,但是很容易舉出反例:兩個物品:a(價值5,體積5)、b(價值8,體積7),揹包大小為10。那麼用上述貪心演算法,只能選取乙個b物品,獲得價值為8。但是很明顯,正解為10。所以貪心演算法在這裡並不適用。
最優化原理
假設完全揹包的最優解為f(n1,n2,…,nn)(n1,n2 分別代表第1、第2件物品的選取數量),完全揹包的子問題為,將前i種物品放入容量為t的揹包並取得最大價值,其對應的解為:f(n1,n2,…,ni),假設該解不是子問題的最優解,即存在另一組解f(m1,m2,…,mi),使得f(m1,m2,…,mi) > f(n1,n2,…,ni),那麼f(m1,m2,…,mi,…,nn) 必然大於 f(n1,n2,…,nn),因此 f(n1,n2,…,nn) 不是原問題的最優解,與原假設不符,所以f(n1,n2,…,ni)必然是子問題的最優解。
無後效性:
對於子問題的任意解,都不會影響後續子問題的解,也就是說,前i種物品如何選擇,只要最終的剩餘揹包空間不變,就不會影響後面物品的選擇。即滿足無後效性。
因此,完全揹包問題也可以使用動態規劃來解決。
定義dp[ i ][ j ]:在前 i 件物品中選取物品,放到容量為 j 的揹包所獲得的最大價值。
狀態轉移方程:dp[ i + 1 ][ j ] = max ( dp[ i ][ j - k * w[ i ] ] + k * v[ i ] );
因為完全揹包中,第 i 個物品可以選多次,上式中的 k 就代表這個次數。 由於上式左邊揹包最大容積為 j ,所以 k 最大最大不能超過 j / wi; 故k 的範圍是 0<= k <= j / wi。
這個式子很直觀,甚至01揹包也可以用這個式子表示,只要把 k 的取值範圍改正,也就是說,其實01揹包是一種特殊的完全揹包。雖然得出這個結論不難,但是如果這個式子的效率不高,做了很多重複的計算。
所以我們給出新的狀態轉移方程:
dp[ i + 1 ][ j ] = max ( dp[ i ][ j ] , dp[ i + 1 ][ j - w[ i ] ] + v[ i ] )
下面證明二者等價:
首先我們在i,j位置時
那麼考慮,為什麼不需要①位置?這是因為,縱向嚴格單調非遞減。
那麼這樣一來,迴圈次序也就固定了,只能從小到大更新。
將空間壓縮至一維:
for(int i = 0; i < n; i++)
}
動態規劃揹包問題 完全揹包
問題描述 有n種物品,每種均有無窮多個。第i個物品的體積為vi,重量為wi。選一些物品裝到容量為c的揹包中,使得揹包內物品在總體積不超過c的前提下重量盡量大。問題分析 開乙個陣列f i j 表示前i種物品中選取若干件物品放入剩餘空間為j的揹包中所能得到的最大重量。每種物品無窮個,所以還要有乙個k遍歷...
動態規劃揹包問題 完全揹包
問題背景描述 你有乙個容量為v的揹包,現在有n種物品供你選擇,每件物品可以選擇無數次,每種物品所佔的空間為c i 價值為v i 現在讓你作出最佳方案,使揹包中的總價值最大。有了之前01揹包的基礎,我們很快就能寫出完全揹包的狀態轉移方程 f i j max 但是這樣的時間複雜度就很大了o v v c ...
動態規劃 揹包問題(01揹包 完全揹包)
揹包問題 多種物品 重量不同 價值不同 你可以取最多重量不超過w的物品,問最大價值為多少?01揹包 指的是 有n個物品 每個物品的重量為w i 價值為v i 每個物品只有乙個 所有面臨這些物品只有兩種結果 1 拿這件物品,揹包容量減去w i 此時的價值增加v i 2 不拿這件物品,揹包容量不變,最大...