Going from u to v or from v to u?
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 14052 | Accepted: 3676 |
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.
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
传送门:【POJ】2762 Going from u to v or from v to u?
题目大意:给你一副n个点的有向图,问是否能够任选两个点x、y使得x能到达y或者y能到达x。
题目分析:强连通缩点求点权最长路,如果最长路长度等于n则说明任选两点都能使得存在其中一个到达另一个。
代码如下:
传送门:【POJ】2762 Going from u to v or from v to u?
题目大意:给你一副n个点的有向图,问是否能够任选两个点x、y使得x能到达y或者y能到达x。
题目分析:强连通缩点求点权最长路,如果最长路长度等于n则说明任选两点都能使得存在其中一个到达另一个。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define clear( a , x ) memset ( a , x , sizeof a )
const int MAXN = 1005 ;
const int MAXE = 10000 ;
const int MAXQ = 10000 ;
const int INF = 0x3f3f3f3f ;
struct Edge {
int v , n ;
Edge ( int var = 0 , int next = 0 ) : v(var) , n(next) {}
} ;
struct SCC {
Edge edge[MAXE] ;
int adj[MAXN] , cntE ;
int Dfn[MAXN] , Low[MAXN] , dfs_clock ;
int scc[MAXN] , scc_cnt ;
int S[MAXN] , top ;
bool ins[MAXN] ;
void init () {
top = 0 ;
cntE = 0 ;
scc_cnt = 0 ;
dfs_clock = 0 ;
clear ( ins , 0 ) ;
clear ( Dfn , 0 ) ;
clear ( adj , -1 ) ;
}
void addedge ( int u , int v ) {
edge[cntE] = Edge ( v , adj[u] ) ;
adj[u] = cntE ++ ;
}
void Tarjan ( int u ) {
Dfn[u] = Low[u] = ++ dfs_clock ;
S[top ++] = u ;
ins[u] = 1 ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( !Dfn[v] ) {
Tarjan ( v ) ;
Low[u] = min ( Low[u] , Low[v] ) ;
}
else if ( ins[v] )
Low[u] = min ( Low[u] , Dfn[v] ) ;
}
if ( Low[u] == Dfn[u] ) {
++ scc_cnt ;
while ( 1 ) {
int v = S[-- top] ;
ins[v] = 0 ;
scc[v] = scc_cnt ;
if ( v == u )
break ;
}
}
}
void find_scc ( int n ) {
REPF ( i , 1 , n )
if ( !Dfn[i] )
Tarjan ( i ) ;
}
} ;
struct DAG {
Edge edge[MAXE] ;
int adj[MAXN] , cntE ;
int in[MAXN] ;
int d[MAXN] ;
int num[MAXN] ;
int Q[MAXQ] ;
int head , tail ;
void init () {
cntE = 0 ;
clear ( in , 0 ) ;
clear ( num , 0 ) ;
clear ( adj , -1 ) ;
}
void addedge ( int u , int v ) {
edge[cntE] = Edge ( v , adj[u] ) ;
adj[u] = cntE ++ ;
}
int topo ( int n , int tot ) {
head = tail = 0 ;
clear ( d , 0 ) ;
REPF ( i , 1 , n )
if ( !in[i] )
d[Q[tail ++] = i] = num[i] ;
while ( head != tail ) {
int u = Q[head ++] ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( d[v] < d[u] + num[v] )
d[v] = d[u] + num[v] ;
if ( 0 == ( -- in[v] ) )
Q[tail ++] = v ;
}
}
REPF ( i , 1 , n ) {
if ( d[i] == tot )
return 1 ;
}
return 0 ;
}
} ;
SCC C ;
DAG D ;
int read ( int &x ) {
x = 0 ;
char c = ' ' ;
while ( c < '0' || c > '9' )
c = getchar () ;
if ( c == -1 )
return 0 ;
while ( c >= '0' && c <= '9' ) {
x = x * 10 + c - '0' ;
c = getchar () ;
}
return 1 ;
}
void work () {
int n , m ;
int u , v ;
C.init () ;
read ( n ) , read ( m ) ;
//scanf ( "%d%d" , &n , &m ) ;
while ( m -- ) {
read ( u ) , read ( v ) ;
//scanf ( "%d%d" , &u , &v ) ;
C.addedge ( u , v ) ;
}
C.find_scc ( n ) ;
if ( C.scc_cnt == 1 ) {
printf ( "Yes\n" ) ;
return ;
}
D.init () ;
REPF ( u , 1 , n )
for ( int i = C.adj[u] ; ~i ; i = C.edge[i].n ) {
int v = C.edge[i].v ;
if ( C.scc[u] != C.scc[v] ) {
D.addedge ( C.scc[u] , C.scc[v] ) ;
++ D.in[C.scc[v]] ;
}
}
REPF ( i , 1 , n )
++ D.num[C.scc[i]] ;
if ( D.topo ( C.scc_cnt , n ) )
printf ( "Yes\n" ) ;
else
printf ( "No\n" ) ;
}
int main () {
int T ;
scanf ( "%d" , &T ) ;
while ( T -- )
work () ;
return 0 ;
}