A1021. Deepest Root

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

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 int G[10001][10001];
 7 int father[10001];
 8 int maxDepth = -1;
 9 int N;
10 vector<int> temp_, ans;
11 void dfs(int vt, int from, int level){
12     level++;
13     if(maxDepth < level){
14         maxDepth = level;
15         temp_.clear();
16         temp_.push_back(vt);
17     }else if(maxDepth == level){
18         temp_.push_back(vt);
19     }
20     for(int i = 1; i <= N; i++){
21         if(G[vt][i] == 1 && i != from){
22             dfs(i, vt, level);
23         }
24     }
25 }
26 int findFather(int vt){
27     int temp = vt;
28     while(vt != father[vt]){
29         vt = father[vt];
30     }
31     int temp2;
32     while(temp != vt){
33         temp2 = father[temp];
34         father[temp] = vt;
35         temp = temp2;
36     }
37     return vt;
38 }
39 int main(){
40     scanf("%d", &N);
41     int tempA, tempB;
42     int root1, root2;
43     for(int i = 1; i <= N; i++){
44         father[i] = i;
45     }
46     for(int i = 0; i < N - 1; i++){
47         scanf("%d%d", &tempA, &tempB);
48         G[tempA][tempB] = G[tempB][tempA] = 1;
49         root1 = findFather(tempA);
50         root2 = findFather(tempB);
51         if(root1 != root2)
52             father[root2] = root1;
53     }
54     int cnt = 0;
55     for(int i = 1; i <= N; i++){
56         if(father[i] == i)
57             cnt++;
58     }
59     if(cnt > 1){
60         printf("Error: %d components\n", cnt);
61     }else{
62         maxDepth = -1;
63         dfs(1, -1, 0);
64         ans = temp_;
65         temp_.clear();
66         maxDepth = -1;
67         dfs(ans[0], -1, 0);
68         for(int i = 0; i < temp_.size(); i++)
69             ans.push_back(temp_[i]);
70         sort(ans.begin(), ans.end());
71         printf("%d\n", ans[0]);
72         for(int i = 1; i < ans.size(); i++){
73             if(ans[i] != ans[i - 1])
74                 printf("%d\n", ans[i]);
75         }
76     }
77     cin >> N;
78     return 0;
79 }
View Code

 

总结:

1、题意:给出一个可能是树的图,要求找到root(可能多个),使得从root出发可以使树的高度最高。但如果给出的图不是树(因为N个顶点 N - 1条边,如果产生回路只能说明输入的图不是一个连通图),要求输出连通分量的个数。 起初没注意到N个节点 N - 1条边这个条件,没有搞清楚题意,还以为判断是否是树是通过判断图里有没有回路来进行的,莫名奇妙为什么不是树之后就要求联通分量。于是还通过找回路来判断是否是树,结果当然不对。

2、求连通分量首选并查集,如果两个点是联通的就把它们并为一个集合。在读入边的时候就可以做合并,结束之后计数father[ i ] = i 的节点个数就行了。其次可以借助深搜广搜配合visit数组,在遍历完每一个点,检查下一个点的visit为0的即作为一个连通分量。显然,当输入的图连通分量大于1时说明不是树。

3、找能使得树最高的root方法:先随便找一个点A,从它开始做一遍dfs并在过程中将level最大的节点全部保存。这些节点就是答案的一部分,但还存在遗漏。再从已经选出的root中随意选择一个B,从它开始遍历一遍dfs并保存level最大的节点,两部分并起来就是最终答案。(没看书之前我是暴力破解,把所有节点遍历一次以找到最大深度的根,结果有一个测试点超时)

4、visit数组:平时做bfs使用visit数组标记节点是否曾经加入过队列,做dfs标记节点是否被访问过,其实都是为了防止重复访问节点。但本题中一旦确定了是一棵树,说明不存在回路,则可以不需要visit数组。但在无向图中仍然需要一个变量保存上一次访问过的节点,以防止同一条边上的重复访问。比如节点A、B在一条边上,A->B访问结束,到B之后B的联通的节点中又会有A,造成再次访问A(用孩子法存储的树无需考虑该问题,但用图的形式存储的树必须考虑同一条边的重复访问)。

5、找回路:利用visit数组与上次访问节点的序号即可。在碰到一个与当前节点相连接、不是上一次访问过的再同一条边上的节点、visit数组为1,则存在回路。

6、sort的默认排序是从小到大。

posted @ 2018-02-12 23:21  ZHUQW  阅读(124)  评论(0编辑  收藏  举报