1. 程式人生 > >BZOJ1443-[JSOI2009]遊戲Game-博弈+二分圖必匹配點

BZOJ1443-[JSOI2009]遊戲Game-博弈+二分圖必匹配點

寫在前面

並沒有什麼想說的,但是要保持格式=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() ; }