代码链接:
链接:pan.baidu.com/s/1GAFnDuj7-3x6BNa0uOL9Vg
码:pbfv
算法分析与设计 | |||||
时间 | 2020.5.31 | ||||
实验名称 | 用优先队列式分支限界法求解0-1背包问题 | ||||
实验目的 | 通过上机实验,要求掌握优先队列式分支限界法求解 0-1 背包问题的问题描述、算法设计思想、程序设计。 | ||||
实验原理 | 使用优先队列式的分支限界算法,能准确的找出限定容量背包所能装载的商品的最大价值, 并计算出程序运行所需要的时间。 | ||||
实验步骤 | 问题分析: 给定n种物品和一个背包,物品i的重量为wi,价值为vi,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中的物品总价值最大? 实验的要求为使用优先队列式的分支限界法来求解0-1背包问题; 分支限界法的思想是: 分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。 在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。 此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。 0-1背包问题可以用最大值堆来实现优先队列,也可以直接使用STL库中提供的基于堆的优先队列,而优先级的比较则可以通过背包中活结点已有的物品总价值,当然也可以用总价值与所占背包容量的比值来实现。 此外,用于剪枝的上界函数可以用与回溯法相同的算法来完成。 上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。 为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。 算法思路: 整体的思路为:在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展对点。为了有效地选择下一扩展结点,以加速搜索的进程,在每一活结点处,计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解。 算法步骤: 首先,将数据从文件中读取出来后,根据每个物品的重量和价值计算出物品的单价,根据单价将物品进行排序(此步骤与回溯算法基本相同),以下是优先队列式分支限界法的搜索过程: ① 搜索解空间建立二叉树,从根节点开始; ② 广度优先遍历二叉树,并用极大堆表示活结点的优先级,选取扩展结点,找出可行解。 ③应当检查左儿子结点是否是可行结点(即上界大于当前最优值且加上该物品的重量不超过背包容量),如果是则将它加入到活结点优先队列中,而当前扩展结点的右儿子一定是可行结点,仅当右儿子满足上界约束时才将它加入到活结点优先队列中; ④对优先队列进行堆结构的维护,使得堆顶元素依然是优先级最高的结点; ⑤重复②③④步骤直到优先队列为空; ⑥输出结果 | ||||
关键代码 | 关键代码(带注释)1. 初始化函数init() 输入背包容量、物品总数、物品价值重量等数据,求出每一个物品的单位重量的价值,根据该单价进行从大到小的排序; 2. 求上界函数bound(用于剪枝)按照剩余物品的单价将背包的剩余容量塞满(可塞一个物品的一部分),塞满后的背包内的物品总价值即为上界,若该上界小于当前最优值则剪枝; 这里与回溯法的不同点在于,这里的价值和重量来自每个活结点,每个活结点有自己的一份,而回溯法则只有一份,从这里可以看出回溯法的空间复杂度更低; 3. 计算时间部分代码通过时间函数QueryPerformanceFrequency与cpu的主频频率得到程序段的运行时间,可以精确到微妙,比clock函数更精确一些; 4. 添加活结点到优先队列的函数令孩子结点继承父节点的价值、重量信息,接着根据flag判断加入的是左孩子还是右孩子,更新子结点的信息后入队;如果此时达到叶子结点则更新最优值最优解(可以更新的话),叶子结点不用入队。 5. 优先队列式分支限界搜索(核心部分)首先将根节点加入队列,循环将队首元素出队并判断队首元素的左右子孩子是否满足约束条件且满足限界条件,满足则加入队列,持续这个过程直到队列为空。 | ||||
测试结果 | 运行结果截图及分析对于课本样例: 运行结果正确; 对于三种不同规模的文件(10、100、1000): 可以看到对三种规模的文件进行测试的结果,数据规模越大则时间越长,算法运行实际时间比回溯法略长; 时间复杂度分析: 该问题为回溯法的子集树问题,对每一个物品都有放入与不放两种决策,而对于上界函数的求解是需要O(n)的时间复杂度的,因此遍历解空间树的时间复杂度为O(n2n ); 空间复杂度分析: 这里每一个活结点都需要O(n)的空间存储结点信息(主要是解向量的存储),因此空间复杂度也是O(n2n )的。 | ||||
实验心得 | 在前面的学习中我们也学过使用多种方法来求解0-1背包问题,这里的分支限界法与其他方法有着许多异同之处。 分支限界法类似于回溯法,也是一种在问题的解空间树T上搜索问题解的算法。但在一般情况下,分支限界法与回溯法的求解目标不同。回溯法的求解目标是找出T中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。 由于求解目标不同,导致分支限界法与回溯法在解空间树T上的搜索方式也不相同。回溯法以深度优先的方式搜索解空间树T,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树T。 |