https://pintia.cn/problem-sets/994805342720868352/problems/994805482919673856
1021 Deepest Root (25)(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 (<=10000) 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
AC Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int nmax=10000+10;
int father[nmax];
int isRoot[nmax];
vector<int> G[nmax];
int findFather(int u){
if(u==father[u]) return u;
else{
int f=findFather(father[u]);
father[u]=f;
return f;
}
}
void Union(int u,int v){
int fu=findFather(u);
int fv=findFather(v);
if(fu!=fv){
father[fu]=fv;
}
}
void init(int n){
for(int i=1;i<=n;i++){
father[i]=i;
isRoot[i]=0;
}
}
int calblk(int n){//计算连通块数目
int ans=0;
for(int i=1;i<=n;i++){
if(isRoot[findFather(i)]==0){
isRoot[findFather(i)]++;
ans+=1;
}
}
return ans;
}
int maxH=0;
vector<int> tmp;//存放DFS的最远节点结果
vector<int> Ans;//存放答案节点(使树高最大的根节点)
//u为当前访问的节点编号,h为当前树高,pre为u的父节点
void DFS(int u,int h,int pre){
if(h>maxH){
tmp.clear();
tmp.push_back(u);
maxH=h;
}
else if(h==maxH){
tmp.push_back(u);
}
for(int i=0;i<G[u].size();i++){
if(G[u][i]==pre) continue;//无向图,跳过回去的边
DFS(G[u][i],h+1,u);
}
}
int main(int argc, char** argv) {
int n;//点数为n,边数为n-1
while(cin>>n){
memset(father,0,sizeof(father));
memset(isRoot,0,sizeof(isRoot));
init(n);
int u,v;
for(int i=1;i<=n-1;i++){//n-1条边
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
Union(u,v);
}
int blk=calblk(n);
if(blk!=1){//如果不只1个连通块
printf("Error: %d components\n",blk);
}
else{//如果只有1个连通块
DFS(1,1,-1);//u=1,h=1,pre=-1
Ans=tmp; //tmp为集合A,赋给Ans
DFS(Ans[0],1,-1);//从任意一个根节点开始遍历
for(int i=0;i<tmp.size();i++){
Ans.push_back(tmp[i]); //此时tmp为集合B,将其加到Ans中
}
//求两个集合A、B的并集:先排序,输出值只出现1次的节点
sort(Ans.begin(),Ans.end());
printf("%d\n",Ans[0]);
for(int i=1;i<Ans.size();i++){
if(Ans[i]!=Ans[i-1]){
printf("%d\n",Ans[i]);
}
}
}
}
return 0;
}