AI刷题66.魔法甜点之和:小包的新挑战|豆包MarsCode AI刷题

78 阅读4分钟

题目解析

这道题是一个 变种背包问题,结合了阶乘运算。每个甜点的喜爱值有两种选择:原始值或者它的阶乘值。目标是通过选择这些甜点(可以使用魔法棒改变喜爱值)使得它们的喜爱值之和恰好为 S,并计算出所有可能的方案数。

问题的关键点

  1. 选择状态: 每个甜点可以选择两种状态:

    • 原始值:不使用魔法棒,直接采用该甜点的原始喜爱值。
    • 阶乘值:使用魔法棒,将该甜点的喜爱值变为它的阶乘值。
  2. 目标: 最终的目标是通过选择一些甜点,使得它们的喜爱值之和恰好为 S

  3. 限制

    • N 个甜点,每个甜点有两种选择(原值或阶乘值),因此对于每个甜点的选择,我们需要考虑它的两种可能性。
    • 给定的目标和是 S,要求计算出能满足和为 S 的所有选择组合的数量。

动态规划(DP)方法

1. 状态定义

我们用 dp[i] 来表示能够得到和为 i 的方案数。初始时,dp[0] = 1,表示和为 0 的方案只有一种:不选任何甜点。

2. 状态转移

对于每个甜点,我们有两种选择:

  • 选择该甜点的原始喜爱值:更新 dp[j],其中 j 是当前的和,更新方式是 dp[j] += dp[j - love],即从当前和 j 转移到和为 j + love
  • 选择该甜点的阶乘值:更新 dp[j],其中 j 是当前的和,更新方式是 dp[j] += dp[j - fact],即从当前和 j 转移到和为 j + fact

为了避免重复使用同一个甜点,我们从后往前遍历 dp 数组。

代码实现

import math

def count_ways_to_match_sum(N, S, loves):
    # 计算所有甜点的阶乘
    factorials = [math.factorial(love) for love in loves]
    
    # 初始化 dp 数组,dp[i] 表示和为 i 的方案数
    dp = [0] * (S + 1)
    dp[0] = 1  # 和为 0 的方案只有一种,就是不选任何甜点
    
    # 遍历每个甜点
    for i in range(N):
        love = loves[i]
        fact = factorials[i]
        
        # 更新 dp 数组,遍历的顺序从后往前是为了避免重复使用同一个甜点
        for j in range(S, -1, -1):
            if j >= love:
                dp[j] += dp[j - love]
            if j >= fact:
                dp[j] += dp[j - fact]
    
    return dp[S]

# 示例输入
N = 3  # 甜点个数
S = 10  # 目标和
loves = [1, 2, 3]  # 每个甜点的喜爱值

# 计算结果
result = count_ways_to_match_sum(N, S, loves)
print(result)  # 输出结果

代码解析

  1. 计算阶乘

    • 对每个甜点的喜爱值,计算其阶乘值并存储在 factorials 数组中。这是因为对于每个甜点,我们可以选择其阶乘值来替代原始喜爱值。
  2. 动态规划数组 dp

    • dp[i] 表示和为 i 的方案数。初始时 dp[0] = 1,表示和为 0 的方案只有一种,即不选任何甜点。
  3. 遍历每个甜点

    • 对于每个甜点,遍历 dp 数组并更新其状态。如果当前和 j 大于或等于该甜点的原始值 love,我们可以通过选择该甜点的原始值来更新 dp[j]。同理,如果 j 大于或等于该甜点的阶乘值 fact,我们也可以选择其阶乘值来更新 dp[j]
  4. 避免重复选择

    • 更新 dp 数组时,从后往前遍历,避免在同一轮更新中重复使用同一个甜点。
  5. 返回结果

    • 最后,dp[S] 就是所有可能的方案数,即使得甜点的喜爱值之和恰好为 S 的方案数。

例子解析

假设有 3 个甜点,喜爱值分别为 [1, 2, 3],目标和 S = 10

  • 甜点1的喜爱值是 1,可以选择不使用魔法棒,或者使用魔法棒将其变为 1! = 1
  • 甜点2的喜爱值是 2,可以选择不使用魔法棒,或者使用魔法棒将其变为 2! = 2
  • 甜点3的喜爱值是 3,可以选择不使用魔法棒,或者使用魔法棒将其变为 3! = 6

dp 数组中,dp[i] 表示和为 i 的方案数。通过动态规划,我们可以计算出能够得到和为 10 的所有方案数。