/* 题目意思是将连通的无向图转化为有向的强连通图。 显然,其中桥是必须来回都有,剩下就是将桥连接的连通图转化。 不含有桥的连通图必定是由多个圈组成(有公共边或无公共边)。 因此进行一次深搜并在遍历边时加上方向即为所求结果 在求桥的过程中输出所遍历的边时要注意回溯的边要输出,同时要 判断回溯的边所指是否为双亲,因为只有桥才需要输出来回。 */ #include <stdio.h> #include <string.h> #include <vector> #include <stack> using namespace std; vector<int>G[1005]; int index; int dfn[1005],low[1005],p[1005]; int map[1005][1005]; void tarjan(int x)//求桥过程中输出边 { int j; dfn[x] = low[x] = ++index; for(j=0; j<G[x].size(); j++) { if (p[x] == G[x][j])//回指双亲结点时continue continue; if (!dfn[G[x][j]]) { p[G[x][j]] = x; map[G[x][j]][x] = map[x][G[x][j]] = 1; tarjan(G[x][j]); if (low[G[x][j]] < low[x]) low[x] = low[G[x][j]]; if (low[G[x][j]] > dfn[x])//判断为桥的边输出来回 { printf("%d %d\n",x,G[x][j]); printf("%d %d\n",G[x][j],x); } else printf("%d %d\n",x,G[x][j]); } else { if (!map[x][G[x][j]] && !map[G[x][j]][x]) //判断这条边是否回指的边(桥已在前面判断,这里需要忽略), //是则不需要输出,否则输出边并记录 { printf("%d %d\n",x,G[x][j]); map[G[x][j]][x] = map[x][G[x][j]] = 1; } if (dfn[G[x][j]] < low[x]) low[x] = dfn[G[x][j]]; } } } int main(void) { int i,t,n,m,a,b; t = 1; while (scanf("%d%d",&n,&m)==2 && n+m) { for(i=1; i<=n; i++) G[i].clear(); while (m--) { scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } index = 0; p[1] = -1; printf("%d\n\n",t++); memset(dfn,0,sizeof(dfn)); memset(map,0,sizeof(map)); tarjan(1); printf("#\n"); } return 0; }
原文:http://www.cnblogs.com/toufu/p/3614929.html