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

105 阅读4分钟

饭馆菜品选择问题

这个题目要求在有限的预算内选出满足指定条件的菜品组合,关键是如何合理安排含蘑菇和不含蘑菇的菜品,使得价格最小化。我们可以使用贪心算法来实现。

解题思路

  1. 分类处理:首先根据是否含有蘑菇将所有菜品分为两类:

    • 含蘑菇的菜品集合。
    • 不含蘑菇的菜品集合。
  2. 排序:将这两个集合分别按照价格升序排序,这样可以优先选择价格较低的菜品。

  3. 选择策略

    • 假设选择了 x 道含蘑菇的菜品,那么剩下的 k - x 道菜品就必须是不含蘑菇的。
    • 遍历所有可能的 x 值,即含蘑菇菜品数量从 0min(m, 含蘑菇菜品总数)
    • 对于每个 x 值:
      • 如果 x 道含蘑菇的菜品和 k - x 道不含蘑菇的菜品的组合数足够,计算其总价格。
      • 在满足条件的组合中,找出总价格的最小值。
  4. 边界情况:如果找不到满足条件的组合,则输出 -1

代码实现

def solution(s: str, a: list, m: int, k: int) -> int:
    # 将菜品分类
    with_mushroom = []
    without_mushroom = []
    
    # 根据 s 中的值将 a 划分为两部分
    for i in range(len(s)):
        if s[i] == '1':
            with_mushroom.append(a[i])
        else:
            without_mushroom.append(a[i])
    
    # 对两部分菜品分别按价格排序
    with_mushroom.sort()
    without_mushroom.sort()
    
    # 检查边界情况,如果无论如何都凑不齐 k 道菜
    if len(with_mushroom) + len(without_mushroom) < k:
        return -1

    # 用于记录含蘑菇和不含蘑菇菜品的前缀和
    prefix_with = [0] * (len(with_mushroom) + 1)
    prefix_without = [0] * (len(without_mushroom) + 1)

    # 计算含蘑菇和不含蘑菇菜品的前缀和数组
    for i in range(1, len(with_mushroom) + 1):
        prefix_with[i] = prefix_with[i - 1] + with_mushroom[i - 1]
    for i in range(1, len(without_mushroom) + 1):
        prefix_without[i] = prefix_without[i - 1] + without_mushroom[i - 1]

    # 初始化最小总价格为正无穷
    min_cost = float('inf')
    
    # 遍历可能选择的含蘑菇菜品数量
    for x in range(min(m, len(with_mushroom)) + 1):
        y = k - x  # 不含蘑菇的菜品数量
        
        # 检查是否有足够的菜品满足条件
        if y >= 0 and y <= len(without_mushroom):
            # 计算当前选择下的总价格
            cost = prefix_with[x] + prefix_without[y]
            # 更新最小总价格
            min_cost = min(min_cost, cost)
    
    # 如果最小价格没有被更新,说明无法满足条件,返回 -1
    return min_cost if min_cost != float('inf') else -1

# 测试用例
if __name__ == '__main__':
    print(solution("001", [10, 20, 30], 1, 2) == 30)  # 应输出 True
    print(solution("111", [10, 20, 30], 1, 2) == -1)  # 应输出 True
    print(solution("0101", [5, 15, 10, 20], 2, 3) == 30)  # 应输出 True

代码详解

  1. 菜品分类:根据 s 中是否含蘑菇的信息,将菜品分别加入 with_mushroomwithout_mushroom 列表。
  2. 排序:分别对 with_mushroomwithout_mushroom 列表排序,以方便后续的前缀和计算。
  3. 前缀和计算:利用前缀和数组 prefix_withprefix_without,可以快速计算任意数量的菜品总价格。
  4. 遍历组合:对于每一个含蘑菇菜品的数量 x,如果满足条件,则计算总价格,并更新最小总价格。
  5. 返回结果:如果能找到满足条件的最小价格,返回该值,否则返回 -1

测试用例分析

  1. 样例 1
    • s = "001"a = [10, 20, 30]m = 1k = 2
    • 含蘑菇:[30],不含蘑菇:[10, 20]
    • 可以选择 0 道含蘑菇的菜和 2 道不含蘑菇的菜,总价格为 10 + 20 = 30
  2. 样例 2
    • s = "111"a = [10, 20, 30]m = 1k = 2
    • 全部菜品都含蘑菇,无法选出不超过 1 道含蘑菇的菜品且满足 k = 2 道的条件,返回 -1
  3. 样例 3
    • s = "0101"a = [5, 15, 10, 20]m = 2k = 3
    • 含蘑菇:[15, 20],不含蘑菇:[5, 10]
    • 选择 1 道含蘑菇的菜和 2 道不含蘑菇的菜,总价格 5 + 10 + 15 = 30

总结与思考

这个算法通过贪心策略前缀和优化解决了一个菜品组合的选择问题。贪心策略帮助我们优先选择价格最低的菜品,而前缀和则使得价格计算效率更高。