简单博弈论
Nim游戏
如果 \(a_1\) ^ \(a_2\) ^ \(a_3\) ^ \(\ldots\) ^ \(a_n\) = 0,则先手必败,否则必胜。
题意:n 堆石子,两位玩家可以从任意一堆中拿任意数量的石子,但是不能不拿,问先手是否必胜。
#include <bits/stdc++.h>
using namespace std;
const char nl = '\n';
//const int N =
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
int res = 0;
for (int i = 0, x; i < n; ++i){
cin >> x;
res ^= x;
}
if (res) cout << "YES" << nl;
else cout << "NO" << nl;
return 0;
}
SG 函数
\(sg(x_1)\) ^ \(sg(x_2)\) ^ \(sg(x_3)\) ^ \(\ldots\) ^ \(sg(x_n)\) = 0,则先手必败,否则必胜。
题意:给定 n 堆石子以及 m 个不同正整数构成的集合 S,两位玩家只能从任意一堆中拿指定数量的石子,该数量必须包含于 S 集合中,问先手是否必胜。
#include <bits/stdc++.h>
using namespace std;
const char nl = '\n';
const int N = 1e5 + 50;
int n, m;
int s[N], f[N];
int sg(int x){
if (f[x] != -1) return f[x];
unordered_set<int> S;
for (int i = 0; i < m; ++i){
if (x >= s[i]) S.insert(sg(x - s[i]));
}
for (int i = 0; ; ++i)
if (!S.count(i)) return f[x] = i;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> m;
for (int i = 0; i < m; ++i) cin >> s[i];
cin >> n;
memset(f, -1, sizeof(f));
int res = 0;
for (int i = 0, x; i < n; ++i){
cin >> x;
res ^= sg(x);
}
if (res) cout << "YES" << nl;
else cout << "NO" << nl;
return 0;
}