Nim游戏·改(博弈论)

Nim游戏·改(nim.c/cpp/pas)

8.28
思路:
对于一个平等博弈局面X,若它走下一步能达状态集合Y,则:
SG(X) = mex (SG(t)) t∈Y
其中mex(S)为最小的非负整数v满足v !∈ S
首先对于一个终止局面X,也就是说X没法走下一步了,显
然SG(X) = 0。也就是SG(0) = 0.
用这类博弈问题的基础处理方式,即把各游戏独立开,各自求SG后再异或起来。
这题中一堆石子即一个独立的游戏,可以用归纳法证明:
一个有额外机会的石子数为i的一堆,若i为奇数,则SG值为i+1;
若i为偶数,则SG值为i-1。于是O(1)得到每一堆的SG值后异或起来即可。
怎么推呢? SG(0) = 0
SG(1)* = mex (SG(t)) = mex (SG(0), SG(1)**) 因为可以不取所以 SG(1)也是其中一个后继状态
SG(0) = 0, 要注意这里的 SG(1) * 与SG(1) * * 并不相同,SG(1)并没有用过那次不取的机会,SG(1) * 已经没有这个机会了
意思就是说SG(1) * 的后继状态有SG(1),但是SG(1) * * 的后继状态就没有SG(1)了
所以 SG(1) * * = mex (SG(t)) = mex (SG(0)) = 1;所以 SG(1) * = 2;
(下面我们用 * 代表还有不取的机会, * * 代表没有不取的机会)
SG(2)* = mex (SG(t)) = mex (SG(0),SG(1) * ,SG(2)* * )
SG(0) = 0,SG(1)* = 2;同理SG(2) * 与SG(2)* * 并不相同 SG(2) * * = mex (SG(t)) = mex (SG(0), SG(1)**) = 2
所以 SG(2)* = 1;这样推下去就会得到结论。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n, x, y;

int main(){
    freopen("nim.in", "r", stdin) ;
    freopen("nim.out", "w", stdout) ;
    int T; scanf("%d", &T);
    while( T-- ){
        x = 0;
        scanf("%d", &n);
        while( n-- ){
            scanf("%d", &y);
            x ^= y&1 ? y+1 : y-1;
        }
        x ? puts("A") : puts("B");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值