剪网格博弈
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;
}