学习方法与心得
问题描述
小C来到了一家饭馆,这里共有 nn 道菜,第 ii 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 ii 道菜是否含有蘑菇。如果 s_i = '1',那么第 ii 道菜含有蘑菇,否则没有。
小C希望点 kk 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 mm 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1。
题目解析
这道题目要求我们在给定的菜品中选择 k 道菜,使得总价格最低,并且所选菜品中最多有 m 道菜含有蘑菇。题目给出了每道菜的价格和是否含有蘑菇的信息。我们需要在满足条件的情况下,计算出最小的总价格。如果无法满足条件,则返回 -1。
思路
-
动态规划:我们使用动态规划来解决这个问题。定义
dp[i][j][p]表示考虑前i个菜品,选择j个菜品,其中p个含蘑菇的最小总价格。 -
状态转移:
不选择当前菜品:
dp[i][j][p] = dp[i-1][j][p]选择当前菜品:
如果当前菜品不含蘑菇,`dp[i][j][p] = dp[i-1][j-1][p] + 当前菜品价格` 如果当前菜品含蘑菇,`dp[i][j][p] = dp[i-1][j-1][p-1] + 当前菜品价格`,前提是 `p > 0` -
初始化:
dp[0][0][0] = 0,表示不选择任何菜品时的总价格为 0。 -
结果:遍历
dp[n][k][p],找到选择k个菜品时的最小价格。
代码详解
def solution(s: str, a: list, m: int, k: int) -> int:
n = len(s)
INF = float('inf')
# dp[i][j][p] 表示考虑前i个菜品,选择j个菜品,其中p个含蘑菇的最小总价格
dp = [[[INF] * (m + 1) for _ in range(k + 1)] for _ in range(n + 1)]
# 初始化:不选任何菜品的情况
dp[0][0][0] = 0
# 遍历每道菜
for i in range(1, n + 1):
curr_mushroom = int(s[i-1]) # 当前菜品是否含蘑菇
curr_price = a[i-1] # 当前菜品价格
# 遍历已选择的菜品数量
for j in range(k + 1):
# 遍历已选择的含蘑菇的菜品数量
for p in range(m + 1):
# 不选择当前菜品
dp[i][j][p] = min(dp[i][j][p], dp[i-1][j][p])
# 选择当前菜品
if j > 0 and (p > 0 or curr_mushroom == 0):
prev_mushroom = p - curr_mushroom if curr_mushroom == 1 else p
if prev_mushroom >= 0:
dp[i][j][p] = min(dp[i][j][p], dp[i-1][j-1][prev_mushroom] + curr_price)
# 找到选择k个菜品时的最小价格
result = min(dp[n][k][p] for p in range(m + 1))
return result if result != INF else -1
知识总结
在解决这类动态规划问题时,关键在于正确定义状态和状态转移方程。通过这道题,我加深了对多维动态规划的理解,尤其是在处理多个约束条件时,如何有效地进行状态转移。
工具运用
结合 AI 刷题功能,可以快速验证代码正确性,并通过 AI 提供的解析和建议,优化解题思路。同时,结合其他学习资源,如算法书籍和在线课程,全面提升算法能力。对于其他用户,建议在刷题过程中多与 AI 互动,获取不同的解题思路和优化建议。