Nim游戏初探

本文介绍了Nim游戏的玩法和获胜策略,强调了在每堆硬币数量转换为二进制后,通过异或操作判断游戏平衡性的关键。当所有堆的硬币数量异或结果为0时,先手玩家(1号)必败;否则,先手玩家(1号)有获胜机会。给出的C++代码示例展示了如何根据异或结果判断游戏胜负。

规则介绍

  • Nim游戏是一种两个人玩的游戏,玩家双方面对一堆硬币(或者石头或者豆粒)。假设有 k ≥ 1 k\geq 1 k1堆硬币,每堆分别有 n 1 , n 2 , n 3 . . . n k n_1,n_2,n_3...n_k n1,n2,n3...nk枚硬币,游戏的目标是取得最后一枚硬币。游戏规则如下
    (1)玩家轮番出场第一个取子的玩家称为1号,第二个玩家称为二号
    (2)当轮到一个玩家取子时,他们都要从选择的硬币堆中至少取走一枚硬币,也就是说拿哪一堆都可以,可以把这一堆硬币都拿走
    当硬币都拿完的时候游戏结束,最后一个拿的玩家获胜
  • 现在给定硬币堆数 k k k和每堆硬币数量分别为 n 1 , n 2 . . . n k n_1,n_2...n_k n1,n2...nk,假设每步两人都选择最优方案,问1号赢还是2号赢

思路

我们可以考虑最简单的情况

  1. 只有一堆硬币,此时1号玩家只需要全部拿走即可,1号获胜
  2. 有两堆硬币,设数量分别为 n 1 n_1 n1 n 2 n_2 n2,如果 n 1 = n 2 n_1=n_2 n1=n2,假如说1号随便拿,如果我是2号,那么无论1号从哪一堆里面拿多少,我都从另外一堆里面拿走相同数量的硬币,这样我肯定是赢家;那如果 n 1 ≠ n 2 n_1\neq n_2 n1=n2呢?假如 n 1 > n 2 n_1\gt n2 n1>n2,如果我是一号,我要从第一堆里面拿走 n 1 − n 2 n_1-n_2 n1n2个,这样两堆又一样了,相当于刚才 n 1 = n 2 n_1=n_2 n1=n2的情况先手变后手,所以我一定获胜
  3. 经过前两个分析,能够感觉到如果堆数之间是平衡的那么1号必败,那么怎么能够得出一般性结论呢?

可以这样考虑

  • 将每堆硬币数量转换成一个二进制数,比如三堆硬币数量分别为3,5,8,那么转换为二进制数则分别为
    0011 0101 1000 0011\\0101\\1000 001101011000
  • 我们把每一位分开来看,某一位加一起如果是偶数那么就说这一位是平衡的,如果所有位都是平衡的那么就说这个游戏是平衡的,对于一个平衡的Nim游戏,1号玩家总是失败的,2号玩家总能胜利,因为1号玩家必定使得一个平衡游戏变得不平衡,2号玩家必定能使得1号玩家的不平衡游戏变得平衡
  • 用上面这个例子来说明,现在游戏显然是不平衡的,那么1号玩家可以对第三堆进行操作变成下面的情况
    0011 0101 0110 0011\\0101\\0110 001101010110
  • 现在就平衡了,那么2号玩家不管怎么拿,必然使得这个变得不平衡,这样继续拿下去,因为0是平衡的,所以最后拿的一定是1号玩家,也就是说1号玩家必然胜利,那么可以对所有堆的硬币数量进行异或操作,根据异或同出0,异出1的运算法则,如果游戏是平衡的,必然有异或最终结果为0,根据这个思路,可以解决这个问题,具体看下面的例题

例题

Nim模板题

  • 如果异或最终结果为0,那么1号失败,否则2号失败
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 100;
const double eps = 1e-6;
int Data[MAXN];
int main(){
    int n, t, x;
    cin >> t;
    while(t--){
        cin >> n;
        cin >> x;
        for(int i=1;i<n;i++){
            cin >> Data[i];
            x ^= Data[i];
        }
        if(x == 0){
            cout << "No" << "\n";
        }else cout << "Yes" << "\n";
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值