英雄升级与奖励最大化(青训营X豆包MarsCode)|豆包MarsCode AI刷题

124 阅读5分钟

问题描述

在一个游戏中,小W拥有 n 个英雄,每个英雄的初始能力值均为 1。她可以通过升级操作来提升英雄的能力值,最多可以进行 k 次升级。

每次升级操作包含以下步骤:

  1. 选择一个英雄

  2. 选择一个正整数 x

  3. 将该英雄的能力值 aiai​ 更新为:ai=ai+⌊ai/x⌋ai​=ai​+⌊ai​/x⌋

    • 其中 ⌊ ⌋ 表示向下取整操作

游戏规则:

  • 当英雄的能力值首次达到或超过目标值 bibi​ 时,小W可以获得对应的奖励 cici​
  • 每个英雄的奖励只能获得一次
  • 升级操作的选择是自由的,可以多次选择同一个英雄进行升级

请计算在最多进行 k 次升级操作后,小W能获得的最大奖励总和。

题目解析:英雄升级问题

题目理解

小W有 n 个英雄,每个英雄初始能力为 1,并且通过升级可以提升英雄的能力。每次升级时,通过选择一个正整数 x ,可以将英雄的能力值更新为:

ai=ai+aixa_i = a_i + \left\lfloor \frac{a_i}{x} \right\rfloor

其中\left\lfloor \right\rfloor 表示向下取整操作。每当英雄的能力值达到目标值 b_i 时,小W可以获得奖励 c_i ,并且每个英雄的奖励只能获得一次。

目标

在最多进行 k 次升级操作后,我们需要计算小W可以获得的最大奖励总和。


代码解析:思路与实现

本题的核心在于合理地选择英雄进行升级,使得在有限次数的升级中,能够获得尽可能多的奖励。我们使用动态规划来求解。

1. 动态规划状态设计

定义二维数组 dp[i][j] ,表示前 i 个英雄在进行 j 次升级操作后能够获得的最大奖励总和。

  • 状态转移方程
    • 如果某个英雄无需升级或者已经达到目标值 b_i ,则我们不需要增加操作次数,只需继承之前的状态。
    • 如果英雄需要升级,考虑升级后的奖励是否能带来更大的总奖励。

2. 升级次数的计算

为了计算每个英雄达到目标值 b_i 所需要的升级次数,我们模拟每次升级并计算升级的效果。对于每个英雄,计算需要进行多少次升级才能使其能力达到目标值 b_i 。

3. 完整代码实现

public class Main {
    public static int solution(int n, int k, int[] b, int[] c) {
        // 动态规划数组
        int[][] dp = new int[n + 1][k + 1];
        // 记录每个英雄达到目标所需要的升级次数
        int[] step = new int[n + 1];
        
        // 计算每个英雄的升级次数
        for (int i = 0; i < step.length; i++) {
            step[i] = 0;
        }
        for (int i = 1; i < step.length; i++) {
            double a_i = 1;
            int x = 1;
            while (a_i != b[i - 1]) {
                if (a_i + Math.floor(a_i / x) <= b[i - 1]) {
                    step[i]++;
                    a_i = a_i + Math.floor(a_i / x);
                } else if (a_i + Math.floor(a_i / x) > b[i - 1]) {
                    x++;
                }
            }
        }

        // 初始化DP数组
        for (int j = 0; j < k + 1; j++) {
            dp[0][j] = 0;
        }
        for (int z = 1; z < n + 1; z++) {
            if (step[z] == 0) {
                dp[z][0] = c[z - 1] + dp[z - 1][0];
            } else {
                dp[z][0] = dp[z - 1][0];
            }
        }

        // 动态规划计算最大奖励
        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < k + 1; j++) {
                if (j < step[i]) {
                    dp[i][j] = dp[i - 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - step[i]] + c[i - 1]);
                }
            }
        }

        return dp[n][k];
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(4, 4, new int[]{1, 7, 5, 2}, new int[]{2, 6, 5, 2}) == 9);
        System.out.println(solution(3, 0, new int[]{3, 5, 2}, new int[]{5, 4, 7}) == 0);
    }
}

知识总结:动态规划与状态转移

知识点 1:动态规划的状态设计

动态规划的核心在于通过定义状态和状态转移来求解问题。在本题中,我们定义了一个二维数组 dp[i][j] ,表示前 i 个英雄在进行 j 次升级后能够获得的最大奖励。

知识点 2:如何计算英雄的升级次数

本题的难点之一在于如何计算每个英雄达到目标值所需的升级次数。通过模拟每次升级,并更新英雄的能力值,最终得出升级次数。

知识点 3:优化动态规划

在动态规划的实现过程中,通过合理初始化和更新状态,可以避免冗余计算,提高效率。


学习计划:高效学习动态规划

阶段一:理解动态规划的基础

从经典的动态规划问题入手,如斐波那契数列、背包问题等,掌握状态转移的基本思路。

阶段二:逐步攻克复杂问题

在基础知识的基础上,逐渐挑战更复杂的动态规划问题。此类问题通常涉及多个状态的转换和选择,需要深入分析和模拟。

阶段三:错题复盘

通过平台的错题记录,回顾自己在动态规划中的常见错误,理解出错的原因,并反思如何避免。


工具运用:利用平台与其他资源提升学习效果

1. 平台刷题与模拟训练

使用豆包MarsCode AI平台进行刷题,针对性训练算法题目,查找薄弱点并加以提升。

2. 可视化工具

借助可视化工具,直观了解动态规划的状态转移过程,帮助加深理解。

3. 结合学习书籍与视频

阅读经典的算法书籍,如《算法导论》中的动态规划章节,并结合视频教程加强理论与实践的结合。


结语

通过分析这个英雄升级问题,我不仅学到了如何运用动态规划解决复杂的优化问题,还加深了对状态转移方程和算法优化的理解。在学习动态规划时,重点在于明确问题的最优子结构和如何通过子问题的解来构建全局最优解。希望这篇文章能帮助你在算法学习的道路上取得更好的进展!