BZOJ1443-[JSOI2009]遊戲Game-博弈+二分圖必匹配點
阿新 • • 發佈:2018-11-11
寫在前面
並沒有什麼想說的,但是要保持格式=w=
題目
BZOJ1443傳送門
看題可戳傳送門
解法
其實和 BZOJ2463 思路差不多
在棋盤上走,不染個色就虧了對吧 =w=
(思路來著Menci)
那麼我們黑白染色一下,然後跑有效格子的最大匹配
假設我們一開始放在一個非匹配點上,那麼先手要麼就不能移動,要麼移動到一個匹配點上,而後手可以沿著匹配邊移動,這就是一個尋找增廣路的過程,因為是最大匹配,所以最後一定停在一開始的一側。所以我們可以知道,所有的非匹配點,如果作為起點,就是先手必敗的
如果一開始放在最大匹配上呢?先手沿匹配邊走,後手沿非匹配邊走。如果後手走到一個非匹配點,先手就輸了,而我們將這條路徑取反,就是另一個最大匹配。所以不一定在最大匹配中的點,作為起點就是先手必敗的
然後求不一定在最大匹配中的點,跑一遍Dinic之後,dfs打標記就好了
一些自己的思考:
在這個題裡面的先手必勝和必敗,都是對於 確定的局面 而言的
局面才是狀態,而棋子位置不是
下面是程式碼
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
bool inS[105*105] , Ppos[105*105] , vis[105*105] ;
char mp[105][105] ;
int N , M , tp = 1 , id[105][105 ] , id_c , head[105*105] , S , T , Ppos_cnt ;
struct Path{
int pre , to , flow ;
} p[105*105*6] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 , 1 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 , 0 } ; head[t2] = tp ;
}
void preWork(){
for( int i = 1 ; i <= N ; i ++ )
for ( int j = 1 ; j <= M ; j ++ ) if( id[i][j] && ( ( i + j )&1 ) ){
if( id[i+1][j] ) In( id[i][j] , id[i+1][j] ) ;
if( id[i-1][j] ) In( id[i][j] , id[i-1][j] ) ;
if( id[i][j+1] ) In( id[i][j] , id[i][j+1] ) ;
if( id[i][j-1] ) In( id[i][j] , id[i][j-1] ) ;
In( S , id[i][j] ) , inS[ id[i][j] ] = true ;
} else if( id[i][j] ) In( id[i][j] , T ) ;
}
int dis[105*105] , que[105*105] , fr , ba ;
bool BFS(){
memset( dis , -1 , sizeof( dis ) ) ;
fr = 1 , que[ ba = 1 ] = S , dis[S] = 0 ;
while( ba >= fr ){
int u = que[fr++] ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( dis[v] != -1 || !p[i].flow ) continue ;
dis[v] = dis[u] + 1 , que[++ba] = v ;
}
} return dis[T] != -1 ;
}
int dfs_dinic( int u , int flow ){
if( u == T ) return flow ;
int rt = 0 ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to , nowf ;
if( dis[v] != dis[u] + 1 || !p[i].flow ) continue ;
if( ( nowf = dfs_dinic( v , min( flow , p[i].flow ) ) ) ){
p[i].flow -= nowf ;
p[i^1].flow += nowf ;
flow -= nowf , rt += nowf ;
if( !flow ) break ;
}
} if( flow ) dis[u] = -1 ;
return rt ;
}
void dfs_solve( int u , int ef , bool sid ){
vis[u] = true ;
if( inS[u] == sid ) Ppos[u] = true , Ppos_cnt ++ ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( p[i].flow == ef && !vis[v] ) dfs_solve( v , ef , sid ) ;
}
}
void solve(){
while( BFS() ) dfs_dinic( S , 0x3f3f3f3f ) ;
dfs_solve( S , 1 , true ) ;
memset( vis , false , sizeof( vis ) ) ;
dfs_solve( T , 0 , 0 ) ;
puts( Ppos_cnt ? "WIN" : "LOSE" ) ;
for( int i = 1 ; i <= N ; i ++ )
for( int j = 1 ; j <= M ; j ++ )
if( Ppos[ id[i][j] ] ) printf( "%d %d\n" , i , j ) ;
}
int main(){
scanf( "%d%d" , &N , &M ) ;
for( int i = 1 ; i <= N ; i ++ ){
scanf( "%s" , mp[i] + 1 ) ;
for( int j = 1 ; j <= M ; j ++ )
if( mp[i][j] != '#' ) id[i][j] = ++id_c ;
} S = ++id_c , T = ++id_c ;
preWork() ; solve() ;
}