问题描述
01背包问题是所有类型的背包问题中最基础的一种,它是这样描述的:有一个可装下重量为 c a p a c i t y capacity capacity的背包,和一堆重量和价值已经给出的物品,分别由 w 1 , w 2 , . . . w n w_1, w_2, ... w_n w1,w2,...wn和 v 1 , v 2 , . . . , v n v_1, v_2, ... , v_n v1,v2,...,vn表示。求解的目标是在背包可承受重量内,使装入背包内的物品价值总和尽可能大。
显然,我们会考虑求每个物品单位重量的价值,即 v a l u e w e i g h t \frac {value}{weight} weightvalue,优先将比例大的物品放入包中。可是当这个物品不能装满整个背包,而剩下的空间又不足以装入第二个物品只能被浪费时,我们可能就会对这个方案是否为最佳方案产生疑问。
遵循这样朴素的想法,在物品数量较少时我们可以快速想出答案,可随着问题规模增大,这样没有“章法”的求解过程就显得捉襟见肘。所以我们来介绍一种将该问题抽象后,分解为子问题和子子问题等逐级求解的方法,那就是动态规划。
抽象建模
前一篇讲钢条切割问题(rod cutting problem)的文章中提到,要使用动态规划解决问题,必须满足最优子结构原理。
最优子结构原理:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。
适合用动态规划方法求解的最优化问题应该具备的第二个性质是子问题空间必须足够“小”,即用分治法时会反复求解相同的子问题,而不是一直生成新的子问题。
重叠子问题:如果用分治法时存在反复求解同一个子问题的情况,那么我们就称这类问题为重叠子问题。
不满足重叠子问题条件的话,动态规划和分治法将没有本质上的区别。
数学模型
现在我们来将原问题转化为数学模型。每个物品放入或不放入背包可以用1或0来表示,这也是01背包这个名字的由来。我们用一串数字 x 1 , x 2 , . . . , x n x_1, x_2, ... , x_n x1,x2,...,xn来表示各个物品是否放入背包。那么使得总价值最大化这个目标就可以写为
t a r g e t = m a x ( x 1 v 1 + x 2 v 2 + . . . x n v n ) target = max(x_1 v_1 + x_2 v_2 + ... x_n v_n) target=max(x1v