双联通的tarjan算法

Posted Go

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双联通的tarjan算法相关的知识,希望对你有一定的参考价值。

转自:https://www.zhihu.com/question/40746887/answer/88428236

连通分量有三种∶边双连通分量,点双连通分量,强连通分量,前两种属于无向图,后一种属于有向图

定义:

双连通分量又分双连通分量和边双连通分量两种。若一个无向图中的去掉任意一个节点(一条边)都不会改变此图的连通性,即不存在割点(桥),则称作点(边)双连通图。一个无向图中的每一个极大点(边)双连通子图称作此无向图的点(边)双连通分量。

代码如下:

点双联通
struct Edge{
    int u,v;
    Edge(int _u,int _v):u(_u),v(_v){}
}edge[maxn];
int dfn[maxn],low[maxn],cut[maxn],bccno[maxn];
vector<int>gra[maxn],bcc[maxn];
stack<int>stk;
int cnt,bcnt;

void tarjan(int f,int u){
    dfn[u]=low[u]=++cnt;
    int child=0;
    int sz=gra[u].size();
    for(int i=0;i<sz;i++){
        int id=gra[u][i];
        int v=edge[id].v;
        if(!dfn[v]){
            stk.push(id);
            child++;
            tarjan(u,v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                cut[u]=1;
                bcc[++bcnt].clear();
                while(1){
                    int id=stk.top();
                    stk.pop();
                    int uu=edge[id].u;
                    int vv=edge[id].v;
                    if(bccno[uu]!=bcnt){
                        bcc[bcnt].push_back(uu);
                        bccno[uu]=bcnt;
                    }
                    if(bccno[vv]!=bcnt){
                        bcc[bcnt].push_back(vv);
                        bccno[vv]=bcnt;
                    }
                    if(uu==u&&vv==v){
                        break;
                    }
                }
            }
        }else if(dfn[v]<dfn[u]&&v!=f){
            stk.push(id);
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(f<0&&child==1){
        cut[u]=0;
    }
}
边双联通
struct Edge{
    int u,v;
    Edge(int _u,int _v):u(_u),v(_v){}
}edge[maxn];
int dfn[maxn],low[maxn],bccno[maxn];
vector<int>gra[maxn],bcc[maxn];
bool isb[maxn];
void tarjan(int f,int u){
    dfn[u]=low[u]=++cnt;
    int sz=gra[u].size();
    for(int i=0;i<sz;i++){
        int id=gra[u][i];
        int v=edge[id].v;
        if(!dfn[v]){
            tarjan(u,v);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u]){
                isb[id]=isb[id^1]=1;
            }
        }else if(dfn[v]<dfn[u]&&v!=f){
            low[u]=min(low[u],dfn[v]);
        }
    }
}
void dfs(int u){
    dfn[u]=1;
    bccno[u]=bcnt;
    int sz=gra[u].size();
    for(int i=0;i<sz;i++){
        int id=gra[u][i];
        int v=edge[id].v;
        if(isb[id]){
            continue;
        }
        if(!dfn[v]){
            dfs(v);
        }
    }
}
int main(){
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            tarjan(-1,i);
        }
    }
    memset(dfn,0,sizeof(dfn));
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            bcnt++;
            dfs(i);
        }
    }
}

  

 

以上是关于双联通的tarjan算法的主要内容,如果未能解决你的问题,请参考以下文章

poj-3177(并查集+双联通分量+Tarjan算法)

Tarjan三大算法之双连通分量(双连通分量) (转载)

Tarjan算法及其应用

Tarjan系列1

Tarjan算法总结

[HDOJ4738]Caocao's Bridges(双联通分量,割边,tarjan)