Anti-Nim博弈原理与证明

简介

Anti-Nim博弈是Nim博弈的变形,它的定义是:

给定 \(n\) 堆物品,第 \(i\) 堆物品有 \(A_i\) 个,两人轮流取,每次可以任选一堆取走任意多个物品,可以取光但不能不取,最后把物品全部取完者失败

判断先手是否有必胜策略

推理

先手必胜当且仅当:

  1. 每堆的物品数都为 \(1\) 且Nim和为 \(0\)
  2. 有些堆的物品数大于 \(1\) 且Nim和不为 \(0\)

证明:

第一种情况:每堆物品数都为 \(1\) 且Nim和为 \(0\) ,那么 \(n\) 为偶数,易知先手必胜

第二种情况:

  • 若Nim和不为 \(0\)

    • 若至少还有两堆物品数大于 \(1\) ,那先手一定可以将局势变为至少有一堆物品数大于 \(1\) 且Nim和为 \(0\)

    • 若只有一堆物品数大于 \(1\) ,则先手一定可以将局势变为有奇数个 \(1\)

  • 若Nim和为 \(0\)

    至少有两堆物品数大于 \(1\) ,则先手决策完之后,必定至少有一堆物品数大于 \(1\) 且Nim和不为 \(0\) ,由上段的论证我们可以发现, 此时,无论先手如何决策,都只会将游戏带入先手必胜局,所以先手必败

例题

Luogu 4279

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int t, n, a, res, maxx;
    scanf("%d", &t);
    while(t--) {
        maxx = res = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a);
            res = res ^ a;
            maxx = max(maxx, a);
        }
        if(maxx == 1)
            printf("%s\n", res == 0 ? "John" : "Brother");
        else
            printf("%s\n", res ? "John" : "Brother");
    }
    return 0;
}
上一篇:javascript中字符串常用操作总结、JS字符串操作大全


下一篇:[AcWing] 892. 台阶-Nim游戏 (C++实现)博弈论Nim游戏例题