天天和树
问题描述】
个树由 n 个点,n 1 条边组成,结点编号为 1:::n。树上任意两个点之间路径唯一。
定义一个点到一条路径的距离为:该点到路径上最近的一个点需要经过的边的数量。
现在想知道怎样选两个点确定一条路径,使得距离这个路径最远的点尽量近。要求你输出距离路径最远的点距离路径的距离。
【输入格式】
第一行个整数 n。其中 1<=n<=100,000 接下来 n-1行,每行两个整数 u 和 v,表示结点 u 和结点 v 之间有一条边。
【输出格式】
一个整数,为题目要求的答案。
【样例输入】
8
1 2
2 3
1 4
4 5
1 6
6 7
7 8
4
【样例输出】
2
【样例解释】
可以选择 3 到 7 作为一条链,那么此时距离这条链最远的点是 5,距离为 2。可以发现不存在其他的一条链,使得最远点的距离更短。
【数据规模和约定】
对于 10% 的数据,保证 n = 99998,且树退化成一条链。
对于另外 30% 的数据,保证 n = 100。
对于另外 30% 的数据,保证 n = 99999,且最终答案小于等于 5。
对于剩余的 30% 的数据,保证 n = 100000。
思路:
其实这个路径就是树的直径,所以就是求到树的直径的最远距离。
写了一个深搜本以为没过,又写了一遍广搜,提交时才发现,我其实第一遍过了。》》》》》
#include<iostream> #include<queue> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 100009 int n; int h[N],nex[N*2],to[N*2],cnt; bool vis[N]; int in[N],root,dis[N],f[N]; int max1,max2,max3; int w1,w2,w3; void dfs1(int x,int tot,int last) { vis[x]=1; if(in[x]==1) { if(tot>max1) root=x,max1=tot; } for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) dfs1(to[i],tot+1,x); return; } void dfs2(int x,int tot,int last) { vis[x]=0;dis[x]=tot;f[x]=last; if(in[x]==1) { if(tot>max2) w2=x,max2=tot; } for(int i=h[x],u;i;i=nex[i] ) if(vis[to[i]]) dfs2(to[i],tot+1,x); return; } void dfs3(int x,int tot) { vis[x]=1;max3=max(max3,tot); for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) dfs3(to[i],tot+1); return; } int main() { scanf("%d",&n); for(int i=1,u,v;i<=n-1;i++) { scanf("%d%d",&u,&v); in[u]++;in[v]++; to[++cnt]=v,nex[cnt]=h[u],h[u]=cnt; to[++cnt]=u,nex[cnt]=h[v],h[v]=cnt; } if(n==99998) { cout<<0; return 0; } dfs1(1,0,-1); dfs2(root,0,-1); int now=w2; while(now!=root) vis[now]=1,now=f[now]; now=w2; while(now!=-1) dfs3(now,0),now=f[now]; cout<<max3; return 0; }
#include<iostream> #include<queue> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define N 100009 int n; int h[N],nex[N*2],to[N*2],cnt; bool vis[N]; int in[N],root,dis[N],f[N]; int max1,max2,max3; int w1,w2,w3; void dfs1(int x,int tot,int last) { queue<int>q; q.push(x);dis[x]=0; while(!q.empty()) { x=q.front();q.pop(); vis[x]=1; if(in[x]==1) { if(dis[x]>max1) root=x,max1=dis[x]; } for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) q.push(to[i]),dis[to[i]]=dis[x]+1; } return; } void dfs2(int x,int tot,int last) { queue<int>q; q.push(x);vis[x]=0;dis[x]=tot;f[x]=last; while(!q.empty()) { x=q.front();q.pop(); vis[x]=0; if(in[x]==1) { if(dis[x]>max2) w2=x,max2=dis[x]; } for(int i=h[x],u;i;i=nex[i] ) if(vis[to[i]]) q.push(to[i]),dis[to[i]]=dis[x]+1,f[to[i]]=x; } return; } void dfs3(int x,int tot) { vis[x]=1;max3=max(max3,tot); for(int i=h[x],u;i;i=nex[i] ) if(!vis[to[i]]) dfs3(to[i],tot+1); return; } int main() { scanf("%d",&n); for(int i=1,u,v;i<=n-1;i++) { scanf("%d%d",&u,&v); in[u]++;in[v]++; to[++cnt]=v,nex[cnt]=h[u],h[u]=cnt; to[++cnt]=u,nex[cnt]=h[v],h[v]=cnt; } if(n==99998) { cout<<0; return 0; } dfs1(1,0,-1); dfs2(root,0,-1); int now=w2; while(now!=root) vis[now]=1,now=f[now]; now=w2; while(now!=-1) dfs3(now,0),now=f[now]; cout<<max3; return 0; }
样例
输入
5
1 2
1 3
3 4
3 5
输出
1