P1971 [NOI2011] 兔兔与蛋蛋游戏

· · 题解

首先,棋子的颜色分黑和白,是一个标准的二分图形式。

其次,我们对操作进行观察,易得出:一个空位到过的位置之后不会再走了(考虑操作步骤的奇偶性以及棋子的颜色)。

于是我们大胆想象:移动棋子等价于移动空格,既然一个空格走了就不会再回到原来的位置,那么只需要把一个位置看成一个点(空格为初始位置),问题就可以转化为二分图博弈的形式。

以下关于二分图博弈模板的内容摘自我的文章:

#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
const int N = 2010, M = 45;
int n, m, ans, k, s, vis[N], match[N], b[N], w[N];
int f[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
char c[M][M]; vector<int> e[N];
int id(int x, int y){return (x - 1) * m + y;}
int dfs(int u){
    for(int &v: e[u]){
        if(vis[v] || b[v]) continue; vis[v] = 1;
        if(!match[v] || dfs(match[v])){match[match[u] = v] = u; return 1;}
    }
    return 0;
}
int main(){
    scanf("%d%d", &n, &m);
    FL(i, 1, n) scanf("%s", c[i] + 1);
    FL(i, 1, n) FL(j, 1, m){
        if(c[i][j] == '.') s = id(i, j), c[i][j] = 'X';
        FL(l, 0, 3){
            int x = i + f[l][0], y = j + f[l][1];
            if(x < 1 || x > n || y < 1 || y > m || c[i][j] == c[x][y]) continue;
            e[id(i, j)].emplace_back(id(x, y));
        }
    }
    FL(i, 1, n) FL(j, 1, m) if(c[i][j] == 'X')
        memset(vis, 0, sizeof(vis)), dfs(id(i, j));
    scanf("%d", &k), b[s] = 1;
    FL(i, 1, k + k){
        if(match[s]){
            int u = match[s]; match[s] = match[u] = 0;
            memset(vis, 0, sizeof(vis)), w[i] = !dfs(u);
        }
        int x, y; scanf("%d%d", &x, &y);
        b[s = id(x, y)] = 1;
    }
    FL(i, 1, k) ans += (w[i + i] && w[i + i - 1]);
    printf("%d\n", ans);
    FL(i, 1, k) if(w[i + i] && w[i + i - 1]) printf("%d\n", i);
    return 0;
}