hdu5222 Exploration【并查集+拓扑排序】

本文介绍了一道编程题的解决方案,题目要求判断探险家能否从任一洞穴出发,通过一系列边(包括有向和无向边),访问至少一个其他洞穴后返回起点。文章给出了具体的实现思路,包括使用并查集处理无向边以检测环的存在,并通过拓扑排序判断由无向边构成的新图中是否存在环。

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5222
题意:有一个探险家,探险一个地方,这个地方有n个洞穴,有若干条边,有的边是有向边,有的是无向边,每条边在走过后就坍塌,问你这个探险家能不能选择一个点,然后经过最少一个点,然后回到原点
解析:对于所有的无向边做并查集,如果对于两个点,在未合并前就已经是一个集合了,那么就存在环,即有解,若果此时没有判断出环的话,那么仅仅只靠无向边是找不到的,那么可以把合并后的点生成的一个新的图,于是就相当于判断这个新生成的无向图是否存在环,此时用拓扑排序判断即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
vector<int>G[maxn];
int in[maxn],fa[maxn];
void init(int n)
{
    for(int i=0;i<=n;i++)
    {
        in[i] = 0,fa[i] = i;
        G[i].clear();
    }
}
int getfa(int x)
{
    if(x==fa[x])
        return x;
    return fa[x] = getfa(fa[x]);
}
bool judge(int n)
{
    int cnt = 0;
    queue<int>q;
    for(int i=1;i<=n;i++)
    {
        if(in[i]==0)
            q.push(i);
    }
    while(!q.empty())
    {
        int u = q.front();q.pop();
        cnt++;
        for(int i=0;i<(int)G[u].size();i++)
        {
            int v = G[u][i];
            in[v]--;
            if(in[v]==0)
                q.push(v);
        }
    }
    return cnt!=n;
}
int main(void)
{
    int t,n,m1,m2;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&n,&m1,&m2);
        int x,y,t1,t2,flag = 0;
        init(n);
        for(int i=0;i<m1;i++)
        {
            scanf("%d %d",&x,&y);
            t1 = getfa(x);
            t2 = getfa(y);
            if(t1==t2)
                flag = 1;
            else
                fa[t1] = t2;
        }
        for(int i=0;i<m2;i++)
        {
            scanf("%d %d",&x,&y);
            t1 = getfa(x);
            t2 = getfa(y);
            if(t1==t2)
                flag = 1;
            else if(!flag)
            {
                G[t1].push_back(t2);
                in[t2]++;
            }
        }
        if(flag || judge(n))
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值