洛谷 B4016:树的直径 ← 树形DP + 无权边
【题目来源】
【题目描述】
给定一棵 n 个结点的树,树没有边权。请求出树的直径是多少,即树上最长的不重复经过一个点的路径长度是多少。
【输入格式】
第一行输入一个正整数 n,表示结点个数。
第二行开始,往下一共 n−1 行,每一行两个正整数 (u,v),表示一条边。
【输出格式】
输出一行,表示树的直径是多少。
【输入样例】
5
1 2
2 4
4 5
2 3
【输出样例】
3
【数据范围】
数据保证,1≤n≤10^5。
【算法分析】
● 什么是树的直径?树上任意两结点之间最长的简单路径即为树的直径。
若无负权边,可以采用两次 DFS 或者树形 DP 的方法在 O(n) 时间求出树的直径;若有负权边,则只能采用树形 DP 求解树的直径。显然,一棵树可以有多条直径,因为树中可能存在最长长度相等的多条简单路径。→ 推荐使用树形 DP 求解树的直径。
● 根据树形 DP 法原理,树的直径计算方法如下:
(1)路径定义:树的直径是树中任意两节点间最长的简单路径长度。
(2)状态转移:以某节点为根的子树,其延伸的最长路径长度记为 d1,次长路径长度记为 d2。树的直径即为所有节点 d1+d2 的最大值。
(3)路径特性:最长路径 d1 和次长路径 d2 无公共边,确保路径唯一性。
● 路径更新
若 d1[j]+1>d1[u],说明通过 j 的路径更长,更新 d1[u]=d1[j]+1,同时旧的最长路径 d1[u] 转为次长路径 d2[u]。
若 d1[j]+1<=d1[u] 但 d1[j]+1>d2[u],说明 j 的路径虽非最长,但比当前次长路径更长,更新 d2[u]=d1[j]+1。
● 更新方向
在树形 DP 中,路径长度从叶子节点(无子节点)开始计算,逐层向上更新父节点的路径长度。因此,j(子节点)确实会先于 u(父节点)被处理,符合“自下向上更新”的描述。
d1 和 d2 初始值为 0,表示所有节点的最长和次长路径长度从 0 开始计算,符合树形 DP 的初始化要求。
【算法代码一:无权边】
【算法代码二:有权边】
若边上有权,代码如下所示。
代码详见:
【参考文献】

浙公网安备 33010602011771号