• 强连通分量的模版 Kosaraju+Tarjan+Garbow


      PS:在贴出代码之前,我得说明内容来源——哈尔滨工业大学出版的《图论及应用》。虽然有一些错误的地方,但是不得不说是初学者该用的书。

      从效率的角度来说,Kosaraju <Tarjan<Garbow。一般网上有前两种的代码和分析。Garbow算法是Tarjan的另一种实现,但是Garbow效率更高。

      不过从复杂度来说,三种算法的时间(空间)复杂度都是O(m +n)。

      模版的调用方式很简单,初始化,建图,调用Tarjan(n)或者Kosaraju(n)或者 Garbow(n), scc就是强连通分量的个数。

    (1)Kosaraju
    //Kosaraju
    const int N =10010, M=50010;
    struct node
    {
        int to, next;
    }edge[M],edge2[M]; //edge是逆图,edge2是原图
    int  dfn[N], head[N], head2[N],  belg[N], num[N];
    //dfn时间戳
    //belg记录每个点属于哪个连通分量,num记录强连通分量点的个数
    bool  vis[N];
    int cnt,cnt1,scc,tot,tot1;
    void dfs1(int u)
    {
        vis[u]=1;
        for(int k=head2[u];k!=-1;k=edge2[k].next)
            if(!vis[edge2[k].to]) dfs1(edge2[k].to);
        dfn[++cnt1]=u;
    }
    void dfs2(int u)
    {
        vis[u]=1;
        cnt++;
        belg[u]=scc;
        for(int k=head[u];k!=-1;k=edge[k].next)
            if(!vis[edge[k].to]) dfs2(edge[k].to);
    }
    void  Kosaraju(int n)
    {
        memset(dfn,0,sizeof(dfn));
        memset(vis,0,sizeof(vis));
        cnt1=scc=0;
        for(int i=1;i<=n;i++)
            if(!vis[i]) dfs1(i);
        memset(vis,0,sizeof(vis));
        for(int i=cnt1;i>0;i--)
            if(!vis[dfn[i]])
            {
                cnt=0;
                ++scc;
                dfs2(dfn[i]);
                num[scc] = cnt;
            }
    }
    void init()
    {
        tot=tot1=0;
        memset(head,-1,sizeof(head));
        memset(head2,-1,sizeof(head2));
        memset(num,0,sizeof(num));
    }
    void addedge(int i,int j)
    {
        edge2[tot1].to=j; edge2[tot1].next=head2[i];head2[i]=tot1++;
        edge[tot].to=i; edge[tot].next=head[j];head[j]=tot++;
    }
    (2)Tarjan
    //Tarjan
    const int N =1010, M=100010;
    struct node
    {
        int to, next;
    }edge[M];
    int head[N], low[N], dfn[N], sta[N], belg[N], num[N];
    bool vis[N];
    int scc,index,top, tot;
    void tarbfs(int u)
    {
        int i,j,k,v;
        low[u]=dfn[u]=++index;
        sta[top++]=u;
        vis[u]=1;
        for(i=head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if(!dfn[v])
            {
                tarbfs(v);
                if(low[u]>low[v]) low[u]=low[v];
            }
            else if(vis[v]&&low[u]>dfn[v]) low[u]=dfn[v];
        }
        if(dfn[u]==low[u])
        {
            scc++;
            do
            {
                v=sta[--top];
                vis[v]=0;
                belg[v]=scc;
                num[scc]++;
            }
            while(v!=u) ;
        }
    }
    void Tarjan(int n)
    {
        memset(vis,0,sizeof(vis));
        memset(dfn,0,sizeof(dfn));
        memset(num,0,sizeof(num));
        memset(low,0,sizeof(low));
        index=scc=top=0;
        for(int i=1;i<=n;i++)
            if(!dfn[i]) tarbfs(i);
    }
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int i,int j)
    {
        edge[tot].to=j; edge[tot].next=head[i];head[i]=tot++;
    }
    (3)Garbow
    //Garbow
    const int N =110, M=100010;
    struct node
    {
        int to, next;;
    }edge[M];
    int stk[N],stk2[N],head[N],low[N],belg[N];
    int cn,cm,tot,scc,lay;
    int Garbowbfs(int cur,int lay)
    {
        stk[++cn]=cur; stk2[++cm]=cur;
        low[cur]=++lay;
        for(int i=head[cur];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(!low[v]) Garbowbfs(v,lay);
            else if(!belg[v])
                while(low[stk2[cm]]>low[v]) cm--;
        }
        if(stk2[cm]==cur)
        {
            cm--;
            scc++;
            do
                belg[stk[cn]]=scc;
            while(stk[cn--]!=cur) ;
        }
        return 0;
    }
    
    void Garbow(int n)
    {
        scc=lay=0;
        memset(belg,0,sizeof(belg));
        memset(low,0,sizeof(low));
        for(int i=0;i<n;i++)
            if(!low[i]) Garbowbfs(i,lay);
    }
    void init()
    {
        memset(head,-1,sizeof(-1));
    }
    void addedge(int i,int j)
    {
        edge[tot].to=j; edge[tot].next=head[i];head[i]=tot++;
    }
  • 相关阅读:
    我是如何基于angular+requirejs+node做SPA项目架构的
    阿里云无线&前端团队是如何基于webpack实现前端工程化的
    angularjs源码分析之:angularjs执行流程
    你所必须掌握的三种异步编程方法callbacks,listeners,promise
    自从用了Less 编写css,你比以前更快了~
    对象的深浅拷贝
    throttle/debounce: 为你的cpu减减压(前端性能优化)
    jekyll : 使用github托管你的博客
    html5 drag api详解
    用setTimeout 代替 setInterval实时拉取数据
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/3956604.html
Copyright © 2020-2023  润新知