饭馆菜品选择问题
这个题目要求在有限的预算内选出满足指定条件的菜品组合,关键是如何合理安排含蘑菇和不含蘑菇的菜品,使得价格最小化。我们可以使用贪心算法来实现。
解题思路
-
分类处理:首先根据是否含有蘑菇将所有菜品分为两类:
- 含蘑菇的菜品集合。
- 不含蘑菇的菜品集合。
-
排序:将这两个集合分别按照价格升序排序,这样可以优先选择价格较低的菜品。
-
选择策略:
- 假设选择了
x道含蘑菇的菜品,那么剩下的k - x道菜品就必须是不含蘑菇的。 - 遍历所有可能的
x值,即含蘑菇菜品数量从0到min(m, 含蘑菇菜品总数)。 - 对于每个
x值:- 如果
x道含蘑菇的菜品和k - x道不含蘑菇的菜品的组合数足够,计算其总价格。 - 在满足条件的组合中,找出总价格的最小值。
- 如果
- 假设选择了
-
边界情况:如果找不到满足条件的组合,则输出
-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
代码详解
- 菜品分类:根据
s中是否含蘑菇的信息,将菜品分别加入with_mushroom和without_mushroom列表。 - 排序:分别对
with_mushroom和without_mushroom列表排序,以方便后续的前缀和计算。 - 前缀和计算:利用前缀和数组
prefix_with和prefix_without,可以快速计算任意数量的菜品总价格。 - 遍历组合:对于每一个含蘑菇菜品的数量
x,如果满足条件,则计算总价格,并更新最小总价格。 - 返回结果:如果能找到满足条件的最小价格,返回该值,否则返回
-1。
测试用例分析
- 样例 1:
s = "001",a = [10, 20, 30],m = 1,k = 2- 含蘑菇:
[30],不含蘑菇:[10, 20] - 可以选择 0 道含蘑菇的菜和 2 道不含蘑菇的菜,总价格为
10 + 20 = 30。
- 样例 2:
s = "111",a = [10, 20, 30],m = 1,k = 2- 全部菜品都含蘑菇,无法选出不超过 1 道含蘑菇的菜品且满足
k = 2道的条件,返回-1。
- 样例 3:
s = "0101",a = [5, 15, 10, 20],m = 2,k = 3- 含蘑菇:
[15, 20],不含蘑菇:[5, 10] - 选择 1 道含蘑菇的菜和 2 道不含蘑菇的菜,总价格
5 + 10 + 15 = 30。
总结与思考
这个算法通过贪心策略和前缀和优化解决了一个菜品组合的选择问题。贪心策略帮助我们优先选择价格最低的菜品,而前缀和则使得价格计算效率更高。