322. 零钱兑换
思路:
完全背包问题,coins是无限的,求最少硬币数量;amount顺序遍历。组合先迭代物品;注意dp[j-coin]=inf的情况
dp[i][j]表示amount为j,然后前i个硬币的最少数量 size是n+1 amount+1
初始化:j=0时候,最少数量为1
递推:dp[i][j] = min(dp[i-1][j], dp[i][j - coins[i-1]])
递推:dp[j] = min(dp[j], dp[j - coins[i-1]])
注意:零钱兑换问题,有几种方法初始化0为1,如果是最小数量的化初始化0。
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
n = len(coins)
# dp = [0] * (amount + 1) # 注意1:求最小值时候,初始化要初始化最大
dp = [float("inf")] * (amount + 1)
dp[0] = 0 # 注意2:amount为0时候,不需要硬币凑
# 迭代硬币和amount
for coin in coins:
for j in range(coin, amount+1):
# 注意3:dp[j-coin]有意义的时候才转移
if dp[j-coin] != float("inf"):
dp[j] = min(dp[j], dp[j-coin]+1) # 注意4:如果取coin硬币,需要+1
# 注意5:没有答案的情况
return dp[amount] if dp[amount] != float("inf") else -1
279. 完全平方数
class Solution(object):
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
# 定义:和为 i 的平方数的最小数量是 dp[i]
dp = [float('inf')] * (n+1) # 计算最小,初始化时候需要最大
# base case
dp[0] = 0
# 状态转移方程
for j in range(1, n+1):
for i in range(1, int(n**0.5)+1):
dp[j] = min(dp[j], dp[j - i*i]+1) # # j-i*i 只要再加一个平方数 i * i 即可凑出 i
return dp[n]
class Solution(object):
def numSquares(self, n):
"""
:type n: int
:rtype: int
"""
# 定义:和为 i 的平方数的最小数量是 dp[i]
dp = [float('inf')] * (n+1) # 计算最小,初始化时候需要最大
# base case
dp[0] = 0
# 状态转移方程
for i in range(1, int(n**0.5)+1):
for j in range(i*i, n+1):
dp[j] = min(dp[j], dp[j - i*i]+1) # # j-i*i 只要再加一个平方数 i * i 即可凑出 i
return dp[n]
139. 单词拆分
思路:
dp[i]表示前i个字符s[0,..,i-1]是否能被正确分割
dp[0]=True # 空字符串true
递推:假设存在j [0,...,i]使得dp[j]=true 并且s[j:i]在wordDict里面,那就dp[i]=true
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n = len(s)
wordSet = set(wordDict)
dp = [False] * (n+1)
dp[0] = True
for i in range(1, n+1):
for j in range(i):
if dp[j] and s[j:i] in wordSet: # s[0,...,j]=true,并且s[j:i]是字典中子串
dp[i] = True
break # 找到一个有效的分割,退出内层循环
return dp[n]
多重背包
题目描述
你是一名宇航员,即将前往一个遥远的行星。在这个行星上,有许多不同类型的矿石资源,每种矿石都有不同的重要性和价值。你需要选择哪些矿石带回地球,但你的宇航舱有一定的容量限制。
给定一个宇航舱,最大容量为 C。现在有 N 种不同类型的矿石,每种矿石有一个重量 w[i],一个价值 v[i],以及最多 k[i] 个可用。不同类型的矿石在地球上的市场价值不同。你需要计算如何在不超过宇航舱容量的情况下,最大化你所能获取的总价值。
输入描述
输入共包括四行,第一行包含两个整数 C 和 N,分别表示宇航舱的容量和矿石的种类数量。
接下来的三行,每行包含 N 个正整数。具体如下:
第二行包含 N 个整数,表示 N 种矿石的重量。
第三行包含 N 个整数,表示 N 种矿石的价格。
第四行包含 N 个整数,表示 N 种矿石的可用数量上限。
输出描述
输出一个整数,代表获取的最大价值。
输入示例
10 3 1 3 4 15 20 30 2 3 2
输出示例
90
提示信息
数据范围:
1 <= C <= 2000;
1 <= N <= 100;
1 <= w[i], v[i], k[i] <= 1000;
思路:
多重背包是物品数量有多个但不是无限,可以当成0-1背包问题,把物品数量展开为1。
C, N = list(map(int, input().split(" ")))
weights = list(map(int, input().split(" ")))
values = list(map(int, input().split(" ")))
nums = list(map(int, input().split(" ")))
# 多重背包问题,当成0-1背包,把物品展开来,然后再迭代容量后多迭代一次k nums[i] dp[j] = max(dp[j], dp[j-k*weights[i]+k*values[i])
# 注意组合!背包一维需要从后往前遍历!!!
def multi_pack(C, N,weights,values,nums):
dp = [0] * (C+1)
dp[0] = 0
for i in range(N):
for j in range(C,weights[i]-1 , -1):
#for j in range(1, C+1): # 错误!0-1背包逆序,防止重复
for k in range(1, nums[i]+1):
# j大于k*weights[i]
if j >= k*weights[i]:
dp[j] = max(dp[j], dp[j-k * weights[i]] + k* values[i])
return dp[C]
print(multi_pack(C, N,weights,values,nums))