刷题实践 | 豆包MarsCode AI刷题

57 阅读4分钟

问题描述

小R不再追求甜点中最高的喜爱值,今天他想要的是甜点喜爱值之和正好匹配他的预期值 S。为了达到这个目标,他可以使用魔法棒来改变甜点的喜爱值,使其变为原来喜爱值的阶乘。每个甜点只能使用一次魔法棒,也可以完全不用。

下午茶小哥今天带来了 N 个甜点,每个甜点都有一个固定的喜爱值。小R有 M 个魔法棒,他可以选择任意甜点使用,但每个甜点只能使用一次魔法棒。他的目标是通过选择一些甜点,可能使用魔法棒,使得这些甜点的喜爱值之和恰好为 S。

请计算小R有多少种不同的方案满足他的要求。如果两种方案中,选择的甜点不同,或者使用魔法棒的甜点不同,则视为不同的方案。

思路整理

首先一共有四个参数,n为甜点个数,m为魔法棒个数,S为所需要的喜爱值之和,like数组为初始喜爱值。 我们可以先判断初始时,喜爱值之和是否已经满足S。之后又因为如果选择的甜点不同,或者使用魔法棒的甜点不同,视为不同的方案。所以我们可以用三维的dp数组,判断每个参数改变的结果是否满足。 所以在此我们可以先把我们的思路发送给豆包AI,让它帮我们判断一下思路可行性。

image.png 并且给出相当详细的具体步骤和具体代码

    public static int solution(int n, int m, int s, int[] like) {
        // 初始化 DP 数组
        int[][][] dp = new int[n+1][m+1][s+1];
        dp[0][0][0] = 1;

        // 计算阶乘
        int[] factorials = new int[10]; // 假设喜爱值最大为 9
        factorials[0] = 1;
        for (int i = 1; i < 10; i++) {
            factorials[i] = factorials[i-1] * i;
        }

        // 填充 DP 数组
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= s; k++) {
                    // 不使用魔法棒
                    if (k >= like[i-1]) {
                        dp[i][j][k] += dp[i-1][j][k - like[i-1]];
                    }
                    // 使用魔法棒
                    if (j > 0 && k >= factorials[like[i-1]]) {
                        dp[i][j][k] += dp[i-1][j-1][k - factorials[like[i-1]]];
                    }
                }
            }
        }

        // 返回最终结果
        return dp[n][m][s];
    }

    public static void main(String[] args) {
        int[] like1 = {1, 2, 3};
        int[] like2 = {1, 1, 1};

        System.out.println(solution(3, 2, 6, like1) == 5);
        System.out.println(solution(3, 1, 1, like2) == 6);
    }
}

初次验证结果

这里也是直接报错了哈,那我们就来看一下哪里出现了什么问题

修改方向

1.未考虑阶乘溢出,阶乘的增长速度飞快,可能直接导致数值变成负值。

2.动态规划转移逻辑未处理边界情况,当 like[i−1]like[i-1]like[i−1] 超过阶乘数组大小(例如未修正 factorials)时,factorials[like[i-1]] 会引发越界错误。所以我们得添加边界检查,确保 like[i−1]like[i-1]like[i−1] 的值在有效范围内。

经过修改之后关键代码为

        // 实际使用的魔法棒数量不能超过甜点数量
        M = Math.min(M, N);

        // 预计算阶乘值(限制最大阶乘计算值为 10)
        int[] factorialValues = new int[11]; // 0! 到 10!
        factorialValues[0] = 1; // 0! = 1
        for (int i = 1; i <= 10; i++) {
            factorialValues[i] = factorialValues[i - 1] * i;
        }

        // 初始化 DP 表
        int[][][] dp = new int[N + 1][S + 1][M + 1];
        dp[0][0][0] = 1; // 初始条件

        // 动态规划过程
        for (int i = 1; i <= N; i++) {
            int value = values[i - 1];
            int factValue = (value <= 10) ? factorialValues[value] : Integer.MAX_VALUE;

            for (int j = 0; j <= S; j++) {
                for (int k = 0; k <= M; k++) {
                    // 不选第 i 个甜点
                    dp[i][j][k] = dp[i - 1][j][k];

                    // 选第 i 个甜点,不使用魔法棒
                    if (j >= value) {
                        dp[i][j][k] += dp[i - 1][j - value][k];
                    }

                    // 选第 i 个甜点,使用魔法棒
                    if (k > 0 && factValue <= S && j >= factValue) {
                        dp[i][j][k] += dp[i - 1][j - factValue][k - 1];
                    }
                }
            }
        }

        // 统计结果
        int result = 0;
        for (int k = 0; k <= M; k++) {
            result += dp[N][S][k];
        }
        return result;
    }

验证结果

这次就直接通过啦

image.png

用豆包AI辅助做题的好处是可以快速验证自己的思路,并转换成代码,并在此基础上修改,可以快速提升我们刷题的效率。