浙大pat甲级题目---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 (<=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就要寻找每一个顶点所对应的树高,并输出最大的树高所对应的节点。
针对第一部分,我们使用并查集的概念去做(基本是固定套路),对于什么是并查集,并查集怎么用,我是参考的这篇博客,写的非常有意思,大家可以研究:
http://blog.csdn.net/u013546077/article/details/64509038
这里不做太多赘述。
针对第二部分,这里选用dfs得到每个顶点的最短路径
#include <iostream> #include<vector> #include<algorithm> #include<cstdio> #include<cstring> #define MAX 100001 using namespace std; //并查集解决联通分之数的问题,dfs解决最高树问题 int a[MAX];//并查集 vector<int>graph[MAX];//学会用这种方式表达图的临街表 vector<int>result;//存放最后输出结果的 int visit[MAX]; int length[MAX];//存放每个节点的最深长度 void init(int n)//并查集初始化 { for(int i=1;i<=n;i++) { a[i]=i; } } int find(int i)//查找i的根节点,且带路径压缩。目前看到最短版本 { if(a[i]!=i)//当他的根不是自己(即还没找到根) a[i]=find(a[i]);//递归的寻找父亲 return a[i]; } void join(int i,int j)//节点i和j连接在一起 { int x=find(i); int y=find(j); if(x!=y) a[x]=y;//联通两个分之 } int dfs(int i)//以i为根,返回最大深度 { int ans=0; int num=(int)graph[i].size(); if(visit[i]==1)//叶子节点 return 0; visit[i]=1; for(int j=0;j<num;j++) { int next=graph[i][j]; if(visit[next]!=1) { int deep=dfs(next); ans=max(deep,ans); } } return ans+1; } int main() { int n; int count=0; int max=-1; int index=0; scanf("%d",&n); init(n); for(int i=1;i<n;i++)//学会这种写临界表的方式 { int x,y; scanf("%d%d",&x,&y); join(x,y); //将两者相连 graph[x].push_back(y); graph[y].push_back(x); } for(int i=1;i<=n;i++) { if(a[i]==i)//当发现一个根的时候,联通分之数加一 count++; } if(count!=1) { printf("Error: %d components\n",count); } else { for(int i=1;i<=n;i++) { memset(visit,0, sizeof(visit));//注意每一次都要清空 length[i]=dfs(i); } for(int i=1;i<=n;i++)//当题目中要求 输出很多相同大小的数的索引的时候,学会这种方法 { if(length[i]>max) { max=length[i]; index=i; } } for(int i=1;i<=n;i++) { if(length[i]==length[index])//很巧妙,相当于记下来最大的数,再循环 printf("%d\n",i); } } return 0; }