问题描述
小C来到了一家饭馆,这里共有 nn 道菜,第 ii 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 ii 道菜是否含有蘑菇。如果 s_i = '1',那么第 ii 道菜含有蘑菇,否则没有。
小C希望点 kk 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 mm 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1。
测试样例
样例1:
输入:
s = "001", a = [10, 20, 30], m = 1, k = 2
输出:30
样例2:
输入:
s = "111", a = [10, 20, 30], m = 1, k = 2
输出:-1
样例3:
输入:
s = "0101", a = [5, 15, 10, 20], m = 2, k = 3
输出:30
分析这道题的关键点可以帮助我们更好地理解问题的核心,并确保解决方案的正确性和效率。以下是这道题的关键点:
1. 问题定义
-
目标: 小C希望点
k道菜,且总价格尽可能低。 -
限制条件:
- 最多只能选择
m道含有蘑菇的菜。 - 如果无法满足上述条件,则输出
-1。
- 最多只能选择
2. 输入数据
s: 字符串,长度为n,表示每道菜是否含有蘑菇('1' 表示含有,'0' 表示不含)。a: 列表,长度为n,表示每道菜的价格。m: 整数,表示最多可以选择多少道含有蘑菇的菜。k: 整数,表示需要选择的菜品总数。
3. 关键步骤
a. 分类菜品
-
根据是否有蘑菇将菜品分为两组:
with_mushroom: 含有蘑菇的菜品的价格列表。without_mushroom: 不含蘑菇的菜品的价格列表。
b. 排序
- 对这两组菜品的价格进行排序,以便后续计算最小成本时能够快速找到最优组合。
c. 前缀和计算
-
使用
itertools.accumulate计算每个数组的前缀和,这样可以快速查找任意数量的菜品组合的成本。prefix_sum_without: 存储without_mushroom的前缀和。prefix_sum_with: 存储with_mushroom的前缀和。
d. 寻找最小成本
- 遍历可能的选择方案,即选择不同数量的含有蘑菇的菜品(从0到m),并相应地选择不含蘑菇的菜品以达到总共k道菜品的要求。
x是选择的含有蘑菇的菜品的数量。y是选择的不含蘑菇的菜品的数量,由y = k - x得出。- 如果
y在有效范围内(即y >= 0且y <= len(without_mushroom)),则计算当前组合的成本,并更新最小成本。
e. 返回结果
- 最后,如果找到了有效的组合,则返回最小成本;否则返回
-1表示无法满足条件。
from itertools import accumulate
def solution(s, a, m, k):
n = len(s)
with_mushroom = []
without_mushroom = []
# 分类菜品
for i in range(n):
if s[i] == '1':
with_mushroom.append(a[i])
else:
without_mushroom.append(a[i])
# 按价格排序
with_mushroom.sort()
without_mushroom.sort()
# 计算前缀和以便快速查找
prefix_sum_without = [0] + list(accumulate(without_mushroom))
prefix_sum_with = [0] + list(accumulate(with_mushroom))
# 寻找最小成本
min_cost = float('inf')
for x in range(min(m + 1, len(with_mushroom) + 1)): # x 是有蘑菇的菜的数量
y = k - x # y 是没有蘑菇的菜的数量
if y >= 0 and y <= len(without_mushroom):
cost = prefix_sum_with[x] + prefix_sum_without[y]
min_cost = min(min_cost, cost)
return min_cost if min_cost != float('inf') else -1