迷宫城堡
问题来源:hdu-1269
Problem Description
为了训练小希的方向感,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
源代码:
代码分析:Tarjin算法是基于dfs来实现的算法,dfn记录入栈的次序(时间戳,入栈之后并不会改变),low记录它能直接或间接达到的最小时间戳顶点,所以当dfn[i]==low[i]时,请栈中取出相应元素即可找出一个强连通分量
问题来源:hdu-1269
Problem Description
为了训练小希的方向感,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
源代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
const int MAX = 10002;
const int INF = 1<<30;
vector <int> G[MAX]; //vector构图
stack <int> S; //利用数据结构栈实现
int N , M , now , sum;
int dfn[MAX] , low[MAX] , mark[MAX];
int Min( int a , int b ){ return a <= b ? a : b; }
void Tarjin( int u );
int main( ){
int a , b;
while( cin>>N>>M && N+M ){
sum = now = 0;
memset( dfn , 0 , sizeof( dfn ) );
memset( low , 0 , sizeof( low ) );
memset( mark , 0 , sizeof( mark ) );
for( int i=0 ; i<MAX ; i++ ) G[i].clear( );
while( !S.empty() ) S.pop( );
while( M-- ){
cin>>a>>b;
G[a].push_back( b ); //建立单向的图
}
for( int i=1 ; i<=N ; i++ ){ //每个点都可能是新的强连通分量,需要统统遍历
if( !mark[i] )
Tarjin( i );
}
if( sum==1 ) //强连通分量的数量只为1,即整个图是一个强连通图
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
void Tarjin( int u ){
int v;
dfn[u] = low[u] = ++now; //时间戳和最小标号
mark[u] = 1; //标记扫过
S.push( u ); //入栈
for( int i=0 ; i<G[u].size() ; i++ ){ //对于该点为弧尾的每一条边
v = G[u][i];
if( !dfn[v] ){ //递归进行Tarjin
Tarjin( v );
low[u] = Min( low[u] , low[v] ); //如果v没有搜过,更新最小标号
}
else if( mark[v] )
low[u] = Min( low[u] , dfn[v] ); //搜过了该点,已经入栈,则更新最小标号
}
if( dfn[u]==low[u] ){ //找到强连通分量
sum++; //数量累加
while( !S.empty() ){
int tmp = S.top( );
S.pop( );
if( tmp==u ) //找到相等的就break
break;
}
}
}
代码分析:Tarjin算法是基于dfs来实现的算法,dfn记录入栈的次序(时间戳,入栈之后并不会改变),low记录它能直接或间接达到的最小时间戳顶点,所以当dfn[i]==low[i]时,请栈中取出相应元素即可找出一个强连通分量