Description
Input
Output
Sample Input
7 10 1 2 1 3 2 4 3 4 4 5 4 6 5 7 6 7 2 5 3 6 7 9 1 2 1 3 1 4 2 4 3 4 4 5 5 6 5 7 7 6 0 0
Sample Output
1 1 2 2 4 3 1 3 6 4 3 5 2 5 4 6 4 6 7 7 5 # 2 1 2 2 4 3 1 4 1 4 3 4 5 5 4 5 6 6 7 7 5 #
题意大概是说把一个无向图转化为有向图,需要取出一些边,(双向变成单向),得到一个有向强连通图,显然,桥不能修改,加个标记就行了。代码如下:
/**************************** * author:crazy_石头 * date:2014/01/18 * algorithm:tarjan * Pro:亲友团训练-图论1-B ***************************/ #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> #include <map> #include <string> using namespace std; #define INF 1<<29 #define eps 1e-8 #define A system("pause") #define rep(i,h,n) for(int i=(h);i<=(n);i++) #define ms(a,b) memset((a),(b),sizeof(a)) const int maxn=200020; const int maxm=20; struct edge { int from,to,next; int iscut; }e[maxn<<1]; int head[maxn],dfn[maxn],low[maxn],instack[maxn],cnt,index,n,m; inline void addedge(int u,int v) { e[cnt].from=u; e[cnt].to=v; e[cnt].next=head[u]; e[cnt].iscut=-1; head[u]=cnt++; } inline void tarjan(int u,int f) { low[u]=dfn[u]=++index; instack[u]=true; for(int i=head[u];~i;i=e[i].next) { int v=e[i].to; if(v==f) continue; if(e[i].iscut!=-1)continue;//不为-1说明该边已经修改过了; e[i].iscut=1;//修改正向边,去掉反向边; e[i^1].iscut=0; if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>dfn[u])//是桥的条件,则正反向边均可通过,桥是不能修改的; { e[i].iscut=1; e[i^1].iscut=1; } } else if(instack[v]) low[u]=min(low[u],dfn[v]); } } inline void init() { ms(head,-1),cnt=0; } inline void gao() { index=0; ms(low,0),ms(dfn,0),ms(instack,0); rep(i,1,n) if(!dfn[i]) tarjan(i,-1); } inline void solve() { rep(i,0,cnt-1) if(e[i].iscut==1)printf("%d %d\n",e[i].from,e[i].to); } int main() { int test=1; while(~scanf("%d%d",&n,&m),n||m) { init(); while(m--) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } gao(); printf("%d\n\n",test++); solve(); printf("#\n"); } return 0; }