【PAT甲级】1021 Deepest Root (25)(dfs+并查集)

47 篇文章 0 订阅
19 篇文章 0 订阅

题目链接

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

题意:给一个无环图,问是否是一棵树,不是,则输出Error: K components;是的话就输出deepest root(定义为节点i作为根,整棵树最深)

思路:因为是树,很容易想到dfs,当然这里也可以bfs,dp;

1.首先这里使用dfs+并查集,使用并查集合并后,看是否有多个连通分量,有的话直接输出;只有一个继续dfs,n次dfs后可以得到每个节点作为根时的最大深度,最后取最大值,输出与此最大值相等所对应的节点即可。

2.bfs,先将某个点u作为根,第一次bfs向外扩展找到最远的叶节点v,将节点v作为根节点,再来一次bfs得到的应该就是树的最大深度

3.应该也可以DP来写,参考https://blog.csdn.net/feng_zhiyu/article/details/79209689

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <sstream>
#include <algorithm>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define mem(a,n) memset(a,n,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
const ll INF=0x3f3f3f3f;
const int N = 2e5+5;

int par[N];///par[i]表示i的父节点
bool vis[N];///访问标记
int dis[N];///dis[i]表示 节点i作为deepest root时的最长路径
vector<int>g[N];///存储无向图
int dfs(int u) {
    if(vis[u]) return 0;///此时的节点已经访问过了
    int cnt=0;
    vis[u]=1;
    for(int i=0; i<g[u].size(); i++) {
        int v=g[u][i];
        if(!vis[v]) {
            cnt=max(cnt,dfs(v));
        }
    }
    return cnt+1;
}
int Find(int x) { ///找根
    return par[x]==x?x:(par[x]=Find(par[x]));
}
void Unite(int x,int y) {///合并压缩路径
    x=Find(x),y=Find(y);
    if(x!=y) {
        par[x]=y;
    }
}
void init(int n) {
    for(int i=0; i<=n; i++) par[i]=i;
}
int main() {
    int n;
    cin>>n;
    init(n);
    for(int i=1; i<n; i++) {
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
        Unite(x,y);
    }
    int cnt=0;
    for(int i=1; i<=n; i++) {
        if(i==par[i]) cnt++;
    }
    if(cnt>1) {
        cout<<"Error: "<<cnt<<" components";
        return 0;
    }
    for(int i=1; i<=n; i++) {
        mem(vis,0);
        dis[i]=dfs(i);
//        cout<<dis[i]<<endl;
    }
    int maxDepth=-1,index=0;
    for(int i=1; i<=n; i++) {
        if(dis[i]>maxDepth) {
            maxDepth=dis[i];
            index=i;
        }
    }
//    cout<<"maxDepth="<<maxDepth<<"   index="<<index<<endl;
    for(int i=1; i<=n; i++) {
        if(dis[i]==dis[index]) {
//            cout<<"index="<<index<<endl;
            cout<<i<<endl;
        }
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值