zoukankan      html  css  js  c++  java
  • 图论--无向图点双连通分量模板

    对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量,而点双联通分量之间是由割点隔开,割点就是如果删去这个点,原图的连通块数会增加,那么这个点就是割点。

    通过tarjan算法,我们可以用一次 dfs 标记出所有的割点以及所有双连通分量。

    注释版:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stack>
     4 #include<algorithm>
     5 #include<vector>
     6 using namespace std;
     7 
     8 const int maxn=1e5+5;
     9 const int maxm=1e5+5;
    10 
    11 int head[maxn],point[maxm],nxt[maxm],size;
    12 int n,t,bcccnt;                            
    13 //n点数,t是dfs的时间轴,bcccnt是双连通分量个数
    14 int stx[maxn],low[maxn],bcc[maxn],cut[maxn];    
    15 //stx是节点在dfs时间轴的位置,low是该点能够通过后继节点到达的最远祖先,bcc是某个点所属的双连通分量编号(割点的编号无效),cut是是否为割点
    16 vector<int>bccs[maxn];
    17 //双连通分量内的节点
    18 stack<int>S;
    19 
    20 void init(){
    21     memset(head,-1,sizeof(head));
    22     size=0;
    23 }
    24 
    25 void add(int a,int b){
    26     point[size]=b;
    27     nxt[size]=head[a];
    28     head[a]=size++;
    29     point[size]=a;
    30     nxt[size]=head[b];
    31     head[b]=size++;
    32 }
    33 
    34 void dfs(int s,int pre){
    35     stx[s]=low[s]=++t;        //记录点的时间轴标号,初始化能访问到的最远祖先节点是自己
    36     S.push(s);
    37     int son=0;                //为了判定根节点是否是割点
    38     for(int i=head[s];~i;i=nxt[i]){
    39         int j=point[i];
    40         if(!stx[j]){
    41             son++;
    42             dfs(j,s);
    43             low[s]=min(low[s],low[j]);    //用子节点的low值更新自己
    44             if(low[j]>=stx[s]){            //如果子节点最远只能访问自己或后继节点,则出现双连通分量
    45                 cut[s]=1;                //自己是割点
    46                 bcccnt++;
    47                 bccs[bcccnt].clear();
    48                 while(1){
    49                     int u=S.top();S.pop();
    50                     bcc[u]=bcccnt;
    51                     bccs[bcccnt].push_back(u);
    52                     if(u==j)break;
    53                 }
    54                 bcc[s]=bcccnt;
    55                 bccs[bcccnt].push_back(s);
    56             }
    57         }
    58         else if(j!=pre)low[s]=min(stx[j],low[s]);
    59     }
    60     if(pre==-1&&son==1)cut[s]=0;        //若根节点只有一个子节点,则不是割点
    61 }
    62 
    63 void setbcc(){
    64     memset(cut,0,sizeof(cut));
    65     memset(stx,0,sizeof(stx));
    66     memset(bcc,0,sizeof(bcc));
    67     t=bcccnt=0;
    68     for(int i=1;i<=n;++i)if(!stx[i])dfs(i,-1);
    69 }
    70 
    71 int main(){
    72     int m;
    73     scanf("%d%d",&n,&m);
    74     init();
    75     while(m--){
    76         int a,b;
    77         scanf("%d%d",&a,&b);
    78         add(a,b);
    79     }
    80     setbcc();
    81     for(int i=1;i<=n;++i){
    82         printf("%d:%d %d
    ",i,cut[i],bcc[i]);
    83     }
    84     for(int i=1;i<=bcccnt;++i){
    85         printf("%d:",i);
    86         for(int j=0;j<bccs[i].size();++j){
    87             printf("%d ",bccs[i][j]);
    88         }
    89         printf("
    ");
    90     }
    91     return 0;
    92 }

    无注释版:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<stack>
     4 #include<algorithm>
     5 #include<vector>
     6 using namespace std;
     7 
     8 const int maxn=1e5+5;
     9 const int maxm=1e5+5;
    10 
    11 int head[maxn],point[maxm],nxt[maxm],size;
    12 int n,t,bcccnt;
    13 int stx[maxn],low[maxn],bcc[maxn],cut[maxn];
    14 vector<int>bccs[maxn];
    15 stack<int>S;
    16 
    17 void init(){
    18     memset(head,-1,sizeof(head));
    19     size=0;
    20 }
    21 
    22 void add(int a,int b){
    23     point[size]=b;
    24     nxt[size]=head[a];
    25     head[a]=size++;
    26     point[size]=a;
    27     nxt[size]=head[b];
    28     head[b]=size++;
    29 }
    30 
    31 void dfs(int s,int pre){
    32     stx[s]=low[s]=++t;
    33     S.push(s);
    34     int son=0;
    35     for(int i=head[s];~i;i=nxt[i]){
    36         int j=point[i];
    37         if(!stx[j]){
    38             son++;
    39             dfs(j,s);
    40             low[s]=min(low[s],low[j]);
    41             if(low[j]>=stx[s]){
    42                 cut[s]=1;
    43                 bcccnt++;
    44                 bccs[bcccnt].clear();
    45                 while(1){
    46                     int u=S.top();S.pop();
    47                     bcc[u]=bcccnt;
    48                     bccs[bcccnt].push_back(u);
    49                     if(u==j)break;
    50                 }
    51                 bcc[s]=bcccnt;
    52                 bccs[bcccnt].push_back(s);
    53             }
    54         }
    55         else if(j!=pre)low[s]=min(stx[j],low[s]);
    56     }
    57     if(pre==-1&&son==1)cut[s]=0;
    58 }
    59 
    60 void setbcc(){
    61     memset(cut,0,sizeof(cut));
    62     memset(stx,0,sizeof(stx));
    63     memset(bcc,0,sizeof(bcc));
    64     t=bcccnt=0;
    65     for(int i=1;i<=n;++i)if(!stx[i])dfs(i,-1);
    66 }
    67 
    68 int main(){
    69     int m;
    70     scanf("%d%d",&n,&m);
    71     init();
    72     while(m--){
    73         int a,b;
    74         scanf("%d%d",&a,&b);
    75         add(a,b);
    76     }
    77     setbcc();
    78     for(int i=1;i<=n;++i){
    79         printf("%d:%d %d
    ",i,cut[i],bcc[i]);
    80     }
    81     for(int i=1;i<=bcccnt;++i){
    82         printf("%d:",i);
    83         for(int j=0;j<bccs[i].size();++j){
    84             printf("%d ",bccs[i][j]);
    85         }
    86         printf("
    ");
    87     }
    88     return 0;
    89 }
  • 相关阅读:
    css的em是根据什么来写的
    向一个对象数组里面添加新的属性 + 将一个对象数组数据拿出来变成另一个对象
    微信里iphone后退不刷新问题解决方案
    进到页面后input输入框自动获取焦点
    jquery checkbox反复调用attr('checked', true/false)只有第一次生效
    js promise中如何取到[[PromiseValue]]
    js 取得当天0点 / 23:59:59 时间
    jQuery获取包括当前元素的HTML
    C++ 实现 STL 标准库和算法(二)template 编程和迭代器粗解 实验楼笔记
    我现在怎么写博客笔记?
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4839738.html
Copyright © 2011-2022 走看看