最近在做调度系统相关的事情,看到论文中描述通过最大流来解决调度的整体最优。然后我们尝试使用背包问题来解决,背包问题能不能解决调度最优不重要,重要的是我看到网上描述的背包问题的解法容易把人看蒙圈了,所以我做个视频讲一下01背包问题。
1.01背包问题的描述
有n个不可分割的物品,它们有各自的重量和价值,现有固定容量的背包,选择把哪些物品放入背包可以让背包中物品的价值最大。
2.错觉
按照价值和重量的比值(性价比)进行排序,依次尝试放入直到放不进背包为止。但是细想思考一下就能发现,这个贪心算法是有问题的,看下面一个例子。背包容量10kg,有3物品: {1kg|4¥} ,{4kg|5¥}, {6kg|6¥}。如果使用贪心算法,得出如下图的结果,这显然不行。
3.正确的解法
3.1 简单粗暴的方式:
把每种可能性都尝试一次。有n个物品,每个物品有两种选择(放入背包,不放入背包)。一共有2的n次方种可能。每种可能计算出总重量和总价值,在满足背包重量的可能情况中选择出价值最大的。
3.2 问题分解/动态规划:
3.2.1 动态规划的基本思路:
动态规划的基本思想是将待求解的问题分解成若干子问题,先求解子问题,然后从子问题的解得到原问题的解。我们可以用一个表格来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表格中。这就是动态规划法的基本思路。
3.2.2 使用动态规划的思路进行思考:
n个物品,编号分别从1到n(无需排序)。
1.处理第一个物品,处理的过程很简单,把背包容量是0到背包总量的情况都计算出背包最大能容纳下的价值。
2.考虑怎么在已经存在了部分解的情况下继续找出最大价值。处理2到n物品时,情况类似。都是基于已经有部分解的情况下进行处理。把当前处理的物品标记为物品i。下面分析i是怎么处理的,然后让i从2到n依次的进行处理。处理第i个物品有两种情况(和处理物品1时情况一样):
A.背包放不下物品i (背包的总容量,而不是剩余空间),i最优解和i-1的最优解一样
B.背包放得下物品i(分两种情况):
B.1.不把i放入背包,价值和i-1一样
B.2.把i放入背包,在i-1的背包问题解中,去除i的重量,然后把i加进去,
对B中的两种情况分别进行计算,在两者中选出大的那个值,f[i,j] = max{ f[i-1,j], f[i-1.j-Wi] + Pi}。(注:j是背包的容量,f[i,j]是背包容量为j处理到i物品时的最大价值,Wi时i物品的重量,Pi时i物品的价值)
3.2.3 做个表格试试吧:
现在有5个物品,分别为 A{4kg|6¥},B{5kg|4¥},C{6kg|5¥},D{2kg|3¥},E{2kg|6¥}。背包容量10kg。我们看一下视频(如果不明白上面的表达式,需要通过这个视频来理解):
视频中最后得到的表格如下图,表格中右上角的数字15就是最终的解。
4.延伸一下
4.1 多重背包问题
和01背包问题的区别是,第i件物品有 n[i]件(不止一件)。这个问题可以通过转换变成01背包来处理。把物品i的多件物品当作不同的物品进行处理。从新编号成每个物品都有唯一的编号,就变成了01背包问题。
4.2 完全背包问题,
和01背包类似,不同的是每件物品数量无限。把他转换成多重背包进行处理。把i物品的数量从无限转换成有限。转换的方式为背包只放i物品能放下几个,这是物品i的件数。
5.思考
通过最后的表格,是否能看出来,哪件物品被选中了。如果能看出来说明理解了。
6.后续
可能会讲一下红黑树是怎么调节平衡的,linux的伙伴系统,或者是矩阵运算规则。