pan.baidu.com/s/1w-VSMWmr9ntEWWdxZoD4Yw
码:jnlh
算法分析与设计 | |||||
时间 | 2020.5.16 | ||||
实验名称 | 用回溯法求解0-1背包问题 | ||||
实验目的 | 通过上机实验,要求掌握回溯算法的问题描述、算法设计思想、程序设计。 | ||||
实验原理 | 给定任意几组数据,利用回溯算法的限界与剪枝的思想,求解0-1背包问题并输出答案。 | ||||
实验步骤 | 问题分析:给定n种物品和一背包。物品i的重量是wi>0,其价值为vi>0,背包的容量为c。问应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? (要求使用回溯法) 书上例题: 手动求解应该选择1、3、4三个物品,最优值为20; 算法思想:01背包属于找最优解问题,用回溯法需要构造解的子集树。对于每一个物品i,对于该物品只有选与不选2个决策,总共有n个物品,可以顺序依次考虑每个物品,这样就形成了一棵解空间树; 基本思想就是遍历这棵树,以枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,该方案就是最后的答案。 在搜索状态空间树时,只要左子节点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其减去(剪枝)。 上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。 为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。 算法步骤:① 将用例数据从文件中读取,初始化数据; ② 将物品按照单位重量的价值从大到小排序; ③ 进行操作如下: 利用回溯法试设计一个算法求出0-1背包问题的解,也就是求出一个解向量Xi(即对n个物品放或不放的一种的方案) 其中, (Xi= 0 或1,Xi = 0表示物体i不放入背包,Xi =1表示把物体i放入背包)。 从第0层开始进行递归函数Backtrack, 当i>n时,算法搜索至叶子结点,得到一个新的物品装包方案,此时算法适时更新当前的最优价值和最优解; 当i<n时,当前扩展结点位于排列树的第(i-1)层,此时算法选择下一个要安排的物品,以深度优先方式递归的对相应的子树进行搜索,对不满足上界约束的结点,则剪去相应的子树。 ④当整个解空间树遍历完成则输出最优值与最优解; | ||||
关键代码 | 关键代码(带注释)1. 初始化函数init()
输入背包容量、物品总数、物品价值重量等数据,求出每一个物品的单位重量的价值,根据该单价进行从大到小的排序; 2. 求上界函数bound(用于剪枝)按照剩余物品的单价将背包的剩余容量塞满(可塞一个物品的一部分),塞满后的背包内的物品总价值即为上界,若该上界小于当前最优值则剪枝; 3. 计算时间部分代码通过时间函数QueryPerformanceFrequency与cpu的主频频率得到程序段的运行时间,可以精确到微妙,比clock函数更精确一些; 4. 随机数生成程序利用rand()函数生成大小为10、100、1000的三个文件,其中全为随机数; 3、4两个部分与之前的实验所用方法相同; 5. 回溯函数(核心部分)如果当前层达已处理完最后一个物品,则说明当前的价值比现在的最优值要大,因此更新最优值与最优解; 如果当前层未处理完最后一个物品,则如果当前物品可放入背包则直接进入左子树,如果右子树(不放入当前物品)的上界大于当前最优值则可以进入右子树; | ||||
测试结果 | 运行结果截图及分析对于课本样例: 运行结果正确; 对于三种不同规模的文件(10、100、1000): 可以看到对三种规模的文件进行测试的结果,数据规模越大则时间越长; 因为剪枝的原因看不出其O(2^n)的时间复杂度; 时间复杂度分析: 该问题为回溯法的子集树问题,对每一个物品都有放入与不放两种决策,因此遍历解空间树的时间复杂度未O(2^n); | ||||
实验心得 | 通过这次实验,我回顾了回溯算法的基本原理,回溯法的剪枝与限界方法在本问题中有着清晰简洁的体现,加深了我对它们的使用的熟练度。为更难更深层次的问题的回溯法求解打下基础。 |