树:树的直径

很久没写blog了,今天水一篇。
今天来讲讲树的直径

树的直径

什么?你不知道什么是树?点此处
什么是树的直径呢?
树的直径就是树中两个节点最远的距离。
那该如何求呢?
其实也很简单。

方法一:树形dp

我们可以运用树形dp,设 g x g_x gx 表示从节点x出发走向以x为根的自述,能够到达最远节点的距离,若 e d g e ( x , y ) edge(x,y) edge(x,y) 表示边权,y表示x的子节点,则有:
g x = m a x ( g y + e d g e ( x , y ) ) g_x=max(g_y+edge(x,y)) gx=max(gy+edge(x,y))
接着,我们考虑经过节点x的最长链的长度,设为 F x F_x Fx,则答案为
m a x x = 1 − n ( F x ) max_{x=1-n}(F_x) maxx=1n(Fx)
那么我们想如何转移 F x F_x Fx,显然
F x = m a x ( g y i + g y j + e d g e ( x , y i ) + e d g e ( x , y j ) ) F_x=max(g_{y_i}+g_{y_j}+edge(x,y_i)+edge(x,y_j)) Fx=max(gyi+gyj+edge(x,yi)+edge(x,yj))
但是这样去枚举的时间复杂度难道不是很不能接受吗?
那我们想一想怎么优化吧~
请大家想一想g数组是怎么弄成的?
在未转移完g数组时,g数组是不是就指的是已做的儿子的max?是吧
那么我们就可以先转移F,再转移g了,具体实现看代码。

void dfs(int u,int fa){
	for (int i=head[u];i;i=e[i].next){//链式前向星
		int v=e[i].to;
		if (v==fa) continue;
		dfs(v,u);
		ans=max(ans,g[u]+g[v]+e[i].w);//e[i].w指的是边权
		g[u]=max(g[u],g[v]+e[i).w;
	}
	return;
}

方法二:两次BFS/DFS

我们设一棵树的根为root,那么先用DFS/BFS求出离root最远的点p,再从点p开始DFS/BFS,求出最远的q,那么p和q的路径就是树的直径。
因为不是的话,一定能找到更长的链,但与直径定义矛盾
具体证明留给读者。
就不来程序了。

总结

大家应该能看懂!点个赞吧!
对了,我的blog!
若有不当的地方,欢迎大家指出!

你可能感兴趣的:(图论)