1. 程式人生 > >BZOJ2437 [Noi2011]兔兔與蛋蛋 【博弈論 + 二分圖匹配】

BZOJ2437 [Noi2011]兔兔與蛋蛋 【博弈論 + 二分圖匹配】

read cls www 判斷 ring get 必須 out AI

題目鏈接

BZOJ2437

題解

和JSOI2014很像
只不過這題動態刪點

如果我們把空位置看做\(X\)的話,就會發現我們走的路徑是一個\(OX\)交錯的路徑
然後將圖二分染色,當前點必勝,當且僅當當前點必須作為最大匹配的匹配點
移動相當於刪點,刪點的話只需打個標記即可
判斷當前點是不是必選,只需嘗試更改當前點匹配點的匹配點即可

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 1605,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int h[maxn],ne = 1;
struct EDGE{int to,nxt;}ed[maxm];
inline void build(int u,int v){
    ed[++ne] = (EDGE){v,h[u]}; h[u] = ne;
    ed[++ne] = (EDGE){u,h[v]}; h[v] = ne;
}
char s[45][45];
int X[4] = {0,0,-1,1},Y[4] = {-1,1,0,0};
int lk[maxn],vis[maxn],N,M,sx,sy,n;
int id[45][45],px[maxn],py[maxn],c[maxn],Out[maxn];
int win[maxn],ans[maxn],ansi;
int bd[maxn][maxn];
void dfs(int x,int y,int co){
    id[x][y] = ++n; px[n] = x; py[n] = y; c[n] = co;
    int nx,ny;
    for (int k = 0; k < 4; k++){
        nx = x + X[k];
        ny = y + Y[k];
        if (nx < 1 || ny < 1 || nx > N || ny > M || s[nx][ny] == s[x][y])
            continue;
        if (id[nx][ny]){
            if (!bd[id[nx][ny]][id[x][y]]) build(id[x][y],id[nx][ny]);
            bd[id[nx][ny]][id[x][y]] = bd[id[x][y]][id[nx][ny]] = true;
        }
        else {
            dfs(nx,ny,co ^ 1);
            if (!bd[id[nx][ny]][id[x][y]]) build(id[x][y],id[nx][ny]);
            bd[id[nx][ny]][id[x][y]] = bd[id[x][y]][id[nx][ny]] = true;
        }
    }
}
bool find(int u){
    Redge(u) if (!vis[to = ed[k].to] && !Out[to]){
        vis[to] = true;
        if (!lk[to] || find(lk[to])){
            lk[to] = u; lk[u] = to;
            return true;
        }
    }
    return false;
}
int main(){
    N = read(); M = read();
    REP(i,N) scanf("%s",s[i] + 1);
    REP(i,N) REP(j,M) if (s[i][j] == '.'){sx = i,sy = j,s[i][j] = 'X';break;}
    dfs(sx,sy,0);
    int K = read() << 1,x,y,nx = sx,ny = sy,u;
    REP(i,n) if (!c[i]) cls(vis),find(i);
    REP(i,K){
        cls(vis);
        x = read(); y = read();
        Out[u = id[nx][ny]] = true;
        if (lk[u]){
            win[i] = !find(lk[u]);
            if (win[i]) lk[lk[u]] = 0;
        }
        else win[i] = 0;
        lk[u] = 0;
        nx = x; ny = y;
    }
    win[K] = true;
    for (int i = 1; i <= K; i += 2)
        if (win[i] && win[i + 1]) ans[++ansi] = (i + 1) >> 1;
    printf("%d\n",ansi);
    REP(i,ansi) printf("%d\n",ans[i]);
    return 0;
}

BZOJ2437 [Noi2011]兔兔與蛋蛋 【博弈論 + 二分圖匹配】