树的直径 POJ 1985 Cow Marathon

定义:

  给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径,即直径是一个 数值概念,也可代指一条路径


树的直径通常有两种求法,时间复杂度均为O(n)。我们假设树以N个点N-1条边的无向图形式给出,并存储在邻接表中。

法一:树上DP

优点:1.代码简单

   2.可以处理出当前点为根时每个子树的最长链。

缺点:不易求出直径的两个端点。

法二:两遍DFS(BFS)

优点:容易计算出直径上的具体节点。

缺点:只能求直径和距离。

证明就不再赘述,比较简单,网上也都有。

打的裸题是POJ 1985 Cow Marathon

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define R register
#define ll long long
inline ll read()
{
	ll aa=0;char cc=getchar();
	while(cc<'0'||cc>'9')cc=getchar();
	while(cc>='0'&&cc<='9')
		{aa=(aa<<3)+(aa<<1)+(cc^48);cc=getchar();}
	return aa;
}
const int N=1e6;
int tot,ver[N<<1],nxt[N<<1],edge[N<<1],first[N];
inline void add(int x,int y,int z)
{
	ver[++tot]=y;nxt[tot]=first[x];
	edge[tot]=z;first[x]=tot;return;
}
int n,f[N],ans;
void dp(int x,int fa)
{
	f[x]=0;
	for(R int i=first[x],v;i;i=nxt[i]){
		v=ver[i];if(v==fa)continue;
		dp(v,x);
		f[0]=max(f[0],f[x]+f[v]+edge[i]);
		f[x]=max(f[x],f[v]+edge[i]);
	}
}
int dis[N],pi,pj;
void dfs(int x,int fa)
{
	for(R int i=first[x],v;i;i=nxt[i]){
		v=ver[i];if(v==fa)continue;
		dis[v]=dis[x]+edge[i];dfs(v,x);
		if(dis[pj]<dis[v])pj=v;
	}
}
queue<int>qi;
void bfs(int x)
{
	memset(dis,-1,sizeof(dis));dis[x]=0;
	qi.push(x);
	while(!qi.empty()){
		int u=qi.front();qi.pop();
		for(R int i=first[u],v;i;i=nxt[i]){
			v=ver[i];if(dis[v]!=-1)continue;
			dis[v]=dis[u]+edge[i];qi.push(v);
			if(dis[v]>dis[pj])pj=v;
		}
	}
}
int main()
{
	n=read();read();
	for(R int i=1,x,y,z;i<n;++i){
		x=read();y=read();z=read();
		add(x,y,z);add(y,x,z);
	}
	f[0]=0;dp(1,1);ans=f[0];//dp
	
	dis[1]=0;pj=1;dfs(1,1);pi=pj;
	dis[pi]=0;dfs(pi,pi);ans=dis[pj];//dfs
	
	pj=1;bfs(1);pi=pj;
	bfs(pi);ans=dis[pj];//bfs
	
	printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/toot-wjh/p/11573183.html