zoukankan      html  css  js  c++  java
  • 无向图的边双连通分量和点双连通分量

     概念:

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

    #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
  • 相关阅读:
    02-最简C语言程序
    Go学习笔记-GO编程语言手册
    Go学习笔记-Effective Go
    go学习笔记-语法
    机器学习-数据挖掘
    windows下jupyter notebook的安装及配置
    wpf学习笔记
    windows下安装mingW及控制台启用
    nginx
    MFC学习笔记
  • 原文地址:https://www.cnblogs.com/starve/p/10964358.html
Copyright © 2011-2022 走看看