SP1437 PT07Z - Longest path in a tree(树的直径模板题)

本题为树的直径模板题。

题意

给定一棵树,求出树中最远的两个节点之间的距离(树的直径)。

思路

树的直径一般有两种做法,树型\(DP\)和两次\(BFS\)。时间复杂度都为\(O(n^2)\)。这里介绍树型\(DP\)的做法。

\(1\)号节点为根节点。

\(d[u]\)表示以\(u\)为根节点向下能到达的最远距离。\(v_i\)\(u\)的儿子,那么\(d[u]=max(d[v_i]+w[i])\)

设经过\(u\)的最长链的长度为\(f[u]\)。设\(v_i\)\(v_j\)\(u\)的两个不同儿子。显然,\(f[u]=max(d[v_i]+w[i]+d[v_j]+w[j])\)。但是如果直接枚举\(u\)的儿子,时间复杂度就会到达\(O(n^2)\)级别,显然无法通过本题。
考虑优化,不妨设\(i<j\),那么对于确定的\(j\)\(d[v_j]+w[j]\)就是一个确定的常数。同时可以惊奇的发现,\(max(d[v_i]+w[i])\)就是在遍历\(v_j\)之前的\(d[u]\)!发现这个结论以后,就可以做到\(O(n)\)时间内解决这道题。

最终的答案就是\(max(f[u])\)

code:

#include<cstdio>
using namespace std;
const int N=1e4+10;
const int M=2e4+10;
int d[N],f[N],n,idx,h[N],ans;
struct edge{
	int v,w,nex;
}e[M];
int max(int a,int b){return a>b?a:b;}
void add(int u,int v,int w)
{
	e[++idx].v=v;
	e[idx].w=w;
	e[idx].nex=h[u];
	h[u]=idx;
}
void dp(int u,int fa)
{
	for(int i=h[u];i;i=e[i].nex)
	{
		int v=e[i].v;
		if(v==fa) continue;
		dp(v,u);
		ans=max(ans,d[u]+e[i].w+d[v]);
		d[u]=max(d[u],e[i].w+d[v]);
	}
}
int main()
{
	scanf("%d",&n);
	for(int u,v,i=1;i<n;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v,1),add(v,u,1);//本题默认一条边的长度为1 
	}
	dp(1,-1);
	printf("%d\n",ans);
	return 0;
}
posted @ 2021-05-30 18:38  曙诚  阅读(128)  评论(0)    收藏  举报