定义:
树的直径,即 树上最远的两点的距离(即 树上最大距离),若树的边权全为 ,则树的直径即是 树上的最长链。
通常有两种树的直径的求法,时间复杂度均为
①树形DP求树的直径
改方法只需遍历一次,即可求得树的直径大小,但无法求得直径的具体路径。
选取任意结点为根遍历树,设 表示结点 为根的子树结点最远距离。
则有:
- 为根的子树结点最远距离 的子结点
最后直径即为 根结点 的 两个最远距离之和
int d[maxn],len=0;
void DP(int u,int pre)
{
d[u]=0; //初始为0
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v,w=e[i].w;
if(v==pre)
continue;
DP(v,u);
len=max(len,d[u]+d[v]+w); //更新直径
d[u]=max(d[u],d[v]+w);
}
}
②两次DFS求直径
该方法要遍历两次,第一次任选结点为根进行DFS,找到距离最远的结点;第二次以该距离最远的结点为根进行DFS,找到距离最远的结点,两点距离即为直径大小,两点简单路径即为直径。
设 表示 结点到根结点的距离
- 若要记录路径,可 对第二次DFS进行修改,因为 第一次DFS得到的距离最远结点一定为直径的一个端点,只要以其为根DFS找到距离最远的点(令一个端点),路径即为直径。
int dist[maxn],s,max_dist;
void DFS(int u,int pre)
{
if(dist[u]>max_dist)
{
max_dist=dist[u];
s=u;
}
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v,w=e[i].w;
if(v==pre)
continue;
dist[v]=dist[u]+w;
DFS(v,u);
}
}
int get_len()
{
max_dist=dist[1]=0;
s=1;
DFS(1,-1);
max_dist=dist[s]=0;
DFS(s,-1);
return max_dist;
}