无向图的边双连通分量和点双连通分量

 概念:

边双连通分量:不存在桥的无向图为边双连通图, 极大边双连通图为边双连通分量(以点存)

#include<bits/stdc++.h>
#define N 100010
using namespace std;
struct node{
    int v,nextt;
}e[N<<1];
//c[x]储存x所在的e-DCC的编号,dcc存e-DCC的数量
int head[N],tot=1,n,m,cnt,dfn[N],low[N],c[N],bridge[N],dcc;
void addedge(int u,int v){
    e[tot].v=v;
    e[tot].nextt=head[u];
    head[u]=tot++;
}
void tarjan(int u,int in_edge){//in_edge表示递归进入每个节点的边的编号 
    dfn[u]=low[u]=++cnt;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(!dfn[v]){
            tarjan(v,i);
            low[u]=min(low[u],low[v]);//在搜索树上的边
            if(low[v]>dfn[u])//桥判定法则
                bridge[i]=bridge[i^1]=1;//这条边和它的反向边都是桥
        }
        else if(i!=(in_edge^1))
            low[u]=min(low[u],dfn[v]);//不在搜索树上的边
    }
}//Tarjan标记桥
void dfs(int x){
    c[x]=dcc;//标号
    for(int i=head[x];~i;i=e[i].nextt){
        int v=e[i].v;
        if(c[v]||bridge[i])continue;//如果已经有标号了或者这条边是桥就不访问
        dfs(v);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);addedge(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i,0);
    for(int i=1;i<=n;i++){
        if(!c[i]){
            ++dcc;dfs(i);//每个联通块都进去标号
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d %d
",i,c[i]);
    return 0;
}
View Code

点双连通分量:不存在割点的无向图为点双连通图, 极大点双连通图为点双连通分量(以边存)

模板:

void tarjan(int x){
    dfn[x]=low[x]=++cnt;
    stk[++top]=x;//第一次访问该节点,入栈
    if(x==rt && head[x]==-1){//判断孤立点,直接插入vector
        dcc[++num].push_back(x);
        return;
    }
    int flag=0;
    for(int i=head[x];i;i=nxt(i)){
        int y=to(i);
        if(!dfn[y]){
            tarjan(y);
            low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x]){//割点判定法则
                flag++;
                if(x!=rt||flag>1)cut[x]=1;
                num++;int z;//根据上面描述的做法,把所有栈中的节点插入vector
                do{
                    z=stk[top--];
                    dcc[num].push_back(z);//全部插入
                }while(z!=y);
                dcc[num].push_back(x);//包括x自己
            }
        }else low[x]=min(low[x],dfn[y]);//不在搜索树上,继续更新low
    }
}
int main(){
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        addedge(x,y);addedge(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i);
    for(int i=1;i<=num;i++){
        printf("%d:",i);//第i个v-DCC
        for(int j=0;j<dcc[i].size();j++)
            printf(" %d",dcc[i][j]);//第i个v-DCC中所有的点
        putchar('
');
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/10964358.html