树的直径
一、什么是树的直径
直径往往和圆有关系。数学中,圆的直径是圆内最长的一条线段。那么在树中,树的直径就是树中最长的一段距离。
二、计算树的直径的思路
命题:
①在树上任取一个点x,找到距离x最远的一个点,即为y。y就是直径的一段。
②再找到距离y最远的一个点,即为z。这时候,y->z的路径就是树的直径了。
证明命题:(分①②两步证)
①:任取一点,距离这个点最远的点就是直径的一段。
分两种情况。
情况一:x点位于直径上。
在直径上的话图大概是长这样的。
直径的一段(y)
若干节点
选取的点(x)
若干节点
直径的另一段(z)
x
→
y
x→y
x→y和
x
→
z
x→z
x→z中必然有一个是较长的,y或z中的一个也肯定是距离x最远的点。
你可能会担心:要是有另外一个点w是距离x最远的点呢?
其实这个担心是多余的。
按刚才所想的那样,现在有三条路通向x节点,分别是:x->y(长度为a),x->z(长度为b),x->w(长度为c)。
我们要选择其中最长两条相连接作为直径。
若c>a或c>b,那么最长的两条就是(c,a)或者(c,b)了,而不是命题中所提到的
(
y
→
x
→
z
)
(y→x→z)
(y→x→z)这条路。
情况二:x点位于直径外。
其实这个证明方法与情况一相似,只需要注意一点:将x->y或x->z转化为另一条路径(先到直径上的一点再到直径的端点)即可。
②:知道了直径的一段,选最远的一个点,相连即为直径。
这个就不用证明了吧,就是定义啊。
三、计算树的直径的代码
这里就需要一个重要的函数——用于计算距离最远的点。
可以用
d
f
s
dfs
dfs实现。因为这道题的特殊性,所以树要用无向图存储。所以还要加一个参数
l
a
s
t
last
last,表示上一次遍历的点,下一次就不能访问了,否则会导致死循环。
代码:
int point, mx = -1;
void dfs(int u, int last, int dis){
if(dis > mx){
mx = dis;
point = u;
}
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i].first;
int w = G[u][i].second;
if(v == last)continue;
dfs(v, u, dis + w);
}
}
调用时很简单:
dfs(1, -1, 0);
mx = -1;//这是一个易错点,要记得初始化。
dfs(point, -1, 0);
cout << mx << endl;