1021 Deepest Root (25 分)
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on the selected root. Now you are supposed to find the root that results in a highest tree. Such a root is called the deepest root.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤104) which is the number of nodes, and hence the nodes are numbered from 1 to N. Then N−1 lines follow, each describes an edge by given the two adjacent nodes' numbers.
Output Specification:
For each test case, print each of the deepest roots in a line. If such a root is not unique, print them in increasing order of their numbers. In case that the given graph is not a tree, print Error: K components
where K
is the number of connected components in the graph.
Sample Input 1:
5
1 2
1 3
1 4
2 5
Sample Output 1:
3
4
5
Sample Input 2:
5
1 3
1 4
2 5
3 4
Sample Output 2:
Error: 2 components
这个题思路:
先使用并查集搞定是否有多个连通分量,如果 只有一个连通分量,那就找最远路径的点。
本来我的想法是每个元素进行一次深度搜索,看看从这个元素出发,最深路径有多远,结果是超时,说明一定有更简单思想。
查了查发现大家都是用的下面这种算法:
第一步 任意选择一个结点,从这个结点出发,找到最远的结点(有几个算几个)
第二步 再从最远结点中任意选择一个结点,从该结点出发,再次寻找最远结点,两次寻找的结果的并集就是所求的结果。
最后的证明 最能说服我的是牛客一个老哥写的:http://m.nowcoder.com/questionTerminal?uuid=f793ad2e0c7344efa8b6c18d10d4b67b
整体思路就是,因为n个结点n-1个边,如果有环肯定不是一个联通分量。所以如果是一个联通分量肯定是没环的。那么特殊情况就是有分叉。比如1-2-3-4-5 并且3-6。相当于3链接了4又连接6,但是最长路径应该是1-2-3-4-5 ,3-6只是个分叉。那么以分叉结点作为定位点,在分叉结点3 右边的,距离1肯定最远,在分叉结点左边的,距离5肯定最远(因为分叉的长度肯定没有从主路径一段到分叉结点长度长,否则他就不是分叉了,而是主路径了)。而分叉结点上的结点,也肯定到主路径某一端最长。所以,从任意结点开始搜索,必定能够找到一个最深的结点。而从这个最深的结点再次开始,必定能够找到其他最深的结点。其实如果出现多个最深结点,他们关系应该类似于 1-2-3 2-4. 1 3 4地位相等。
代码没这么优化,有点乱,太懒了我
#include <iostream>
#include <algorithm>
#include <vector>
#include <hash_set>
#include <set>
#include <queue>
using namespace std;
int pre[10001];
int Find(int x)
{
int r=x;
//寻找老大 最差就是自己就是老大了
while(r!=pre[r])
r=pre[r];
//把寻找路径上所有结点老大固定为一个最后寻找到的老大结点
//下面一步也称之为路径压缩
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void mix(int x,int y)//合并
{
int fx=Find(x),fy=Find(y);
if(fx!=fy)
{
pre[fy]=fx;
}
}
int main()
{
int n;
cin>>n;
int a[n+1]= {0};
int b[n+1]= {0};
for(int i=1; i<n; i++)
pre[i]=i;
for(int i=1; i<n; i++)
{
cin>>a[i]>>b[i];
mix(a[i],b[i]);
}
for(int q=1; q<=n; q++)
Find(q);
set<int> ss;
for(int i=1; i<=n; i++)
{
ss.insert(pre[i]);
}
if(ss.size()>1)
cout<<"Error: "<<ss.size()<<" components";
else if(n==1)
cout<<'1';
else if(n>1)
{
//还是有问题
int visit[n+1];
int sign[n+1];
fill(visit,visit+n+1,0);
fill(sign,sign+n+1,0);
int time=1;
queue<int> que;
que.push(1);
que.push(-1);
visit[1]=1;
int maxx=-1;
while(que.size()!=0)
{
int start=que.front();
if(start==-1){
time++;
que.pop();
if(que.size()==0)
break;
start=que.front();
que.push(-1);
}
que.pop();
for(int i=1; i<n; i++)
{
if(a[i]==start&&visit[b[i]]==0)
{
que.push(b[i]);
visit[b[i]]=1;
sign[b[i]]=time;
if(maxx<time)
maxx=time;
}
if(b[i]==start&&visit[a[i]]==0)
{
que.push(a[i]);
visit[a[i]]=1;
sign[a[i]]=time;
if(maxx<time)
maxx=time;
}
}
}
set<int> sett;
for(int i=1; i<=n; i++)
{
if(sign[i]==maxx)
{
sett.insert(i);
}
}
//第二次
fill(visit,visit+n+1,0);
fill(sign,sign+n+1,0);
maxx=-1;
time=1;
que.push(*sett.begin());
visit[*sett.begin()]=1;
que.push(-1);
while(que.size()!=0)
{
int start=que.front();
if(start==-1){
time++;
que.pop();
if(que.size()==0)
break;
start=que.front();
que.push(-1);
}
que.pop();
for(int i=1; i<n; i++)
{
if(a[i]==start&&visit[b[i]]==0)
{
que.push(b[i]);
visit[b[i]]=1;
sign[b[i]]=time;
if(maxx<time)
maxx=time;
}
if(b[i]==start&&visit[a[i]]==0)
{
que.push(a[i]);
visit[a[i]]=1;
sign[a[i]]=time;
if(maxx<time)
maxx=time;
}
}
}
for(int i=1; i<=n; i++)
{
if(sign[i]==maxx)
{
sett.insert(i);
}
}
set<int>::iterator it;
vector<int> out;
for(it=sett.begin(); it!=sett.end(); it++)
{
out.push_back(*it);
}
sort(out.begin(),out.end());
int first=1;
for(int i=0; i<out.size(); i++)
{
if(first==1)
{
cout<<out[i];
first=0;
}
else
cout<<endl<<out[i];
}
}
return 0;
}