zoukankan      html  css  js  c++  java
  • Tarjan算法求强连通图

    先把参考资料的传送门放一下:

    1、优质的B站视频讲解
    (里面老师给出了一个很不错的代码模板)

    2、tarjan求强连通分量+缩点+割点/割桥(点双/边双)以及一些证明(原理简述)


    先不论缩点是怎么做的,
    根据第一个B站视频里的模板,
    先用线性的邻接表维护有向图,
    基本实现一下Tarjan算法。

    const int maxn = 1e5 + 10;
    
    //线性邻接表维护有向图
    
    class Node{
    public:
        int nd,nxt;
        Node(){};
        Node(int nd_,int nxt_):nd(nd_),nxt(nxt_){};
    };
    
    Node G[maxn];
    int head[maxn];
    int cnt;
    
    void add(int u,int v){
        G[cnt] = Node(v,head[u]);
        head[u] = cnt++;
    }
    
    void init_G(){
        memset(head,-1,sizeof(head));
        cnt = 0;
    }
    
    //下面是Tarjan算法求强连通图
    int Low[maxn];
    int Dfn[maxn];
    int num = 0;//编号变量-赋值不能是0
    int out[maxn];//标记被栈弹出过的元素
    int Stack[maxn];//模拟栈
    int cur = 0;//cur应当始终指向Stack的尾端元素
    
    int ans = 0;
    
    /*我们假设结点的编号从1开始*/
    int dfs(int u){
        Low[u] = Dfn[u] = ++num;//结点编号
        Stack[++cur] = u;//结点入栈
        //下面开始遍历u的临界结点
        for(int i=head[u];~i;i=G[i].nxt){
            int v = G[i].nd;
            if(Dfn[v] == 0){//v没有被访问
                dfs(v);
                Low[u] = min(Low[u],Low[v]);
            }else if(!out[v]){//v已经被访问且还在栈中
                Low[u] = Low[v];//形成环
            }
        }
        //输出强连通分量
        if(Low[u] == Dfn[u]){
            int cur_num = 0;
            do{
                cur_num++;
                out[Stack[cur]]=1;
            }while(Stack[cur--] != u);
            //这里做的处理是为了统计点个数大于1的连通区块的总个数ans
            if(cur_num>1)ans++;
        }
        return 0;
    }
    
    int main(){
        frein("in.txt");
        int n,m;
        cin>>n>>m;
        init_G();
        for(int i=0;i<m;i++){
            int a,b;
            cin>>a>>b;
            add(a,b);
        }
        //由于图并不一定是弱连通图
        //所以这里对每一个没有访问过的结点都进行搜索
        //当然,一般这并不会让复杂度达到O(n*n)
        for(int i=1;i<=n;i++){
            if(!Dfn[i]){
                dfs(i);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    

    OK

  • 相关阅读:
    搜索进阶1、八数码(HDU1043)
    D.迷宫2 (BFS+优先队列)
    小H的询问(线段树)
    B.迷宫(BFS)
    【UVA】10935 Throwing cards away I(STL队列)
    【UVA】10391 Compound Words(STL map)
    【UVA】12100 Printer Queue(STL队列&优先队列)
    【UVA】1596 Bug Hunt(模拟)
    【UVA】201 Squares(模拟)
    【UVA】1595 Symmetry(模拟)
  • 原文地址:https://www.cnblogs.com/savennist/p/13887259.html
Copyright © 2011-2022 走看看