浙大 PAT 甲级 1021 Deepest Root C++ 并查集 深度优先搜索

分析

知识点:并查集 + 深度优先搜索

本题首先使用并查集检验该图是否是连通图,如果不是连通图,输出连通子图个数。如果是连通图,则使用深度优先搜索。

题目中要求以某节点为树根,树的最大深度,实质上是求从某节点出发,能达到的最远距离。那么进行一次循环,对每一节点,都以它为起点做深度优先搜索得到最大深度,找到能够有最大的最大深度的根节点。

 

代码

如果对并查集和DFS不熟练的小伙伴建议看看王道论坛的《机试指南》,里面对必须要掌握的基础算法做了详细的说明和例题分析。

这题的test case不算坑,一遍过啦~

#include<stdio.h>
#include<vector>

using namespace std;

vector<int> edges[10001]; // 邻接链表保存图
bool mark[10001]; // 深度优先搜索时会用到,mark[i]=true代表编号为i的节点已走过
int Tree[10001]; // 并查集求连通子图个数时会用到,Tree[i]代表编号为i的节点的双亲节点,若为-1,则表示该节点不存在双亲节点,为根

int bestLevel = 0; // 记录最大的最大深度
vector<int> bestRoot; // 可能有多个节点都可达到最大的最大深度

int findRoot(int x) // 查找某个节点所在树的根节点,并查集
{
    if (Tree[x] == -1)
    {
        return x;
    }
    else
    {
        int tmp = findRoot(Tree[x]);
        Tree[x] = tmp;
        return tmp;
    }
}

int DFS(int x, int level) // 深度优先搜索,从x节点开始,level为x节点此时的深度,返回经过x的这棵树的最大深度
{
    int currentLevel = level;
    for (int i = 0; i < edges[x].size(); i++) // 对x的且未被走到过的邻点进行递归
    {
        if (mark[edges[x][i]] == false)
        {
            mark[edges[x][i]] = true;
            int tmpLevel = DFS(edges[x][i], currentLevel + 1);
            if (tmpLevel > level)
            {
                level = tmpLevel;
            }
            mark[edges[x][i]] = false;
        }
    }
    return level;
}

int main()
{
    int N;
    scanf("%d", &N);
    for (int i = 1; i <= N; i++) // 初始化
    {
        Tree[i] = -1;
        mark[i] = false;
        edges[i].clear();
    }
    for (int i = 0; i < N - 1; i++) // 并查集
    {
        int a, b;
        scanf("%d%d", &a, &b);
        edges[a].push_back(b);
        edges[b].push_back(a);
        a = findRoot(a);
        b = findRoot(b);
        if (a != b)
        {
            Tree[a] = b;
        }
    }
    int components = 0;
    for (int i = 1; i <= N; i++)
    {
        if (Tree[i] == -1)
        {
            components++;
        }
    }
    if (components > 1)
    {
        printf("Error: %d components\n", components);
    }
    else
    {
        for (int i = 1; i <= N; i++) // 将每个节点都作为根节点,检验哪个节点做根节点时能有最大的最大深度
        {
            mark[i] = true;
            int level = DFS(i, 0); // 节点i做根节点,起始层数为0,返回此时的最大深度level
            if (level > bestLevel) // 如果此时的最大深度大于已有的最大的最大深度,则更新
            {
                bestLevel = level;
                bestRoot.clear();
                bestRoot.push_back(i);
            }
            else if (level == bestLevel) // 如果此时的最大深度等于已有的最大的最大深度,将节点i添加到bestRoot中
            {
                bestRoot.push_back(i);
            }
            mark[i] = false;
        }
        for (int i = 0; i < bestRoot.size(); i++)
        {
            printf("%d\n", bestRoot[i]);
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值