背包问题解析(二)-递归算法
一、题目:
有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
二、递归方法:
首先对于每个物品,我们的选择只有两个:放或者不放。我们将所有的可能都穷举出来,就可以得到下面这个树状图(只画了前四个结点):
所以对于每一个子问题,由于前面的子问题已被解决,因此我们都只需要做两个选择:放,还是不放。
假设我们已经知道了前i−1个物品放入背包的最优方案F(i−1,v i−1 ),那么对于第i个物品要放入背包就有三种情况:
1、若物品的体积c i 大于背包剩余的容量v i−1 ,那么只能丢弃这个物品:
F(i,vi)=F(i−1,vi−1)
2、否则就有两种选择:
(1)、不放第i个物品:
F(i,vi)=F(i−1,vi−1)
(2)、放第i个物品:
F(i,vi)=wi+F(i−1,vi−1−ci)
要从这两个方案中选择总价值最大的,所以:
三、python代码实现如下:
def rec_bag(c, w, v, i=0): """ param c: 物品体积 param w: 物品价值 param v: 当前背包剩余容量 param i: 当前物品编号 return: 背包装下物品的最大价值 """ if i > len(c) - 1: return 0 elif v <= 0: # 体积不能为负 return 0 elif v > 0: if c[i] <= v: A = w[i] + rec_bag(c, w, v - c[i], i + 1) B = rec_bag(c, w, v, i + 1) res = max(A, B) # 两种方案中选最优的那个并返回 else: res = rec_bag(c, w, v, i + 1) # 物品体积大于背包容量,直接返回 return res a = rec_bag([5,4,3,2], [6,5,4,3], 10, 0) print(a)
查看运行结果:
四、算法分析:
递归方法最大的缺点就在于有较多重复的计算,通过上面的树状图可以知道,递归会遍历这棵树的所有结点,所以它的时间复杂度为:O(2 n )
O(2n),指数阶的时间复杂度对于计算机来说简直就是灾难!
有没有什么办法减少这些重复的计算呢?这就是接下来要说的动态规划,它可以通过存储已经计算出来的结果来减少重叠子问题。