給定n種物品和乙個揹包。物品i的重量是wi,其價值位vi ,揹包的容量為c。問應該如何選擇裝入揹包的物品,使得轉入揹包的物品的總價值為最大?
在選擇物品的時候,對每種物品i只有兩種選擇,即裝入揹包或不裝入揹包。不能講物品i裝入多次,也不能只裝入物品的一部分。因此,該問題被稱為0-1揹包問題。
把這個過程理解下,在前i件物品放進容量c的揹包時,它有兩種情況:
第一種是第i件不放進去,這時所得價值為:v[i-1][j]
第二種是第i件放進去,這時所得價值為:v[i-1][j-w[i]]+v[i] (容量j-w[i]裡就要放進前i-1件物品)
狀態:狀態表示每個階段開始面臨的自然狀況或客觀條件,它不以人們的主觀意志為轉移,也稱為不可控因素。在上面的例子中狀態就是前i件物品放入容量j的揹包
定義了狀態後,下面就是定義狀態的轉移
可以得出狀態轉移方程
v[i][j]=max
在這裡使用乙個(n+1)*(c+1)的表來計算v[i,j]的值
假設3個物品容量為5
w分別 1 ,2 ,3
v分別 6,10,12
動態規劃的過程如下
//(非必須)輸出v陣列顯示動態規劃的過程
for(int x=0; x<=n; x++)
}//返回能裝下的最大價值
return v[n][c];
}int main() ;
int v[3]=;
cout
<3,5,w,v);
return
0;}上面使用了二維陣列來儲存中間狀態,我們也可以使用一維陣列得到結果,也就是滾動陣列
現在使用f[v]儲存中間狀態,我們想要達到的效果是,第i次迴圈後,f[v]中儲存的是前i個物體放到容量v時的最大價值
f陣列是從上到下,從右往左計算的。在計算f(i,j)之前,f[i]裡儲存的是上乙個迴圈,也就是f(i-1,j)的值,而f[j-w]裡儲存的是f(i-1,j-w)的值。這裡的重點是容量是逆序列舉的!
假設容量按照順序列舉,來檢測第 i 件物品是否能放。此時在執行第i次迴圈此時f[j-w]儲存的是f(i,j-w)因為,v > v - w,第i次迴圈中f[j-w]中儲存的實際是f(i,j-w)而非f(i-1,j-w)重點內容
int knapsack()
} return f[c];
}
在遞推法中,如果計算順序很特殊,而且計算新狀態所用到的原狀態不多。可以嘗試使用滾動陣列減少記憶體開銷,但滾動陣列也有侷限,例如列印方案較困難,當動態規劃結束後,只有最後乙個狀態的值,而沒有前面的值。總結一下
根據上例分析和動態規劃的基本概念,可以得到動態規劃的基本模型如下:(1)確定問題的決策物件。
(2)對決策過程劃分階段。
(3)對各階段確定狀態變數。
(4)根據狀態變數確定費用函式和目標函式。
(5)建立各階段狀態變數的轉移過程,確定狀態轉移方程。
動態規劃(2) 01揹包
給定n種物品和乙個揹包。物品i的重量是wi,其價值位vi 揹包的容量為c。問應該如何選擇裝入揹包的物品,使得轉入揹包的物品的總價值為最大?在選擇物品的時候,對每種物品i只有兩種選擇,即裝入揹包或不裝入揹包。不能講物品i裝入多次,也不能只裝入物品的一部分。因此,該問題被稱為0 1揹包問題。把這個過程理...
動態規劃系列(2) 01揹包問題的動態規劃解法
問題 有n 個物品,它們有各自的重量和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?dynamic programming 0 1 package problem include include include using namespace std struct item i...
動態規劃 揹包
揹包經典問題 揹包問題01 乙個揹包容積為t 0 t 2000 現在有n 0 如下 includeusing namespace std int s 1005 bool f 3000 int main 揹包問題02 若每種物品有無限多個。從這n種物品中選取若干個裝入揹包內,使揹包所剩的空間最小。請求...