4213: One-Way Roads
Time Limit: 1 Sec
Memory Limit: 128 MB
Special Judge
Submit: 133
Solved: 45
Description
In the ACM kingdom, there are N cities connected by M two-way roads. These cities are connected, i.e., one can reach from any city X to any other city Y by going through some of these roads. One day, the government wishes to assign for each road a direction, such that one can still reach from any city to any other. You are asked to determine whether this task is possible.
Input
The first line of input contains T(0 ≤ T ≤ 100), the number of test cases. The first line of each test case consists of two integers, N(1 ≤ N ≤ 50), and M(1 ≤ M ≤ N(N − 1)/2). Each of the next M lines describes a road, and consists of two integers, X and Y, (1 ≤ X, Y ≤ N; X ≠ Y), indicating that there is a road between city X and Y. There is at most one road that directly connects each pair of cities.
Output
For each test case, if it is impossible, output a single line NO
. Otherwise, output YES
on the first line, followed by M lines describing one possible direction assignment to these M roads. Each of these M lines should consist of two integers, X, Y, indicating that there is a one-way road from city X to city Y. These Mlines can be output in any order.
Sample Input
3
3 3
1 2
2 3
1 3
4 3
1 2
1 3
1 4
4 5
1 2
2 3
4 3
1 4
2 4
Sample Output
YES
1 2
2 3
3 1
NO
YES
1 2
2 3
3 4
4 1
2 4
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=60,M=3600,Z=1e9+7,ms63=0x3f3f3f3f;
int casenum,casei;
int n,m,x,y;
int id,tim,top,color,g;
int first[N],s[N],low[N],dfn[N];bool e[N];
int w[M],nxt[M];pair<int,int>ans[M];
void ins(int x,int y)
{
++id;
w[id]=y;
nxt[id]=first[x];
first[x]=id;
}
void tarjan(int x,int lastz)
{
low[x]=dfn[x]=++tim;
s[++top]=x;e[x]=1;
for(int z=first[x];z;z=nxt[z])
{
if((z^lastz)==1)continue;
int y=w[z];
if(dfn[y]==0)
{
ans[++g]=make_pair(x,y);
tarjan(y,z);
}
if(e[y])
{
if(dfn[y]<dfn[x])ans[++g]=make_pair(x,y);
gmin(low[x],low[y]);
}
}
if(dfn[x]==low[x])
{
if(++color>1)return;
while(1)
{
int y=s[top--];
e[y]=0;
if(y==x)break;
}
}
return;
}
int main()
{
scanf("%d",&casenum);
for(casei=1;casei<=casenum;++casei)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
dfn[i]=low[i]=0;
first[i]=0;
e[i]=0;
}
id=1;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&x,&y);
ins(x,y);
ins(y,x);
}
tim=top=color=g=0;
tarjan(1,0);
if(color==1)
{
puts("YES");
for(int i=1;i<=g;++i)printf("%d %d\n",ans[i].first,ans[i].second);
}
else puts("NO");
}
return 0;
}
/*
【题意】
比赛的时候要是有spj,这道题就1A了,这场比赛是大概能够AK的。唉= =
给你一个联通无向图,让你使得每一条边有向化,
问你可否在这个基础上,使得图上的任意两点间都存在一条可达路径。
【类型】
双连通分量
【分析】
这题只要判定图中是否存在一个极大(包含图上所有点)双连通分量即可。
于是我们直接套上可以解决双连通分量的tarjan算法。
从父节点连向子节点的边,我们不再次处理(否则就出错了),
其他所有边的方向,只要顺着dfs的方向连就好啦!
然后看看是否双连通分量只有一个。如果是,输出YES和具体的连边方案就好啦。
注意,一条边只能连一次。
我们是可能从一个时间戳较大的点,走到一个时间戳较小的点的。
而这条边也恰恰需要从这个时间戳较大的点,指向时间戳较小的点。
然而,这是深搜,我们可能后来还会走回那个时间戳较小的点,这时要注意,不要再把边的连向搞反了。
换句话说,我们连边的原则是——
1,连向一个新的点时,方向是指向新的点的。
2,放弃返祖边。
3,两个点都不是新点时,方向是指向旧的点(时间戳小的点)。
【时间复杂度&&优化】
O(n)
*/