完全背包问题,即资源没有数量限制
题目
硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)
解法
根据背包九讲里面的完全背包的递推公式,可以简化时间复杂度。本来完全背包问题可以拆分为01背包,但是就多出一个for循环。
dp[i][j]描述了只用前i个硬币, 能拼出钱j的方案数目。初始化的话,如果只用一分硬币,那所有钱数只有一种方案。注意。第二维是n+1的长度,且第一位初始化为1,因为如果j - coin==0, 那么用coin只有一种方案能拼出j,就是全部都用coin
dp的定义非常重要。
class Solution:
def waysToChange(self, n: int) -> int:
coins = [1, 5, 10, 25]
dp = [[0] * (1+n) for _ in range(4)] # 4, n
for i in range(n+1): # 初始化 只用1分硬币 只有1种
dp[0][i] = 1
for i in range(4):
dp[i][0] = 1
for i in range(1, 4):
coin = coins[i]
for j in range(n+1):
if j - coin >= 0:
# 注意这里是对完全背包的优化 当前状态i下的j-coin
dp[i][j] = dp[i][j - coin] + dp[i-1][j]
else:
dp[i][j] = dp[i-1][j]
dp[i][j] = dp[i][j] % 1000000007
return dp[3][-1]
另外组合总数IV 和这道题相似,但解法完全不一样。组合总数IV要求,只要顺序不相同,哪怕值是一样的,都算不一样的组合。这和背包问题的解法是完全不一样的。完全背包问题的组合是独一无二的,即第k个元素,要吗加0次,要吗加1次。要吗加2次。。。,直到超出容量。 不关心加的位置在哪。