[笔记]关于tarjan求连通分量 & 缩点

来源:互联网 发布:三国吴国知乎 编辑:程序博客网 时间:2024/06/16 01:11

PS:本文图均用链式前向星存储
一.连通分量(模板)
  1.有向图

inline void tarjan(int p){    dfn[p]=low[p]=++dfn_t;    q.push(p);    for(int i=head[p];i;i=edge[i].next)    {        int y=edge[i].to;        if(!dfn[y])        {            tarjan(y);            low[p]=min(low[p],low[y]);        }else        if(!belong[y])//是否在栈内            low[p]=min(low[p],dfn[y]);    }    if(dfn[p]==low[p])    {        //++scc_t;        for(int x=0;x!=p;)        {            x=q.top();            q.pop();            belong[x]=p;            // or col[x]=scc_t;        }    }}

2.无向图
(与有向图的唯一区别就是判断前驱,去环)

inline void tarjan(int u,int pre){    dfn[u]=low[u]=++dfn_t;    q.push(u);    for(int i=head[u];i;i=edge[i].next)    if(edge[i].to!=pre)//不回去    {        int v=edge[i].to;        if(!dfn[v])        {            tarjan(v,u);            low[u]=min(low[u],low[v]);        }else        //if(!belong[v]) 网上有种说法,貌似用有向图的方法也可以判断        if(dfn[v]<dfn[u])            low[u]=min(low[u],dfn[v]);    }    if(dfn[u]==low[u])    {        for(int x=-1;x!=u;)        {            x=q.top();            q.pop();            belong[x]=u;        }    }}

二.缩点
1.关于标记/染色 ( belong[]/col[] )
  -目测有两种方式:
  -第一种直接标记成u

        for(int x=-1;x!=u;)        {            x=q.top();            q.pop();            belong[x]=u;        }

  -第二种用联通块个数标记

     ++scc_t;        for(int x=-1;x!=u;)        {            x=q.top();            q.pop();            col[x]=scc_t;        }

2.关于缩点方式
ps:缩点后注意每次判断 col[x]!=col[y] || belong[x]!=belong[y]
  -在原图上修改(移花接木) 比较喜欢第一种,省内存
    
PS:手打并未测试(可画图理解)

for(int i=1;i<=n;++i)if(i!=belong[i]){    for(int j=head[i];j;)    if(belong[i]!=belong[edge[j].to])    {        int tmp=edge[j].next;        edge[j].next=head[belong[i]];        head[belong[i]]=j;        j=tmp;    }}

  -重建图

    for(int i=1;i<=n;++i)    for(int j=head1[i];j;j=edge1[j].next)    if(col[i]!=col[edge1[j].to])    {        int y=edge1[j].to;        add(col[i],col[y],cnt2,head2,edge2);    }

欢迎dalao指出错误