目录
1.定义 :
树的直径是树上两点间距离的最大值。即树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链
最长链:4-2-1-7-6-3
所以这颗树的直径是15,直径路径为4-2-1-3-6
2.直径的性质:
直径的性质1:直径的端点一定是叶子节点
直径的性质2:任意点的最长链端点一定是直径端点
直径的性质3:如果一棵树有多条直径且边权都为正,那么它们必然相交,且有极长连续段(可以是一个点,交点为树的中心)
直径的性质4:树T1的直径为x,y,树T2的直径为s,t。现有一边u,v与两颗树相连,新树的直径端点一点是x,y,s,t中的两个
3.树的直径求解方法:
引理性质2:任意点的最长链端点一定是直径端点。方法:我们随意找一个点x,进行dfs找到最长链的端点s,再以端点s做第二遍dfs,此时可以找到直径的第二个端点t。此时端点s到t的距离就是树的直径。
输入一颗无根树,第一行为一个正整数n(n<1e5),表示这颗树有n个节点接下来的n−1行,每行三个正整数u,v,w,表示u,v(u,v<=n)有一条权值为w(w<100)的边相连,求树的直径。
#include<bits/stdc++.h>
using namespace std;
int n,data[100005],pl,maxn;
vector<int> v[100005];
vector<int> w[100005];
void dfs(int x,int fa) {
for(int i=0; i<v[x].size(); i++) {
int y=v[x][i];
if(y==fa) continue;
data[y]=data[x]+w[x][i];
if(data[y]>maxn) maxn=data[y],pl=y;//记录端点
dfs(y,x);
}
}
int main() {
cin>>n;
for(int i=1; i<n; i++) {
int x,y,z;cin>>x>>y>>z;
v[x].push_back(y);
v[y].push_back(x);
w[x].push_back(z);
w[y].push_back(z);
}
dfs(1,0);//寻找直径
memset(data,0,sizeof data);//清空距离
dfs(pl,0);//从pl出发寻找端点
cout<<maxn;
return 0;
}
4.直径端点求解方法:
我们通过记录父亲节点的方式能够把直径上的所有点全部记录下来。在树中,直径端点是常用点(假设端点为s,t),我们树上任意一点p所能到的最大距离,只有可能是到ps或pt
那如何找到所有点到两个直径端点的距离?
朴素方法:
求出直径端点后,以每个点为根做dfs,找到根节点到端点的距离。复杂度O(N2)。
优化方法:
第一次从任意点出发,必然能到达直径的一个端点s。第二次从s点进行dfs找到端点t,此时记录所有点到s的距离。第三次从t点进行dfs,记录所有点到t的距离。复杂度:O(n)