題目來源:牛客網 01揹包
現有一個容量大小為V的揹包和N件物品,每件物品有兩個屬性,體積和價值,請問這個揹包最多能裝價值為多少的物品
輸入描述:
第一行兩個整數V和n 接下來n行,每行兩個整數體積和價值,1≤N≤1000,1≤V≤20000 每件物品的體積和價值範圍在[1,500]
輸出描述:
輸出揹包最多能裝的物品價值
Example:
Input: 6 3
3 5
2 4
4 2
Output: 9
複製程式碼
原理
根據動態規劃解題步驟(問題抽象化、建立模型、尋找約束條件、判斷是否滿足最優性原理、找大問題與小問題的遞推關係式、填表、尋找解組成)找出01揹包問題的最優解以及解組成,然後編寫程式碼實現。
動態規劃與分治法類似,都是把大問題拆分成小問題,通過尋找大問題與小問題的遞推關係,解決一個個小問題,最終達到解決原問題的效果。但不同的是,分治法在子問題和子子問題等上被重複計算了很多次,而動態規劃則具有記憶性,通過填寫表把所有已經解決的子問題答案紀錄下來,在新問題裡需要用到的子問題可以直接提取,避免了重複計算,從而節約了時間,所以在問題滿足最優性原理之後,用動態規劃解決問題的核心就在於填表,表填寫完畢,最優解也就找到。
最優性原理是動態規劃的基礎,最優性原理是指“多階段決策過程的最優決策序列具有這樣的性質:不論初始狀態和初始決策如何,對於前面決策所造成的某一狀態而言,其後各階段的決策序列必須構成最優策略”。
實現細節(重要)
核心資料結構是dp[i][j]
,指在揹包當前容量為j
的情況下,前i
個物品最佳組合的價值。
- 01揹包的資料從
dp[0][0]
開始增長,顯然dp[0][0]
是值為0
的情況。
- 此後以先討論前
i
個物品在不同當前剩餘揹包容量即j
的情況下的最大可容納值。
- 用
w[i]
表示當前第i
件物品的體積:
- 如果
dp[i][j]
中的j
小於w[i]
,說明在當前要裝的第j
個物品不能被放入dp[i-1][j]
表示的情況,即j<w[i]
dp[i][j] = dp[i-1][j]
。在這種情況下沒得選,只能將第i
件物品放棄,即保持dp[i-1][j]
表示的情況。 - 如果
dp[i][j]
中的j
大於w[i]
,說明在當前要裝的第j
個物品可以被放入dp[i-1][j]
表示的情況,這個時候有兩種選擇:放、不放。那選擇標準肯定是最大化的價值,即j>=w[i]
dp[i,j] = max {dp[i-1,j],dp[i-1,j-w[i]]+v[i]}
,其比較過程在max
函式中完成。關鍵是理解不放的時候比放的時候價值還要大的情況,即同樣在前i-1的種類中,可能dp[i-1,j-w[i]]
會比dp[i-1,j]
小很多的情況(當前可用揹包容量j-w[i]
太小,即使加上了v[i]
也不足以超過同樣種類容量為j
時的最佳方案)。
表格填完最優解即是右下角的值。
程式碼
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int V = 0, n = 0;
//讀入揹包容量和物品數量
cin>>V>>n;
int w[n+1],v[n+1],dp[n+1][V+1];
//初始化矩陣值
for(int i = 0;i<n+1;i++){
for(int j = 0;j<V+1;j++){
dp[i][j] = 0;
}
}
//依次讀入物品體積及價值
for(int i = 1; i<=n; i++){
cin>>w[i]>>v[i];
}
//按前i件物品的順序填表
for(int i = 1;i<=n;i++){
//噹噹前剩餘容量j小於揹包的最大值時
for(int j = 1;j<=V;j++){
//程式碼實現兩種情況
if(j<w[i]){
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
}
}
}
//輸出右下角的值
cout<<dp[n][V]<<endl;
return 0;
}複製程式碼
揹包問題最優解回溯
通過上面的方法可以求出揹包問題的最優解,但還不知道這個最優解由哪些商品組成,故要根據最優解回溯找出解的組成,根據填表的原理可以有如下的兩種尋解方式
dp[i][j] = dp[i-1][j]
時,即在i-1
種物品的最優情況下,不加入(可能是由於空間不夠或者是實現細節所述的非最優解情況)第i
種物品是前i種物品的最優情況,即回到dp[i-1,j]
;dp[i,j] = dp[i-1,j-w[i]]+v[i]
時,即在i-1
種物品的最優情況下,加入了第i種物品,該物品是最優解組成的一部分,隨後我們得回到裝該物品之前,即回到dp[i-1,j-w[i]]
;
根據上述方法遍歷表格即可獲得最優解的記錄。