问题描述
小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
以下是对这道题目的分析:
题目理解
- 菜品信息描述:题目给出了饭馆菜品的相关信息,包括每道菜的价格(存储在数组
a中)以及是否含有蘑菇(通过字符串s中对应字符表示,'1'表示含蘑菇,'0'表示不含),同时明确了菜品总数n(可由数组a或字符串s的长度得出)。 - 点菜要求:小C要从
n道菜中点k道菜,需满足总价格尽可能低,并且所点的菜中最多只能有m道菜含有蘑菇,若无法按此要求选菜则输出 -1。
解题思路分析
- 暴力枚举思路: - 可以通过枚举所有可能的点菜组合来找到满足条件的最小总价格。即生成从
n道菜中选k道菜的所有组合情况,对于每一种组合,检查其中含蘑菇菜的数量是否不超过m,如果满足条件则计算该组合的总价格,并记录下最小总价格。 - 这种方法的时间复杂度非常高,为,其中表示从n个元素中选k个元素的组合数,随着n和k的增大,计算量会急剧增加,在实际应用中效率很低。 - 贪心算法思路: - 先将菜品按照价格进行排序,这样价格低的菜会排在前面。 - 然后分情况考虑: - 如果不含蘑菇的菜数量大于等于
k,那么直接选择价格最低的k道菜,总价格即为这些菜价格之和,肯定满足最多只有m道菜含蘑菇的条件(因为此时所选的菜都不含蘑菇)。 - 如果不含蘑菇的菜数量小于k,先选择所有不含蘑菇的菜,然后从含蘑菇的菜中选择价格最低的菜来补足k道菜,同时要保证含蘑菇的菜不超过m道。如果在选择过程中发现无法满足条件(即含蘑菇的菜数量不足m道但已经选满k道菜,或者含蘑菇的菜数量超过m道),则输出 -1。 - 这种方法相对暴力枚举在时间复杂度上会有很大提升,排序的时间复杂度通常为,后续选择菜品的操作时间复杂度接近,整体时间复杂度大致为。 ### 三、代码实现思路(以Python为例)
`` ### 测试样例分析
- 样例1: - 输入:
s = "001",a = [10, 20, 30],m = 1,k = 2。 - 首先将菜品信息组合并排序后得到[(10, 0), (20, 0), (30, 1)]。 - 不含蘑菇的菜有[(10, 0), (20, 0)],数量小于k。 - 先选择所有不含蘑菇的菜,总价格为10 + 20 = 30,此时已选2道菜,满足k = 2的要求,且含蘑菇的菜数量为0,满足m = 1的要求,所以输出30 - 样例2: - 输入:
s = "111",a = [10, 20, 30],m = 1,k = 2。 - 组合并排序后得到[(10, 1), (20, 1), (30, 1)]。 - 不含蘑菇的菜数量为0,小于k。 - 先选择所有不含蘑菇的菜,总价格为0,然后需要从含蘑菇的菜中选2道菜来补足k道菜,但此时含蘑菇的菜数量超过了m(因为所有菜都含蘑菇,而m = 1),所以无法按照要求选择菜品,输出 -1。 - 样例3: - 输入:
s = "0101",a = [5, 15, 10, 20],m = 2,k = 3。 - 组合并排序后得到[(5, 0), (10, 0), (15, 1), (20, 1)]。 - 不含蘑菇的菜有[(5, 0), (10, 0)],数量小于k。 - 先选择所有不含蘑菇的菜,总价格为5 + 10 = 15。 - 还需要选3 - 2 = 1道含蘑菇的菜,从含蘑菇的菜中选价格最低的[(15, 1)],总价格变为15 + 15 = 30,且含蘑菇的菜数量为1,满足m = 2的要求,所以输出30。
总结感悟
- 问题转化与分析的重要性:本题通过将点菜问题转化为对菜品信息的处理和选择问题,清晰地明确了目标和限制条件。这让我认识到在面对实际问题时,要善于将其转化为数学或编程可处理的形式,仔细分析各种条件之间的关系,以便找到合适的解题思路。
- 算法选择的影响:暴力枚举虽然能解决问题,但时间复杂度太高,在实际应用中可能无法有效处理大规模数据。而贪心算法通过合理的排序和分情况选择,大大降低了时间复杂度,提高了算法的运行效率。这表明在解决问题时,要根据问题的特点和要求,选择合适的算法,以达到最优的解决方案。
- 代码实现细节:在代码实现过程中,如对菜品信息的组合、排序以及根据不同情况进行选择等操作,都需要准确无误地进行。这提醒我在编程时要注重细节,确保代码能够正确地实现所设计的算法思路,避免因小失大,导致结果错误。 附代码实现 def solution(s, a, m, k): n = len(a) dishes = [(price, has_mushroom) for price, has_mushroom in zip(a, map(int, s))] min_price = float('inf') for i in range(2**n): combination = [] mushroom_count = 0 total_price = 0 for j in range(n): if i & (1 << j): combination.append(dishes[j]) mushroom_count += dishes[j][1] total_price += dishes[j][0] if len(combination) == k and mushroom_count <= m: min_price = min(min_price, total_price) return min_price if min_price < float('inf') else -1