算法筆記(c++)--完全背包和多重背包問題
完全背包
完全背包不同於01背包-完全背包里面的東西數量無限
假設現在有5種物品重量為5,4,3,2,1
價值為1,2,3,4,5
背包容量為10
#include <iostream> #include<algorithm> using namespace std; int main() { int total_weight = 10; int w[6] = { 0,5,4,3,2,1}; int v[6] = { 0,1,2,3,4,5}; int dp[11] = { 0 }; for (int i = 1; i <= 5; i++) for (int j = w[i]; j <= 10;j++) dp[j] = max(dp[j],dp[j - w[i]] + v[i]); cout << "總的價值為: " << dp[10] << endl; return 0; }
其他都和01背包一樣,就是遍歷j時候的初始化不一樣。
這里的dp[j]還是表示前i件物品放入一個為j容量的背包獲得的最大價值,每次更新必然保證是當前最優解。就像求最長遞增子序列一樣。都是把所有情況過一遍然后拿最大的結果。
不多講直接推算幾步就全懂了。
1)首先是當只有物品1號的時候,j初始化為1號物品的重量為5
dp[5]=max(dp[5],dp[5-5]+1]=1
dp[6]到dp[9]都是1,dp[10]=2
2)然后現在是有物品1號和2號,j初始化為2號物品重量4
dp[4]=max(dp[4],dp[4-4]+2)=2
dp[5]=max(dp[5],dp[5-4]+2)=2
dp[..8]=max(dp[8],dp[8-4]+2)=4
其實到這里也差不多了,下面都是一樣的。
我們要決定是不是要放這個物品,就從這個物品的大小出發遍歷背包容量,然后每次遍歷都對比下假如現在騰出這個物品的空間並且放進去比原來的價值還大的話,就放進去。
區別------------01背包和完全背包
01背包遍歷是反向的,這樣更新就不會影響前面的。
而完全背包正向遍歷,會改變前面的所以也就可出現多次存放的了。
多重背包
多重背包再加點限制,數量有限制。
數據如下:
數量 | 重量 | 價值 |
0 | 0 | 0 |
1 | 5 | 1 |
2 | 4 | 2 |
1 | 3 | 3 |
2 | 2 | 4 |
1 | 1 | 5 |
同樣設背包為10大小
代碼如下:
#include <iostream> #include<algorithm> using namespace std; int main() { int total_weight = 10; int w[6] = { 0,5,4,3,2,1 }; int v[6] = { 0,1,2,3,4,5 }; int cot[6] = { 0,1,2,1,2,1 }; int dp[11] = { 0 }; for (int i = 1; i <= 5; i++) for (int k = 1; k <= cot[i];k++) for (int j = 10; j >= w[i]; j--) dp[j] = max(dp[j], dp[j - w[i]] + v[i]); cout << "總的價值為: " << dp[10] << endl; return 0; }
這次不一步步來了,懂01就可以了。
因為每次01都是放一個而完全背包是放多個,我們也不知道完全 背包放了幾個。所以多重背包算是01背包的變種。
既然我們每次遍歷都是判斷放不放這一個物品,那我們干脆就有幾個就遍歷幾遍。再遍歷外面再加一個for就好了
很好理解。