leetcode的背包问题

这篇博客探讨了LeetCode中的背包问题,包括01背包和完全背包。01背包问题涉及如何选择物品以最大化价值,同时不超过背包的容量。在题解中,通过动态规划方法初始化数组并建立转移方程。完全背包问题则允许每种物品无限数量,解法与01背包相似,但更关注在容量限制下物品的最大价值组合。
摘要由CSDN通过智能技术生成

01 背包

题目

N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是v[i],求将哪些物品装入背包可使价值总和最大。

题解

  1. 定义数组
dp[i][j] # 代表前i个商品,放入一个容量为j的背包,所获得的最大价值
  1. 初始化
# 如果要求恰好放满背包,则数组初始化为 -inf
dp = [[-inf] * (amount + 1) for _ in range(n)]
# 如果要求恰好放满背包,则数组初始化为 0
dp = [[0] * (amount + 1) for _ in range(n)]

需要格外强调的是:第一、无论初始化是如何进行的,但是我们每次迭代商品的时候:dp[i][0]一定要等于0,因为放满容量为0的背包,价值肯定是0。第二、动态数组的长度是(容量+1)(要考虑容量为0的情形)。

  1. 转移方程
for i in range(n+1): # 初始化工作对i==0的时候已经做了处理,所以这里可以不用再考虑。
	for j in range(w[i],v+1): # 正序
		f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

01 背包简化

我们观察转移方程:

f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

发现f[i][j]只和上一行正上方上一行的左上方有关。如果我们只用一行数据正序遍历的话,我们会将上一行左上方的数据先覆盖掉。所以我们采用逆序遍历。

def package_01(size, values, weights):
    # dp[j]代表装满容量为j的背包能产生的最大价值

    import numpy
    # 如果不要求完全装满
    dp = numpy.array([0] * (size + 1))
    # 如果要求完全装满
    # dp = [-float("inf")] * (size + 1)

    # 初始化,无论是要求装满还是不装满,初始化规则一样,只是如果要求不装满,已经是0,可以省略初始化条件
    dp[0] = 0

    for i in range(len(values)):
        for j in range(size, weights[i] - 1, -1): # 逆序
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[size]

完全背包

题目

N种商品和一个容量为V的背包。第i件物品有无数件,且费用是w[i],价值是v[i],求将哪些物品装入背包可使价值总和最大。

题解

完全背包和01背包的逻辑基本类似,但是由于物品可以任意次取,所以我们每个物品取用多少次 取决于当 0<=k*w[i]<=j时,f[i−1][j−k*w[i]]+k*v[i]最大。

f[i][j]=max(f[i−1][j−k*w[i]]+k*v[i]) 0<=k*w[i]<=j

将上面的逻辑转为程序语言

k = 1
while k * weights[i] <= j:
    dp[i][j] = max(dp[i][j], dp[i - 1][j - k * weights[i]] + k * weights[i])
    k += 1

最终解法:

def package_total(size, values, weights):
    import numpy
    # 如果不要求完全装满
    dp = numpy.array([[0] * (size + 1) for _ in range(len(values))])

    # 初始化,无论是要求装满还是不装满,初始化规则一样,只是如果要求不装满,已经是0,可以省略初始化条件
    dp[0][0] = 0

    for i in range(len(values)):
        for j in range(weights[i], size + 1):
            k = 1
            while k * weights[i] <= j:
                dp[i][j] = max(dp[i][j], dp[i - 1][j - k * weights[i]] + k * weights[i])
                k += 1

    return dp[-1][-1]

完全背包简化

def package_total(size, values, weights):
    # dp[j]代表装满容量为j的背包能产生的最大价值

    import numpy
    # 如果不要求完全装满
    dp = numpy.array([0] * (size + 1))

    # 如果要求完全装满
    # dp = [-float("inf")] * (size + 1)

    # 初始化,无论是要求装满还是不装满,初始化规则一样,只是如果要求不装满,已经是0,可以省略初始化条件
    dp[0] = 0

    for i in range(len(values)):
        for j in range(weights[i], size + 1): # 正序
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值