迷宫城堡-Tarjin

迷宫城堡
问题来源: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]时,请栈中取出相应元素即可找出一个强连通分量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章