代码随想录算法训练营第三十七天 |动态规划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])
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
-
确定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 组合总和 Ⅳ
如果不能重复的话,下面代码就是对的
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. 爬楼梯 (进阶)
思路: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] = 1
for j in range(n+1):
for i in range(1,m+1):
if j >= i :
dp[j] += dp[j-i]
print(dp[n])