完全背包问题基础
完全背包问题是在0-1背包问题的上的基础得来的,区别在于在于物品可以无限制的重复选择。
有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包和01背包问题唯一不同的地方就是,每种物品有无限件。
这里的循环是从小到大的,因为我们可以重复选择物品
在完全背包中,对于一维dp数组来说,其实两个for循环嵌套顺序是无所谓的!
零钱兑换 II
给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 amount
表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
输入:amount = 5, coins = [1, 2, 5] 输出:4 解释:有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
这个就是一个完全背包问题,但是需要注意,这里其实求的是组合数
也就是说,你凑成5 2 2 1 和 1 2 2 是等价的! 为什么要分辨这个呢,
因为这个关系到遍历顺序,到底是物品是内循环还是外循环。
如果物品是内循环,容量是外循环,那么你就是将 2 2 1 和 1 2 2 当初两种不同的方式。
同时,遍历5部曲
1. 确定dp数组定义
dp[j] 凑成总金额j的货币组合数为dp[j]
2. 递推公式
组合 就是需要累加 dp[j] += dp[j - coins[i]];
3. dp数组如何初始化
首先dp[0]一定要为1,dp[0] = 1是 递归公式的基础。如果dp[0] = 0 的话,后面所有推导出来的值都是0了。
4. 确定遍历顺序
这是本题的关键
如果物品是外循环,算的是组合数,因此你每个物品只是被计算一次
如果物品是内循环,算的是排列数,背包的每一个值,都会过物品
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(len(coins)):
for j in range(1, amount + 1):
if coins[i] <= j:
dp[j] += dp[j-coins[i]]
return dp[amount]
377. 组合总和 Ⅳ
给你一个由 不同 整数组成的数组 nums
,和一个目标整数 target
。请你从 nums
中找出并返回总和为 target
的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
输入:nums = [1,2,3], target = 4 输出:7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)
这个题就是求排列了,我们需要修改遍历顺序。 物品要在内循环
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
# 这个就是求排列 遍历顺序不一样
dp = [0] * (target + 1)
dp[0] = 1
for j in range(1, target + 1):
for i in range(len(nums)):
if nums[i] <= j:
dp[j] += dp[j-nums[i]]
return dp[target]
70. 爬楼梯(进阶版)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
输入描述:输入共一行,包含两个正整数,分别表示n, m
输出描述:输出一个整数,表示爬到楼顶的方法数。
输入示例:3 2
输出示例:3
提示:
当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。
此时你有三种方法可以爬到楼顶。
- 1 阶 + 1 阶 + 1 阶段
- 1 阶 + 2 阶
- 2 阶 + 1 阶
这个题其实就是完全背包求排列数,和上面的题类似
n是容量, m是物品个数
def stairsPlus():
n, m = [int(x) for x in input().split()]
dp = [0] * (n + 1)
dp[0] = 1
for j in range(1, n+1):
for i in range(1, m+1):
if i <= j:
dp[j] += dp[j-i]
return dp[n]
if __name__ == "__main__":
print(stairsPlus())