UOJ #590. 天天和树

【题目描述】:
一个树由n个点,n-1条边组成,结点编号为1…n。树上任意两个点之间路径唯一。

定义一个点到一条路径的距离为该点到路径上最近的一个点需要经过的边的数量。

现在想知道怎样选两个点确定一条路径,使得距离这个路径最远的点尽量近。要求你输出距离路径最远的点距离路径的距离。

【输入描述】:
第一行一个整数n。其中1≤n≤1000

接下来n-1行,每行两个整数u和v,表示结点u和结点v之间有条边。

【输出描述】:
一行一个整数,为题目要求的答案。

【样例输入】:
8
1 2
2 3
1 4
4 5
1 6
6 7
7 8
【样例输出】:
2
【样例说明】:
可以选择3到7作为一条链,那么此时距离这条链最远的点是5,距离为2。可以发现不存在其他的一条链,使得最远点的距离更短。

【时间限制、数据范围及描述】:
时间:1s 空间:256M

对于10%的数据,保证n=99998,且树退化成一条链。

对于另外30%的数据,保证n=100。

对于另外30%的数据,保证n=99999,且答案小于等于5。

对于剩余的30%的数据,保证n=100000。

本题可以先找树的直径,然后从树的直径上的每一个点进行dfs,之后统计答案即可.

Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=100005;
int n,head[N],dep[N],fa[N],cnt,ans;
bool vis[N];
struct Node{
	int u,v,nxt;
}edge[N*2];
void add(int u,int v){
	++cnt;
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].nxt=head[u];
	head[u]=cnt;
}
int bfs(int s){
	queue<int> q;
	int depth=s;
	q.push(s);
	dep[s]=1;
	fa[s]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=edge[i].nxt){
			int v=edge[i].v;
			if(!dep[v]){
				dep[v]=dep[u]+1;
				fa[v]=u;
				q.push(v);
				depth=dep[depth]<dep[v]?v:depth;
			}
		}
	}
	return depth;
}
int dfs(int u){
	int s=0;
	vis[u]=1;
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].v;
		if(!vis[v]){
			s=max(dfs(v),s);
		}
	}
	return s+1;
}
int main(){
	int u,v,re;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	re=bfs(1);
	memset(dep,0,sizeof(dep));
	memset(fa,0,sizeof(fa));
	re=bfs(re);
	for(int i=re;i;i=fa[i]){
		vis[i]=1;
	}
	for(int i=re;i;i=fa[i]){
		for(int j=head[i];j;j=edge[j].nxt){
			int v1=edge[j].v;
			if(!vis[v1]){
				ans=max(ans,dfs(v1));
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-09-24 13:14  prestige  阅读(142)  评论(0编辑  收藏  举报