用二维动态规划维护走到每个位置的最大路径和,状态只来自上一层相邻两个位置。
OJ: luogu
题目 ID: P1216
难度:入门
标签:dp动态规划
日期: 2026-06-19 11:04
题意
给出一个数字三角形。
从顶部出发,每次只能走到下一行相邻的两个位置之一。
要求求出从顶到底的最大路径和。
思路
最直接的教学版做法是搜索所有路径:
cpp
// brute.cpp:搜索所有从顶部到底部的路径,作为教学版和对拍基准程序。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 30;
int n;
int a[MAXN][MAXN];
int ans;
void dfs(int x, int y, int sum) {
sum += a[x][y];
if (x == n) {
ans = max(ans, sum);
return;
}
dfs(x + 1, y, sum);
dfs(x + 1, y + 1, sum);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
cin >> a[i][j];
}
}
dfs(1, 1, 0);
cout << ans << '\n';
return 0;
}但正式解法用标准 DP 更直接。
设 dp[i][j] 表示走到第 i 行第 j 个位置时的最大路径和。
由于当前位置只可能从上一行相邻两个位置走来,所以:
dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + a[i][j]
初始 dp[1][1] = a[1][1],最后答案是最后一行中的最大值。
DP 公式
设
转移为:
不存在的位置按
公式解释:三角形中第 i 行第 j 个位置只能从上一行相邻的两个位置走来。选择其中路径和较大的一个,再加上当前格子的值,就是到达该位置的最优值。
样例 DP 表格
以样例为例,数字三角形为:
text
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5逐行计算
| 行 |
|||||
|---|---|---|---|---|---|
| 1 | 7 | ||||
| 2 | |||||
| 3 | |||||
| 4 | |||||
| 5 |
答案
代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int n;
int a[MAXN][MAXN];
int dp[MAXN][MAXN]; // dp[i][j]:走到第 i 行第 j 个数时的最大和
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
cin >> a[i][j];
}
}
dp[1][1] = a[1][1];
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i; j++) {
dp[i][j] = max(dp[i - 1][j - 1], dp[i - 1][j]) + a[i][j];
}
}
int ans = 0;
for (int j = 1; j <= n; j++) {
ans = max(ans, dp[n][j]);
}
cout << ans << '\n';
return 0;
}复杂度
- 时间复杂度:
- 空间复杂度:
总结
这题是数字三角形 DP 的最经典模型。
看清“一个位置只依赖上一层相邻两个位置”,就可以直接写出转移。
一图流解析
这张图把本题的建模、关键转移、实现检查和训练方法压缩到一页,适合读完正文后复盘。

