PAT练习题 P1021 Deepest Root (25分)【并查集+图的遍历】


传送门:P1021


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



题目大意:
给出n个结点和n-1条边,问它们能否形成一棵n个结点的树,如果能,从中选出一个点作为根节点,使整棵树的高度最大。输出所有满足要求的可以作为树根的结点。如果不能构成一棵树,就输出他有几个集合。


解题思路:
首先先判断是否可以构成一棵树,这个操作可以用并查集来实现。
确定图连通后,则确定了树,选择合适根结点使树高最大的做法为:
先任意选择一个结点,从该节点开始遍历整棵树,获取能达到的最深的结点,记为集合A;然后从集合A中任意一个结点出发遍历整棵树,获取能达到的最深顶点,记为结点集合B。集合A与B的并集就是所求结果。

参考博客



AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e4+10;
int n,flag,maxn;
vector<int> rd[N];
vector<int> ans,temp;
int deep[N],father[N],vis[N];
int find(int x)
{
  while(x!=father[x])
    x=father[x];
  return x;
}
void Union(int x,int y)
{
  int fx=find(x),fy=find(y);
  if(fx!=fy)
  {
    father[fx]=fy;
  }
}
void dfs(int x,int deep)
{
  int flag=0;
  for(int i=0;i<rd[x].size();i++)
  {
    int y=rd[x][i];
    if(!vis[y])
    {
      flag=1;
      vis[y]=1;
      dfs(y,deep+1);
      vis[y]=0;
    }
  }
  if(!flag)
  {
    if(deep>maxn)
    {
      maxn=deep;
      temp.clear();
      temp.push_back(x);
    }
    if(deep==maxn)
      temp.push_back(x);
  }
}

int main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    father[i]=i;
  for(int i=0;i<n-1;i++)
  {
    int a,b;
    scanf("%d%d",&a,&b);
    Union(a,b);
    rd[a].push_back(b);
    rd[b].push_back(a);
  }
  int sum=0;
  for(int i=1;i<=n;i++)
  {
    if(father[i]==i)
      sum++;
  }
  if(sum!=1)
  {
    printf("Error: %d components\n",sum);
    return 0;
  }
  vis[1]=1;
  maxn=0;
  dfs(1,1);
  ans=temp;
  int pos=ans[0];
  memset(vis,0,sizeof(vis));
  vis[pos]=1;
  dfs(pos,1);
  for(int i=0;i<temp.size();i++)
    ans.push_back(temp[i]);
  sort(ans.begin(),ans.end());
  printf("%d\n",ans[0]);
  for(int i=1;i<ans.size();i++)
  {
    if(ans[i]!=ans[i-1])
      printf("%d\n",ans[i]);
  }
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值