根据 李煜东大牛:图连通性若干拓展问题探讨 ppt学习。
有割点不一定有割边,有割边不一定有割点。
理解low[u]的定义很重要。
1.无向图求割点、点双联通分量:
如果对一条边(x,y),如果low[y]>=dfn[x],表示搜索树中y为根的子树必须要通过x才能到达树的上端,则x必为割点。
x属于多个点双联通分量,所以出栈的时候保留x(所以栈出到y就好!否则可能会把其他支路的节点一起出栈)。
附上一个小例子。
这个打个模板吧。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=1010; 8 int n,m,al,cnt,num,sl,dfn[N],low[N],vis[N],s[N],first[N],b[N][100]; 9 struct node{int x,y,next;}a[N*2]; 10 11 void ins(int x,int y) 12 { 13 a[++al].x=x;a[++al].y=y; 14 a[al].next=first[x];first[x]=al; 15 } 16 17 int minn(int x,int y){return x<y ? x:y;} 18 19 void tarjan(int x) 20 { 21 dfn[x]=low[x]=++num; 22 s[++sl]=x; 23 for(int i=first[x];i;i=a[i].next) 24 { 25 int y=a[i].y; 26 if(!dfn[y]) 27 { 28 tarjan(y); 29 low[x]=minn(low[x],low[y]); 30 if(low[y]>=dfn[x])//key 31 { 32 cnt++; 33 b[cnt][++b[cnt][0]]=x; 34 while(1) 35 { 36 int z=s[sl--]; 37 b[cnt][++b[cnt][0]]=z; 38 if(z==y) break; 39 } 40 } 41 } 42 else low[x]=minn(low[x],low[y]); 43 } 44 } 45 46 47 int main() 48 { 49 freopen("a.in","r",stdin); 50 scanf("%d%d",&n,&m); 51 al=0; 52 memset(first,0,sizeof(first)); 53 num=0;cnt=0;sl=0; 54 memset(dfn,0,sizeof(dfn)); 55 memset(vis,0,sizeof(vis)); 56 memset(b,0,sizeof(b)); 57 for(int i=1;i<=m;i++) 58 { 59 int x,y; 60 scanf("%d%d",&x,&y); 61 ins(x,y);ins(y,x); 62 } 63 for(int i=1;i<=n;i++) 64 if(!dfn[i]) tarjan(i); 65 for(int i=1;i<=cnt;i++) 66 { 67 for(int j=1;j<=b[i][0];j++) 68 printf("%d ",b[i][j]); 69 printf(" "); 70 } 71 return 0; 72 }
2.无向图求割边、边双联通分量:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=1010; 8 int n,m,al,cnt,num,sl,dfn[N],low[N],vis[N],s[N],first[N],b[N][100]; 9 struct node{int x,y,next,tmp;}a[N*2]; 10 11 void ins(int x,int y) 12 { 13 a[++al].x=x;a[al].y=y;a[al].tmp=0; 14 a[al].next=first[x];first[x]=al; 15 } 16 17 int minn(int x,int y){return x<y ? x:y;} 18 19 void tarjan(int x) 20 { 21 dfn[x]=low[x]=++num; 22 s[++sl]=x; 23 for(int i=first[x];i;i=a[i].next) 24 { 25 if(a[i].tmp) continue; 26 a[i].tmp=1; 27 a[(i%2)==0 ? i-1:i+1].tmp=1;//key 28 int y=a[i].y; 29 if(!dfn[y]) 30 { 31 tarjan(y); 32 low[x]=minn(low[x],low[y]); 33 if(low[y]>dfn[x])//key 34 { 35 cnt++; 36 while(1) 37 { 38 int z=s[sl--]; 39 b[cnt][++b[cnt][0]]=z; 40 if(z==y) break; 41 } 42 } 43 } 44 else low[x]=minn(low[x],low[y]);//前提:x->y不是搜索树上的边,故前面应该把走过的边的反向边去掉。 45 } 46 } 47 48 49 int main() 50 { 51 //freopen("a.in","r",stdin); 52 scanf("%d%d",&n,&m); 53 al=0; 54 memset(first,0,sizeof(first)); 55 num=0;cnt=0;sl=0; 56 memset(dfn,0,sizeof(dfn)); 57 memset(vis,0,sizeof(vis)); 58 memset(b,0,sizeof(b)); 59 for(int i=1;i<=m;i++) 60 { 61 int x,y; 62 scanf("%d%d",&x,&y); 63 ins(x,y);ins(y,x); 64 } 65 for(int i=1;i<=n;i++) 66 { 67 if(!dfn[i]) 68 { 69 tarjan(i); 70 if(sl) //key 71 { 72 cnt++; 73 b[cnt][0]=sl; 74 for(int j=1;j<=sl;j++) b[cnt][j]=s[j]; 75 sl=0; 76 } 77 } 78 } 79 for(int i=1;i<=cnt;i++) 80 { 81 for(int j=1;j<=b[i][0];j++) 82 printf("%d ",b[i][j]); 83 printf(" "); 84 } 85 return 0; 86 }