青训营X豆包MarsCode 技术训练营第一课 | 豆包MarsCode AI 刷题

79 阅读3分钟

学习方法与心得

问题描述

小C来到了一家饭馆,这里共有 nn 道菜,第 ii 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 ii 道菜是否含有蘑菇。如果 s_i = '1',那么第 ii 道菜含有蘑菇,否则没有。

小C希望点 kk 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 mm 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1

题目解析

这道题目要求我们在给定的菜品中选择 k 道菜,使得总价格最低,并且所选菜品中最多有 m 道菜含有蘑菇。题目给出了每道菜的价格和是否含有蘑菇的信息。我们需要在满足条件的情况下,计算出最小的总价格。如果无法满足条件,则返回 -1

思路

  1. 动态规划:我们使用动态规划来解决这个问题。定义 dp[i][j][p] 表示考虑前 i 个菜品,选择 j 个菜品,其中 p 个含蘑菇的最小总价格。

  2. 状态转移:

    不选择当前菜品: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`
    
  3. 初始化:dp[0][0][0] = 0,表示不选择任何菜品时的总价格为 0。

  4. 结果:遍历 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 互动,获取不同的解题思路和优化建议。