刷题篇:饭馆菜品选择问题 | 豆包MarsCode AI刷题

198 阅读4分钟

刷题篇:饭馆菜品选择问题 | 豆包MarsCode AI刷题

问题描述

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

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

问题分析

小C面临的问题是一个典型的组合优化问题,具体来说,是一个带有约束条件的最小化问题。她需要从n道菜中选择k道菜,同时满足以下条件:

  1. 所选的k道菜的总价格尽可能低。
  2. 所选的k道菜中最多只有m道含有蘑菇。

为了解决这个问题,我们可以采用以下策略:

  • 首先,我的想法是先给菜单价格从小到大排序,然后遍历获取并计算总价
  • 注意,要记录含蘑菇菜品的数量,超过了m,就不能再点含蘑菇的菜品了
  • 然后,对于每一种组合,我们检查其中含有蘑菇的菜品数量是否超过了m道。如果没有超过,我们就计算这个组合的总价格。
  • 在所有满足条件的组合中,我们找出总价格最低的那个组合。
  • 如果没有任何组合满足条件,即所有可能的组合都含有超过m道蘑菇的菜品,那么输出-1。

解题思路

  1. 输入检查:
    • 首先检查菜品的数量是否足够。如果菜品数量少于 k,直接返回错误(-1)。
  2. 初始化变量:
    • count_1 用于记录当前已选择的含蘑菇菜品的数量。
    • count 用于记录当前已选择的菜品总数。
    • price 用于记录当前已选择菜品的总价格。
  3. 合并和排序:
    • 将价格数组 a 和是否含蘑菇标志数组 s 合并成一个包含元组的列表 combined
    • 按照价格对 combined 进行升序排序,得到 sorted_combined
  4. 遍历排序后的列表:
    • 遍历 sorted_combined 列表,逐个处理每个菜品。
    • 如果已经选择了 k 道菜,则停止循环。
    • 如果当前已选择的含蘑菇菜品数超过 m,且当前菜品含蘑菇,则跳过该菜品。
    • 否则,如果当前菜品含蘑菇,增加 count_1
    • 累加当前菜品的价格到 price,并增加已选择的菜品数 count
  5. 结果检查:
    • 如果最终选择的菜品数少于 k,返回错误(-1)。
    • 否则,返回总价格 price

解题代码

def solution(s: str, a: list, m: int, k: int) -> int:
    # write code here
     
    #  不够菜点返回错误
    if len(a) < k:
        return -1

    count_1 = 0
    count = 0
    price = 0

    # 将两个数组合并为一个包含元组的列表
    combined = list(zip(a, s))
    # 对合并后的列表按照第一个数组的值进行排序
    sorted_combined = sorted(combined, key=lambda x: x[0])

    # 遍历 sorted_combined 列表
    for item in sorted_combined:
        #点够了就结束循环
        if count > k - 1:
            break
        
        # 大于m道蘑菇就不加蘑菇了,小于m道就可以继续点蘑菇
        if count_1 > m - 1:
            if item[1] == '1':
                continue
        else:
            if item[1] == '1':
                count_1 += 1

        # 计算价格,点菜数
        price += item[0]
        count += 1

    # 没点够菜要返回错误
    if count < k:
        return -1

    return price



if __name__ == '__main__':
    print(solution("0111", [2, 16, 11, 5], 1, 8) == -1)
    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("100111110010000", [3,4,9,13,16,4,3,9,1,11,7,7,4,4,11], 1, 4) == 12)

总结与思考

遇到的问题

  1. 遗漏了无法按照要求选择菜品的情况,导致结果错误
  2. if_else的关系没有理清(缩进错误),导致大于m道蘑菇就不加蘑菇时,没有蘑菇的菜也被略过了

收获与感悟

我发现我解题都喜欢用暴力破解的方法,算法的性能都不高,以后联系要学会运用高级算法和灵活运用各类数据结构来解题。例如,这道题可以通过动态规划或者回溯算法来解决。动态规划通常用于解决具有重叠子问题和最优子结构性质的问题,而回溯算法则是一种通过探索所有可能的候选解来找到所有解的算法。在实际应用中,由于n和k的值可能很大,直接枚举所有组合可能会非常耗时,因此我需要改进现有的算法。