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

37 阅读3分钟

题目链接

小M的能力选择挑战 - MarsCode

问题描述

小M最近在玩一款叫做“狼人拯救者”的游戏。在游戏中,玩家可以通过消耗金币来购买能力,这些能力会增加攻击力,但也会影响攻击速度。
小M是一个以攻击力为优先的玩家,但他必须保证自己的攻击速度不能低于0,因为攻击速度为负时将无法攻击。
现在小M面对商店中的N种能力,他拥有G枚金币和S点初始攻击速度。他想知道,在保持攻击速度大于等于0的前提下,他最多可以获得多少攻击力。

商店中每种能力用三元组表示为 array[i] = [c, s, d],其中:

  • c 表示购买该能力需要的金币数;
  • s 表示该能力对攻击速度的影响,可以为正数、零或负数;
  • d 表示该能力对攻击力的增加值。

题目分析

  1. 问题核心:在给定金币和初始攻击速度的情况下,选择一些能力以最大化攻击力,同时确保攻击速度不低于0。
  2. 输入输出
    • 输入:金币数 G,初始攻击速度 S,能力列表 array,每个能力由 [c, s, d] 表示。
    • 输出:最大攻击力。
  3. 约束条件
    • 攻击速度不能低于0。
    • 每种能力只能购买一次。

解题思路

  1. 动态规划
    • 使用动态规划来解决这个问题,定义一个三维数组 dp[i][j][2],表示前 i 种能力中,使用不超过 j 枚金币时的最大攻速和最大攻击力。
  2. 状态转移
    • 对于每种能力 array[k] = [c, s, d],有两种选择:
      • 不购买该能力:dp[i][j] = dp[i-1][j]
      • 购买该能力:dp[i][j] = [f[i - 1][j - c][0] + s, f[i - 1][j - c][1] + d],前提是 j >= c f[i - 1][j - c][0] + s >= 0,其中 f[i - 1][j - c][0] 是已选择能力对攻击速度的总影响。
  3. 初始化
    • dp[0][0] = [S, 0],表示没有能力时,攻速为S,攻击力为0。
  4. 结果
    • 最终答案为 max(dp[n][j][1]),其中 n 是能力的数量,j 是金币数。

具体代码实现

def solution(n, G, S, array):
    # 初始化dp数组,dp[i][j]表示在前i种能力中,花费j金币时能够获得的最大攻速和最大攻击力
    # 初始攻速为S,攻击力为0
    f = [[[S, 0] for _ in range(G + 1)] for _ in range(n + 1)]
    # 遍历每种能力
    for i in range(1, n + 1):
        c, s, d = array[i - 1]
        # 遍历金币数
        for j in range(1, G + 1):
            # 如果金币不足以选择当前能力,或者选择后攻速小于0,则不选择当前能力
            if j < c or f[i - 1][j - c][0] + s < 0:
                f[i][j] = f[i - 1][j]
                continue
            # 选择当前能力获得的攻击力更大
            if f[i - 1][j - c][1] + d > f[i - 1][j][1]:
                f[i][j] = [f[i - 1][j - c][0] + s, f[i - 1][j - c][1] + d]
            # 选择当前能力获得的攻速更大
            elif f[i - 1][j - c][1] + d == f[i - 1][j][1] and f[i - 1][j - c][0] + s > f[i - 1][j][0]:
                f[i][j] = [f[i - 1][j - c][0] + s, f[i - 1][j - c][1] + d]
            else:
                # 不选择当前能力
                f[i][j] = f[i - 1][j]
    return max(_[1] for _ in f[n])

复杂度分析

  • 时间复杂度O(N * G),其中 N 是能力的数量,G 是金币数。每次计算新状态时需要遍历已选择的能力。
  • 空间复杂度O(N * G * 2),用于存储 dp 数组。

总结

通过动态规划的方法,我们可以有效地解决这个问题。关键在于正确地定义状态和状态转移方程,并确保攻击速度始终不小于0。代码实现时需要注意细节,特别是攻击速度的计算。