AI 刷题 小M的能力选择挑战题解 | 豆包MarsCode AI刷题

44 阅读4分钟

小M的能力选择挑战题解

问题描述

小M在玩一款名为“狼人拯救者”的游戏,玩家通过消耗金币来购买能力,从而提升自己的攻击力。然而,这些能力也会对玩家的攻击速度产生影响,可能会增加或减少攻击速度。小M是一个以攻击力为优先的玩家,但他必须保证攻击速度大于或等于 0,因为攻击速度为负时将无法进行攻击。

现在,小M面对商店中 N 种能力,每种能力有三个参数:[金币数 c,攻击速度的影响 s,攻击力的增加值 d]。小M拥有 G 枚金币和 S点初始攻击速度。问题要求计算在不使攻击速度低于 0 的前提下,小M最多能够获得的攻击力。

思路解析

这个问题类似于一个背包问题,核心挑战是如何在保持攻击速度不为负数的前提下,最大化攻击力的总和。我们可以通过动态规划来解决这个问题。

  1. 状态表示

    使用 dp[i][j] 表示在使用了 i 枚金币,攻击速度为 j时,能够获得的最大攻击力。i 是从 0 到 G,j 是攻击速度的值。为了处理攻击速度可能为负的情况,我们将攻击速度的值偏移一个常数,使其成为一个非负数。

  2. 状态转移

    我们可以通过遍历所有当前金币数和攻击速度的组合来更新 dp 数组。

    对于当前金币数为 j,攻击速度为 k 的状态,如果选择购买该能力后,攻击速度不为负且在合理范围内,我们就更新该状态。

  3. 边界条件

    初始化时,dp[0][S] = 0,即初始状态下没有花费任何金币,攻击速度为 S 时,攻击力为 0。

解题代码


def solution(n, g, s, array):

    max_possible_speed = s + sum(delta_s for _, delta_s, _ in array if delta_s > 0)
    
    # 初始化
    dp = [[-float('inf')] * (max_possible_speed + 1) for _ in range(g + 1)]
    
    dp[0][s] = 0
    # 遍历
    for c, delta_s, delta_d in array:
        for j in range(g, c - 1, -1):  # 从后向前遍历避免重复计算
            for k in range(max_possible_speed, -1, -1): 
                new_speed = k + delta_s
              
                if 0 <= new_speed <= max_possible_speed:
                    dp[j][new_speed] = max(dp[j][new_speed], dp[j - c][k] + delta_d)

    return max(max(row) for row in dp)

if __name__ == "__main__":
    # Add your test cases here
    test1 = [
        [71, 51, 150],
        [40, 50, 100],
        [40, 50, 100],
        [30, 30, 70],
        [30, 30, 70],
        [30, 30, 70],
    ]
    print(solution(6, 100, 100, test1) == 240)  
    test2 = [
        [71, -51, 150],
        [40, -50, 100],
        [40, -50, 100],
        [30, -30, 70],
        [30, -30, 70],
        [30, -30, 70],
    ]
    print(solution(6, 100, 100, test2) == 210)  

解题思路详解

  1. 初始化

    我们先计算出可能的最大攻击速度 max_possible_speed,即所有能力对攻击速度有正面影响的能力的攻击速度影响之和加上初始攻击速度。这样可以为我们的 dp 数组设定一个合理的大小。

  2. 动态规划状态转移

    使用 dp[i][j] 来表示在使用 i 枚金币,攻击速度为 j 时的最大攻击力。对于每个能力,我们从后向前更新 dp 数组,确保每个能力只会使用一次。

    每次更新时,如果选择购买某个能力后,攻击速度合法,我们就更新状态 dp[j][new_speed]dp[j - c][k] + delta_d,即在原来状态下添加该能力的攻击力增益。

  3. 最终结果

    最终结果是 dp 数组中所有可能状态的最大值,即从所有可行的金币和攻击速度组合中,选择出最大的攻击力。

复杂度分析

  1. 时间复杂度

    每个能力都需要遍历所有可能的金币数和攻击速度。因此,时间复杂度为 O(n * g * max_possible_speed),其中:n 是能力的数量, g是可用的金币数,max_possible_speed 是可能的最大攻击速度。

  2. 空间复杂度

    dp 数组的大小为 (g + 1) x (max_possible_speed + 1),因此空间复杂度为 O(g * max_possible_speed)

感受与注意事项

  • 感受:该问题其实难度不大,但测试用例里面存在攻击速度增加,攻击力也增加的情况,最开始我就是没考虑这种情况才出现了错误,这道题提醒了我在分析问题时要考虑全面。