饭馆菜品选择问题题解 | 豆包MarsCode AI刷题

202 阅读3分钟

题目:

0`FN%NEYJIGZ5SI2PFK4J)9.png


思路:
由于这个题可以用离散的状态表示,所以这是一个可以通过动态规划解决的问题,具体来说是关于在有限的选择下如何最小化总花费。我们使用三元组 (i, j, k) 来表示当前状态,其中 i 表示已经处理到第 i 道菜,j 表示在这 i 道菜中实际选择了 j 道菜,k 表示在这 j 道菜中有 k 道菜含有蘑菇。状态转移方程如下:

(i, j, k) = min((i-1, j-1, k + (第 i 道菜是否含有蘑菇)) + 第 i 道菜的价格, (i-1, j, k))

这个方程的意思是在处理第 i 道菜时,你可以选择吃或者不吃。如果吃这道菜,那么状态会变为 (i-1, j-1, k + (第 i 道菜是否含有蘑菇)) 加上这道菜的价格;如果不吃这道菜,则状态保持为 (i-1, j, k)。

为了确保状态转移的正确性,我们需要处理一些特殊情况:

  • 当 k - 1 小于 0 时,意味着还没有选择任何含有蘑菇的菜,因此不能选择含有蘑菇的菜。此时的状态转移方程为:(i, j, k) = (i-1, j, k)。

  • 当 j - 1 小于 0 时,意味着还没有选择任何菜,这时只能选择 (i, j, k) = 0,因为没有任何选择。

通过动态规划的方法,我们使用一个三维数组dp来存储中间状态和结果。数组dp[i][j][x]表示在处理到第 i 道菜时,已经选择了 j 道菜,其中有 x 道菜含有蘑菇的最小代价。初始状态设为无穷大,然后逐步更新状态直到处理完所有菜。

具体步骤如下:

  • 初始化变量len_s表示字符串s的长度,dp数组用来存储中间结果。
  • 设置初始状态dp[0][0][0] = 0,表示在处理第一个字符之前没有选择任何菜,代价为 0。
  • 设置第一行的状态,根据 k 的值初始化。
  • 使用三层循环遍历每一个状态,更新dp数组:
    • 如果当前状态满足条件,则更新状态转移方程。
    • 特殊情况处理,例如k - 1 < 0和j - 1 < 0的情况。
  • 最后,遍历所有可能的状态,找到最小代价并返回结果。

通过这种方式,我们能够有效地解决问题,利用动态规划的思想确保每一步都做出最优选择,从而得到全局最优解。动态规划方法不仅能够简化复杂度,还能保证算法的高效性和准确性。

def solution(s: str, a: list, m: int, k: int) -> int:
    len_s = len(s)
    dp = [[[float('inf')] * (m + 1) for _ in range(k + 1)] for _ in range(len_s + 1)]
    dp[0][0][0] = 0
    if k > 0:
        dp[0][1][int(s[0])] = a[0]
    for i in range(1, len_s):
        for j in range(k + 1):
            for x in range(m + 1):
                if x == 0 and s[i] == '1':
                    dp[i][j][x] = dp[i - 1][j][x]
                elif j > 0:
                    dp[i][j][x] = min(dp[i - 1][j - 1][x - (s[i] == '1')] + a[i], dp[i - 1][j][x])
                elif j == 0:
                    dp[i][j][x] = 0
    ans = float('inf')
    for i in range(m + 1):
        ans = min(ans, dp[len_s - 1][k][i])
    return -1 if ans == float('inf') else ans