PAT(甲级)1021 Deepest Root (25point(s))

桃扇骨 2024-05-08 06:01 189阅读 0赞
题目

题目链接

思路

题目大意:给一张图,这个图有点特殊,没有环且边数等于节点数-1,即是一棵树;每个节点都可能是根节点,要求是输出那些作为根节点时树的深度最大的节点;
首先要判断是不是联通的,可以用并查集做,可以用图的DFS遍历做;
然后如果是联通的话,需要找到那些作为根节点时树的深度最大的节点;这里有一个方法,那就是DFS两次,第一次从任意一个节点出发,假设从1号节点出发,DFS时会遍历所有点,并得到每个点的深度,我们把那些深度最大的点记录下来,存放在temp中;第二次从temp 数组的任意一个元素出发,再次记录下深度最大的点,这两个集合取并集,就是想要的答案;(证明太难了,我选择记住)
注意:这其实是一个树的遍历问题,但是树是用邻接表存的,所以DFS时要记录父节点,避免走回头路;

代码
  1. #include <iostream>
  2. #include <string>
  3. #include <cstring>
  4. #include <vector>
  5. #include <algorithm>
  6. #include <set>
  7. using namespace std;
  8. const int maxn = 1e4 + 10;
  9. vector<int> graph[maxn];//图
  10. int n;//节点个数
  11. int father[maxn];//father数组和联通分量
  12. int isRoot[maxn];//存放以他为根节点 ,这一联通分枝有几个元素
  13. set<int> temp, ans;
  14. int maxDepth = 0;//最大的深度
  15. int findFa(int a){
  16. int b = a, temp;
  17. //寻找父节点
  18. while(father[a] != a) a = father[a];
  19. //压缩路径
  20. while(father[b] != b){
  21. temp = father[b];
  22. father[b] = a;
  23. b = temp;
  24. }
  25. return a;
  26. }
  27. void myUnion(int a, int b){
  28. int faA = findFa(a), faB = findFa(b);
  29. if(faA != faB){
  30. father[faB] = faA;//B向A合并
  31. //更新isRoot数组
  32. isRoot[faA] += isRoot[faB];
  33. isRoot[faB] = 0;
  34. }
  35. }
  36. void DFS(int root, int depth, int pre){
  37. //如果当前这个节点的深度大于全局的,需要把之前的temp数组清空
  38. if(depth > maxDepth){
  39. temp.clear();
  40. temp.insert(root);
  41. maxDepth = depth;
  42. }
  43. else if(depth == maxDepth) temp.insert(root);//等于全局,直接加进去
  44. for(int i = 0; i < graph[root].size(); i ++){
  45. //用遍历图的方式遍历树,需要防止走回头路
  46. if(graph[root][i] != pre){
  47. DFS(graph[root][i], depth + 1, root);
  48. }
  49. }
  50. }
  51. int main()
  52. {
  53. //初始化father数组
  54. for(int i = 0; i < maxn; i ++) father[i] = i;
  55. memset(isRoot, 1, sizeof(isRoot));
  56. scanf("%d", &n);
  57. //读入边
  58. for(int i = 1; i < n; i ++){
  59. int u, v;
  60. scanf("%d%d", &u, &v);
  61. myUnion(u, v);
  62. graph[u].push_back(v);
  63. graph[v].push_back(u);
  64. }
  65. //计算联通分量
  66. int num = 0;
  67. for(int i = 1; i <= n; i ++){
  68. if(isRoot[i] != 0) num ++;
  69. }
  70. if(num != 1) printf("Error: %d components\n", num);
  71. else{
  72. //计算从第一个点出发能到达的最远的点,将最远的点存放在temp中
  73. DFS(1, 1, -1);
  74. ans = temp;
  75. maxDepth = 0;//注意把最大深度还原到零
  76. DFS(*temp.begin(), 1, -1);
  77. //将第二次的节点与第一次的节点合并,二者取并集是最后的答案
  78. for(auto it = temp.begin(); it != temp.end(); it ++){
  79. ans.insert(*it);
  80. }
  81. //输出结果
  82. for(auto it = ans.begin(); it != ans.end(); it ++){
  83. printf("%d\n", *it);
  84. }
  85. }
  86. system("pause");
  87. return 0;
  88. }

发表评论

表情:
评论列表 (有 0 条评论,189人围观)

还没有评论,来说两句吧...

相关阅读