
本文介绍在每层有3种选择、共100层的树结构中,快速计算从根到叶所有路径中最大累积收益的方法;关键在于利用动态规划思想自顶向下逐层更新节点最大累积收益,时间复杂度仅为 o(n),远优于暴力枚举的 o(3¹⁰⁰)。
该问题本质是带状态转移依赖的树上最大路径和问题:每个节点的即时收益不仅由自身动作决定,还依赖于父节点所选动作(即“当前选择的 payoff 取决于前一节点的选择”),因此不能简单对每层独立取最大值,而需维护“以各动作结尾的最大累积收益”。
最高效解法是采用自顶向下的动态规划(DP)+ 层序遍历(BFS),空间复用、无冗余计算:
- 定义 dp[l][a] 表示到达第 l 层、且该层执行动作 a ∈ {0,1,2} 时所能获得的最大累积收益;
- 初始层(第 0 层,即根):dp[0][a] = 0(无前置动作,或可设为初始奖励);
- 状态转移:对第 l 层每个动作 a,遍历所有可能的父动作 prev_a ∈ {0,1,2},计算 dp[l][a] = max_{prev_a} { dp[l−1][prev_a] + payoff(prev_a → a) };
- 其中 payoff(prev_a → a) 是由前一动作 prev_a 决定当前动作 a 的收益,需通过如题中 get_payoffs(p[prev_a]) 动态计算。
以下为优化后的 Python 实现(去除嵌套 for 循环的指数级膨胀,改为线性层序更新):
import numpy as np
def solve_max_cumulative_payoff(num_layers: int) -> float:
# 初始化:dp[a] = 到达当前层并选择动作 a 的最大累积收益
dp = np.zeros(3) # 第 0 层(根)起始,暂无收益
# 预定义动作间转移收益函数(简化示意)
# 实际中 payoff_matrix[prev_a][a] 应由 get_payoffs(p[prev_a]) 动态生成
# 此处用静态矩阵演示逻辑;真实场景中需按需调用 get_payoffs & get_prob
for layer in range(1, num_layers + 1):
new_dp = np.full(3, -np.inf)
# 对当前层每个动作 a
for a in range(3):
# 枚举所有可能的父动作 prev_a
for prev_a in range(3):
# 模拟:根据 prev_a 计算当前动作 a 的即时收益
# 实际应替换为:payoff = get_payoffs(p[prev_a])[a]
payoff = [[12, 6, 10], [10, 24, 14], [6, 10, 30]][prev_a][a]
new_dp[a] = max(new_dp[a], dp[prev_a] + payoff)
dp = new_dp # 滚动更新至下一层
return float(np.max(dp))
# 示例:100 层树的最优累积收益(毫秒级完成)
optimal_payoff = solve_max_cumulative_payoff(num_layers=100)
print(f"Maximum cumulative payoff: {optimal_payoff}")✅ 关键优势:
- 时间复杂度 O(L × 9) = O(L),其中 L 为层数(100),9 来自 3×3 动作转移组合;
- 空间复杂度仅 O(1)(仅维护两个长度为 3 的数组);
- 完全避免生成全部 3¹⁰⁰ 条路径,也不依赖递归或深度优先搜索导致的栈溢出风险。
⚠️ 注意事项:
- 若 get_payoffs() 和 get_prob() 涉及复杂状态演化(如概率向量 p 随路径变化),需将 p 的演化也纳入 DP 状态——此时状态空间扩大,但若 p 维度固定(如始终为 3 维),仍可维持多项式复杂度;
- 本解法返回的是最大收益值(符合题目要求),若后续需重构最优路径,只需在 DP 过程中额外记录 parent[a] 回溯指针;
- 不要使用原始代码中的 accumulated_payoffs 列表嵌套扩展方式——它会导致内存爆炸与逻辑错乱(t+=1 位置错误、未分层隔离等)。
综上,面对深层树状决策结构,务必放弃路径枚举直觉,转而采用分层状态压缩 + 最优子结构复用这一动态规划范式,方能实现真正高效的求解。









