hdu 5222 Exploration

Exploration

Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1385 Accepted Submission(s): 378

Problem Description
Miceren likes exploration and he found a huge labyrinth underground!

This labyrinth has N caves and some tunnels connecting some pairs of caves.

There are two types of tunnel, one type of them can be passed in only one direction and the other can be passed in two directions. Tunnels will collapse immediately after Miceren passing them.

Now, Miceren wants to choose a cave as his start point and visit at least one other cave, finally get back to start point.

As his friend, you must help him to determine whether a start point satisfing his request exists.

Input
The first line contains a single integer T, indicating the number of test cases.

Each test case begins with three integers N, M1, M2, indicating the number of caves, the number of undirectional tunnels, the number of directional tunnels.

The next M1 lines contain the details of the undirectional tunnels. Each line contains two integers u, v meaning that there is a undirectional tunnel between u, v. (u ≠ v)

The next M2 lines contain the details of the directional tunnels. Each line contains integers u, v meaning that there is a directional tunnel from u to v. (u ≠ v)

T is about 100.

1 ≤ N,M1,M2 ≤ 1000000.

There may be some tunnels connect the same pair of caves.

The ratio of test cases with N > 1000 is less than 5%.

Output
For each test queries, print the answer. If Miceren can do that, output “YES”, otherwise “NO”.

Sample Input
2
5 2 1
1 2
1 2
4 5
4 2 2
1 2
2 3
4 3
4 1

Sample Output
YES
NO

Hint
If you need a larger stack size,
please use #pragma comment(linker, “/STACK:102400000,102400000”) and submit your solution using C++.

解题思路:1、判断图是否有环,每条边(隧道)只能走一次,图的顶点数比较多,只能用邻接表存储图;用深搜判断是否有环,注意边的标记,见代码。
2、用并查集判断无向图是否有环,然后,把同一集合的点合并,判断构成的新图是否存在拓扑序。(原来一个集合中的点加入一条有向边可以自身构成回路,注意!)

dfs代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
using namespace std;
#define LL __int64
#define N 3000010
struct node
{
    int v,next;
}e[N];
int head[N/3];
int it[N];   //记录无向边的两条有向边的相互序号
int vis_b[N]; //记录边是否走过
int vis[N/3];  //记录点是否走过一次
int mark[N/3];//记录在同一次访问中点是否走过一次
int cnt,flag;
void add(int u,int v)
{
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u)
{
    int i,v;
    mark[u]=vis[u]=1;
    for(i=head[u];i!=-1;i=e[i].next){
        if(vis_b[i])
            continue;
        vis_b[i]=vis_b[it[i]]=1;
        v=e[i].v;
        if(mark[v]){
            flag=1;
            return;
        }
        if(!vis[v]){
            dfs(v);
        }
    }
    mark[u]=0;
}
int main()
{
    int T,n,m1,m2;
    int i,u,v;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m1,&m2);
        memset(head,-1,sizeof(head));
        cnt=0;
        while(m1--){
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
            it[cnt-1]=cnt-2;
            it[cnt-2]=cnt-1;
        }
        while(m2--){
            scanf("%d%d",&u,&v);
            add(u,v);
            it[cnt-1]=cnt-1;
        }
        flag=0;
        memset(vis,0,sizeof(vis));
        memset(vis_b,0,sizeof(vis_b));
        memset(mark,0,sizeof(mark));
        for(i=1;i<=n;++i){
            if(!vis[i]){
                dfs(i);
                if(flag)
                    break;
            }
        }
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

并查集+拓扑排序:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<string.h>
using namespace std;
#define LL __int64
#define N 1000010
struct node
{
    int v,next;
}e[N];

int pre[N];
int head[N];
int cnt,flag;
int indeg[N];
int findd(int k)
{
    if(k!=pre[k]){
        pre[k]=findd(pre[k]);
    }
    return pre[k];
}
void add(int u,int v)
{
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
int top_sort(int n)
{
    int i,u;
    queue<int>q;
    int cnt1=0;
    for(i=1;i<=n;++i){
        if(indeg[i]==0){
            q.push(i);
            ++cnt1;
        }
    }
    while(!q.empty()){
        u=q.front();
        q.pop();
        for(i=head[u];i!=-1;i=e[i].next){
            --indeg[e[i].v];
            if(indeg[e[i].v]==0){
                q.push(e[i].v);
                ++cnt1;
            }
        }
    }
    if(cnt1==n)
        return 0;
    return 1;
}
int main()
{
    int i,T,u,v;
    int n,m1,m2;
    int a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m1,&m2);
        for(i=1;i<=n;++i){
            pre[i]=i;
        }
        flag=cnt=0;
        for(i=0;i<m1;++i){
            scanf("%d%d",&u,&v);
            if(flag)
                continue;
            a=findd(u);
            b=findd(v);
            if(a==b){
                flag=1;
            }
            else{
                pre[b]=a;
            }
        }
        memset(indeg,0,sizeof(indeg));
        memset(head,-1,sizeof(head));
        for(i=0;i<m2;++i){
            scanf("%d%d",&u,&v);
            if(flag)
                continue;
            a=findd(u);
            b=findd(v);
            if(a==b){       //同一个集合中的点加入有向边成环
                flag=1;
            }
            else{
                add(a,b);
                ++indeg[b];
            }
        }
        if(!flag)
            flag=top_sort(n);
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011721440/article/details/50601323