简单博弈论

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;
}

posted @ 2021-02-18 00:48  小燃、  阅读(56)  评论(0编辑  收藏  举报