首页 > 技术文章 > 树的直径和证明

iss-ue 2020-03-22 16:17 原文

\(以下阐述部分借鉴\)
博客1
博客2

概念

树的直径:2点距离最远的路径.

结论

先说结论,对于一颗无根树,首先随便找一个点\(u\)开始进行搜索,找到离当前点最远的一点\(s\),然后从\(s\)开始搜最远的点\(t\)树的直径就为\(s-t\)

Ⅰ两遍\(dfs||bfs\)

证明
找到直径,我们只需找到直径2个端点其中的一个,然后找到离当前点最远的点即为另一个端点。
1.如果\(u\)\(s-t\)的路径上,很明显是对的,到达\(u\)最远的点必为\(s\)\(t\),因为是从\(u\)开始搜最远的点的。

2.如果\(u\)不在\(s-t\)的路径上,那么从\(u\)搜最远的点必然与\(s-t\)相交。

如图,如果u搜到最远的点为T,那么\(dis(u,t) > dis(u,x) + dis(x,t)\)
很显然: \(dis(s,t ) = dis(s,x) + dis(x,t) < dis(s,T) = dis(s,x) + dis(u,x) + dis(u,T)\)

所以 很容易得出必与直径相交,且搜到的点为另一个端点。

Ⅱ树型DP

设f[i]表示以i为根,到其子树的叶节点的最大距离。

考虑如何用子节点更新父节点,
当前点到叶节点的最大距离=\(max\){子节点到叶节点的距离+当前点到子节点的距离}。

设u为当前节点,v为u的子节点,\(dis(u,v)\)是从u−>v这条路径上的距离
得到转移方程:

\(f[u]=max\){\(f[v]+dis(u,v)\)}
如何维护以u为根的子树中的直径呢
以u为根子树的直径\(=max\){u到叶节点的最大距离+子节点到叶节点的最大距离+u到叶节点的距离}
然后我们钦定一个节点为根,比如1
得到转移方程:

\(ans=max\){\(f[u]+f[v]+dis(u,v)\)}
ans即为树的直径
需要注意的是,我们要在更新f[u]之前更新ans,因为从u经过v到叶节点的路径是最长的路径,这样这条路径会被更新两次

这样做一定会选出u到叶节点最长的两条路径

void dp(int now)
{
	vis[now]=1;
	for(int i=head[now];i;i=d[i].nxt)
	{
		int v=d[i].to;
		if(vis[v])	continue;
		dp(v);
		ans=max(ans,dis[now]+dis[v]+d[i].w);
		dis[now]=max(dis[now],dis[v]+d[i].w);
	}
}

推荐阅读