这是本文档旧的修订版!
树$T= \langle E, V \rangle$的直径定义为$max\{ \delta(u,v) \} u,v \in V$。其中$\delta(u,v)$表示点$u$和点$v$之间的简单路径。简单来说,在树上任取两个点可以得到它们之间的距离,而最大的那个距离就是直径。
树的直径有这些性质:
1.两端点一定是叶子节点。
证明:显然,如果有一个端点不是叶子则可以延长到一个叶子使直径边长。
2.距任意点最远点一定是直径的端点。
证明:假设不是,我们从$u$找到的最远点是$v$,而直径是从$a$到$b$。如果$v$在$\delta(a,b)$上,那么显然距离$u$最远的点不是$v$,还可以继续延长,矛盾。如果$v$不在$\delta(a,b)$上,那么我们在$\delta(a,b)$上选一个点$p$,那么有$dis(u,v)>dis(u,p)+dis(p,b)$,因此有$dis(a,v) = dis(a,p) + dis(p,u) + dis(u,v) > dis(a,p) + dis(p,b) = dis(a,b)$,得出$\delta(a,b)$不是直径,矛盾。因此得证。
3.两棵树相连,新直径的两端点一定是原四个端点中的两个,且新直径长度最小为max(max(直径1,直径2),半径1+半径2+新边长度) (设k为直径中最接近中点的节点,半径=max(tot-d[k],d[k]))。
证明:显然。
4.一棵树上接一个叶子结点,直径最多改变一个端点
证明:显然不可能改变两个端点,也有可能没有改变
第一种方法是利用性质2,首先从任意一个点开始bfs,找到一个离这个点最远的点,这样就找到了直径的一端,然后我们从这个点再开始bfs就可以同时找出直径的长度和直径的两端。但这种方法的缺点是不能处理有负权的情况。代码实现十分简单,这里就不给出了。
第二种方法是树形DP,令$f_1[i]$表示节点$i$到它叶子节点路径长度的最大值,$f_2[i]$表示节点$i$到它叶子节点路径长度的次大值,我们只需要按照正常记录最大值和次大值的方法更新,最后的答案即为$max\{ f_1[i] + f_2[i] \}$,这一方法可以处理负权,但是很难确定直径的两端是哪两个节点。代码实现可以看这篇博客