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 N1 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条边连接的两个结点。要求判断该无向图是否是一颗树,若是一棵树,由小到大输出以其为根结点时深度最大的点,若不是树则输出连通块数量。

  在解题之前首先看一下题目的限制

  时间限制: 2000 ms
  内存限制: 64 MB
  

  本题结点数量最多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 }
posted @ 2019-01-25 15:31  suvvm  阅读(350)  评论(0编辑  收藏  举报