逐层滚动一维 dp:走到当前层第 j 个数的最大和只由上一层正上方与左上方两格决定,末行最大值即答案。
OJ: roj
题目 ID: 2017
难度:入门
标签:动态规划usacopython
创建: 2026-10-01 03:07
更新: 2026-10-06 09:32
题目描述
给定
样例输入首行为 5,金字塔为 7 / 3 8 / 8 1 0 / 2 7 4 4 / 4 5 2 6 5(/ 表示换行);输出 30(路径
思路
设
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 03:07
# update_at: 2026-10-01 03:11
import sys
from functools import reduce
def extend(above: list[int], row: list[int]) -> list[int]:
"""把“走到上一行为止的最大路径和”延伸到本行:每格只可能从正上方或左上方走来。
先把上一行首尾各复制一份(`above[0]` 补在左边、`above[-1]` 补在右边),
第 j 格的两个来源就固定是补长后的 `sources[j]` 与 `sources[j+1]`;
越界一侧复制到的正是自己,`max` 于是等价于“该格只有一个来源”。
"""
sources = [above[0], *above, above[-1]]
return [v + max(sources[j], sources[j + 1]) for j, v in enumerate(row)]
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
row_count = next(data) # 题面的 R
# 第 i 层恰好有 i 个数,按三角结构逐层消费 token,不依赖文件在哪里换行
rows = (
[next(data) for _ in range(length)]
for length in range(1, row_count + 1)
)
# 自顶向下折叠:每折一层得到该层每格的最大路径和,只需保留最新一行
print(max(reduce(extend, rows)))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 09:32
* update_at: 2026-10-06 09:32
*/
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
const int MAXR = 1005;
ll prev_row[MAXR]; // prev_row[j] 表示走到上一层第 j 个数的最大路径和
ll cur_row[MAXR]; // cur_row[j] 表示走到当前层第 j 个数的最大路径和
int main() {
int R;
if (!(cin >> R)) {
return 0;
}
ll value;
cin >> value;
prev_row[1] = value; // 第一层只有一个数,它就是起点
for (int i = 2; i <= R; i++) {
for (int j = 1; j <= i; j++) {
cin >> value;
// 第 j 个数只能从上一层第 j-1、j 个数走下来;不存在的来源记为 -1
ll from_left = (j >= 2) ? prev_row[j - 1] : -1;
ll from_up = (j <= i - 1) ? prev_row[j] : -1;
cur_row[j] = value + max(from_left, from_up);
}
for (int j = 1; j <= i; j++) {
prev_row[j] = cur_row[j];
}
}
// 终点可以停在底层任意位置,答案是末行的最大值
ll answer = prev_row[1];
for (int j = 2; j <= R; j++) {
answer = max(answer, prev_row[j]);
}
cout << answer << "\n";
return 0;
}