0-1背包问题-(递归,记忆化搜索,动态规划)

现有n件物品和一个容量为c的背包。第i件物品的重量是重量为w[i],价值是v[i]。已知对于一件物品必须选择取(用1表示)或者不取(用0表示),且每件物品只能被取一次(这就是“0-1”的含义)。求放置哪些物品进背包,可使这些物品的重量总和不超过背包容量,且价值总和最大。

关键在于分析出状态转移方程:
(1)i=0 当j<w[0]时,m[0][j]=0;当j>=w[0]时,m[0][j]=v[0]。

(2)i>0 当j<w[i],m[i][j]=m[i-1][j];当j>=w[i],m[i][j]=max{m[i-1][j-w[i]]+v[i],m[i-1][j]}。

具体分析过程参考链接:https://www.nowcoder.com/discuss/3574

递归:

# 直接递归
def _bestvalue(w, v, index, c):
    '''用[0, ...index]的物品填充容积为c的背包的最大价值'''
    if c <= 0 or index < 0:
        return 0
    # 两种方式:
    #   1.不放最后一件物品的最大价值
    #   2.放入最后一件物品的最大价值
    res = _bestvalue(w, v, index-1, c)
    if c >= w[index]:
        # 两种方式比较,取最大值
        res = max(res, _bestvalue(w, v, index-1, c-w[index]) + v[index])
    return res

def main(w, v, c):
    n = len(w)
    return _bestvalue(w, v, n-1, c)


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
print(main(w, v, c))

记忆化搜索:

# 记忆化搜索
def _bestvalue(w, v, index, c):
    '''用[0, ...index]的物品填充容积为c的背包的最大价值'''
    if c <= 0 or index < 0:
        return 0
    if memory[index][c] != -1:
    	return memory[index][c]
    # 两种方式:
    #   1.不放最后一件物品的最大价值
    #   2.放入最后一件物品的最大价值
    res = _bestvalue(w, v, index-1, c)
    if c >= w[index]:
        # 两种方式比较,取最大值
        res = max(res, _bestvalue(w, v, index-1, c-w[index]) + v[index])
    memory[index][c] = res
    return memory[index][c]

def main(w, v, c):
    n = len(w)
    return _bestvalue(w, v, n-1, c)


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
memory = [[-1]*(c+1) for i in range(len(w)+1)]
print(main(w, v, c))

动态规划:

# 动态规划
def bestvalue(w, v, c):
    if c <= 0:
        return 0
    dp = [[0]*(c+1) for i in range(len(w))]
    # 先把第一行只放第1个物品的情况处理了
    for i in range(0, c+1):
        if i >= w[0]:
            dp[0][i] = v[0]
    for i in range(1, len(w)):
        for j in range(0, c+1):
            if j < w[i]:  
                # 剩余容量不足,i号物品不放入背包
                dp[i][j] = dp[i-1][j]
            else:
                # 可以放入i号物品,计算状态转移方程
                dp[i][j] = max(dp[i-1][j], v[i] + dp[i-1][j-w[i]])

    # 计算选出的是哪些背包,1表示取,0表示不取
    x = [0] * len(w)
    for i in range(len(w)-1, 0, -1):
        if dp[i][c] > dp[i-1][c]:
            x[i] = 1
            c -= w[i]
    if c != 0:
        if dp[0][c] != 0:
            x[0] = 1
    return dp[-1][-1], x


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
print(bestvalue(w, v, c))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值