AI 刷题 66. 魔法甜品之和 题解 | 豆包MarsCode AI 刷题

45 阅读3分钟

66. 魔法甜品之和

在本题中,我们面临一个经典的组合问题——通过选取一些甜点并可能使用魔法棒(将其喜爱值变为阶乘)使得它们的总喜爱值恰好等于给定的值 S。我们需要考虑如何在给定的条件下找到不同的方案数。特别地,题目给出了多个参数,要求我们在动态规划的框架下进行求解。本文将详细解析该问题的思路、实现细节,并通过代码实现来说明如何高效地解决该问题。

问题分析

关键难点

  • 需要考虑是否对每个甜点使用魔法棒,因为魔法棒将会使得该甜点的喜爱值变为阶乘。
  • 在选择甜点时,可以选择不使用魔法棒、使用魔法棒或不选择该甜点,因此需要处理多种选择。
  • 由于魔法棒的数量是有限的,需要对每个魔法棒的使用情况进行跟踪。

动态规划思路

1. 定义状态

我们可以使用动态规划来解决这个问题。定义一个三维状态数组 dp[i][j][k],表示前 i 个甜点,使用了 j 个魔法棒,达到喜爱值之和为 k 的方案数。

  • i:表示考虑前 i 个甜点。
  • j:表示使用了 j 个魔法棒。
  • k:表示当前选择的甜点的喜爱值之和。

2. 状态转移

对于每个甜点,可能有三种情况:

  • 不使用魔法棒:直接将当前甜点的喜爱值 like[i-1] 加入到当前总和中。
  • 使用魔法棒:将当前甜点的阶乘值 math.factorial(like[i-1]) 加入到当前总和中。
  • 不选择该甜点:跳过当前甜点,维持当前的状态。

3. 初始化

  • 初始状态:dp[0][0][0] = 1,表示没有选择任何甜点,并且喜爱值为 0 的方案只有一种。

4. 计算结果

最后,我们的目标是找到使用任意数量魔法棒的情况下,喜爱值恰好为 s 的所有方案数。可以通过遍历 dp[n][j][s] 来得到所有符合条件的结果。

代码实现

import math

def solution(n, m, s, like):
    # 初始化 dp 数组
    dp = [[[0 for _ in range(s+1)] for _ in range(m+1)] for _ in range(n+1)]
    dp[0][0][0] = 1 # 初始状态,没有选择任何甜点,喜爱值和为0
    
    # 动态规划填表
    for i in range(1, n + 1):
        value = like[i-1] # 当前甜点的喜爱值
        factorialValue = math.factorial(value) # 计算阶乘值
        for j in range(m + 1): # 使用 j 个魔法棒
            for k in range(s + 1): # 当前喜爱值和为 k
                # 第一种情况:不使用魔法棒
                if k >= value:
                    dp[i][j][k] += dp[i-1][j][k-value]
                # 第二种情况:使用魔法棒
                if j > 0 and k >= factorialValue:
                    dp[i][j][k] += dp[i-1][j-1][k-factorialValue]
                # 第三种情况:当前甜品不加入组合
                dp[i][j][k] += dp[i-1][j][k]
                
     # 计算结果
     result = 0
     for j in range(m + 1): # 所有使用魔法棒的情况
         result += dp[n][j][s]
         
     return result

复杂度分析

  • 时间复杂度:我们需要计算 dp[i][j][k],其中 i 的取值范围是 nj 的取值范围是 mk 的取值范围是 s。因此,时间复杂度为 O(nms)。
  • 空间复杂度:我们使用了一个三维数组 dp,因此空间复杂度也是 O(nms)。

个人思考与优化

在这个问题中,动态规划是一个非常合适的解法。通过逐步构建解,我们能够有效地避免暴力枚举的指数级增长,尤其是在使用魔法棒的选择上,确保每个状态只需要计算一次。尽管时间复杂度已经达到 O(nms),但对于大多数实际输入来说,这已经是一个高效的解法。

然而,随着问题规模的增大,特别是当 n 或 s 非常大的时候,可能需要进一步优化。例如,可以考虑对阶乘值进行缓存,或者使用滚动数组来降低空间复杂度。