背包问题

0-1背包

  • p [ i ] [ j ] p[i][j] p[i][j]中, i i i表示背包中放入第 i i i个物体, j j j表示当前背包的容量大小
  • p [ i ] [ j ] = m a x ( p [ i − 1 ] [ j ] , p [ i − 1 ] [ j − w e i g h t [ i − 1 ] ] + v a l u e [ i − 1 ] ) p[i][j]=max(p[i-1][j],p[i-1][j-weight[i-1]]+value[i-1]) p[i][j]=max(p[i1][j]p[i1][jweight[i1]]+value[i1])表示,放入第 i i i个物体时,我们需要判断是否需要放入这个物体,会使价值更高。
  • p [ i − 1 ] [ j ] p[i-1][j] p[i1][j]表示不放入第 i i i个物体,价值是多少
  • p [ i − 1 ] [ j − w e i g h t [ i − 1 ] ] + v a l u e [ i − 1 ] p[i-1][j-weight[i-1]]+value[i-1] p[i1][jweight[i1]]+value[i1]表示放入第 i i i个物体时,用现在容量减去 i i i物体的重量后背包的总价值加上i物体的价值
def knapback(weight, value, n):
    len_weight = len(weight)
    p = [[0]*(n+1) for i in range(len_weight + 1)]
    for i in range(1, len_weight+1):
        for j in range(1, n+1):
            if weight[i-1] > j:
                p[i][j] = p[i-1][j]
            else:
                p[i][j] = max(p[i-1][j], p[i-1][j-weight[i-1]] + value[i-1])
    return p[len_weight][n], p
0-1背包的优化,只能在空间上优化

我们可以看出 p [ i ] [ j ] p[i][j] p[i][j] p [ i − 1 ] [ j ] p[i-1][j] p[i1][j]有关系,正向推,就是上述逻辑,由 p [ i − 1 ] [ j ] p[i-1][j] p[i1][j]推出 p [ i ] [ j ] p[i][j] p[i][j],反向推,就可以由 [ i ] [ j ] [i][j] [i][j]推出 p [ i − 1 ] [ j ] p[i-1][j] p[i1][j]

def rev_knapback(weight, value, n):
    len_weight = len(weight)
    p = [0] * (n + 1)
    for i in range(0, len_weight):
        for j in range(n, -1, -1):
            if j >= weight[i]:
                p[j] = max(p[j], p[j - weight[i]] + value[i])
    return p

完全背包

  • p [ i ] [ j ] = m a x ( p [ i − 1 ] [ j ] , p [ i ] [ j − w e i g h t [ i − 1 ] ] + v a l u e [ i − 1 ] ) p[i][j]=max(p[i-1][j],p[i][j-weight[i-1]]+value[i-1]) p[i][j]=max(p[i1][j]p[i][jweight[i1]]+value[i1]),有改动的地方就在于每个物体都可以重复装入背包,所以,要在当前的容量下减去当前物体的重量
  • p [ i ] [ j − w e i g h t [ i − 1 ] ] + v a l u e [ i − 1 ] p[i][j-weight[i-1]]+value[i-1] p[i][jweight[i1]]+value[i1]表示放入第 i i i个物体时,用现在容量减去 i i i物体的重量后背包的总价值加上 i i i物体的价值
def knapback(weight, value, n):
    len_weight = len(weight)
    p = [[0]*(n+1) for i in range(len_weight + 1)]
    for i in range(1, len_weight+1):
        for j in range(1, n+1):
            if weight[i-1] > j:
                p[i][j] = p[i-1][j]
            else:
                p[i][j] = max(p[i-1][j], p[i][j-weight[i-1]] + value[i-1])
    return p[len_weight][n], p

0-1背包的变种问题

  • 求数组和为s的所有组合方式,arr = [5, 5, 10, 2, 3],s = 15
  • 相对于背包问题不同的是这里的 p [ i ] [ j ] = p [ i − 1 ] [ j ] + p [ i − 1 ] [ j − a r r [ i − 1 ] ] p[i][j]=p[i-1][j]+p[i-1][j-arr[i-1]] p[i][j]=p[i1][j]+p[i1][jarr[i1]]
  • p [ i − 1 ] [ j ] p[i-1][j] p[i1][j]:在不加上当前的这个数字时,和为 j j j的方法总数
  • [ i − 1 ] [ j − a r r [ i − 1 ] ] [i-1][j-arr[i-1]] [i1][jarr[i1]]:表示在加上当前这个数字时,和为 j j j的方法总数
def method_nums(arr, target):
    len_arr = len(arr)
    p = [[0 for i in range(target + 1)] for j in range(len_arr + 1)]
    for i in range(len_arr + 1):
        p[i][0] = 1
    for i in range(1, len_arr + 1):
        for j in range(1, target + 1):
            if arr[i-1] <= j:
                p[i][j] = p[i-1][j] + p[i-1][j-arr[i-1]]
            else:
                p[i][j] = p[i-1][j]
    return p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值