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 ", 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 ", ans[0]); 72 for(int i = 1; i < ans.size(); i++){ 73 if(ans[i] != ans[i - 1]) 74 printf("%d ", ans[i]); 75 } 76 } 77 cin >> N; 78 return 0; 79 }
总结:
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的默认排序是从小到大。