您的位置:首页 > 其它

Nim游戏·改(博弈论)

2017-08-28 15:37 176 查看

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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: