前言
揹包問題只是動態規劃問題下的一個分類,求解0-1揹包問題的思路本質上與求解動態規劃的一般思路是一致的,我們經常遇到新的題目做不出來,並不是因爲沒有掌握動態規劃的思想,而有可能是因爲沒有遇到這類具有顯著特徵的題目,無法將一般動態規劃的解題思路應用在實戰中。
動態規劃的原理:
① 最優子結構性質:問題的最優解可以轉化爲求子問題的最優解,也就是說問題的最優解可以從子問題的最優解中得出。
② 子問題重疊性質:問題的解由子問題的解組成,所以先構造子問題的解,才能求出最終問題的解。而求問題的解時,由於已經記錄子問題的解,所以不必重新求子問題的解,只需取出來使用即可。
經典例題
物品 | A | B | C | D | E |
---|---|---|---|---|---|
Wealth | 3 | 4 | 5 | 6 | 7 |
Cost | 1 | 2 | 5 | 6 | 8 |
這是最基礎的0-1揹包問題
先看下圖,是在求出問題的解後整個動態規劃表呈現的結果。下面就來看看這張表是如何一步步填上去並求出最終問題解的。
解題思路
① 確定子問題
求容量爲V的揹包裝入物品的價值總和最大,則考慮第i件物品是否放入揹包,使得揹包的價值保持最大。
② 確定狀態及數組
用一個二維數組F[i][j]表示前i件物品放入容量爲j的揹包中可以獲得的最大價值(注意此處的容量是揹包的總容量,而不是揹包的剩餘容量)
③ 確定邊界值
F[0][0…V] = 0:表示不管第0件物品放入任意容量的揹包中其最大價值都是0,因爲不存在第0件物品。
F[0…N][0] = 0:表示任意物品放入容量爲0的揹包中其最大價值都是0,因爲容量爲0的揹包裝不下任何物品。
④ 確定狀態轉移方程
Ⅰ:若第i件物品無法放入容量爲j的揹包中
Ⅱ:若第i件物品可以放入容量爲j的揹包中,則分兩種情況:
例:
第Ⅰ種情況:
當[i,j] = [2,1]時,物品B的耗費空間Cost=2,而揹包的體積 j=1,很明顯物品B無法放入揹包中,所以
第Ⅱ種情況:
當[i,j] = [2,3]時,物品B的耗費空間Cost = 2,而揹包的體積 j=3,物品B可以放入揹包中,所以
作者在理解Ⅱ時有一個困惑:爲什麼第i件物品可以放入容量爲j的揹包中還需要比較不放入的情況?
所以並不是說物品E可以放入就馬上放入,因爲每放入一件物品都要騰出相應的空間
而騰出的空間可以放入其它物品,而有可能放入其它的物品價值總和大於物品E的價值。
⑤ 代碼實現
public class Solution{
public int dp(int[] wealth, int[] cost, int V, int N){
//特殊狀態處理
if(wealth.length != cost.length){return -1;}
if(wealth.length == 0){return 0;}
if(wealth.length == 1){
if(cost[0] > V){
return 0;
}else{
return wealth[0];
}
}
int[][] F = new int[N + 1][V+1];
//邊界值處理
for(int i = 1; i < N + 1; i++){
for(int j = 1; j < V + 1; j++){
//先假設不能放入容量爲j的揹包
F[i][j] = F[i-1][j];
//判斷能不能放入揹包
if(j >= cost[i-1]){
F[i][j] = Math.max(F[i-1][j], F[i-1][j-cost[i-1]] + wealth[i-1]);
}
}
}
return F[N][V];
}
}
時間有限,能力有限,若有誤希望能夠指出,樂意與大家交流!