当前位置:   article > 正文

完全背包&多重背包问题(动态规划)

完全背包&多重背包问题(动态规划)

完全背包问题:

每个物品使用次数没有限制,与0-1背包的不同之处在于遍历背包的顺序是正序。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main(){
  4. int n, v;
  5. cin >> n >> v;
  6. vector<int> weight(n), values(n), dp(v+1, 0); // dp[j]:容量为j的背包的最大价值
  7. for(int i=0; i<n; i++){
  8. cin >> weight[i] >> values[i];
  9. }
  10. for(int i=0; i<n; i++){
  11. for(int j=weight[i]; j<=v; j++){ // j的取值比较关键
  12. dp[j] = max(dp[j], dp[j-weight[i]]+values[i]);
  13. }
  14. }
  15. cout << dp[v];
  16. return 0;
  17. }

多重背包问题:

与完全背包的区别在于,每一种物品是有个数限制的,不能无限选择。这篇博客讲解的非常详细,可以参考学习:

多重背包问题---超详细讲解+优化(不懂你揍我)-CSDN博客文章浏览阅读2.1w次,点赞83次,收藏259次。多重背包我们其实可以看成为01背包和完全背包的组合。但是怎么组合的呢?也可以就把多重背包问题转换成01背包问题,我们一起来看看解题思路。1.状态表示DP问题我们先来看状态表示二维数组的表示,F[i][j]代表前 i 个物品中,背包容量为 j 时所能拿到的最大价值。然后我们就看如何把多重背包转换成01背包与完全背包。2.转换(1)转换为01背包我们知道,01背包问题指的是各个物品只有一件,但在多重背包问题中,我们每种物品有 Si 件。我们可以考虑将多个同种物品合成一件物品。.._多重背包https://blog.csdn.net/windfriendc/article/details/123892024

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main(){
  4. int n, v;
  5. cin >> n >> v;
  6. vector<int> weight(n), values(n), nums(n), dp(v+1, 0);
  7. for(int i=0; i<n; i++){
  8. cin >> weight[i] >> values[i] >> nums[i];
  9. }
  10. for(int i=0; i<n; i++){ // 先遍历物品
  11. if(nums[i]*weight[i] >= v){ // 如果nums[i]*weight[i] >= v,则可以转换为完全背包问题
  12. for(int j=weight[i]; j<=v; j++){ // 完全背包要正序遍历
  13. dp[j] = max(dp[j], dp[j-weight[i]]+values[i]);
  14. }
  15. }else{ // 否则转换为0-1背包问题
  16. for(int j=v; j>=weight[i]; j--){ // 0-1背包要倒序遍历
  17. for(int k=nums[i]; k>=0; k--){ // 每件物品有k的数量限制
  18. if(j >= k*weight[i])
  19. dp[j] = max(dp[j], dp[j-k*weight[i]]+k*values[i]);
  20. }
  21. }
  22. }
  23. }
  24. cout << dp[v];
  25. return 0;
  26. }

多重背包问题的二进制优化:

假设我们想要拿1024件物品,按照转化成0-1背包的方法做,我们需要从拿1件枚举到拿1024件。而二进制优化则是利用倍增思想,把拿多少件物品分为拿1、2、4、8、16、...、256、512、...、2^n件,枚举的时候10次就到1024件了。基于上述思想,无论是多少件,总能用一些数的组合来表示,比如15(二进制形式:1111)就可以用8 + 4 + 2 + 1来表示,只需要枚举4次。这就是二进制优化的思想。

解题思路:将1、2、4...的物品分别保存下来它们的重量和价值,然后转化为0-1背包问题

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int main(){
  4. int N, V;
  5. cin >> N >> V;
  6. vector<int> s(N), v(N), w(N), dp(V+1, 0);
  7. vector<int> biV, biW; // 合成的新物品体积和价值
  8. for(int i=0; i<N; i++){
  9. cin >> v[i] >> w[i] >> s[i];
  10. for(int k=1; k<=s[i]; s[i]-=k, k*=2){ // 用k取遍物品i所有个数,这里的 s[i]-=k, k*=2 顺序不能变,否则会出错
  11. biV.push_back(k*v[i]);
  12. biW.push_back(k*w[i]);
  13. }
  14. if(s[i] > 0){
  15. biV.push_back(s[i]*v[i]);
  16. biW.push_back(s[i]*w[i]);
  17. }
  18. }
  19. for(int i=0; i<biV.size(); i++){ // 转换成0-1背包
  20. for(int j=V; j>=biV[i]; j--){
  21. dp[j] = max(dp[j], dp[j-biV[i]]+biW[i]);
  22. }
  23. }
  24. cout << dp[V];
  25. return 0;
  26. }

以上代码均为测试用的样例代码,实际问题需要根据题目要求进行修改。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/354697
推荐阅读
相关标签
  

闽ICP备14008679号