小M的光明之魂速通挑战 | 豆包MarsCode AI刷题

166 阅读4分钟

小M的光明之魂速通挑战

问题描述

小M想知道,在不违反规则的前提下,他最多能够击败多少个Boss。

规则如下:

  1. 每个Boss对应唯一的类型编号。
  2. 每把武器能够击杀两种编号的boss且只能使用一次。
  3. 必须按照给定的顺序击杀Boss。

输入拥有的武器数量n 、需要击败的Boss数量m、Boss的顺序boss:长度为m的list、可以使用的武器array:一个长度为n的二维列表,每个元素为 [x, y],可以击败编号为 x 和 y 的Boss。

输出最多击败多少个boss。

问题分析

本题我们需要解决两个问题:

  1. 每次是否能够击败当前的boss
  2. 选哪把武器能打倒之后更多的boss

对于问题1,我们很好处理,我们只需要遍历所有的武器,找到能解决这个boss的武器即可。

而对于问题2,为了能击败更多的boss,我们就需要考虑如何从能打到boss的武器中挑一把对之后打倒更多boss影响最小的武器。

由于原本问题中,我们输入的boss编号并不是从1到m这样子排序的,输入的boss可能很乱,这很不利于计算每把可以选择的武器的优先级。因此我们做出一个大胆的举动,我们将boss的编号连同武器对应的编号都改为按照boss出场顺序的编号。

for i in range(m):
    for j in range(n):
        if array[j][0] == boss[i]:
            array[j][0] = i
        if array[j][1] == boss[i]:
            array[j][1] = i

我们甚至发现在这样修改之后我们不需要再使用boss这个数组了,我们使用range(m)可以起到同样的用途。

接着我们讨论如何遍历所有武器找到最适合打倒boss的武器。首先我们需要先将所有可以打倒当前boss的武器放入一个数组中。同样的,当没有武器可以打倒这个boss时,数组为空,这样也可以作为我们输出结果的依据。

for i in range(m):
    weapon_list = []
    for j in range(len(array)):
        if array[j][0] == i or array[j][1] == i:
            weapon_list.append(j)
    if len(weapon) == 0:
        return i

接着我们考虑如何选取最适合的武器,我们希望我们尽量不要选择能够打倒之后会出现的boss的武器,也就是说,同时也能够打倒在当前boss出现之前的boss的武器最优先。接着,若是不存在这种武器,我们希望选择一把对之后打boss影响最小的武器。或许你想到了此时应该用递归法来解这个题目,因为很明显,这个题目用递归法讨论所有情况时必然会找到最优解。由于它的性能并不太高,我决定在没有找到同时也能够打倒在当前boss出现之前的boss的武器这种情况下再使用递归法。

回溯法的思想很简单,即递归的思想,找到所有情况中打倒boss最大的值,加上一后传回上一层调用它的递归函数里。 而如何递归,我们决定对所有可以使用的武器都讨论一遍,选取最后能打倒最多boss的情况即可。

我们令当前的boss为AkA_k,函数使用的boss记作为AA,可以打倒AkA_k的武器的集合为BB,所有的武器集合为WW,此时我们要调用的函数就是max(对于任意Bi属于B,AAk,WBi)max(对于任意B_i属于B, A-A_k,W-B_i)

find_best = False
best_index = -1
for j in range(len(weapon_list):
    if array[weapon_list][0] < i or array[weapon_list][1] < i:
        find_best = True
        best_index = weapon_list[j]
if find_best:
    # 我们使用这种武器时,去掉当前boss的boss数组和去掉这个武器的array数组
    array = [...]
    boss = [...]
    return 1+solution(n-1, m-1, boss, array)
else:
    # 我们将讨论去掉任何一个weapon_list后可能的结果
    ans_list = []
    boss = [...]
    for j in range(weapon_list):
        array = [...]
        ans_list.append(solution(n-1, m-1, boss, array)
    return 1+max(ans_list)

借助递归的方法,我们成功得到了所有的答案。