Nim游戏的概述:
还记得这个游戏吗?一般规则是规定拿光铜板的人赢。
Nim游戏的数学理论论述:
Nim游戏是博弈论中最经典的模型,它又有着十分简单的规则和无比优美的结论
对于第三条,我们有更进一步的定义Position,我们将Position分为两类:
P-position:在当前的局面下,先手必败。
N-position:在当前的局面下,先手必胜。
他们有如下性质:
1.合法操作集合为空的局面是P-position;
2.可以移动到P-position的局面是N-position;
3.所有移动都只能到N-position的局面是P-position。
重要结论:对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0,其中^表示异或(xor)运算。
Nim游戏的形象具体论述:
as + bs + … + ms 是偶数
a1 + b1 + … + m1 是偶数
a0 + b0 + … + m0是偶数
23 = 8 | 22 = 4 | 21 = 2 | 20 = 1 | |
大小为7的堆 | 0 | 1 | 1 | 1 |
大小为9的堆 | 1 | 0 | 0 | 1 |
大小为12的堆 | 1 | 1 | 0 | 0 |
大小为15的堆 | 1 | 1 | 1 | 1 |
23 = 8 | 22 = 4 | 21 = 2 | 20 = 1 | |
大小为7的堆 | 0 | 1 | 1 | 1 |
大小为9的堆 | 1 | 0 | 0 | 1 |
大小为12的堆 | 0 | 0 | 0 | 1 |
大小为15的堆 | 1 | 1 | 1 | 1 |
归根结底,Nim取子游戏的关键在于游戏开始时游戏处于何种状态(平衡或非平衡)和第一个游戏人是否能够按照取子游戏的获胜策略来进行游戏。
今天我们要认识一对新朋友,Alice与Bob。
Alice与Bob总是在进行各种各样的比试,今天他们在玩一个取石子的游戏。
在这个游戏中,Alice和Bob放置了N堆不同的石子,编号1..N,第i堆中有A[i]个石子。
每一次行动,Alice和Bob可以选择从一堆石子中取出任意数量的石子。至少取1颗,至多取出这一堆剩下的所有石子。
Alice和Bob轮流行动,取走最后一个石子的人获得胜利。
假设每一轮游戏都是Alice先行动,请你判断在给定的情况下,如果双方都足够聪明,谁会获得胜利?
提示:Nim?!
第1行:1个整数N。表示石子堆数。1≤N≤100
第2行:N个整数,第i个整数表示第i堆石子的个数A[i],1≤A[i]≤10000
第1行:1个字符串,若Alice能够获胜输出"Alice",否则输出"Bob"
3 3 2 1
Bob
Nim游戏是经典的公平组合游戏(ICG),对于ICG游戏我们有如下定义:
1、两名选手;
2、两名选手轮流行动,每一次行动可以在有限合法操作集合中选择一个;
3、游戏的任何一种可能的局面(position),合法操作集合只取决于这个局面本身;局面的改变称为“移动”(move)。
4、若轮到某位选手时,该选手的合法操作集合为空,则这名选手判负。
对于第三条,我们有更进一步的定义Position,我们将Position分为两类:
P-position:在当前的局面下,先手必败。
N-position:在当前的局面下,先手必胜。
他们有如下性质:
1.合法操作集合为空的局面是P-position;
2.可以移动到P-position的局面是N-position;
3.所有移动都只能到N-position的局面是P-position。
对于一个局面,当且仅当A[1] xor A[2] xor ... xor A[N] = 0时,该局面为P局面
代码如下:
#include
#include
#include
using namespace std;
int main()
{
int n;
int a,p;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i
问题:首先有两堆石子,博弈双方每次可以取一堆石子中的任意个,不能不取,或者取两堆石子中的相同个。先取完者赢。
解决思路:A:设(ai,bi)(ai ≤bi ,i=0,1,2,…,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。任给一个局势(a,b),如下公式判断它是不是奇异局势: ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,…,n 方括号表示取整函数)。
判断是否为奇异局势的代码如下
#include
#include
#include
using namespace std;
#define P sqrt(5.0)
int main()
{
int a,b,t;
while(scanf("%d",&a,&b)!=EOF)
{
if(a>b)
{
t=a;
a=b;
b=a;
}
t=b-a;
if(a==(int)(t*(1+P)/2))///奇异局势
printf("为奇异局势");
}
return 0;
}
如果为奇异局势,则先手必输。
Sherlock and Watson are playing the following modified version of Nim game:
Giving the initial situation of each game, you are required to figure out who will be the winner
The first contains an integer, g, denoting the number of games. The 2×g subsequent lines describe each game over two lines:
1. The first line contains a prime integer, n, denoting the number of piles.
2. The second line contains n space-separated integers describing the respective values of ,,...,.
For each game, print the name of the winner on a new line (i.e., either "Sherlock
" or "Watson
")
2 3 2 3 2 2 2 1
Sherlock Watson
#include
#include
#include
#include
#include
using namespace std;
int a[1000];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0; i