问题描述
小R不再追求甜点中最高的喜爱值,今天他想要的是甜点喜爱值之和正好匹配他的预期值 S。为了达到这个目标,他可以使用魔法棒来改变甜点的喜爱值,使其变为原来喜爱值的阶乘。每个甜点只能使用一次魔法棒,也可以完全不用。
下午茶小哥今天带来了 N 个甜点,每个甜点都有一个固定的喜爱值。小R有 M 个魔法棒,他可以选择任意甜点使用,但每个甜点只能使用一次魔法棒。他的目标是通过选择一些甜点,可能使用魔法棒,使得这些甜点的喜爱值之和恰好为 S。
请计算小R有多少种不同的方案满足他的要求。如果两种方案中,选择的甜点不同,或者使用魔法棒的甜点不同,则视为不同的方案。
思路整理
首先一共有四个参数,n为甜点个数,m为魔法棒个数,S为所需要的喜爱值之和,like数组为初始喜爱值。 我们可以先判断初始时,喜爱值之和是否已经满足S。之后又因为如果选择的甜点不同,或者使用魔法棒的甜点不同,视为不同的方案。所以我们可以用三维的dp数组,判断每个参数改变的结果是否满足。 所以在此我们可以先把我们的思路发送给豆包AI,让它帮我们判断一下思路可行性。
并且给出相当详细的具体步骤和具体代码
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;
}
验证结果
这次就直接通过啦
用豆包AI辅助做题的好处是可以快速验证自己的思路,并转换成代码,并在此基础上修改,可以快速提升我们刷题的效率。