思路
显然这是道博弈论 的题,而且是图上的。 我们可以在图上标记必胜点和必败点,显然终点是必败点,所有没有出边的点是必败点。 我们可以发现规律:能到必败点的一定是必胜点;只能到必胜点的是必败点 。 起点状态未知,终点状态已知,所以我们可以从已知的必败点开始按照拓扑序反向bfs
,判断每个点的状态。
代码1(我有点没搞明白)
# include <cstdio>
# include <queue>
# include <cstring>
# define ri register int
# define max ( a, b) a> b? a: b
using namespace std;
const int maxn= 1e5 + 21 ;
struct E {
int v, n;
} e[ 5 * maxn] ;
int head[ maxn] , cnt;
int o[ maxn] , in[ maxn] , out[ maxn] , f[ maxn] ;
int n, m, Q, s, t;
int read ( ) {
int x= 0 ; char c= getchar ( ) ;
while ( c> '9' || c< '0' ) c= getchar ( ) ;
while ( c>= '0' && c<= '9' ) x= ( x<< 3 ) + ( x<< 1 ) + c- 48 , c= getchar ( ) ;
return x;
}
void add ( int u, int v) {
e[ ++ cnt] . v= v;
e[ cnt] . n= head[ u] ;
head[ u] = cnt;
}
int a[ maxn] ;
queue< int > q;
void d ( int u) {
f[ u] = 1 ;
for ( ri i= head[ u] ; i; i= e[ i] . n) {
int v= e[ i] . v;
out[ v] -- ;
if ( ! out[ v] ) q. push ( v) ;
}
}
void bfs ( ) {
for ( ri i= 1 ; i<= n; ++ i) if ( ! out[ i] ) a[ i] = - 1 , q. push ( i) ;
a[ t] = - 1 , q. push ( t) ;
while ( q. size ( ) ) {
int u= q. front ( ) ; q. pop ( ) ;
if ( f[ u] ) continue ;
if ( a[ s] != 0 ) break ;
d ( u) ;
if ( a[ u] == - 1 ) {
for ( ri i= head[ u] ; i; i= e[ i] . n)
if ( ! a[ e[ i] . v] )
a[ e[ i] . v] = 1 , d ( e[ i] . v) ;
}
else if ( ! in[ u] ) a[ u] = - 1 ;
else {
a[ u] = - 1 ;
for ( ri i= head[ u] ; i; i= e[ i] . n)
if ( ! a[ e[ i] . v] ) a[ e[ i] . v] = 1 , d ( e[ i] . v) ;
}
}
while ( q. size ( ) ) q. pop ( ) ;
}
int main ( ) {
n= read ( ) , m= read ( ) , Q= read ( ) ;
for ( ri i= 1 ; i<= m; ++ i) {
int u= read ( ) , v= read ( ) ;
add ( v, u) ; o[ u] ++ , in[ v] ++ ;
}
while ( Q-- ) {
s= read ( ) , t= read ( ) ;
for ( ri i= 1 ; i<= n; ++ i) out[ i] = o[ i] ;
memset ( a, 0 , sizeof a) ;
memset ( f, 0 , sizeof f) ;
bfs ( ) ;
printf ( "%d\n" , a[ s] ) ;
}
return 0 ;
}
代码2(个人认为更易接受)
# include <cstdio>
# include <queue>
# define ri register int
# define max ( a, b) a> b? a: b
using namespace std;
const int maxn= 1e5 + 21 ;
struct E {
int v, n;
} e[ 5 * maxn] ;
int head[ maxn] , cnt;
int o[ maxn] , out[ maxn] ;
int n, m, q, s, t;
int read ( ) {
int x= 0 ; char c= getchar ( ) ;
while ( c> '9' || c< '0' ) c= getchar ( ) ;
while ( c>= '0' && c<= '9' ) x= ( x<< 3 ) + ( x<< 1 ) + c- 48 , c= getchar ( ) ;
return x;
}
void add ( int u, int v) {
e[ ++ cnt] . v= v;
e[ cnt] . n= head[ u] ;
head[ u] = cnt;
}
int a[ maxn] ;
void bfs ( ) {
queue< int > q;
for ( ri i= 1 ; i<= n; ++ i) if ( ! out[ i] || i== t) a[ i] = - 1 , q. push ( i) ;
while ( q. size ( ) )
{
int u= q. front ( ) ; q. pop ( ) ;
for ( ri i= head[ u] ; i; i= e[ i] . n)
{
int v= e[ i] . v;
if ( a[ v] != 0 ) continue ;
if ( a[ u] == - 1 ) a[ v] = 1 , q. push ( v) ;
if ( a[ u] == 1 )
{
out[ v] -- ;
if ( ! out[ v] ) q. push ( v) , a[ v] = - 1 ;
}
}
}
}
int main ( ) {
n= read ( ) , m= read ( ) , q= read ( ) ;
for ( ri i= 1 ; i<= m; ++ i)
{
int u= read ( ) , v= read ( ) ;
add ( v, u) ; o[ u] ++ ;
}
while ( q-- )
{
s= read ( ) , t= read ( ) ;
for ( ri i= 1 ; i<= n; ++ i) out[ i] = o[ i] , a[ i] = 0 ;
bfs ( ) ;
printf ( "%d\n" , a[ s] ) ;
}
return 0 ;
}