1021 Deepest Root (25 分)

本文探讨了在一个连接且无环的图中寻找能够产生最高树的根节点问题,通过输入节点数量和边信息,利用并查集判断图的连通性,并提出了一种算法来找出所有符合条件的根节点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 (≤10​4​​) 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个节点的树,如果能 从中选出节点做为树根,使树的高度最大。输出满足要求的所有结点 ,首先对于构建的图应该判断其是否连通,通过并查集来判断,每读入一条边,判断其根是否相同,不同则加入到一个集合中,最终可通过判断集合数是否为1来判断给定的图是否相通。当图连通时,肯定能构成树,如何选择合适的根节点,使树的高度最大,可以任选一结点 进行遍历,获取此时的最深的根节点的集合(A),然后从集合A中任意一个节点出发遍历整个树, 获取能达到最深的节点B集合。A和B的并集就是使树最高的根节点。

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
vector<int> G[maxn];
int n,a,b,fath[maxn];
bool root[maxn],vis[maxn];
int findf(int x)
{
    int a=x;
    while(x!=fath[x]) x=fath[x];
    while(a!=fath[a])
    {
        int z=a;
        a=fath[a];
        fath[z]=x;
    }
    return x;
}
int maxh=0;
vector<int> vc,ans;
void dfs(int u,int h)
{
   vis[u]=true;
   if(h>maxh)
   {
    vc.clear();
    vc.push_back(u);
    maxh=h;
   }
   else if(h==maxh) vc.push_back(u);
   for(int i=0;i<G[u].size();i++)
   {
       if(vis[G[u][i]]==false)
       {
          dfs(G[u][i],h+1);
       }
   }
}
int main()
{
   scanf("%d",&n);
   for(int i=1;i<=n;i++) fath[i]=i;
   for(int i=1;i<n;i++)
   {
       scanf("%d%d",&a,&b);
       G[a].push_back(b);
       G[b].push_back(a);
       int fa=findf(a),fb=findf(b);
       if(fa!=fb) fath[fa]=fb;
   }
   int cnt=0;
   for(int i=1;i<=n;i++) root[findf(i)]=true;
   for(int i=1;i<=n;i++) cnt+=root[i];
   if(cnt!=1) printf("Error: %d components",cnt);
   else{
    dfs(1,1);
    ans=vc;
    memset(vis,false,sizeof(vis));
    dfs(vc[0],1);
    for(int i=0;i<vc.size();i++)
    {
       ans.push_back(vc[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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值