PTA (Advanced Level) 1021 Deepest Root
Deepest Root
A graph which is connected and acyclic can be considered a tree. The hight 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 (≤10^4) 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
题目解析
本题给出一个无向图的信息,包括一个数字n,代表无向图有n个结点,之后跟随n-1行分别为n-1条边连接的两个结点。要求判断该无向图是否是一颗树,若是一棵树,由小到大输出以其为根结点时深度最大的点,若不是树则输出连通块数量。
在解题之前首先看一下题目的限制
本题结点数量最多1e4个若用二维数组存储邻接矩阵,虽然数组没有超限但是当节点数取到最大1e4个结点时,需要的内存空间超过382MB,所以在这里使用邻接表来存储无向图。对于判断无向图是否为树,由于无向图有n个结点n-1条边,那么只要这个图是连通图,它便肯定是一颗树。我们只需要维护一个并查集便可以达到判断数与输出连通块数量,由于本题时间限制非常松,时间宽松使人暴力,所以在寻找深度最大的根结点时,这里以所有点为根结点暴力深搜获取深度,用set保存所有深度最大的点,之后将其输出即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX =1e4 + 10; 4 vector<int> G[MAX]; 5 int f[MAX]; 6 int n; 7 void init(){ //初始化并查集 8 for(int i = 1; i <= n; i++) 9 f[i] = i; 10 } 11 int getF(int x) //并查集找爹函数 12 { 13 if(f[x] == x) 14 return x; 15 else 16 return f[x] = getF(f[x]); 17 } 18 int maxH = 0; 19 void DFS_getH(int u, int height, int preNode){ //深搜获取深度 20 maxH = max(maxH, height); 21 for(int i = 0; i < G[u].size(); i++) 22 if(G[u][i] != preNode) 23 DFS_getH(G[u][i], height + 1, u); 24 } 25 int main(){ 26 scanf("%d", &n); //输入结点数量 27 init(); //初始化并查集 28 memset(G, 0, sizeof(G)); 29 for(int i = 0; i < n - 1; i++){ //输入n-1条边 30 int u, v; 31 scanf("%d%d", &u, &v); 32 G[u].push_back(v); 33 G[v].push_back(u); 34 int fu = getF(u); 35 int fv = getF(v); 36 if(fu != fv) //合并一条的两个端点 37 f[fu] = fv; 38 } 39 int cnt = 0; //记录连通块个数 40 for(int i = 1; i <= n; i++){ //获取连通块个数 41 if(f[i] == i) 42 cnt++; 43 }; 44 if(cnt != 1) //若连通块个数不等于1证明给出的图不是一颗树 45 printf("Error: %d components\n", cnt); //输出连通块个数 46 else{ 47 set<int> ans; 48 int ansH = 0; 49 for(int i = 1; i <= n; i++){ 50 maxH = 0; 51 DFS_getH(i, 1, 0); //获取每一个点为根时对应的树高(用maxH记录) 52 if(maxH > ansH){ //ansH记录当前最高深度 53 ansH = maxH; //若找到深度更大的点便清空集合重新记录 54 ans.clear(); 55 ans.insert(i); 56 }else if(maxH == ansH){ //找到深度与当前最大深度相同的点便加入集合 57 ans.insert(i); 58 } 59 } 60 for(auto i : ans){ 61 printf("%d\n", i); 62 } 63 } 64 return 0; 65 }