传送门:【ACdream】1403 Graph Game Andrew Stankevich Contest 21
题目分析:只有该点是二分匹配的关键点,少了这个点匹配数会减小,这个点是N,否则这个点是P。因为二分匹配的路径都是偶数的,如果删除这个点找不到增广路则说明这个点是关键点,从这个点出发的路径只能是偶数,则先手必胜。如果删除这个点能找到增广路则说明这个点不是关键点,从这个点出发的路径可以是奇数,则后手必胜。
我的代码找增广路的时候加了记忆化,跑了48ms。如果用非递归我感觉效果更加好一点?
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std ; typedef long long LL ; #define rep( i , a , b ) for ( int i = a ; i < b ; ++ i ) #define For( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define rev( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) const int MAXN = 505 ; const int MAXE = 100005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v ; Edge* next ; } E[MAXE] , *L[MAXN] , *R[MAXN] , *edge ; int Q[MAXE] , head , tail ; int Lx[MAXN] , Ly[MAXN] ; int dx[MAXN] , dy[MAXN] ; int vis[MAXN] , Time ; int ans[MAXN] ; int n1 , n2 , m ; int dis ; void clear () { edge = E ; clr ( L , 0 ) ; clr ( R , 0 ) ; } void addedge ( int u , int v , Edge* H[] ) { edge->v = v ; edge->next = H[u] ; H[u] = edge ++ ; } int Hopcroft_Krap () { dis = INF ; clr ( dx , -1 ) ; clr ( dy , -1 ) ; head = tail = 0 ; For ( i , 1 , n1 ) if ( Lx[i] == -1 ) { dx[i] = 0 ; Q[tail ++] = i ; } while ( head != tail ) { int u = Q[head ++] ; if ( dx[u] >= dis ) continue ; travel ( e , L , u ) { int v = e->v ; if ( dy[v] == -1 ) { dy[v] = dx[u] + 1 ; if ( ~Ly[v] ) { dx[Ly[v]] = dy[v] + 1 ; Q[tail ++] = Ly[v] ; } else dis = dy[v] ; } } } return dis != INF ; } int hungary ( int u ) { travel ( e , L , u ) { int v = e->v ; if ( vis[v] != Time && dy[v] == dx[u] + 1 ) { vis[v] = Time ; if ( ~Ly[v] && dy[v] == dis ) continue ; if ( Ly[v] == -1 || hungary ( Ly[v] ) ) { Ly[v] = u ; Lx[u] = v ; return 1 ; } } } return 0 ; } int match ( int ans = 0 ) { clr ( Lx , -1 ) ; clr ( Ly , -1 ) ; while ( Hopcroft_Krap () ) { ++ Time ; For ( i , 1 , n1 ) if ( Lx[i] == -1 ) ans += hungary ( i ) ; } return ans ; } int L_augment ( int u ) { vis[u] = Time ; travel ( e , L , u ) { int v = e->v ; if ( Ly[v] == -1 || ans[Ly[v]] == Time ) { ans[u] = Time ; return 1 ; } if ( vis[Ly[v]] == Time ) continue ; if ( L_augment ( Ly[v] ) ) { ans[u] = Time ; return 1 ; } } return 0 ; } int R_augment ( int u ) { vis[u] = Time ; travel ( e , R , u ) { int v = e->v ; if ( Lx[v] == -1 || ans[Lx[v]] == Time ) { ans[u] = Time ; return 1 ; } if ( vis[Lx[v]] == Time ) continue ; if ( R_augment ( Lx[v] ) ) { ans[u] = Time ; return 1 ; } } return 0 ; } void solve () { int u , v ; clear () ; rep ( i , 0 , m ) { scanf ( "%d%d" , &u , &v ) ; addedge ( u , v , L ) ; } match () ; For ( u , 1 , n1 ) travel ( e , L , u ) addedge ( e->v , u , R ) ; ++ Time ; For ( i , 1 , n1 ) { if ( Lx[i] == -1 || R_augment ( Lx[i] ) ) printf ( "P" ) ; else printf ( "N" ) ; } printf ( "\n" ) ; ++ Time ; For ( i , 1 , n2 ) { if ( Ly[i] == -1 || L_augment ( Ly[i] ) ) printf ( "P" ) ; else printf ( "N" ) ; } printf ( "\n" ) ; } int main () { clr ( vis , 0 ) ; Time = 0 ; while ( ~scanf ( "%d%d%d" , &n1 , &n2 , &m ) ) solve () ; return 0 ; }