返回目录
题意
给出n个结点与n-1条边。问它们是否能构成n个结点的树?如果能,则输出结点作为树根,使得树的高度最大,输出所有满足的结点。如果不能,输出连通块的数目。
样例(可复制)
5
1 2
1 3
1 4
2 5
//output
3
4
5
5
1 3
1 4
2 5
3 4
//output
Error: 2 components
注意点
- 本题要解决两个问题,①判断能否构成树②找出能构成树时满足条件的结点
- 对于问题①可以使用并查集或DFS的方法,求得连通块个数block,显然当block=1时能构成树。本题使用了DFS的方式。
- 对于问题②有两种解决办法:第一个:求出任意结点的最远结点集合A,再在A中选任意结点找出最远结点集合B,A和B的并集即为所有满足条件的结点,这里证明略。如果使用该方法使用集合的话可以用STL库set,其中包含了求并集的函数set_union()。第二个:求出每个结点作为根节点时的树的最大高度,最后比较最大高度得出能取得满足条件的结点。本题使用了后者。
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
vector<int> G[N];
bool flag[N]={false};//标记节点是否访问过
int n,block=0;//节点数,连通块数
int maxdepth[N],depth[N];//maxdepth记录每个节点的最大深度,depth记录到root的距离
void DFS(int v,int root){
flag[v]=true;
for(int i:G[v]){
if(!flag[i]){
depth[i]=depth[v]+1;//当前结点深度为其父节点深度+1
maxdepth[root]=max(maxdepth[root],depth[i]);//更新树的深度
DFS(i,root);
}
}
}
int main(){
cin>>n;
int a,b;
for(int i=1;i<n;i++){//输入n-1条边
scanf("%d %d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
for(int i=1;i<=n;i++){
if(!flag[i]){
DFS(i,i);
block++;
}
}
if(block>1){
printf("Error: %d components\n",block);
}else{
for(int i=2;i<=n;i++){//i=1必然遍历过了
memset(depth,0,sizeof(depth));
memset(flag,false,sizeof(flag));
DFS(i,i);
}
vector<int> ans;//存储为根节点时使树的深度最大的结点
int deep=0;//查找所有为根节点时使树的深度最大的结点
for(int i=1;i<=n;i++)
if(maxdepth[i]>deep){
ans.clear();
ans.push_back(i);
deep=maxdepth[i];
}else if(maxdepth[i]==deep)
ans.push_back(i);
for(int i:ans)printf("%d\n",i);
}
return 0;
}