动态规划求解甜点喜爱值之和匹配问题 | 豆包MarsCode AI刷题

116 阅读3分钟

题目描述

给定N个甜点,每个甜点有一个固定的喜爱值。小R有M个魔法棒,可以选择任意甜点使用(每个甜点只能使用一次),使其喜爱值变为原来喜爱值的阶乘。小R的目标是选择一些甜点,可能使用魔法棒,使得这些甜点的喜爱值之和恰好为S。计算满足条件的方案数。

思路分析

这个问题可以通过动态规划(Dynamic Programming, DP)来解决。

动态规划的核心思想是将复杂问题分解成小的、易于解决的子问题,并找到这些子问题之间的递推关系。每个子问题只解决一次,并将其解保存起来,如果再次遇到相同的子问题,只是简单地查表取出已计算的结果。

初始化 dp[0][0] = 1:不使用魔法棒且总喜爱值为0的方案只有一种(即不选择任何甜点)。 其他 dp[i][j] 初始化为0。

定义状态 我们使用一个二维数组dp[i][j]来表示使用i个魔法棒,使得甜点的喜爱值之和为j的方案数。

状态转移方程 对于每个甜点,我们有两种选择:

  1. 不使用魔法棒,直接使用甜点的喜爱值;
  2. 使用魔法棒,将甜点的喜爱值变为其阶乘。

我们从后向前遍历 i 和 j,以避免重复使用同一个甜点(因为数组是覆盖更新的)。

因此,对于每个甜点,我们可以更新dp数组如下:

  • 如果不使用魔法棒,那么dp[i][j + like[k]] += dp[i][j],表示使用i个魔法棒,总喜爱值为j + like[k]的方案数等于使用i个魔法棒,总喜爱值为j的方案数加上当前的方案数。
  • 如果使用魔法棒,那么dp[i+1][j + factor] += dp[i][j],表示使用i+1个魔法棒,总喜爱值为j + factor的方案数等于使用i个魔法棒,总喜爱值为j的方案数加上当前的方案数。

边界条件:我们需要确保在更新dp数组时,ij的值都在合法范围内,即i不能超过魔法棒的总数mj不能超过预期值s

计算结果 最后,我们遍历dp数组,将所有dp[i][s]的值相加,即可得到总方案数。

图解

假设输入为 n = 3, m = 2, s = 6, like = [1, 2, 3]

  1. 初始化 DP 数组

b85c6752167a141b58ab2640b027f94.png

  1. 处理第一个甜点(喜爱值1)

    • 不使用魔法棒:dp[i][j+1] += dp[i][j]
    • 使用魔法棒:dp[i+1][j+1] += dp[i][j](因为 factorial(1) = 1

ea68851856a27bff176af06228a3524.png

  1. 处理第二个甜点(喜爱值2)

    • 不使用魔法棒:dp[i][j+2] += dp[i][j]
    • 使用魔法棒:dp[i+1][j+2] += dp[i][j](因为 factorial(2) = 2

8cff4d5da90dda100edd6a576b63f97.png

  1. 处理第三个甜点(喜爱值3)

    • 不使用魔法棒:dp[i][j+3] += dp[i][j]
    • 使用魔法棒:dp[i+1][j+6] += dp[i][j](因为 factorial(3) = 6

252ffe059b2f9ec71fde56b0017e693.png

在代码中,我们首先定义一个factorial函数来计算阶乘。然后,我们定义solution函数来解决这个问题。我们使用一个二维数组dp来存储状态,并根据状态转移方程来更新这个数组。最后,我们遍历dp数组,将所有可能的方案数相加,得到最终结果。