背包问题
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
这就是典型的背包问题(又称为0-1背包问题),也是具体的、没有经过任何延伸的背包问题模型。
背包问题的传统求解方法较为复杂,现定义有一个可以载重为8kg的背包,另外还有4个物品,物品的价值和质量数据如下表,不考虑背包的容量。4个物品的总质量大于8kg,所以要想在有限载重的背包携带更多质量的物品,就要有一套算法进行取舍,最终寻找到最优解。
传统的背包问题解法是根据动态规划解题步骤(问题抽象化、建立模型、寻找约束条件、判断是否满足最优性原理、找大问题与小问题的递推关系式、填表、寻找解组成)找出0-1背包问题的最优解以及解组成。实现流程图如图:
根据算法流程,不妨计算一下上述问题,由于物体有8个,且其质量都是整千克数,背包最大载荷是8kg,定义V(i,j)为当前背包容量为j,前i个物品最佳组合对应的价值。建立一个4行8列的表格,如表:
在表中,依次计算每列的数据,如i=1,j=1时,对应的方块的值V(1,1)代表当前背包容量为1,前1个物品(即表\ref{tableproblem1}中的物品1)最佳组合对应的价值。因为第1个物品质量为2kg,所以不能装进背包,故V(1,1)=0.继续计算V(1,2),比较V(1-1,2)=V(0,2)=0与V(1-1,2-w(1))+v(1)=3的值,V(1,2)即为两者中的较大值3.因为i=1时,仅有物品1可以装进背包,所以不论背包容量是多少都最多只能放入物品1,所以i=1对应的其余V都是3,即:V(1,3)=V(1,4)=V(1,5)=V(1,6)=V(1,7)=V(1,8)=3.
继续计算i=2的情况。V(2,1)很显然等于1,因为2-w(2)<0,所以V(2,2)=3.V(2,3)的取值用V(2-1,3)=3和V(2-1,3-w(2))+v(2)=V(1,0)+v(2)=0+4=4两者的大值,所以V(2,3)=4.同理,V(2,4)的取值用V(2-1,4)=3和V(2-1,4-w(2))+v(2)=V(1,1)+v(2)=0+4=4两者的大值,所以V(2,4)=4.V(2,5)用V(2-1,5)=3和V(2-1,5-w(2))+v(2)=V(1,2)+v(2)=3+4=7两者的大值,所以V(2,5)=7.基于此方法,可以求得所有的V(i,j),如表:
根据表的结果,背包最大能存放价值为10元的物品。通过查阅资料,了解到此结果为确定的最优解。但是如果例子里的数值范围较大,如表\ref{tableproblem2},难道需要列一个60行的表格计算吗?如果甚至质量值不是整数呢?因此,就有了下面的贪心算法。
贪心算法
贪心算法,又称贪婪算法,是寻找最优解问题的常用方法,这种方法模式一般将求解过程分成若干个步骤,但每个步骤都应用贪心原则,选取当前状态下最好的或最优的选择(局部最有利的选择),并以此希望最后堆叠出的结果也是最好或最优的解。贪婪法的每次决策都以当前情况为基础并根据某个最优原则进行选择,不从整体上考虑其他各种可能的情况。
正是因为贪心算法只考虑当前步骤,而不对整体优化问题的其余任何部位进行考虑,所以它往往没有较好的搜索终点的能力,更无法找到理想的解,所以贪心算法会跟其他算法进行融合,或者说是对其他算法进行补充,以达到快速计算的目的。
贪心算法用于背包问
更改前述问题数值,将背包载重扩大到150kg,各物品参数如表
运用最小重量贪心策略(python程序见附录),结果如图\ref{结果}。求得最终总重量为:140,总价值为:155。
若运用最小价值密度\footnote{价值密度定义为重量/价值,可以兼具重量小于价值高的要求}贪心策略,求得最终总重量为:150,总价值为:170。
总结
传统算法精度高,能找到确定的值。贪心算法运算过程非常快,但是从两种不同贪心策略的计算结果不同这个事实即可认为贪心算法的解精度可能并不高,甚至会与真实值偏离较大,所以一般并不适用于作为某个求解问题的最终算法。
python代码
# edit by JBR, data 2020.11.21
class Good:def __init__(self, weight, value, status):self.weight