算法笔记(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就好了
很好理解。