题解:甜点喜爱值之和问题
题目分析
小R的问题可以建模为一个状态搜索问题,通过动态规划或深度优先搜索(DFS)的方法找到所有符合条件的组合。
问题的核心在于:
- 对于每个甜点,有三种选择:
- 不选该甜点。
- 选该甜点的原始喜爱值。
- 选该甜点的阶乘值(消耗一个魔法棒)。
- 目标是找到所有满足甜点喜爱值之和恰好为 (S) 的方案。
问题的约束和变量:
- (N) 表示甜点的数量。
- (M) 表示魔法棒的最大数量。
- (S) 表示目标喜爱值。
- (like[i]) 表示第 (i) 个甜点的初始喜爱值。
求解思路
本题需要考虑所有可能的选择组合,可以采用深度优先搜索(DFS)+ 记忆化搜索 或 动态规划 的方式来求解。
求解思路详解
1. 状态定义
使用 DFS,定义以下状态:
- 当前甜点索引 (index)。
- 已使用的魔法棒数量 (used_magic)。
- 当前甜点喜爱值之和 (current_sum)。
2. 状态转移
对于每个甜点,存在三种选择:
- 不选择当前甜点:状态转移为 (dfs(index+1, used_magic, current_sum))。
- 选择原始值:状态转移为 (dfs(index+1, used_magic, current_sum + like[index]))。
- 选择阶乘值(需要魔法棒):前提是剩余魔法棒数量足够,状态转移为 (dfs(index+1, used_magic+1, current_sum + factorial(like[index])))。
3. 终止条件
- 当 (current_sum > S) 或 (used_magic > M) 时,返回 0。
- 当 (index == N) 时,判断是否 (current_sum == S),如果相等返回 1,否则返回 0。
4. 记忆化搜索
为了避免重复计算,将中间状态结果存储在 memo 中,键为 ((index, used_magic, current_sum))。
代码实现
from math import factorial
def solution(n, m, s, like):
# 状态记录 memo[(index, used_magic, current_sum)] = ways
memo = {}
def dfs(index, used_magic, current_sum):
# 如果超出目标和或者使用的魔法棒超出数量,直接返回 0
if current_sum > s or used_magic > m:
return 0
# 如果到达所有甜点并且和刚好为 s,返回 1 种方案
if index == n:
return 1 if current_sum == s else 0
# 如果状态已存在,直接返回结果
if (index, used_magic, current_sum) in memo:
return memo[(index, used_magic, current_sum)]
# 不使用当前甜点
res = dfs(index + 1, used_magic, current_sum)
# 使用当前甜点的原始值
res += dfs(index + 1, used_magic, current_sum + like[index])
# 使用当前甜点的阶乘值(需要魔法棒)
if used_magic < m:
res += dfs(index + 1, used_magic + 1, current_sum + factorial(like[index]))
# 记录当前状态
memo[(index, used_magic, current_sum)] = res
return res
# 从第 0 个甜点开始
return dfs(0, 0, 0)
# 测试用例
if __name__ == "__main__":
print(solution(3, 2, 6, [1, 2, 3])) # 输出:5
print(solution(3, 1, 1, [1, 1, 1])) # 输出:6
print(solution(5, 3, 24, [1, 2, 3, 4, 5])) # 输出:1
print(solution(4, 0, 10, [1, 3, 3, 3])) # 输出:1
print(solution(6, 1, 35, [5, 5, 5, 5, 5, 5])) # 输出:0
代码解析
-
DFS 函数:
- 遍历每种可能的选择(不使用、使用原始值、使用阶乘值)。
- 判断是否满足约束条件(超出 (S) 或使用魔法棒数超过 (M) 时剪枝)。
- 递归搜索剩余的甜点。
-
记忆化:
- 避免重复计算相同的状态。
- 减少搜索次数,提高效率。
-
复杂度分析:
- 状态空间大小为 (O(n \times m \times S)),其中:
- (n):甜点数量。
- (m):魔法棒数量。
- (S):目标和。
- 由于记忆化的优化,时间复杂度近似为状态空间大小。
- 状态空间大小为 (O(n \times m \times S)),其中:
测试结果
样例:
-
样例1:(n = 3, m = 2, s = 6, like = [1, 2, 3])
输出:5。 -
样例2:(n = 3, m = 1, s = 1, like = [1, 1, 1])
输出:6。 -
样例3:(n = 5, m = 3, s = 24, like = [1, 2, 3, 4, 5])
输出:1。 -
样例4:(n = 4, m = 0, s = 10, like = [1, 3, 3, 3])
输出:1。 -
样例5:(n = 6, m = 1, s = 35, like = [5, 5, 5, 5, 5, 5])
输出:0。
总结
该问题使用 DFS+记忆化搜索 有效解决:
- 考虑了所有可能的组合方案。
- 避免重复计算,显著提高了效率。
- 代码结构清晰,便于理解和扩展。