前面提到:

不知道大家注意到没有?上述实现方式没有使用单位体积价值的排序,和之前提到01背包回溯法基于单位体积价值实现不一样(先装单位体积价值高的)。

我们网上经常看到都是基于以上实现的,到底这个用有什么好处了?实际上基于排序的单位体积价值是一个非常精确的限界函数

基于优先级队列的实现方式,就需要用到以上的结构:

优先级队列方式需要数据预处理,为什么需要预处理数据了,这里使用的是优先级队列,这个优先级的选区非常重要,也非常重要
之前的策略curValue+rest就不行了,不是不行,是不够好,那是一个粗糙的界,可以看到一开始选的就不是最优,然后又往回跳跃,因为在这种策略下,无法保证最优,这时需要精心挑选优先级,使之尽可能少往回跳跃或者跳低点,就像思考贪心策略那样,实际上就是思考贪心策略,贪心就是配合优先级队列使用的这里首先把数据安装单位体积价值降序排列。

代码实现如下:

import heapq
class Nodes:def __init__(self,CurValue=None,CurCost=None,depth =None,parent=None,Flag=None):# 部分解所占体积self.CurCost = CurCost# 部分解所占价值self.CurValue = CurValue# 处于那一层self.depth = depth# 当前结点是否选择了物品        self.isleft = Flag# 前一个结点是谁self.parent = parentclass PQ_pack_01_with_solution_tracking:def __init__(self,N,V,C,W):self.num = Nself.volume = Vself.cost = Cself.value = W#(0当前的价值,1,当前体积,2当前的深度,3父节点,4是否选择了该物品)self.bestnode = Nodes(0,0,0,None,False)# 保存最后的方案self.bestsolution = [False]*N# 数据预处理,为什么需要预处理数据了,这里使用的是优先级队列,这个优先级的选区非常重要,也非常重要# 之前的策略curValue+rest就不行了,因为在这种策略下,无法保证最优,这时需要精心挑选优先级,就像# 思考贪心策略那样,实际上就是思考贪心策略,贪心就是配合优先级队列使用的# 这里首先把数据安装单位体积价值降序排列,self.order记录与之前排列的标号,用于恢复最后结果self._cost,self._value,self.order = self.sort_group(N,C,W)# 把数据安装单位体积价值降序排列def sort_group(self,N,C,W):# 原来数据的标号O = [i for i in range(N)]perp = [0]*Nfor i in range(N):perp[i] = W[i]/C[i]for i in range(N-1):for j in range(i+1,N):if  perp[i] < perp[j]:                    temp = perp[i]perp[i] = perp[j]perp[j] = temptemp = O[i]O[i] = O[j]O[j] = temptemp = C[i]C[i] = C[j]C[j] = temptemp = W[i]W[i] = W[j]W[j] = temp                    return C,W,O# 限界函数,这个限界函数就非常精确,确保了每一次往下都是最优的策略def bound(self,depth,CurCost,CurValue):left_weight = self.volume - CurCostb = CurValuewhile depth < self.num and self._cost[depth] <= left_weight:left_weight -=self._cost[depth]b += self._value[depth]depth +=1if depth < N:b += (self._value[depth]/self._cost[depth]) * left_weightreturn bdef PQ_pack_01(self):pqueue = []   # 初始化,从root开始current_node = Nonecurrent_value = 0current_cost = 0depth = 0# 终止条件,优先级队列里面存的是(0当前的价值,1,当前体积,2当前的深度,3父节点,4是否选择了该物品)# 只要取第self.num层最优的current_value就可以了,只要到self.num层终止就行了while depth != self.num:# 满足约束条件,存入左结点if current_cost + self._cost[depth] <= self.volume:# 每次进入左结点更新最优质,这样方便剪枝,让没有必要的点不放进优先级队列if current_value + self._value[depth] > self.bestnode.CurValue:self.bestnode.CurValue =current_value + self._value[depth]# 确定待放入结点的上界temp = self.bound(depth+1,current_cost+self._cost[depth],current_value+self._value[depth])# 把待放入结点的上界,当前价值,当前花费,当前层次,父亲,是左是右放入优先级队列# 因为是要求最大堆,随意优先级取了-,heapq默认是取最小堆,直接求最大堆的包还不知道怎么用heapq.heappush(pqueue,(-temp,Nodes(current_value + self.value[depth],current_cost+self._cost[depth],depth+1,current_node,True)))# 对于右结点计算上界up = self.bound(depth+1,current_cost,current_value)# 加入上界小于当前最优质,就没有必要放入优先级队列,免得给优先级队列增加负担# 等于的情况需要放进去,因为这时路径必须的,没有等于0,就没法深入了if up >= self.bestnode.CurValue:heapq.heappush(pqueue,(-up,Nodes(current_value,current_cost,depth+1,current_node,False)))# 弹出下一个最优的结点,0代表上界,1包含了所需要的信息current_node = heapq.heappop(pqueue)[1]current_value = current_node.CurValuecurrent_cost = current_node.CurCostdepth = current_node.depthprint(depth,current_value)self.bestnode = current_nodeprint(self.bestnode.CurValue)# 追踪解   def solution_tracking(self):# 追踪解,获取最优方案BestResult =[False]*Nfor i in range(self.num -1,-1,-1):BestResult[i] = self.bestnode.isleftself.bestnode = self.bestnode.parent# 将最优方案翻译成原来的排序    for i in range(N):if BestResult[i]:self.bestsolution[self.order[i]] = Trueprint(self.bestsolution)N = 8
V = 30
C = [11,2,3,9,13,6,15,7]
W = [5.0,2.0,5.0,7.0,5.0,11.0,6.0,14.0]tt =PQ_pack_01_with_solution_tracking(N,V,C,W)
tt.PQ_pack_01()
tt.solution_tracking()1 14.0
2 25.0
3 30.0
4 32.0
5 39.0
6 39.0
7 39.0
4 30.0
8 39.0
39.0
[False, True, True, True, False, True, False, True]

限界分支法:01背包问题,优先级队列(包含解的追踪)相关推荐

  1. 限界分支法(实际上没有剪枝,介绍的是广度优先搜索):01背包问题,队列实现方式(FIFO)

    限界分支法:队列实现方式 前面已经介绍过限界分支法大部分是基于广度优先搜索,广度优先搜索一般借助于队列实现,剪枝的情况可以借助于优先级队列. 实现如下: #%% class FIFO_01_Pack: ...

  2. 限界分支法(队列方式)追踪解:01背包问题

    追踪解 追踪解,上述实现的情况下,解都在最后一层,根本不知道之前的路径是怎样的,广度优先搜索,同一个纬度,假如不加指标判断的话,根本不知道最优解是选择的哪一个,所以需要同一个纬度的每一个结点,记住他之 ...

  3. 货郎问题:回溯法和限界分支法

    这个问题可以堪称一个全排列,[起点,剩下的全排列] 回溯法 import numpy as npclass backtracking_Traveling_saleman:# 初始化,明确起点def _ ...

  4. 限界分支法优先级队列方式出口和追踪解的两种方法总结

    在优先级队列分支限界法法中,何时为出接口,也就是while循环何时退出了? 解空间为[0,1,2-,n-1],当depth = n-1时,就可以记录结果了,可以考虑循环体退出了(实际上能不能出,还要看 ...

  5. 【算法】回溯法——0-1背包问题

    [fishing-pan:https://blog.csdn.net/u013921430转载请注明出处] 回溯法        回溯法是一种非常有效的方法,有"通用的解题法"之称 ...

  6. C++STL之优先级队列详解

    priority_queue 文章目录 priority_queue priority_queue的使用 priority_queue在OJ中的使用 数组中第k个最大元素 priority_queue ...

  7. 动态规划之0-1背包问题(思路详解+表格演示过程+最优解打印方法+详细代码)

    问题简介 输入:n种物品和一个背包 物品i的重量是wi,价值为vi 背包的容量是C 输出:装入背包的物品 优化目标是:装入背包的物品总价值最大 优化子结构 设(x1,x2,x3-xn)是0-1背包问题 ...

  8. python 回溯法 01背包问题_回溯法-01背包问题

    一.问题描述 给定 n 件物品,物品的重量为 w[i],物品的价值为 c[i].现挑选物品放入背包中,假定背包能承受的最大重量为 V,问应该如何选择装入背包中的物品,使得装入背包中物品的总价值最大 二 ...

  9. python 回溯法 01背包问题_回溯法解决01背包问题

    回溯法是一个既带有系统性又带有跳跃性的搜索算法. 它在包含问题的所有解的解空间树中按照 深度优先的策略, 从根节点出发搜索解空间树. 算法搜索至解空间树的任一节点时, 总是先判断 该节点是否肯定不包含 ...

最新文章

  1. 神经网络:多层网络与C++实现
  2. vm虚拟机和windows共享文件夹
  3. 什么是codepage?
  4. NYOJ 752 又见回文串
  5. java普通类跳转到jsp_JSP跳转到Servlet的两种配置
  6. 淡黄色电子书阅读器网站模板
  7. GitHu的诞生记 转 https://blog.csdn.net/fanpeihua123/article/details/58151161
  8. JVM初学之类java的类加载器和双亲委派模型
  9. python中的with使用方法[探索5]
  10. 2021-2025年中国车轮运动防护产品行业市场供需与战略研究报告
  11. linux 防火墙安装在哪,Linux下Shorewall防火墙安装和配置
  12. 海康网络摄像头web端展示
  13. 羡慕的核心是焦虑_焦虑是自由的头晕
  14. 《高效能人士的7个习惯》PDF,复习笔记(上)
  15. html— Meta— http-equiv属性
  16. Linux_常用的磁盘列阵(RAID)
  17. Windows PE 第四章 导入表
  18. docker部署教程
  19. ccd和cmos的区别
  20. Github报错fatal unable to access No such file or directory

热门文章

  1. mysql数据冗余_MySQL冗余数据的三种方案
  2. linux inotifywait脚本,使用inotify/fswatch构建自动监控脚本
  3. 密度图的密度估计_基于核密度的宝鸡地名文化特征与时空分布研究
  4. word手写字体以假乱真_学会Word上下标,搞定公式输入
  5. 【spring boot】【spring cloud】异常:找不到方法HikariDataSource.getMetricsTrackerFactory()
  6. JVM学习笔记(四)
  7. tfds.load()和tf.data.Dataset的简介
  8. suse 11 oracle 10g,suse11+oracle10g安装
  9. android解析ip地址,android – 如何从IP地址解析网络主机名
  10. java 采样_java 采集数据