Nim游戏·改(博弈论)

来源:互联网 发布:淘宝客服自我评价 编辑:程序博客网 时间:2024/05/19 13:55

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");    }}
原创粉丝点击