迷宮城堡-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]時,請棧中取出相應元素即可找出一個強連通分量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章