1021 Deepest Root
1021 Deepest Root (25分)
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 (≤104) 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
审题
题目要求找出“最深根”,可选做法为DFS和BFS.如果使用DFS方法需要在遍历结束后找出不同路径深度的最大值。而如果使用BFS在遍历结束后的层数就是该根的深度。这里选择DFS较为方便。除此之外,我们还需判断该图能不能形成一个N个结点的树,因为题中保证有N-1条边,根据结论“如果N个结点的图是一个连通图,且有N-1条边,那么这个图就可以形成一棵树”,这样问题就转化为求连通块的个数,用并查集可以实现。
主要函数和功能部件
并查集:求连通块的个数
main(): 按题目要求读入图
DFS( int root, int depth,int pre ):DFS用递归来实现,所以需要参数root来记录当前结点,又因为程序要求根的深度,所以需要参数depth来记录当前深度。同时,本题的模型是一个无向图,所以要避免回头访问——跳过回去的边,用pre记录前驱结点可以解决这个问题。
坑点

注意并不是一次DFS就可以解决问题,如上图,如果开始结点在A区,那么一次遍历的结果是B区的所有深度最大的结点,只遍历这一次就漏掉了A区的结点,所以在一次遍历之后还要以B区的任一结点为开始结点再遍历一次才能得到全部结果。这里暂时无法提供形式化证明,有待进一步研究。
参考代码
1 #include<iostream> 2 #include<vector> 3 #include<stdio.h> 4 #include<algorithm> 5 using namespace std; 6 7 vector<int> adj[10001]; 8 vector<int> temp,ans; 9 int father[10001]; 10 bool isRoot[10001]={false}; 11 int n; 12 int maxdepth=0; 13 14 //查找根节点 15 int findfather(int x) 16 { 17 int a=x; 18 while(x!=father[x]){ 19 x=father[x]; 20 } 21 //路径压缩 22 while(a!=father[a]){ 23 int z=a; 24 a=father[a]; 25 father[z]=x; 26 } 27 return x; 28 } 29 30 //合并集合 31 void Union(int a,int b) 32 { 33 int faA=findfather(a); 34 int faB=findfather(b); 35 if(faA!=faB){ 36 father[faA]=faB; 37 } 38 } 39 40 //初始化并查集 41 void init(int n) 42 { 43 for(int i=1;i<=n;i++){ 44 father[i]=i; 45 } 46 } 47 48 //求连通块的数量 49 int calBlock(int n) 50 { 51 int num=0; 52 for(int i=1;i<=n;i++) 53 { 54 isRoot[findfather(i)]=true; 55 } 56 for(int i=1;i<=n;i++){ 57 if(isRoot[i]==true){ 58 num++; 59 } 60 } 61 return num; 62 } 63 64 //DFS用递归来实现,所以需要参数root来记录当前结点,又因为程序要求根的深度,所以 65 //需要参数depth来记录当前深度。同时本题的模型是一个无向图,所以要避免回头遍历, 66 //所以要用pre来记录前驱结点。 67 void DFS(int u,int depth,int pre) 68 { 69 if(depth>maxdepth){ 70 temp.clear(); 71 maxdepth=depth; 72 temp.push_back(u); 73 } else if(depth==maxdepth){ 74 temp.push_back(u); 75 } 76 for(int i=0;i<adj[u].size();i++){ 77 if(adj[u][i]==pre){ 78 continue; 79 } else { 80 DFS(adj[u][i],depth+1,u); 81 } 82 } 83 } 84 85 int main() 86 { 87 cin>>n; 88 init(n);//不能掉了初始化 89 for(int i=1;i<n;i++){ 90 int a,b; 91 cin>>a>>b; 92 adj[a].push_back(b); 93 adj[b].push_back(a); 94 Union(a,b); 95 } 96 int sum=calBlock(n); 97 if(sum!=1){ 98 printf("Error: %d components\n",sum); 99 } else { 100 DFS(1,1,-1); 101 ans=temp; 102 temp.clear(); 103 DFS(ans[0],1,-1); 104 for(int i=0;i<temp.size();i++){ 105 ans.push_back(temp[i]); 106 } 107 sort(ans.begin(),ans.end()); 108 cout<<ans[0]<<endl; 109 for(int i=1;i<ans.size();i++){ 110 if(ans[i]!=ans[i-1]){ 111 cout<<ans[i]<<endl; 112 } 113 } 114 } 115 return 0; 116 }

浙公网安备 33010602011771号