Nim博弈与Anti-Nim博弈

Nim博弈的原题:

问题1:今有若干堆火柴,两人依次从中拿取,规定每次只能从一堆中取若干根, 可将一堆全取走,但不可不取,最后取完者为胜,求必胜的方法。 

定义:若所有火柴数异或为0,则该状态被称为利他态,用字母T表示;否则, 为利己态,用S表示。

注意:这篇博文是先定义s和t,再通过它们的性质推出结论。

[定理1]:对于任何一个S态,总能从一堆火柴中取出若干个使之成为T态。

证明:

若有n堆火柴,每堆火柴有A(i)根火柴数,那么既然现在处于S态, c = A(1) xor A(2) xor … xor A(n) > 0;

把c表示成二进制,记它的二进制数的最高位为第p位,则必然存在一个A(t),它二进制的第p位也是1。

(否则,若所有的A(i)的第p位都是0,这与c的第p位就也为0矛盾)。

那么我们把x = A(t) xor c,则得到x < A(t).这是因为既然A(t)的第p位与c的第p位同为1,那么x的第p位变为0,而高于p的位并没有改变。

所以x < A(t).而

A(1) xor A(2) xor … xor x xor … xor A(n)

= A(1) xor A(2) xor … xor A(t) xor c xor … xor A(n)

= A(1) xor A(2) xor… xor A(n) xor A(1) xor A(2) xor … xor A(n)

= 0

这就是说从A(t)堆中取出 A(t) - x 根火柴后状态就会从S态变为T态。证毕

[定理2]:T态,取任何一堆的若干根,都将成为S态。

证明:用反证法试试。

c = A(1) xor A(2) xor … xor A(i) xor … xor A(n) = 0;

c' = A(1) xor A(2) xor … xor A(i') xor … xor A(n) = 0;

则有:

c xor c' = A(1) xor A(2) xor … xor A(i) xor … xor A(n) xor A(1) xor A(2) xor … xor A(i')  xor … xor A(n) = A(i) xor A(i') =0

进而推出A(i) = A(i'),这与已知矛盾。所以命题得证。

[定理 3]:S态,只要方法正确,必赢。 

最终胜利即由S态转变为T态,任何一个S态,只要把它变为T态,(由定理1,可以把它变成T态。)对方只能把T态转变为S态(定理2)。这样,所有S态向T态的转变都可以有己方控制,对方只能被动地实现由T态转变为S态。因为全零属于T态,故S态必赢。(不能单单从对称拿取来考虑这个问题。例如a=b xor c,然后求sg这种情况。因为证不出来。。定理1只是说存在这种情况,并没有说对称拿取。)

[定理4]:T态,只要对方法正确,必败。 

 由定理3易得。 


反尼姆博弈

问题2:今有若干堆火柴,两人依次从中拿取,规定每次只能从一堆中取若干根, 可将一堆全取走,但不可不取,最后取完者为负,求必胜的方法。

定义:若一堆中仅有1根火柴,则被称为孤单堆。若大于1根,则称为充裕堆

定义:T态中,若充裕堆的堆数大于等于2,则称为完全利他态,用T2表示;若充裕堆的堆数等于0,则称为部分利他态,用T0表示。

孤单堆的根数异或只会影响二进制的最后一位,但充裕堆会影响高位(非最后一位)。一个充裕堆,高位必有一位不为0,则所有根数异或不为0。故不会是T态。

同上S表示异或和>0,T表示异或和为0

[定理5]:S0态,即仅有奇数个孤单堆,必败。T0态必胜。 

S0表示异或和>0且无充裕堆(只有孤单堆) => 因为孤单堆只会影响二进制的最后一位,

所以当异或和>0时说明仅有奇数个孤单堆 于是必败(比如有3个孤单堆,先手肯定把最后一个给拿走,先手必输。)

同理,T0表示异或和为0且无充裕堆 => 于是一定仅有偶数个孤单堆。(后手一定把最后一个给拿走,先手必胜。)

[定理6]:S1态,只要方法正确,必胜。 

S1态表示异或和>0,且有1个充裕堆。注:不存在T1态,因为有一个充裕堆的时候,其异或值一定不为0(充裕堆会影响高位)

有两个操作

1.当孤单堆为奇数的时候,先手只需要将唯一的充裕堆给全拿走。后手就进入了S0态。先手必胜!

2.当孤单堆为偶数的时候,先手只需要将唯一的充裕堆拿的只剩下一个。后手又进入里S0态。先手必胜!

[定理7]:S2态不可转一次变为T0态。 

充裕堆数量不可能一次从2个变成1个

[定理8]:S2态可一次转变为T2态。 

由定理1可证明S态一定可以通过某种操作变成T态。

又由定理7可以得知S2态不可能变成T0态,且不存在T1态,于是只能变成T2态。

[定理9]:T2态,只能转变为S2态或S1态。 

由定理7可以得知,2个充裕堆不可能一次变成0个

又由定理二可以得知T态通过任意的变化都要变成S态

于是T2态只能变成S2态或者S1态

[定理10]:S2态,只要方法正确,必胜. 

方法如下: 

 1)  S2态,就把它变为T2态。(由定理8) 

2)  对方只能T2转变成S2态或S1态(定理9)

 若转变为S2,  转向1) 

 若转变为S1,  这己必胜。(定理6) 

[定理11]:T2态必输。

证明同定理10

先手只能将T2变成S1或S2

1)S1态 后手胜!

2)S2态 后手将S2变成T2,先手重新选择。


所以:
必胜态:T0,S1,S2

必败态:S0,T2


比较2题

T0(第一题做法)。哪一方控制了S1态,他即可以有办法使自己得到最后一根(转变为 T0),

也可以使对方得到最后一根(转变为S0)。 

 所以,抢夺S1是制胜的关键! 

 为此,始终把T2态让给对方,将使对方处于被动状态,他早晚将把状态变为S1.



例题


HDU1907

反Nim博弈原题

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int caset;scanf("%d",&caset);
    while(caset--) {
        int cnt = 0,ans = 0;
        int n;scanf("%d",&n);
        for(int i=0,x;i<n;i++) {
            scanf("%d",&x);
            if(x > 1) cnt++;
            ans ^= x;
        }
        if(ans) {  /// S
            if(cnt == 0) printf("Brother\n"); /// S0
            else printf("John\n");            /// S1,S2
        }
        else {     /// T
            if(cnt == 0) printf("John\n");    /// T0
            else printf("Brother\n");         /// T2
        }
    }
    return 0;
}

HDU-2509

反尼姆博弈

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n)) {

        int cnt = 0,ans = 0;
        for(int i=0,x;i<n;i++) {
            scanf("%d",&x);
            if(x > 1) cnt++;
            ans ^= x;
        }
        if(ans) { /// S
            if(cnt == 0) printf("No\n"); /// S0
            else printf("Yes\n");        /// S1,S2
        }
        else {    /// T
            if(cnt == 0) printf("Yes\n");/// T0
            else printf("No\n");         /// T2
        }
    }
    return 0;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值