PAT.A1021 Deepest Root

返回目录在这里插入图片描述

题意

给出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

注意点

  1. 本题要解决两个问题,①判断能否构成树②找出能构成树时满足条件的结点
  2. 对于问题①可以使用并查集或DFS的方法,求得连通块个数block,显然当block=1时能构成树。本题使用了DFS的方式。
  3. 对于问题②有两种解决办法:第一个:求出任意结点的最远结点集合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;
}
发布了177 篇原创文章 · 获赞 5 · 访问量 6656

猜你喜欢

转载自blog.csdn.net/a1920993165/article/details/105555810
今日推荐