这题做的好艰辛。。
先说题意:
给n个点 m条边 m条边中有单向边或双向边。题目保证给定的边一定构成一个连通图。
现在要求 尽可能多的重定向双向边为单向边。使图最后的结果为强连通图。输出所有双向边的情况(定向或者没定向的都要输出)
思路:
1.首先看哪些边一定不能重定向(就是原样输出的那些无向边)。先把所有的边看成无向边,求桥(tarjan)。把这些桥原样输出(这些桥一定是无向边,题目保证了图是连通的)(为什么桥不能重定向。因为重定向后图就不连通了)。
2.这些桥把许多个连通块连通起来。我们删掉这些桥。对这些连通块内部的无向边进行重定向
3.重定向边。参考tarjan算法。建立一颗dfs树。
1)如果无向边是树边。
如果u能到达u的祖先,也就是dfn[u]>=low[u],说明这条边是正确的 直接输出 u v 1。
如果u不能到达u的祖先,dfn[u]<low[u],说明这条边需要反向 输出 v u 1
2)如果无向边是回边。
说明方向是对的,因为借助这条边可以回到祖先。直接输出u v 1
这题做的好艰辛。。vector建图MLE 邻接矩阵建图MLE 邻接表才是真爱。AC
//author: CHC //First Edit Time: 2014-07-06 14:29 //Last Edit Time: 2014-07-06 14:29 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <map> #include <queue> #include <set> #include <algorithm> using namespace std; #define MAXN 2001 #define MAXM 2000000 int head[MAXN]; int tot; struct Edge { int to,next; }edge[MAXM]; void init(){ tot=0; for(int i=0;i<MAXN;i++)head[i]=-1; } void Add_edge(int u,int v) { edge[tot].next=head[u]; edge[tot].to=v; head[u]=tot; ++tot; } int dfn[MAXN],low[MAXN],pre[MAXN],n,m; int times=0,top; char flag[MAXN][MAXN]; void tarjan_3(int u){ dfn[u]=low[u]=++times; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ pre[v]=u; tarjan_3(v); low[u]=min(low[u],low[v]); } else if(pre[u]!=v) low[u]=min(low[u],dfn[v]); } } void solve(){ times=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(pre,0,sizeof(pre)); tarjan_3(1); for(int i=1;i<=n;i++){ if(pre[i]>0&&dfn[pre[i]]<low[i]){ printf("%d %d %d\n",pre[i],i,2); flag[pre[i]][i]=flag[i][pre[i]]=3; } } //puts(""); top=times=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(pre,0,sizeof(pre)); void tarjan(int ); for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); /* puts(""); for(int i=1;i<=n;i++) printf("%d ",dfn[i]); puts(""); for(int i=1;i<=n;i++) printf("%d ",low[i]); puts(""); */ } void tarjan(int u){ dfn[u]=low[u]=++times; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(flag[u][v]==3)continue; if(!dfn[v]){ pre[v]=u; tarjan(v); low[u]=min(low[u],low[v]); if(flag[u][v]==2){ if(dfn[u]>=low[u]){ printf("%d %d %d\n",u,v,1); flag[v][u]=0; } else { printf("%d %d %d\n",v,u,1); flag[u][v]=0; } } } else if(pre[u]!=v) { if(flag[v][u]==2)printf("%d %d %d\n",u,v,1); flag[u][v]=0; low[u]=min(low[u],dfn[v]); } } } int main() { while(~scanf("%d%d",&n,&m)){ init(); memset(flag,0,sizeof(flag)); for(int i=0;i<m;i++){ int x,y; int val; scanf("%d%d%d",&x,&y,&val); if(val==1){ Add_edge(x,y); Add_edge(y,x); flag[x][y]=1; flag[y][x]=3; } else { Add_edge(x,y); Add_edge(y,x); flag[x][y]=flag[y][x]=2; } } solve(); } return 0; } /* 5 5 1 3 2 1 2 2 2 5 2 4 5 1 3 4 2 5 5 1 2 2 1 3 2 2 5 2 4 5 1 3 4 2 */