John(POJ 3480) 逆尼姆博弈

逆尼姆博弈

John

 
Little John is playing very funny game with his younger brother. There is one big box filled with M&Ms of different colors. At first John has to eat several M&Ms of the same color. Then his opponent has to make a turn. And so on. Please note that each player has to eat at least one M&M during his turn. If John (or his brother) will eat the last M&M from the box he will be considered as a looser and he will have to buy a new candy box. 

Both of players are using optimal game strategy. John starts first always. You will be given information about M&Ms and your task is to determine a winner of such a beautiful game. 

InputThe first line of input will contain a single integer T – the number of test cases. Next T pairs of lines will describe tests in a following format. The first line of each test will contain an integer N – the amount of different M&M colors in a box. Next line will contain N integers Ai, separated by spaces – amount of M&Ms of i-th color. 

Constraints: 
1 <= T <= 474, 
1 <= N <= 47, 
1 <= Ai <= 4747 

OutputOutput T lines each of them containing information about game winner. Print “John” if John will win the game or “Brother” in other case. 

Sample Input
2
3
3 5 1
1
1
Sample Output
John
Brother

题意:有N堆石子每堆任意多个,每次可以从其中一堆中取出任意多个,最后取的人输。
题解:
  我们可以知道,如果有一堆多于1的石子个数为m,我们通常做法是将其中的m-1个石子取走,将只剩下1个石子的状态留给对方,那么先手必胜。那么
这个题的状态便一共有以下几种:
  (1)所有堆石子个数均为1
稍微模拟一下就知道,如果堆数为奇数,那么先手必败,如果堆数为偶数,先手必胜。
  (2)有一堆石子个数大于1
    如果剩下的个数为1的堆的个数为奇数,先手可以从这堆个数大于1的堆中取走m-1,使其变成1,那么先手必胜;
如果剩下的个数为1的堆的个数为偶数,
先手可以把这堆全取走,那么先手必胜。故有一堆石子大于1的状态先手必胜。
  (3)有多于一堆的石子个数大于1
    <3.1 所有堆石子个数的抑或和为0
    这种情况下,可转移堆状态只有两种:
      ① 变成只有一堆石子个数大于1且抑或和不为0 如(1 2 3)->(1 1 3)
        这种状态和(2)相同,先手必胜。
      ② 变成有多于1堆石子的抑或和不为0 如
(1 2 3)->(1 2 2)
        这种状态和<3.2相同,以下讨论。
    <3.2 所有堆石子个数的抑或和不为0
    这种状态一定存在一种取法将状态转化为<3.1或者(2) 至此我们可以知道,后手要么直接让先手胜,要么将相同堆<3.2状态交还给先手。
综上:面对<3.1状态的人必败,面对<3.2状态的人必胜。
   即:当前局面为必胜态 等价于
      所有堆的石子个数均为1且尼姆和等于0,或者至少有一堆石子个数大于1且尼姆和不为0。
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=1e4+10;
 6 int a[maxn];
 7 int sg[maxn];
 8 int main()
 9 {
10     int casen;
11     int n;
12     cin>>casen;
13     while(casen--)
14     {
15         memset(sg,0,sizeof(sg));
16         scanf("%d",&n);
17         int flag=0;
18         for(int i=0;i<n;i++)
19         {
20             scanf("%d",&a[i]);
21             if(a[i]!=1)
22             {
23                 sg[i]=1;
24                 flag++;
25             }
26             else
27             {
28                 sg[i]=0;
29             }
30         }
31         if(flag==0)
32         {
33             if(n%2==1)
34             {
35                 printf("Brother\n");
36                 continue;
37             }
38             else
39             {
40                 printf("John\n");
41                 continue;
42             }
43         }
44         else if(flag==1)
45         {
46             printf("John\n");
47             continue;
48         }
49         else
50         {
51             int ans=0;
52             for(int i=0;i<n;i++)
53                 ans^=a[i];
54             if(ans==0)
55                printf("Brother\n");
56             else
57                 printf("John\n");
58             continue;
59         }
60     }
61 }

 

 
posted @ 2018-10-22 08:28  *starry*  阅读(178)  评论(0编辑  收藏  举报