题目链接:http://hihocoder.com/problemset/problem/1050
题意:有n个点,他们之间有n-1条无向边,形成一棵树,并且保证任意两个点间都不存在两条不同的路径可以互相到达。求这棵树中哪两个结点之间的距离最长?这里的距离是指从一个结点走到另一个结点经过的边数。
解析:树中的最长路一定实在两个叶子节点之间。所以我们进行两次bfs,随便从一个节点出发进行第一次bfs,找到从该点出发最深的叶子节点,假设为v,然后再从v点出发进行第二次bfs,这次也是要找最深的叶子节点,和上次不同的是:这次从我们指定的v节点出发。假设找到的最深的叶子节点是w,那么v和w之间的路径长度就是这棵树中的最长路。
代码:
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
#define M 200010
struct Edge{int to,w,next;
}e[M]; //e数组存边
int totEdge,n,deepPoint,maxdis;
bool vis[M]; //记录在一次bfs过程中节点访问情况
int dis[M]; //dis[i]是在bfs时记录i节点到根节点的距离
int head[M]; //head[s]是指以s为起点的边的号码,主要在一个点有多个子节点时,记录所有该点到子节点所在边的编号,这个编号通过head[s]记录最新一个,之前的边用e[head[s]].next记录void init()
{totEdge=0;for(int i=1;i<=n;i++) //每个点都还没连边head[i]=-1;
}
void add(int form,int to,int w)//加入一条边,起点form,终点to,边权值为w
{e[totEdge].to=to;e[totEdge].w=w;e[totEdge].next=head[form];//起点form的上一条边head[form]=totEdge++; //起点form的最新边
}
void bfs(int start) //st做根节点,即转折点
{queue<int>q;int i,now;memset(vis,false,sizeof(vis));memset(dis,0,sizeof(dis));maxdis=0;deepPoint=start;vis[start]=true;dis[start]=0;q.push(start);while(!q.empty()){now=q.front();q.pop();for(i=head[now];i!=-1;i=e[i].next)//遍历点now的所有子节点{int v=e[i].to;if(!vis[v]){vis[v]=true;dis[v]=e[i].w+dis[now];if(maxdis<dis[v]){maxdis=dis[v]; //最深点到起点的距离deepPoint=v; //deepPoint是从起点start出发,到达的最深点}q.push(v);}}}
}
int main()
{int i,u,v;scanf("%d",&n);init();for(i=1;i<n;i++){scanf("%d%d",&u,&v);add(u,v,1);add(v,u,1);}bfs(1); //先bfs一次找到deepPointbfs(deepPoint); //deepPoint即是距离最远的两点中的一个端点cout<<maxdis<<endl;return 0;
}