剪网格博弈

Split Game

题目大意

现有一个 \(N*M\) 的网格纸,A 和 B 要用它玩一个游戏来确定谁更有发言权(和本题无关)。
游戏是这样的:两人轮流把网格纸撕成两部分,谁先撕出一个 \(1*1\) 的网格纸谁就被视为认输。
撕纸的过程中网格纸会越来越多,越来越混乱,而且两人都是绝顶聪明,现在请你判断一下谁能获胜。

输入描述

每组测试样例都有两个数组成,分别是 \(N,M\)

输出描述

对于每组样例输出最终的获胜者。

测试样例

输入

1 2
1 6
4 3
3 5

输出

Bob
Alice
Alice
Bob

思路:记忆化搜素 \(sg\) 函数
\(sg定理:\) 游戏和的 \(sg\) 函数等于每个游戏 \(sg\) 函数的 \(NIM\) 和。
游戏的 \(sg\) 函数等于 \(mex\{所有后继状态的游戏和的sg函数\}\)

#include<bits/stdc++.h>

using namespace std;

int sg[201][201];

int dfs(int x, int y) {
    if (x > y) swap(x, y);
    if (sg[x][y] != -1) return sg[x][y];
    set<int> s;
    for(int i = 1; i < x; ++ i) {
        if (y == 1 && (i == 1 || x-i == 1)) continue;
        s.insert(dfs(i, y) ^ dfs(x-i, y));
    }
    for(int i = 1; i < y; ++ i) {
        if (x == 1 && (i == 1 || y-i == 1)) continue;
        s.insert(dfs(x, i) ^ dfs(x, y-i));
    }
    int res = 0;
    while(s.count(res)) res ++;
    return sg[x][y] = res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    memset(sg, -1, sizeof sg);
    while(cin >> n >> m) {
        if (dfs(n, m)) cout << "Alice\n";
        else cout << "Bob\n";
    }
    return 0;
}

posted @ 2021-02-07 19:13  Daowuu  阅读(57)  评论(0编辑  收藏  举报