迷宫城堡 HDU - 1269

为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间。Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i。

Input输入包含多组数据,输入的第一行有两个数:N和M,接下来的M行每行有两个数a和b,表示了一条通道可以从A房间来到B房间。文件最后以两个0结束。
Output对于输入的每组数据,如果任意两个房间都是相互连接的,输出"Yes",否则输出"No"。
Sample Input

3 3
1 2
2 3
3 1
3 3
1 2
2 3
3 2
0 0

Sample Output

Yes

No

强连通分量:对于一个有向图顶点的子集S,如果在S内任取两个顶点u和v,都能找到一条从u到v的路径,那么就称S是强连通的。如果在强连通的顶点集合S中加入其他任意顶点集合后,它都不再是强连通的,那么就称S是原图的一个强连通分量。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn=1e4+4;
 9 
10 int n,m,cmp[maxn];
11 bool use[maxn];
12 
13 vector<int> vs;        //顶点的标识 
14 vector<int> G1[maxn];  //图的邻接表表示
15 vector<int> G2[maxn];  //反向图的表示
16 
17 void Inite(){
18     vs.clear();
19     for(int i=1;i<=n;i++){
20         G1[i].clear();
21         G2[i].clear();
22     }
23 }
24 
25 void addedge(int u,int v){
26     G1[u].push_back(v);
27     G2[v].push_back(u);
28 }
29 
30 void DFS_P(int v){   //给顶点标号
31     use[v]=true;
32     for(int i=0;i<G1[v].size();i++) if(!use[G1[v][i]]) DFS_P(G1[v][i]);
33     vs.push_back(v); 
34 }
35 
36 void DFS_R(int v,int k){    //遍历的顶点集合就是一个强连通分量
37     use[v]=true;
38     cmp[v]=k;
39     for(int i=0;i<G2[v].size();i++) if(!use[G2[v][i]]) DFS_R(G2[v][i],k); 
40 }
41 
42 int Scc(){
43     memset(use,0,sizeof(use));
44     for(int i=1;i<=n;i++) if(!use[i]) DFS_P(i);
45     memset(use,0,sizeof(use));
46     
47     int k=0,b=vs.size()-1;
48     for(int i=b;i>=0;i--) if(!use[vs[i]]) DFS_R(vs[i],k++);
49     return k;
50 }
51 
52 int main()
53 {   while(~scanf("%d%d",&n,&m)){
54         if(n==0&&m==0) break;
55         Inite();
56         for(int i=0;i<m;i++){
57             int a,b;
58             scanf("%d%d",&a,&b);
59             addedge(a,b);
60         }
61         int ans=Scc();
62         if(ans!=1) cout<<"No"<<endl;
63         else cout<<"Yes"<<endl;
64     }
65     return 0;
66 }

并查集的实现(还没明白原理)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn=1e4+5;
 8 
 9 int n,m;
10 int Fa[2][maxn];
11 
12 int Find(int a,int i){
13     if(a==Fa[i][a]) return a;
14     return Fa[i][a]=Find(Fa[i][a],i);
15 }
16 
17 void Union(int a,int b){
18     if(a!=n){
19         a=Find(a,0);
20         b=Find(b,0);
21         if(a!=b) Fa[0][a]=b;
22     }
23     if(b!=n){
24         a=Find(a,1);
25         if(a!=b) Fa[1][b]=a;
26     }
27 }
28 
29 int main()
30 {   while(~scanf("%d%d",&n,&m)){
31         if(m==0&&n==0) break;
32         for(int i=0;i<=n;i++) Fa[0][i]=Fa[1][i]=i;
33         for(int i=1;i<=m;i++){
34             int a,b;
35             scanf("%d%d",&a,&b);
36             Union(a,b);
37         }
38         bool flag=false;
39         for(int i=1;i<=n;i++){
40             if(Find(i,0)!=n||Find(i,1)!=n){
41                 flag=true;
42                 break;
43             }
44         }
45         if(flag) printf("No\n");
46         else printf("Yes\n");
47     }
48     return 0;
49 }

 



posted @ 2017-11-23 12:50  天之道,利而不害  阅读(126)  评论(0)    收藏  举报