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

来源:互联网 发布:bi数据产品经理 编辑:程序博客网 时间:2024/05/20 21:23

题目链接: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;}