HDU 2176 取(m堆)石子游戏 —— (Nim博弈)

  如果yes的话要输出所有情况,一开始觉得挺难,想了一下也没什么。

  每堆的个数^一下,答案不是0就是先取者必胜,那么对必胜态显然至少存在一种可能性使得当前局势变成必败的。只要任意选取一堆,把这堆的数目变成其他堆异或和即可,这样,它们异或一下就是0了(变成了必败态)。所以说,在这题就是,对任意一堆,变化以后的数目如果不大于这堆原来的数目,就是可能的第一次取的情况。代码如下:

 1 #include <stdio.h>
 2 #include <algorithm>
 3 using namespace std;
 4 const int N = 200000 + 5;
 5 int a[N];
 6 int main()
 7 {
 8     int n;
 9     while(scanf("%d",&n)==1 && n)
10     {
11         int temp = 0;
12         for(int i=1;i<=n;i++) {scanf("%d",a+i);temp^=a[i];}
13         if(temp == 0 )
14         {
15             puts("No");
16             continue;
17         }
18         else
19         {
20             puts("Yes");
21             for(int i=1;i<=n;i++)
22             {
23                 int other = a[i]^temp;
24                 int x = other^0;
25                 if(x <= a[i])
26                 {
27                     printf("%d %d
",a[i],x);
28                 }
29             }
30         }
31     }
32 }

  同时,nim博弈转化成sg来理解也是没有问题的,每一堆的sg函数怎么计算的呢?显然对一堆,个数为n的话,因为可以取>=1的任意个数,所以n的后续态为0~n-1的连续整数,那么sg[n]=mex{sg[0],sg[1],...,sg[n-1]}。而sg[0]=0,sg[1]=mex{sg[0]}=mex{0}=1, sg[2]=mex{sg[0],sg[1]}=mex{0,1}=2... 因此可以递推得到sg[n]=n。所以根据sg胜利的条件是所有sg值相异或不为0,这正是nim博弈下胜利的条件。

原文地址:https://www.cnblogs.com/zzyDS/p/5690812.html