当前位置:   article > 正文

0-1背包问题(分支限界法)_分支限界法0-1背包问题

分支限界法0-1背包问题

需求分析

0.问题描述

给定一背包的容量C,和n个物品的重量wi价值vi,求在背包容量允许的条件下能装入的最大价值

1.问题分析

①解空间:子集树,第i层每个节点有两棵子树:选择物品i,不选择物品i

优先队列的优先级如何确定?

每个节点的祖先节点都已经确定,那么可以得到已经装入背包的物品的价值,加上剩余 物品能装入背包的最大价值,依此得到优先级,即当前结点的“值”。

这里用的是近似,剩余的物品按照单位重量价值非升序排序,将单位重量价值大的先放 入,放不下整个物品的话,就放入一部分。

③剪枝:进入左子节点时,物品的重量小于剩余背包的容量;进入右子结点时,要满足 上界约束。进入一个子结点就把它加入优先队列。

上界约束:当前结点的“值”比最优解的值要大。

2.输入数据

输入背包的容量,物品的重量和价值

3.输出数据

输出能装入背包的最大价值

4.测试样例设计

  1. 100 5
  2. 77 92
  3. 22 22
  4. 29 87
  5. 50 46
  6. 99 90
  7. 200 8
  8. 79 83
  9. 58 14
  10. 86 54
  11. 11 79
  12. 28 72
  13. 62 52
  14. 15 48
  15. 68 62
  16. 300 10
  17. 95 89
  18. 75 59
  19. 23 19
  20. 73 43
  21. 50 100
  22. 22 72
  23. 6 44
  24. 57 16
  25. 89 7
  26. 98 64

算法设计与分析

1.算法的基本思想

 

变成了非层次遍历

 

比如:

  1. 第一层根结点,左右子结点都满足条件,加入队列;右结点优先级比较高
  2. 处理根节点的右结点,它的左右子结点都可以加入,现在队列里面有它父结点的左子结点和它的两个子节点,其中它的左子结点优先级比较高
  3. 处理根节点的右子结点的左子结点,两个子节点都可以加入……

基本思想:

①输入的物品重新排序,按照单位重量价值降序排序

②在一个优先队列里面保存目前待处理的结点,取出的队首元素是值最大的,目前最有 可能成为最优解路径的一部分。

③不断取出队首元素进行处理,考察其左右子结点,满足条件加入优先队列

④不断重复以上③步骤,直到处理的结点是叶子结点,那么它到根节点的路径一定是最 优解。

2.输入和输出的格式

从文件输入,输出到文件。

有多组输入,每组数据第一行是背包的容量C,和物品的件数n,接下来的n行第i行 是物品i的重量,物品i的价值。

3.算法的具体步骤

 

 

4.算法的时空分析

①空间复杂性:限界函数为O(1),最坏情况下需搜索2^(n +1) –2个节点,需O(2^n ) 个空间存储节点,则算法空间复杂性为O(2^n )。
②时间复杂性:限界函数时间复杂度为O(n),而最坏情况有2^(n +1) – 2个节点,若 对每个节点用限界函数判断,则其时间复杂度为O(n2^n).而算法中时间复杂度主要依赖 限界函数,则算法的时间复杂度为O(n2^n)。

、测试结果

 

全部代码:

  1. #include <bits/stdc++.h>
  2. #include <fstream>
  3. #include <iostream>
  4. using namespace std;
  5. class Object
  6. {
  7. public:
  8. int id;//编号
  9. int weight;//重量
  10. int price;//价值
  11. float d;//单位重量价值
  12. };
  13. class MaxHeapQNode
  14. {
  15. public:
  16. MaxHeapQNode *parent;//父结点,可以记录下路径
  17. int lchild;//左子结点
  18. int upprofit;//值
  19. int profit;//当前价值
  20. int weight;//重量
  21. int lev;//层次
  22. };
  23. //建立优先队列时使用的
  24. struct cmp
  25. {
  26. bool operator()(MaxHeapQNode *&a, MaxHeapQNode *&b) const
  27. {
  28. return a->upprofit < b->upprofit;
  29. }
  30. };
  31. //用于预处理的重排
  32. bool compare(const Object &a, const Object &b)
  33. {
  34. return a.d >= b.d;
  35. }
  36. int n;//物品件数
  37. int c;//背包容量
  38. int cw;//当前重量
  39. int cp;//当前解
  40. int bestp;//最优解的值
  41. Object obj[100];//物品集合
  42. int bestx[100];//最优解的物品集合
  43. ifstream in("input.txt");
  44. ofstream out("output.txt");
  45. //上界函数
  46. int Bound(int i)
  47. {
  48. int tmp_cleft = c - cw;
  49. int tmp_cp = cp;
  50. while(tmp_cleft >= obj[i].weight && i <= n)
  51. {
  52. tmp_cleft -= obj[i].weight;
  53. tmp_cp += obj[i].price;
  54. i++;
  55. }
  56. if(i <= n)
  57. {
  58. tmp_cp += tmp_cleft * obj[i].d;
  59. }
  60. return tmp_cp;
  61. }
  62. //添加节点到优先队列
  63. void AddAliveNode(priority_queue<MaxHeapQNode *, vector<MaxHeapQNode *>, cmp> &q, MaxHeapQNode *E, int up, int wt, int curp, int i, int ch)
  64. {
  65. MaxHeapQNode *p = new MaxHeapQNode;
  66. p->parent = E;
  67. p->lchild = ch;
  68. p->weight = wt;
  69. p->upprofit = up;
  70. p->profit = curp;
  71. p->lev = i + 1;
  72. q.push(p);
  73. }
  74. //分支限界法求解
  75. void MaxKnapsack()
  76. {
  77. //运用了优先队列,里面存储结点的指针,建立在动态数组上,以cmp来确定优先级
  78. priority_queue<MaxHeapQNode *, vector<MaxHeapQNode *>, cmp > q;
  79. //初始化
  80. MaxHeapQNode *E = NULL;
  81. cw = cp = bestp = 0;
  82. int i = 1;
  83. int up = Bound(1);
  84. //当处理的层次没有达到叶子结点,不断处理队列中的结点
  85. while(i != n + 1)
  86. {
  87. //左子结点,如果小于背包剩余容量,可以加入
  88. int wt = cw + obj[i].weight;
  89. if(wt <= c)
  90. {
  91. if(bestp < cp + obj[i].price)
  92. bestp = cp + obj[i].price;
  93. AddAliveNode(q, E, up, cw + obj[i].weight, cp + obj[i].price, i, 1);
  94. }
  95. //右子结点,如果可能产生最优解,可以加入
  96. up = Bound(i + 1);
  97. if(up >= bestp) //(注意这里必须是大于等于)
  98. {
  99. AddAliveNode(q, E, up, cw, cp, i, 0);
  100. }
  101. //取出队首结点给下一次循环来处理
  102. E = q.top();
  103. q.pop();
  104. cw = E->weight;//(结点的重量)
  105. cp = E->profit;//(结点的价值)
  106. up = E->upprofit;//(结点的值)
  107. i = E->lev;//(结点的层次)
  108. }
  109. //构造最优解的物品集合
  110. for(int j = n; j > 0; --j)
  111. {
  112. bestx[obj[E->lev-1].id] = E->lchild;
  113. E = E->parent;
  114. }
  115. }
  116. //输入&&预处理
  117. int InPut()
  118. {
  119. if(in>>c){
  120. in>>n;
  121. for(int i = 1; i <= n; ++i)
  122. {
  123. in>>obj[i].weight>>obj[i].price;
  124. obj[i].id = i;
  125. obj[i].d = 1.0 *obj[i].price / obj[i].weight;
  126. }
  127. //重排
  128. sort(obj + 1, obj + n + 1, compare);
  129. return 1;
  130. }
  131. return 0;
  132. }
  133. //输出
  134. void OutPut()
  135. {
  136. out<<bestp<<'\n';
  137. for(int i = 1; i <= n; ++i)
  138. if(bestx[i] == 1)
  139. out<<i<<' ';
  140. out<<'\n';
  141. }
  142. int main()
  143. {
  144. while(InPut()){
  145. MaxKnapsack();
  146. OutPut();
  147. }
  148. in.close();
  149. out.close();
  150. return 0;
  151. }

 

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

闽ICP备14008679号