[DFS树] Codeforces 118E Bertown roads
题目大意
给定一个 \(n\) 个点 \(m\) 条边的无向连通图,给每条边定向,使得生成的有向图是强连通图,若不可能,输出0。\(2\leq n\leq 10^5,n-1\leq m\leq 3\times 10^5\)。
题解
如果原图有桥,显然给每条边定向后不可能强连通。考虑原图的DFS树,不妨令所有树边组成一棵外向树,这样从根节点出发可以到达图中的所有顶点。然后令所有非树边为后向边,那么任意结点都可以回到根节点,因为对于任意非根节点 \(u\),因为图中没有桥,一定存在一条非树边跨越连接 \(u\) 和它父亲的这条边,我们可以通过这条非树边到达 \(u\) 的祖先,如此重复操作就能到达根节点。因此,这样给边定向后得到的有向图是强连通图。
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType &T){
elemType X=0,w=0; char ch=0;
while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
T=(w?-X:X);
}
struct Graph{
struct edge{int Next,to,w;};
edge G[600010];
int head[100010];
int cnt;
Graph():cnt(2){}
void clear(int node_num=0){
cnt=2;
if(node_num==0) memset(head,0,sizeof(head));
else fill(head,head+node_num+5,0);
}
void add_edge(int u,int v,int w){
G[cnt].w=w;
G[cnt].to=v;
G[cnt].Next=head[u];
head[u]=cnt++;
}
};
struct Edge{int u,v;};
Edge E[300010];
Graph G;
int DFN[100010],dp[100010];
bool vis[100010];
int N,M,Index=0;
bool flag;
void DFS(int u,int fa,int id){
vis[u]=true;DFN[u]=++Index;dp[u]=0;
for(int i=G.head[u];i;i=G.G[i].Next){
int v=G.G[i].to;
int x=G.G[i].w;
if(!vis[v]){DFS(v,u,G.G[i].w);dp[u]+=dp[v];E[x].u=u;E[x].v=v;}
else if(v!=fa || (v==fa && id!=G.G[i].w)){
if(DFN[v]<DFN[u]){++dp[u];E[x].u=u;E[x].v=v;}
else{--dp[u];E[x].u=v;E[x].v=u;}
}
}
if(dp[u]==0 && fa!=0) flag=true;
return;
}
int main(){
Read(N);Read(M);
for(RG i=1;i<=M;++i){
int u,v;
Read(u);Read(v);
G.add_edge(u,v,i);
G.add_edge(v,u,i);
E[i].u=u;E[i].v=v;
}
DFS(1,0,0);
if(flag){printf("0\n");return 0;}
for(RG i=1;i<=M;++i)
printf("%d %d\n",E[i].u,E[i].v);
return 0;
}