一、题目:

有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

 

二、递归方法:

首先对于每个物品,我们的选择只有两个:放或者不放。我们将所有的可能都穷举出来,就可以得到下面这个树状图(只画了前四个结点):

背包问题java 递归 递归解决背包问题_树状图

 

所以对于每一个子问题,由于前面的子问题已被解决,因此我们都只需要做两个选择:放,还是不放。

假设我们已经知道了前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)

要从这两个方案中选择总价值最大的,所以:

背包问题java 递归 递归解决背包问题_结点_02

 

三、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)

查看运行结果:

背包问题java 递归 递归解决背包问题_树状图_03

 

 

四、算法分析:

递归方法最大的缺点就在于有较多重复的计算,通过上面的树状图可以知道,递归会遍历这棵树的所有结点,所以它的时间复杂度为:O(2 n )

O(2n),指数阶的时间复杂度对于计算机来说简直就是灾难!

有没有什么办法减少这些重复的计算呢?这就是接下来要说的动态规划,它可以通过存储已经计算出来的结果来减少重叠子问题。