迷宫城堡 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 }