你的揹包讓我走得好緩慢,借了終於陪着我腐爛
1. 0/1揹包
有一個腐爛的揹包,容量爲v,現有n件物品,每件物品有兩個屬性,體積w,和價格p,我們要選擇物品往揹包裏放,使得在物品總容積不超過v的情況下價值最大。
思路:
1)我們只在乎某件物品放不放進揹包,而不在乎放進去的順序,因爲物品一樣,順序不一樣,結果相同。
2)我們從第一件物品開始考慮,只有兩種情況,放或不放,然後考慮第二件物品,放或不放,。。。。。。第n件物品放或不放。
3)放則記爲1,不放記爲0.那麼假如共4件物品,所有可能的情況爲0000,0001,0010,0011.....1111共16種情況。只要枚舉完這16種情況我們就知道最大價值是多少。
4)雖然上面說有16種情況,但實際上有些情況是不存在的,例如1111,放入第四個物品會超出揹包容量,所以應爲1110。
5)我們定義maxValue(n,v)爲容量爲v時,選取物品1~n中若干件所能得到的最大價值。我們從第n件到第1件物品一次判斷是否選取,每步都有下面的公式。不選maxValue(n-1,v),選maxValue(n-1,v-Vn)+Pn,取max
0 1
---maxValue(n,v)=max(maxValue(n-1,v), maxValue(n-1,v-Vn)+Pn),
當第k件物品遇到Vrest<Vk那麼第k件物品只能不選取:
---maxValue(n,v)=maxValue(n-1,v)
這樣在邊界的時候我們是可以直接得出結果的,然後回溯得出maxValue(n,v)。
解法:
1)我們可以用遞歸函數來求,注意的是要用一個temp[n][v]數組存儲已經求過的maxValue(n,v)來避免重複計算,因爲到達狀態[n,v]的可能不止一種情況。
2)用動態規劃,遞歸是自頂向下,到達邊界在回溯,而動態規劃則是直接自底向上。
每個maxValue(n,v)關聯的狀態只有maxValue(n-1,v)或maxValue(n-1,v-Vn).所以我們我們填一個n+1行v+1列的表,從maxValue(0,0)一直到maxValue(n,v),一直迭代。詳細解釋見https://blog.csdn.net/qq_38410730/article/details/81667885
2. 完全揹包
在完全揹包中是不限制每件物品的數量的,而0/1揹包是每種物品只有一件。此時的問題不是針對每種物品放或不放(放0個或1個),而是放幾個的問題(放0個,1個,2個。。。。or n個),這裏物品i最多放maxSpace//vi件。因此我們在放每件物品的時候要多加一個循環,分別算出maxValue(i,v)在物品i取0至maxSpace//vi件時的值,取最大的作爲maxValue[i][v]的最終值。動態規劃填表一行一行的填。詳細見https://www.cnblogs.com/mfrank/p/10803417.html
3.多重揹包
每種物品的數量爲num[i]個,完全揹包的物品數是無限的,多重揹包是有限個。和完全揹包基本相同,核心是每種物品放幾個,從0~num[i], 個數不超過num[i]的同時空間也不能超過揹包容量,詳細見https://www.cnblogs.com/mfrank/p/10816837.html
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int space,kind;
cin>>space>>kind;
vector<vector<int>>data(kind+1,vector<int>(3,0));
vector<vector<int>>dp(kind+1,vector<int>(space+1,0));
//space price num
//注意這裏是從1開始,只有物品1~kind,沒有物品0
for(int i=1;i<kind+1;i++)cin>>data[i][0]>>data[i][1]>>data[i][2];
for(int i = 1; i<kind+1;i++){
for(int j=1;j<space+1;j++){
for(int k=0;k<=data[i][2]&&j>=k*data[i][0];k++){//0表示不選,注意選的第i件物品總體積不超過當前的容量
//由於這裏考慮的是選k件物品的數量,所有下面每次減掉的空間是k*data[i][0],增加的價值是k*data[i][1]
dp[i][j]=max(dp[i][j],dp[i-1][j-k*data[i][0]]+k*data[i][1]);
}
}
return 0;
}
我不生產知識,我只是知識的搬運工------農夫