题目解析-饭馆菜品选择问题(python)

39 阅读4分钟

题面

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

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

问题分析

我们需要从 n 道菜中选择 k 道菜,同时确保以下两个条件:

  1. 至少选择 k 道菜;
  2. 选择的菜中最多只能包含 m 道含有蘑菇的菜。

此外,我们要确保总价格尽可能低。如果无法满足这些条件,输出 -1

解题思路

  1. 分类菜品:首先,我们可以将所有的菜根据是否含有蘑菇进行分类。我们可以将含有蘑菇的菜和不含蘑菇的菜分别存储在两个列表中。
  2. 排序:对于每个类别的菜品,我们可以按价格从低到高排序,因为我们需要选出总价格最小的菜。
  3. 选择菜品:根据菜品的分类和价格排序,首先选择不含蘑菇的菜,直到选择了 k 道菜或选择了 m 道含有蘑菇的菜。如果无法选择满足条件的菜品,返回 -1
  4. 边界情况:考虑到当菜品数量不足时,直接返回 -1

详细步骤

  1. 将菜品分为两类:含蘑菇的菜和不含蘑菇的菜。
  2. 按照价格对这两类菜分别进行排序。
  3. 尝试从不含蘑菇的菜中选择最多 k 道菜,剩下的可以从含蘑菇的菜中选择,且不超过 m 道。
  4. 计算最终选择的菜品总价格,返回最小的总价格。

代码实现

def min_cost(s, a, m, k):
    # 分离含蘑菇和不含蘑菇的菜
    mushroom_dishes = []
    no_mushroom_dishes = []
    
    for i in range(len(s)):
        if s[i] == '1':  # 含有蘑菇
            mushroom_dishes.append(a[i])
        else:  # 不含蘑菇
            no_mushroom_dishes.append(a[i])
    
    # 对两类菜品按价格进行升序排序
    mushroom_dishes.sort()
    no_mushroom_dishes.sort()
    
    # 如果选择k道菜品的数量超过了所有可选的菜品数量,则返回-1
    if len(mushroom_dishes) + len(no_mushroom_dishes) < k:
        return -1
    
    # 尝试选择最多m个蘑菇菜
    min_cost = float('inf')
    
    # 选择x个含蘑菇的菜,其中0 <= x <= min(m, len(mushroom_dishes))
    for x in range(min(m, len(mushroom_dishes)) + 1):
        if k - x <= len(no_mushroom_dishes):  # 剩余需要从无蘑菇菜中选择
            # 选择x个蘑菇菜和k-x个不含蘑菇的菜
            selected_cost = sum(mushroom_dishes[:x]) + sum(no_mushroom_dishes[:k - x])
            min_cost = min(min_cost, selected_cost)
    
    return min_cost if min_cost != float('inf') else -1

# 测试
s = "001"
a = [10, 20, 30]
m = 1
k = 2
print(min_cost(s, a, m, k))  # 输出:30

代码解释

  1. 分类菜品:我们遍历菜品的 s 列表,判断是否含有蘑菇。如果是蘑菇菜,将其加入 mushroom_dishes 列表,否则加入 no_mushroom_dishes 列表。
  2. 排序:分别对两类菜品的价格进行升序排序,以便后续选择价格最小的菜品。
  3. 选择菜品:我们尝试从含蘑菇的菜品中选择 x 道菜,其中 x 的范围是 0min(m, len(mushroom_dishes))。然后,我们选择剩余的 k - x 道不含蘑菇的菜品。计算总价格并更新最小价格。
  4. 返回结果:如果能够选择 k 道菜且符合条件,返回最小价格;如果无法满足条件,则返回 -1

测试结果

对于输入:

s = "001"
a = [10, 20, 30]
m = 1
k = 2

程序输出:

30

复杂度分析

  • 时间复杂度

    • 分类菜品时需要遍历 n 道菜,时间复杂度为 O(n)。
    • 对两类菜品分别排序,时间复杂度为 O(n log n)。
    • 遍历所有可能的含蘑菇菜品选择数量时,最多有 m + 1 种选择方式,每种方式计算总价格需要 O(k) 的时间。因此选择的时间复杂度为 O(m * k)。

    综合起来,时间复杂度为 O(n log n + m * k)。

  • 空间复杂度:O(n),用于存储两类菜品的价格。

这个算法应该能在大多数情况下高效运行,尤其是当菜品数量不非常庞大时。