【ZSTU4213 2015年12月浙理工校賽 D】【雙連通分量tarjan演算法】One-Way Roads 無向連通圖確定邊的方向使得全圖任意兩點間可達
4213: One-Way Roads
Time Limit:1 Sec Memory Limit:128 MB Special JudgeSubmit:133 Solved:45
Description
In the ACM kingdom, there areNcities connected byMtwo-way roads. These cities are connected, i.e., one can reach from any cityXto any other cityYby 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 containsT(0 ≤ T ≤ 100), the number of test cases. The first line of each test case consists of two integers,N(1 ≤ N ≤ 50), andM(1 ≤ M ≤ N(N − 1)/2). Each of the nextMlines describes a road, and consists of two integers,XandY,(1 ≤ X, Y ≤ N; X ≠ Y), indicating that there is a road between city
Output
For each test case, if it is impossible, output a single lineNO
. Otherwise, outputYES
on
the first line, followed byMlines describing one possible direction assignment to theseMroads.
Each of theseMlines should consist of two integers,
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)
*/