动态规划 ---- 0-1背包问题

0-1背包问题

问题描述:

有 n 件物品和一个最大承重为 W 的背包,每件物品的重量是 𝑤i、价值是 𝑣i 在保证总重量不超过 W的前提下,选择某些物品装入背包,背包的最大总价值是多少?
注意:每个物品只有 1 件,也就是每个物品只能选择 0 件或者 1 件
定义状态
#values:是价值数组;weights:是重量数组
假设dp(i, j)是最大承重为j,有前i件物品可选时的最大总价值,
初始值设定
dp(i, 0)、dp(0, j)初始值均为0
动态转移方程
如果j < weights[i - 1],则无法选择最后一件物品,则dp[i][j] = dp[i - 1][j]
如果j >= weightsi - 1,则可选可不选,则dp[i][j] = max(dp[i - 1][j], values[i - 1] + dp[i - 1][j - weights[i - 1]])


def maxValues(values, capacity, weights):
    if values == None or len(values) == 0:
        return 0
    if weights == None or len(weights) == 0:
        return 0
    if len(values) != len(weights) or capacity <= 0:
        return 0
    #设定一个长为capacity,宽为len(values)的二维数组
    dp = [[0] * (capacity + 1) for _ in range(len(values) + 1)]
    for i in range(1, len(values) + 1, 1):
        for j in range(1, capacity + 1, 1):
            if j < weights[i - 1]:
                continue
            else:
                dp[i][j] = max(dp[i - 1][j], values[i - 1] + dp[i - 1][j - weights[i - 1]])
    return dp[len(values)][capacity]

在这里插入图片描述
以j = 10这列为例:
第一个物品v= 6, w = 2可选可不选,如果不选则dp[1][10] = dp[0][10],如果选,则dp[1][10] = 6 + dp[0][10 - 2] = 6,所以最终dp[1][10] = 6
依次类推…
优化:将二维dp数组优化为一维动态数组
由于在计算dp[i][j]时可能会用到dp[i - 1][j - weights[i - 1]]的值,因此最好是从右往左进行计算,这样新计算到的值不会影响前面可能用到的值

def maxValues(values, capacity, weights):
    if values == None or len(values) == 0:
        return 0
    if weights == None or len(weights) == 0:
        return 0
    if len(values) != len(weights) or capacity <= 0:
        return 0
    #设定一个长为capacity
    dp = [0] * (capacity + 1)
    for i in range(1, len(values) + 1, 1):
        for j in range(capacity, 0, -1):
            if j < weights[i - 1]:
                continue
            else:
                dp[j] = max(dp[j], values[i - 1] + dp[j - weights[i - 1]])
    return dp[capacity]

继续优化
j在遍历时,从capacity到weights[i - 1]即可,因为再继续遍历下去,j的值会比weights[i - 1]的值小,因此一直无法选择weights[i - 1]这个值

def maxValues(values, capacity, weights):
    if values == None or len(values) == 0:
        return 0
    if weights == None or len(weights) == 0:
        return 0
    if len(values) != len(weights) or capacity <= 0:
        return 0
    #设定一个长为capacity
    dp = [0] * (capacity + 1)
    for i in range(1, len(values) + 1, 1):
        for j in range(capacity, weights[i - 1] - 1, -1):
            # if j < weights[i - 1]:
            #     continue
            # else:
                dp[j] = max(dp[j], values[i - 1] + dp[j - weights[i - 1]])
    return dp[capacity]

问题变形

有 n 件物品和一个最大承重为 W 的背包,每件物品的重量是 𝑤i、价值是 𝑣i 在保证总重量恰好等于 W的前提下,选择某些物品装入背包,背包的最大总价值是多少? 注意:每个物品只有 1 件,也就是每个物品只能选择 0 件或者 1 件
values:是价值数组;weights:是重量数组 假设dp(i, j)是最大承重为j,有前i件物品可选时的最大总价值, dp(i,0)初始值为0,总重量恰好为0,最大总价值必然为0
dp(0, j) = -∞,j >= 1, 负数在这里代表无法恰好装满,只能用inf,保证无法恰好装满的值一直为inf 如果j < weights[i - 1],则无法选择最后一件物品,则dp[i][j] = dp[i - 1][j] 如果j >= weightsi - 1,则可选可不选,则dp[i][j] = max(dp[i - 1][j], values[i - 1] + dp[i - 1][j - weights[i - 1]])

def maxVlaues_(values, capacity, weights):
    if values == None or len(values) == 0:
        return 0
    if weights == None or len(weights) == 0:
        return 0
    if len(values) != len(weights) or capacity <= 0:
        return 0
    dp = [0] * (capacity + 1)
    for j in range(1, capacity + 1, 1):
        dp[j] = -float('inf')
    for i in range(1, len(values) + 1, 1):
        for j in range(capacity, weights[i - 1] - 1, -1):
            dp[j] = max(dp[j], values[i - 1] + dp[j - weights[i - 1]])
    return dp[capacity] if dp[capacity] > 0 else -1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值