题解:洛谷 P2959 The Leisurely Stroll
【题目来源】
洛谷:P2959 [USACO09OCT] The Leisurely Stroll G - 洛谷
【题目描述】
Bessie 通过牛棚的大门向外望去,发现今天是一个美丽的春季早晨。她想,“我真的好想好想沐浴着春风,走在草地之中,感受嫩草温柔地抚摸四蹄的感觉。”她知道一旦她离开了牛棚,她将沿着一条小径走一段路,然后就会出现一个三岔路口,她必须在两条小径中选择一条继续走下去。然后她又会遇到更多的三岔路口,进行更多的选择,直到她到达一个青翠的牧场为止。
她决定作一个选择使得她在去吃早草的路途中可以走过最多的小径。给你这些小径的描述,求出 Bessie 最多可以走过多少条小径。假定 Bessie 一出牛棚就有 \(2\) 条路径,Bessie 需要从中选择一条。
农场中有 \(P-1\)(\(1 \le P \le 1000\))个分岔节点(范围是 \(1 \ldots P-1\)),引向 \(P\) 片草地,它们之间由小径连接。对任意一个节点来说,只有一条从牛棚(被标记为节点 \(1\))开始的路径可以到达。
考虑下面的图。线段表示小径,% 表示草地。右边的图中的 # 表示一条到达草地的高亮的路径。
% %
/ /
2----% 7----8----% 2----% 7####8----%
/ \ / \ # # # #
1 5----6 9----% 1 5####6 9----%
\ \ \ \ \ \ \ #
\ % % % \ % % %
\ \
3-----% 3-----%
\ \
4----% 4----%
\ \
% %
从分岔节点 \(9\) 到达的草地是两个可以让 Bessie 走过最多小径的草地之一。在去吃早草的路上 Bessie 将走过 \(7\) 条不同的小径。这些草地是离牛棚也就是节点 \(1\) 最“远”的。
由 \(3\) 个整数来表示每一个节点:\(C,D_1,D_2\),\(C\) 是节点的编号(\(1 \le C < P\)),\(D_1\) 和 \(D_2\) 是由该节点引出的两条小径的终点(\(0 \le D_1,D_2 < P\))。如果 \(D_1\) 为 \(0\),表示这条小径引向的是一片牧草地,\(D_2\) 也一样。
【输入】
第一行,一个正整数 \(P\)。
以下 \(P-1\) 行,每行 \(3\) 个整数 \(C,D_1,D_2\) 表示一个节点。
【输出】
输出一行一个整数,代表 Bessie 可以经过最多节点数。
【输入样例】
10
7 8 0
5 0 6
9 0 0
6 0 7
3 4 0
2 5 0
8 0 9
4 0 0
1 2 3
【输出样例】
7
【核心思想】
-
问题分析:给定一棵以节点 \(1\) 为根的满二叉树(每个非叶子节点恰好有两条出边,分别指向子节点或叶子草地),求从根节点到最远叶子节点的路径长度(经过的边数)。这是一个树的最长路径/BFS求树高问题,关键在于将节点信息按编号排序后,用BFS从根节点开始逐层扩展,记录最大深度。
-
算法选择:
- 按节点编号排序:输入的节点信息无序,先按 \(C\) 排序确保节点按编号顺序处理
- BFS层序扩展:从根节点的两个子节点开始BFS,逐层向下遍历,记录到达每个节点的深度(经过的边数)
- 叶子节点判定:\(D_1 = 0\) 或 \(D_2 = 0\) 表示该方向指向草地(叶子),更新最大深度
-
关键步骤:
- 读取输入:\(P\) 和 \(P-1\) 个节点的 \((C, D_1, D_2)\)
- 初始化:所有节点的 \(step = 0\)
- 排序:按 \(C\) 从小到大排序节点
- BFS初始化:将节点 \(1\) 的两个子节点 \(D_1\) 和 \(D_2\) 入队,\(step = 1\)
- BFS扩展:
- 取出队首 \(tp\)
- 检查 \(D_1\):
- 若为 \(0\)(叶子):\(maxn = \max(maxn, p[tp].step)\)
- 否则:子节点入队,\(step = p[tp].step + 1\)
- 检查 \(D_2\):同上
- 输出 \(maxn + 1\)(加上从牛棚到节点 \(1\) 的那条边)
-
时间/空间复杂度:
- 时间复杂度:\(O(P \log P)\),排序主导
- 空间复杂度:\(O(P)\),节点数组和队列
-
BFS求树高的核心思想:
- 树的层次遍历:BFS天然按层扩展,每扩展一层深度加 \(1\),首次到达叶子节点时的深度即为该路径长度
- 排序恢复结构:输入无序,按节点编号排序后用数组索引直接访问子节点,避免复杂建树
- 满二叉树特性:每个节点恰好有两个分支(子节点或叶子),BFS时统一处理即可
- 适用于"无序输入的树结构 + 求最远叶子距离"类问题,核心是排序后用BFS层序遍历
【解题思路】

【算法标签】
普及- #BFS-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int P, maxn, maxc;
struct node {
int c, d1, d2, step;
}p[1005];
bool cmp(node x, node y)
{
return x.c < y.c;
}
int main()
{
cin >> P; // 输入P
for (int i=1; i<P; i++) { // 遍历P-1次的输入
cin >> p[i].c >> p[i].d1 >> p[i].d2; // 记录每个数c及对应的d1、d2
p[i].step=0; // 初始化到达每个牛棚的step为0
}
sort(p+1, p+P, cmp); // 按照从小到大排序
queue<int> q; // 定义队列q
int tp = {p[1].d1}; // 将牛棚1的d1和d2压入队列中
p[p[1].d1].step = p[1].step+1; // 同时更新其step为原来牛棚1的step加1
q.push(tp);
tp = {p[1].d2};
p[p[1].d2].step = p[1].step+1; // 同时更新其step为原来牛棚1的step加1
q.push(tp);
while (!q.empty()) { // BFS模板
tp = q.front();
q.pop();
if (p[tp].d1==0) { // 当前牛棚的d1为0时
if (p[tp].step>maxn) { // 判断其step是否比maxn还大
maxn = p[tp].step; // 更新maxn
}
} else { // 否则将p[tp].d1压入队列
int t = p[tp].d1;
q.push(t);
p[t].step = p[tp].step+1; // 更新其step为当前牛棚的step加1
}
if (p[tp].d2==0) { // 当前牛棚的d2为0时
if (p[tp].step>maxn) { // 判断其step是否比maxn还大
maxn = p[tp].step; // 更新maxn
}
} else { // 否则将p[tp].d2压入队列
int t = p[tp].d2;
q.push(t);
p[t].step = p[tp].step+1; // 更新其step为当前牛棚的step加1
}
}
cout << maxn+1 << endl; // 最后输出maxn,需要再加上1(从牛棚到草坪的那段路径)
return 0;
}
【运行结果】
10
7 8 0
5 0 6
9 0 0
6 0 7
3 4 0
2 5 0
8 0 9
4 0 0
1 2 3
7
浙公网安备 33010602011771号