Going from u to v or from v to u?
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 17761 Accepted: 4766
Description
In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors connecting some rooms. Each time, Wind choose two rooms x and y, and ask one of their little sons go from one to the other. The son can either go from x to y, or from y to x. Wind promised that her tasks are all possible, but she actually doesn’t know how to decide if a task is possible. To make her life easier, Jiajia decided to choose a cave in which every pair of rooms is a possible task. Given a cave, can you tell Jiajia whether Wind can randomly choose two rooms without worrying about anything?
Input
The first line contains a single integer T, the number of test cases. And followed T cases.
The first line for each case contains two integers n, m(0 < n < 1001,m < 6000), the number of rooms and corridors in the cave. The next m lines each contains two integers u and v, indicating that there is a corridor connecting room u and room v directly.
Output
The output should contain T lines. Write ‘Yes’ if the cave has the property stated above, or ‘No’ otherwise.
Sample Input
1
3 3
1 2
2 3
3 1
Sample Output
Yes
Source
POJ Monthly–2006.02.26,zgl & twb
#include<iostream>
#include<cstring>
#include<stack>
#include<cstdio>
using namespace std;
const int maxn = 1010 ;
const int maxm = 6010 ;
stack<int> st;
int chudu[maxn],rudu[maxn];
int head[maxn],link[maxn],tot1,tot2;
int belong[maxn],cur,dfn[maxn],low[maxn],visx;
bool exist[maxn];
struct Edge{ int from,to,next; }e[maxm],ee[maxm];
void PrePare(){
memset(link,0,sizeof link );
memset(head,0,sizeof head );
memset(rudu,0,sizeof rudu );
memset(chudu,0,sizeof chudu );
tot1=tot2=visx=cur=0;
memset(exist,0,sizeof exist );
memset(dfn,-1,sizeof dfn );memset(low,-1,sizeof low );
memset(belong,0,sizeof belong );
}
void Add_Edge(int u,int v){ e[++tot1].to=v;e[tot1].from=u;e[tot1].next=head[u];head[u]=tot1; }
void Add_Edgee(int u,int v){ ee[++tot2].to=v;e[tot2].next=link[u];link[u]=tot2; }
int n,m;
void Tarjan(int u){
dfn[u]=low[u]= ++visx;
exist[u]=true;st.push(u);
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(dfn[v]==-1){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(exist[v]&&low[u]>dfn[v]) low[u]=dfn[v];
}
int k;
if(low[u]==dfn[u]){
++cur;
do{
k=st.top();st.pop();exist[k]=false;
belong[k]=cur;
}while(k!=u);
}
}
bool Topo(){
int tp=0,maxt=0;
for(int i=1;i<=cur;i++){
if(rudu[i]==0){ tp++; }
if(chudu[i]>maxt)maxt=chudu[i];
}
if(tp>1)return 0;// 入度等于0的缩点只能有一个 否则..
if(maxt>1)return 0;
return 1;
}
int main(){
int T;cin>>T;
while(T--){
PrePare();
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
Add_Edge(u,v);
}
for(int i=1;i<=n;i++)
if(dfn[i]==-1) Tarjan(i);
for(int i=1;i<=tot1;i++){
int u=e[i].from,v=e[i].to;
if(belong[u]!=belong[v]){
Add_Edgee(belong[u],belong[v]);
rudu[belong[v]]++;chudu[belong[u]]++;
}
}
if(Topo()==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}