对于一个无向图,如果一个点集,它内部的任意一个点对之间,至少有两条点完全不重复的路径,那么这个点集就是原图的一个点双连通分量,而点双联通分量之间是由割点隔开,割点就是如果删去这个点,原图的连通块数会增加,那么这个点就是割点。
通过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 }
时间: 2024-08-04 03:16:30