求有向图的强连通分量 Tarjan算法学习笔记

网上翻了很多篇博客都比较难懂,最后终于找到一篇好理解的
推荐给大家http://blog.csdn.net/acmmmm/article/details/16361033
认真看肯定能懂,我当时是只用了十分钟就看明白了,写的真的很易懂。
不过他的代码我是没看懂,这里给一份我自己写的代码。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

const int MAXN = 10005;

bool is_instack[MAXN];//记录节点是否在栈中
int mystack[MAXN],top;
bool map[MAXN][MAXN];//存图,这里用的矩阵仅供理解,具体做题自己调整
int DFN[MAXN];//记录节点第一次被访问时的时间
int LOW[MAXN];//记录节点与节点的子树节点中最早的步数
int times;
int Belong[MAXN];//记录每个节点属于的强连通分量编号
int N,M,cnt;//N是点数M是边数,cnt是强连通分量编号

void Tarjan(int x){
    DFN[x] = LOW[x] = ++times;
    is_instack[x] = true;
    mystack[++top] = x;
    for(int i=0 ; i<N ; i++){//这里注意根据题进行更改
        if(map[x][i] == false)continue;
        if(!DFN[i]){
            Tarjan(i);
            if(LOW[i]<LOW[x]){
                LOW[x] = LOW[i];
            }
        }
        else if(is_instack[i]){
             LOW[x] = min(LOW[x],DFN[i]);
        }
    }
    if(DFN[x] == LOW[x]){
        ++cnt;
        int mid;
        do{
            mid = mystack[top--];
            is_instack[mid] = false;
            Belong[mid] = cnt;
        }while(mid != x);
    }
}

void init(){
    memset(map,false,sizeof(map));
    memset(DFN,0,sizeof(DFN));
    memset(LOW,0,sizeof(LOW));
    memset(is_instack,false,sizeof(is_instack));
    times = cnt = top = 0;
}

int main(){

    while(cin>>N>>M){
        init();
        for(int i=0 ; i<M ; i++){
                int a,b;
                cin>>a>>b;
                map[a][b] = true;
        }
        for(int i=1 ; i<=N ; i++){
            if(!DFN[i])Tarjan(i);//有可能不是连通图所以遍历一遍
        }
    }

    return 0;
}
posted @ 2017-12-04 16:28  Assassin_poi君  阅读(131)  评论(0编辑  收藏  举报