news 2026/11/3 12:47:51

数字金字塔问题的DFS与动态规划解法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数字金字塔问题的DFS与动态规划解法详解

1. 题目背景与需求分析

数字金字塔是东华大学OJ平台上的一道经典算法练习题(题号72),也是动态规划和深度优先搜索算法的典型教学案例。题目给出一个由数字组成的金字塔结构,要求从顶层到底层找到一条路径,使得路径上数字的总和最大。

金字塔结构示例:

5 3 6 7 2 9

1.1 问题建模

我们需要将金字塔结构转化为可计算的数据模型。常见存储方式包括:

  • 二维数组表示:dp[i][j]表示第i层第j个数字
  • 邻接表表示:适合图论解法
  • 树形结构表示:便于递归处理

对于这个规模的问题(通常金字塔层数n≤100),二维数组是最直观的存储方式。数组下标从0开始还是从1开始需要根据编程习惯确定,本文示例采用数学坐标系(第1层第1个元素为dp[1][1])。

2. 深度优先搜索(DFS)解法

2.1 算法思路

DFS解法采用递归思想,从金字塔顶端出发,每次可以选择向左下或右下的数字移动,直到到达最底层。所有路径中取最大值。

递归公式:

dfs(i,j) = dp[i][j] + max(dfs(i+1,j), dfs(i+1,j+1))

其中i表示当前层数,j表示当前层中的位置索引。

2.2 代码实现(C++)

#include <iostream> #include <algorithm> using namespace std; const int MAXN = 105; int dp[MAXN][MAXN]; int n; int dfs(int i, int j) { if (i == n) return dp[i][j]; return dp[i][j] + max(dfs(i+1, j), dfs(i+1, j+1)); } int main() { cin >> n; for (int i = 1; i <= n; ++i) for (int j = 1; j <= i; ++j) cin >> dp[i][j]; cout << dfs(1, 1) << endl; return 0; }

2.3 算法分析

时间复杂度:O(2^n) —— 每个节点有两个分支,形成二叉树结构 空间复杂度:O(n) —— 递归栈深度

注意:纯DFS解法在n>30时就会超时,需要配合记忆化优化

3. 动态规划(DP)解法

3.1 算法思路

动态规划采用自底向上的递推方式,从金字塔底层开始计算每个位置到底层的最大路径和,逐步推导到顶层。

状态转移方程:

dp[i][j] += max(dp[i+1][j], dp[i+1][j+1])

3.2 代码实现(C++)

#include <iostream> #include <algorithm> using namespace std; const int MAXN = 105; int dp[MAXN][MAXN]; int main() { int n; cin >> n; for (int i = 1; i <= n; ++i) for (int j = 1; j <= i; ++j) cin >> dp[i][j]; for (int i = n-1; i >= 1; --i) for (int j = 1; j <= i; ++j) dp[i][j] += max(dp[i+1][j], dp[i+1][j+1]); cout << dp[1][1] << endl; return 0; }

3.3 算法优化

空间优化版(滚动数组):

int dp[2][MAXN]; // 使用 dp[i%2] 和 dp[(i+1)%2] 交替更新

3.4 算法分析

时间复杂度:O(n^2) —— 双层循环 空间复杂度:O(n^2) 或 O(n)(优化后)

4. 两种解法的对比与实践建议

4.1 性能对比表

指标DFS解法DP解法
时间复杂度O(2^n)O(n^2)
空间复杂度O(n)O(n^2)/O(n)
适用场景教学演示实际应用
编码难度较简单中等
扩展性较差较好

4.2 选择建议

  1. 教学目的:建议先实现DFS解法,理解问题本质
  2. 竞赛场景:必须使用DP解法
  3. 数据规模:
    • n≤20:两种方法均可
    • 20<n≤1000:必须用DP
    • n>1000:考虑空间优化版DP

4.3 常见错误排查

  1. 数组越界:确保循环边界正确(特别是j≤i)
  2. 初始化问题:DP解法需要从n-1层开始递推
  3. 输入格式:注意金字塔的输入方式(逐行输入)
  4. 最大和溢出:使用long long代替int处理大数据

5. 算法扩展与变种

5.1 输出具体路径

在DP解法中增加路径记录:

int path[MAXN]; // 记录路径选择 // 在状态转移时记录选择 if (dp[i+1][j] > dp[i+1][j+1]) { dp[i][j] += dp[i+1][j]; path[i] = j; } else { dp[i][j] += dp[i+1][j+1]; path[i] = j+1; }

5.2 三维金字塔问题

当每个位置有三个选择(左、中、右)时:

dp[i][j] += max({dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1]});

5.3 最小路径和问题

将max改为min即可求最小路径和:

dp[i][j] += min(dp[i+1][j], dp[i+1][j+1]);

6. 实际应用场景

  1. 游戏AI路径规划:如RPG游戏中的最优收益路线
  2. 投资决策:分层决策模型中的最优选择
  3. 资源分配:多层资源分配的最大效益问题
  4. 神经网络:某些网络结构的正向传播计算

7. 编程技巧与优化

  1. 输入优化:使用快速读取方法处理大规模输入
    ios::sync_with_stdio(false); cin.tie(0);
  2. 边界处理:在数组周围填充0避免边界判断
    for (int i = 0; i <= n+1; ++i) for (int j = 0; j <= i+1; ++j) dp[i][j] = -INF; // 初始化
  3. 记忆化搜索:DFS+记忆化的混合解法
    int memo[MAXN][MAXN]; int dfs(int i, int j) { if (memo[i][j] != -1) return memo[i][j]; // ...其余相同 }

8. 不同语言的实现差异

8.1 Python实现特点

# DP解法 n = int(input()) dp = [list(map(int, input().split())) for _ in range(n)] for i in range(n-2, -1, -1): for j in range(i+1): dp[i][j] += max(dp[i+1][j], dp[i+1][j+1]) print(dp[0][0])

注意事项:

  • Python递归深度限制(默认1000)
  • 使用lru_cache实现记忆化
  • 处理大数自动转为长整型

8.2 Java实现注意点

// 需要处理输入输出效率 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 数组初始化为0 int[][] dp = new int[n+2][n+2];

9. 测试用例设计

有效测试用例应包括:

  1. 最小用例(n=1):

    1 5

    预期输出:5

  2. 常规用例:

    3 1 2 3 4 5 6

    预期输出:10(1→3→6)

  3. 边界用例:

    • 所有元素相同
    • 严格递增/递减
    • 包含负数
  4. 最大规模用例(n=100):验证算法效率

10. 学习路线建议

  1. 基础阶段:

    • 理解递归和递推的区别
    • 掌握二维数组操作
    • 熟悉基本输入输出处理
  2. 进阶阶段:

    • 学习记忆化搜索技术
    • 掌握滚动数组优化
    • 理解状态压缩DP
  3. 扩展学习:

    • 图论中的最短路径算法
    • 树形DP问题
    • 背包问题的变种

在实际编程练习中,建议从简单的DFS实现开始,逐步过渡到DP解法,最后尝试各种优化技巧。东华大学OJ平台上的这道题目是算法学习的经典案例,掌握其解法对后续学习更复杂的动态规划问题大有裨益。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 12:46:46

错误模型设计:数据、异常与正常返回的取舍

错误处理这件事&#xff0c;几乎所有项目都在做&#xff0c;但绝大多数团队从来没有坐下来认真讨论过一个根本问题&#xff1a;当一段代码失败时&#xff0c;我们到底希望它用什么方式把"失败"这件事告诉上一级&#xff1f;我见过太多反面案例&#xff1a;有的模块把…

作者头像 李华
网站建设 2026/11/3 12:46:32

STM32 PM2.5空气净化器毕设:从采样到触屏档位控制

简介&#xff1a;这份毕业设计文档围绕基于STM32单片机的办公室空气净化器控制系统展开&#xff0c;面向电子信息、电气工程及自动化等专业的本科毕业生与嵌入式入门者&#xff0c;可用于课程设计、毕业设计选题参考及STM32综合项目练手。压缩包内为1个docx文件&#xff0c;约2…

作者头像 李华
网站建设 2026/11/3 12:46:32

IPFDDP算法:基于狄利克雷过程的贝叶斯非参数建模实践

1. 项目概述 IPFDDP算法技术是一种创新的联合逆向学习框架&#xff0c;其核心在于依赖狄利克雷过程&#xff08;DDP&#xff09;构建贝叶斯非参数模型。这个框架特别适合处理复杂、高维且结构不明确的数据分析问题&#xff0c;在机器学习、数据挖掘和统计建模领域具有广泛的应用…

作者头像 李华
网站建设 2026/11/3 12:46:31

逻辑思维驱动类脑大模型,重构智能驾驶程序设计

看到这个题目的时候&#xff0c;说实话我挺有感触的。平时在团队里带嵌入式软件和算法相关的项目&#xff0c;经常会碰到一种尴尬局面&#xff1a;代码写得飞起&#xff0c;工程结构却一塌糊涂&#xff1b;模型调参调到麻木&#xff0c;换一个场景就全线崩溃。做汽车智能驾驶这…

作者头像 李华
网站建设 2026/11/3 12:45:27

GPT API接入前必须确认的四件事:地址、模型、倍率与稳定性

上周帮一个做跨境电商的朋友排查接口问题&#xff0c;卡了整整一下午。他把 GPT API 接进了一套自动客服系统&#xff0c;症状很怪&#xff1a;本地测试一切正常&#xff0c;部署到服务器后有的请求能返回&#xff0c;有的请求直接超时&#xff0c;偶尔还会报一条 model not fo…

作者头像 李华
网站建设 2026/11/3 12:45:25

智能截流井技术:城市排水系统的智能解决方案

1. 智能截流井技术概述&#xff1a;城市排水系统的"智能阀门" 在城市化进程加速的今天&#xff0c;暴雨内涝和初期雨水污染已成为困扰各大城市的顽疾。传统截流井依靠简单的机械结构进行雨污分流&#xff0c;就像一位反应迟钝的守门人——要么过早开启导致污水溢流&a…

作者头像 李华