代码随想录算法训练营第三十七天 |动态规划part05

97 阅读2分钟

代码随想录算法训练营第三十七天 |动态规划part05

完全背包理论基础

完全背包:每个物品可以使用无数次

    0-1背包
    for weight in weights: # 物品
        for j in range(bag,weight-1,-1): # 背包
            dp[j] = max(dp[j],dp[j-weight] + value)

完全背包,只需要遍历背包时改成正序遍历。

而且两个for循环可以进行颠倒。

    for i in range(len(weight)):
        for j in range(weight[i],len(bag)+1):
            dp[j] = max(dp[j],dp[j-weight[i]] + value[i])

image-20250115234349435.png

    n,v = map(int,input().split())
    weight = []
    value = []
    for i in range(n):
        a,b = map(int,input().split())
        weight.append(a)
        value.append(b)
    dp = [0] * (v+1)
    for i in range(n): # 物品
        for j in range(weight[i],v+1): # 背包
            dp[j] = max(dp[j],dp[j-weight[i]] + value[i])
    print(dp[v])

518 零钱兑换 II

image-20250115234412569.png

  • 确定dp数组以及下标的含义

    • dp[j] 装满背包容量为j的背包有dp[j]种方法
  • 递推公式

    • 装满背包有多少种方法,递推公式都是下面的
    • dp[j] += dp[j-coins[i]]
  • dp数组如何初始化

    • dp[0] = 1
  • 遍历顺序

  • 打印dp数组

    • return dp[amount] 装满容量为amount的背包有dp[amount]种方法
    dp = [0] * (amount+1)
    dp[0] = 1
    for coin in coins:
        for j in range(coin,amount+1):
            dp[j] += dp[j-coin]
    return dp[amount]

377 组合总和 Ⅳ

image-20250115234429482.png

如果不能重复的话,下面代码就是对的

dp = [0] * (target + 1)
dp[0] = 1
for num in nums:
    for j in range(num,target+1):
        dp[j] += dp[j-num]
return dp[target]

但是这是一个排列的题目,所以就需要做一些改变。

之前说过遍历物品和遍历背包是可以反过来的。

如果先遍历物品,再遍历背包是组合

先遍历背包再遍历物品,就是排列了。

dp = [0] * (target + 1)
dp[0] = 1
for j in range(1,target+1):
    for num in nums:
        if j-num >=0 :
            dp[j] += dp[j-num]
return dp[target]

70. 爬楼梯 (进阶)

image-20250115234442051.png

思路:n对应着容量,m对应着每个背包的最大价值

每一次的选择可以重复,这是一个完全背包的问题。

dp[j] : 爬到j层楼有dp[j]种方法

初始化 dp = [0] * (n+1)

返回值 return dp[n]

题目说,相当于背包的容量和价值都是 [1,m]

我们需要装满容量为j的背包 有多少种方法

dp[j] += dp[j-m]

n,m = map(int,input().split())
​
dp = [0] * (n+1)
​
dp[0] = 1for j in range(n+1):
    for i in range(1,m+1):
        if j >= i :
            dp[j] += dp[j-i]
​
print(dp[n])