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

通过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\n",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("\n");
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\n",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("\n");
87     }
88     return 0;
89 }