贪心算法应用例题| 豆包MarsCode AI刷题

35 阅读4分钟

问题描述

假设我们有若干种菜品,每种菜品可能含有蘑菇,也可能不含蘑菇。每道菜的价格和是否含蘑菇已知。现在需要从这些菜品中选出 k 道菜,且含蘑菇的菜品数量最多为 m,以满足用户对蘑菇的限制条件。目标是使选择的菜品总价格最小。


解决方案

我们可以使用贪心算法解决这个问题,通过以下步骤实现:

  1. 分类菜品

    • 将菜品根据是否含有蘑菇分为两类,分别存储在mushroom(含蘑菇)和no_mushroom(不含蘑菇)列表中。
  2. 排序

    • 将两个列表中的菜品按价格从低到高排序,以便优先选择价格最低的菜。
  3. 枚举分配方案

    • 枚举选择含蘑菇菜的数量 x0 <= x <= mx <= k),根据 x 计算需要选择的不含蘑菇的菜数量 y = k - x
    • 如果 xy 超过各自类别菜品的数量,则跳过该方案。
  4. 计算总价格

    • 对每种分配方案,计算从两类菜中选出的价格总和,并记录最小值。
  5. 结果返回

    • 如果没有找到满足条件的方案,返回 -1;否则返回最小总价格。

实现代码

def solution(s: str, a: list, m: int, k: int) -> int:
    # 将菜品分为含蘑菇和不含蘑菇两类
    mushroom = []
    no_mushroom = []
    
    for i in range(len(s)):
        if s[i] == '1':
            mushroom.append(a[i])
        else:
            no_mushroom.append(a[i])
    
    # 按价格升序排序
    mushroom.sort()
    no_mushroom.sort()
    
    # 如果菜品总数不足 k 道,直接返回 -1
    if len(mushroom) + len(no_mushroom) < k:
        return -1
    
    # 滑动窗口枚举选择方案
    min_price = float('inf')
    for x in range(0, min(m + 1, k + 1)):  # x 表示选择的含蘑菇菜的数量
        y = k - x  # y 表示选择的不含蘑菇菜的数量
        
        if x > len(mushroom) or y > len(no_mushroom):
            continue
        
        # 计算当前组合的总价格
        price = sum(mushroom[:x]) + sum(no_mushroom[:y])
        min_price = min(min_price, price)
    
    return min_price if min_price != float('inf') else -1

代码解析

  1. 分类

    • 遍历字符串 s,判断每道菜是否含有蘑菇,将价格加入相应列表中。
  2. 排序

    • 对两个列表分别按价格升序排序,使得选择最便宜的菜变得高效。
  3. 枚举选择方案

    • 遍历可能的蘑菇菜数量 x,根据需求计算不含蘑菇菜的数量 y
    • 跳过无法满足条件的方案(如所需菜品数量超出类别数量)。
  4. 计算价格

    • 对于每种合法的组合,计算其总价格并更新最小价格。
  5. 返回结果

    • 如果存在符合条件的组合,返回最小总价格;否则返回 -1

测试代码

if __name__ == '__main__':
    print(solution("001", [10, 20, 30], 1, 2))  # 输出: 30
    print(solution("111", [10, 20, 30], 1, 2))  # 输出: -1
    print(solution("0101", [5, 15, 10, 20], 2, 3))  # 输出: 30
    print(solution("101", [5, 10, 15], 1, 2))  # 输出: 15
    print(solution("000", [5, 10, 15], 1, 2))  # 输出: 15

测试样例结果分析

测试样例 1:

  • 输入:s = "001", a = [10, 20, 30], m = 1, k = 2
  • 输出:30
  • 分析:选择不含蘑菇的两道菜(1020),总价为 30

测试样例 2:

  • 输入:s = "111", a = [10, 20, 30], m = 1, k = 2
  • 输出:-1
  • 分析:所有菜都含蘑菇,而蘑菇菜数量上限为 1,无法满足条件。

测试样例 3:

  • 输入:s = "0101", a = [5, 15, 10, 20], m = 2, k = 3
  • 输出:30
  • 分析:选择 510(不含蘑菇)以及 15(含蘑菇),总价为 30

测试样例 4:

  • 输入:s = "101", a = [5, 10, 15], m = 1, k = 2
  • 输出:15
  • 分析:选择 5(不含蘑菇)和 10(含蘑菇),总价为 15

时间复杂度分析

  1. 分类和排序:O(n + n log n) = O(n log n),其中 n 是菜品数量。
  2. 枚举选择方案:最多枚举 m + 1 次,每次计算总价格需要 O(k)。
  3. 总体复杂度:O(n log n + m * k)。

总结

  • 贪心思想:通过优先选择价格最低的菜品,尽可能降低总成本。
  • 高效实现:使用分类、排序和滑动窗口的结合,减少计算复杂度。
  • 适用场景:该方法适用于需要根据多条件优化选择问题的场景。

希望这篇文章能够帮助你深入理解该问题的解决思路和实现方法!