//点双连通分量的求解
//就是通过tarjan算法求出关节点时,与关节点的子树就是一个连通分量,可以通过画图得到
//所以可以将与顶点u有关的边放到栈中,然后一但满足low[v]>=dfn[u](表面点u是割点)(注释:由于dfs,已经建好了u
//的子树,所以栈中有顶点u的子树),就可以进行退栈,直到遇到与u相关的边(由于dfs原因,之前的边都已经存入栈中
//所以第一个(u,v)边是最后一个退栈的,所以到其为止即可。)由于让访问过的边map[u][v]=map[v][u]=2,所以之前访问
//过的边不会再被访问。在dfs生成树图中能够很明显看出,就是关节点未被访问过的子树。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stack> 4 using namespace std; 5 int min(int x,int y) 6 { 7 return x<y?x:y; 8 } 9 10 int map[100][100],vis[100],dfn[100],depth,low[100],n,m; 11 void init() 12 { 13 int i,j; 14 memset(vis,0,sizeof(vis)); 15 vis[1]=1; 16 low[1]=dfn[1]=1; 17 depth=1; 18 } 19 struct edge 20 { 21 int x; 22 int y; 23 }; 24 stack<edge>s; 25 void dfs(int u) 26 { 27 int i,j; 28 for(i=1;i<=n;i++) 29 { 30 if(map[u][i]==1) 31 { 32 map[u][i]=map[i][u]=2;//标记为2使该边使用后不再被使用 33 edge t={u,i}; 34 s.push(t); 35 if(!vis[i]) 36 { 37 vis[i]=1; 38 depth++; 39 dfn[i]=low[i]=depth; 40 dfs(i); 41 low[u]=min(low[u],low[i]); 42 if(low[i]>=dfn[u]) 43 { 44 while(1)//不断退栈,直到遇到边(u,v) 45 { 46 edge temp; 47 temp=s.top(); 48 s.pop(); 49 printf("%d-%d ",temp.x,temp.y); 50 if((temp.x==u&&temp.y==i)||(temp.x==i&&temp.y==u)) 51 { 52 break; 53 } 54 } 55 printf(" "); 56 } 57 } 58 else low[u]=min(low[u],dfn[i]); 59 } 60 } 61 } 62 int main() 63 { 64 int i,j,v,u; 65 while(scanf("%d%d",&n,&m)!=EOF) 66 { 67 memset(map,0,sizeof(map)); 68 for(i=0;i<m;i++) 69 { 70 scanf("%d%d",&u,&v); 71 map[u][v]=map[v][u]=1; 72 } 73 init(); 74 dfs(1); 75 } 76 } 77 /* 78 7 9 79 1 2 80 1 3 81 1 6 82 1 7 83 2 3 84 2 4 85 2 5 86 4 5 87 6 7 88 */