博弈论 Nim博弈 反Nim博弈 SG函数

Nim游戏 HDU1846

若各堆石子异或和为不为零,则先手胜 ,后手当且仅当异或和为零时取胜

此题问要想先手取胜第一步的取法,考虑到上述引理,只需遍历一遍石子找到异或和的最高位匹配的个数。

int a[105];

int main() {
    int m;
    while (scanf("%d", &m),m) {
        int cnt = 0;
        for (int i = 0; i < m; i++) scanf("%d", &a[i]);
        int nim = a[0];
        for (int i = 1; i < m; i++) nim ^= a[i];
        if (nim == 0) printf("0\n");
        else {
            int tmp = 0;
            while (nim) nim /= 2, tmp++;
            tmp--;
            for (int i = 0; i < m; i++) if (a[i] & (1 << tmp)) cnt++;
            printf("%d\n", cnt);
        }
    }
    return 0;
}
View Code

HDU 1848

在上题的基础上取法只许取斐波那契数列的大小

考虑SG函数模板

int f[50], sg[1005], mex[1005];
int getSG(int n) {
    sg[0] = 0;
    for (int i = 1; i <= n; i++) {
        memset(mex, 0, sizeof mex);
        for (int j = 1; f[j] <= i; j++) {
            mex[sg[i - f[j]]] = 1;
        }
        for (int j = 0;; j++) if (!mex[j]) {
            sg[i] = j;
            break;
        }
    }
    return sg[n];
}

int main() {
    int n, m, p;
    f[1] = 1, f[2] = 2;
    for (int i = 2; f[i] <= 1005; i++) {
        f[i+1] = f[i] + f[i - 1];
    }
    while (scanf("%d%d%d", &n, &m, &p),n||m||p) {
        if (getSG(n) ^ getSG(m) ^ getSG(p)) printf("Fibo\n");
        else printf("Nacci\n");
    }
    return 0;
}
View Code

HDU1907 

反Nim游戏,最后一步取的人败

先手必胜的情况有两种,只要是这两种情况之一就为先手必胜,

一:各堆石子数目异或结果不为零,且至少有一堆石子数目大于1

二:各堆石子数目异或结果为零,且所有堆石子数目均为1;

int a[50];

int main() {
    int T;
    int n;
    int ans;
    scanf("%d", &T);
    while (T--) {
        int rich = 0;
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &a[i]);
            if (a[i] > 1) rich++;
            if (!i) ans = a[i];
            else ans ^= a[i];
        }
        if (ans == 0 && rich == 0) printf("John\n");
        else if (ans && rich) printf("John\n");
        else printf("Brother\n");
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/hznumqf/p/12644132.html