浙大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;
}

 

转载于:https://www.cnblogs.com/SK1997/p/8588527.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值