题解:洛谷 B4016 树的直径
【题目来源】
【题目描述】
给定一棵 \(n\) 个结点的树,树没有边权。请求出树的直径是多少,即树上最长的不重复经过一个点的路径长度是多少。
【输入】
第一行输入一个正整数 \(n\),表示结点个数。
第二行开始,往下一共 \(n-1\) 行,每一行两个正整数 \((u,v)\),表示一条边。
【输出】
输出一行,表示树的直径是多少。
【输入样例】
5
1 2
2 4
4 5
2 3
【输出样例】
3
【核心思想】
-
问题分析:给定一棵 \(n\) 个结点的无权树,需要求出树的直径,即树上任意两点之间的最长路径长度。由于树中两点之间路径唯一,问题等价于找到所有点对中距离最大的那一对的距离。直接枚举所有点对会超时(\(O(n^2)\)),需利用树的特殊性质进行优化。
-
算法选择:
- 两次 DFS/BFS 法:利用树的一个重要性质——从任意点出发,最远点一定是直径的一个端点。因此,第一次 DFS 从任意点(如 1 号点)出发找到最远点 \(t\),第二次 DFS 从 \(t\) 出发找到最远点,两者的距离即为树的直径。
- 树形 DP(备选):也可通过树形 DP 求每个节点子树内的最长链和次长链,取最大值得到直径。但两次 DFS 实现更简洁直观。
- 复杂度:两次 DFS 均为 \(O(n)\),总时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。
-
关键步骤:
- 建图:读入 \(n\) 和 \(n-1\) 条边,构建无向邻接表。
- 第一次 DFS:从节点 1 出发,DFS 遍历整棵树,记录每个节点的深度
deep[u](从起点到该节点的边数),同时维护最大深度maxx和对应的节点t。遍历完成后,t即为距离节点 1 最远的节点(直径的一个端点)。 - 第二次 DFS:重置
deep数组和maxx,从节点 \(t\) 出发再次 DFS,找到距离 \(t\) 最远的节点,此时的maxx即为树的直径长度。 - 输出答案:输出
maxx。
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),两次 DFS 均遍历所有节点和边。
- 空间复杂度:\(O(n)\),存储邻接表和深度数组。
-
两次 DFS 求直径的核心思想:
- 树的性质:在树中,从任意节点出发,最远到达的节点一定是树的直径的某个端点。这个性质保证了第一次 DFS 能找到直径的一个端点,第二次 DFS 从该端点出发就能找到直径的另一端,从而确定直径长度。
- 正确性证明:利用反证法或树的直径性质可证明上述结论,是树结构中最经典的直径求解方法。
- 适用场景:适用于无权树(边权为 1)或有权树(边权为正)的直径求解;若边权为负,则需使用树形 DP。
【解题思路】

【算法标签】
普及 #树形DP
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005, M = N*2;
int n, u, v, deep[N], t, maxx;
int h[N], e[M], ne[M], idx;
// 添加无向边
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
// 深度优先搜索
void dfs(int u, int fa)
{
// 计算当前节点的深度
if (fa)
{
deep[u] = deep[fa] + 1;
}
// 更新最深节点
if (deep[u] > maxx)
{
maxx = deep[u]; // 更新最大深度
t = u; // 记录最深的节点
}
// 遍历所有邻接节点
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (j == fa) continue; // 跳过父节点
dfs(j, u); // 递归搜索子节点
}
}
int main()
{
memset(h, -1, sizeof(h)); // 初始化邻接表
cin >> n; // 读入节点数
// 读入边,构建无向图
for (int i = 1; i < n; i++)
{
cin >> u >> v;
add(u, v), add(v, u);
}
// 第一次DFS:从任意节点1开始,找到最远的节点t
dfs(1, 0);
// 重置深度数组和最大深度
memset(deep, 0, sizeof(deep));
maxx = 0;
// 第二次DFS:从节点t开始,找到离t最远的节点
dfs(t, 0);
// 输出树的直径(最远两节点间的距离)
cout << maxx << endl;
return 0;
}
【运行结果】
5
1 2
2 4
4 5
2 3
3
浙公网安备 33010602011771号