hdu 5222 Exploration

来源:互联网 发布:python popen c语言 编辑:程序博客网 时间:2024/06/04 00:22

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 3000010struct 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 1000010struct 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;}
0 0
原创粉丝点击