• ACM 第十二天


    博弈论(巴什博奕,威佐夫博弈,尼姆博弈,斐波那契博弈,SG函数,SG定理)

    一.  巴什博奕(Bash Game):

      A和B一块报数,每人每次报最少1个,最多报4个,看谁先报到30。这应该是最古老的关于巴什博奕的游戏了吧。

    其实如果知道原理,这游戏一点运气成分都没有,只和先手后手有关,比如第一次报数,A报k个数,那么B报5-k个数,那么B报数之后问题就变为,A和B一块报数,看谁先报到25了,进而变为20,15,10,5,当到5的时候,不管A怎么报数,最后一个数肯定是B报的,可以看出,作为后手的B在个游戏中是不会输的。

    那么如果我们要报n个数,每次最少报一个,最多报m个,我们可以找到这么一个整数k和r,使n=k*(m+1)+r,代入上面的例子我们就可以知道,如果r=0,那么先手必败;否则,先手必胜。

    巴什博奕:只有一堆n个物品,两个人轮流从中取物,规定每次最少取一个,最多取m个,最后取光者为胜。

     1 #include <iostream>
     2 using namespace std;
     3 int main()
     4 {
     5     int n,m;
     6     while(cin>>n>>m)
     7       if(n%(m+1)==0)  cout<<"后手必胜"<<endl;
     8       else cout<<"先手必胜"<<endl;
     9     return 0;
    10 }
    11  

    二.  威佐夫博弈(Wythoff Game):

    有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。

    直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x;

    记w=(int)[((sqrt(5)+1)/2)*z  ];

    若w=x,则先手必败,否则先手必胜。

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <iostream>
     4 using namespace std;
     5 int main()
     6 {
     7     int n1,n2,temp;
     8     while(cin>>n1>>n2)
     9     {
    10         if(n1>n2)  swap(n1,n2);
    11         temp=floor((n2-n1)*(1+sqrt(5.0))/2.0);
    12         if(temp==n1) cout<<"后手必胜"<<endl;
    13         else cout<<"先手必胜"<<endl;
    14     }
    15     return 0;
    16 }
    17  
    18  

    三.  尼姆博弈(Nimm Game):

    尼姆博弈指的是这样一个博弈游戏:有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。

    结论就是:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。

     1 #include <cstdio>
     2 #include <cmath>
     3 #include <iostream>
     4 using namespace std;
     5 int main()
     6 {
     7     int n,ans,temp;
     8     while(cin>>n)
     9     {
    10         temp=0;
    11         for(int i=0;i<n;i++)
    12         {
    13             cin>>ans;
    14             temp^=ans;
    15         }
    16         if(temp==0)  cout<<"后手必胜"<<endl;
    17         else cout<<"先手必胜"<<endl;
    18     }
    19     return 0;
    20 }
    21  
    22  

    四.  斐波那契博弈:

    有一堆物品,两人轮流取物品,先手最少取一个,至多无上限,但不能把物品取完,之后每次取的物品数不能超过上一次取的物品数的二倍且至少为一件,取走最后一件物品的人获胜。

    结论是:先手胜当且仅当n不是斐波那契数(n为物品总数)

     1 #include <iostream>  
     2 #include <string.h>  
     3 #include <stdio.h>  
     4 using namespace std;  
     5 const int N = 55;    
     6 int f[N];   
     7 void Init()  
     8 {  
     9     f[0] = f[1] = 1;  
    10     for(int i=2;i<N;i++)  
    11         f[i] = f[i-1] + f[i-2];  
    12 }    
    13 int main()  
    14 {  
    15     Init();  
    16     int n;  
    17     while(cin>>n)  
    18     {  
    19         if(n == 0) break;  
    20         bool flag = 0;  
    21         for(int i=0;i<N;i++)  
    22         {  
    23             if(f[i] == n)  
    24             {  
    25                 flag = 1;  
    26                 break;  
    27             }  
    28         }  
    29         if(flag) puts("Second win");  
    30         else     puts("First win");  
    31     }  
    32     return 0;  
    33 } 

    五、SG函数,SG定理

    必胜点和必败点的概念
           P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败。
           N点:必胜点,处于此情况下,双方操作均正确的情况下必胜。
    必胜点和必败点的性质
            1、所有终结点是 必败点 P 。(我们以此为基本前提进行推理,换句话说,我们以此为假设)
            2、从任何必胜点N 操作,至少有一种方式可以进入必败点 P。
            3、无论如何操作,必败点P 都只能进入 必胜点 N。

    Sprague-Grundy定理(SG定理):

            游戏和的SG函数等于各个游戏SG函数的Nim和。这样就可以将每一个子游戏分而治之,从而简化了问题。而Bouton定理就是Sprague-Grundy定理在Nim游戏中的直接应用,因为单堆的Nim游戏 SG函数满足 SG(x) = x。对博弈不是很清楚的请参照http://www.cnblogs.com/ECJTUACM-873284962/p/6398385.html进行进一步理解。

    SG函数:

            首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如mex{0,1,2,4}=3、mex{2,3,5}=0、mex{}=0。

            对于任意状态 x , 定义 SG(x) = mex(S),其中 S 是 x 后继状态的SG函数值的集合。如 x 有三个后继状态分别为 SG(a),SG(b),SG(c),那么SG(x) = mex{SG(a),SG(b),SG(c)}。 这样 集合S 的终态必然是空集,所以SG函数的终态为 SG(x) = 0,当且仅当 x 为必败点P时。

    SG(x)=x

    Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can move one chess in one turn. If there are no other chesses on the right adjacent block of the moved chess, move the chess to its right adjacent block. Otherwise, skip over these chesses and move to the right adjacent block of them. Two chesses can’t be placed at one block and no chess can be placed out of the chessboard. When someone can’t move any chess during his/her turn, he/she will lose the game. Alice always take the first turn. Both Alice and Bob will play the game with the best strategy. Alice wants to know if she can win the game.

    InputMultiple test cases.

    The first line contains an integer T(T100), indicates the number of test cases.

    For each test case, the first line contains a single integer n(n1000), the number of lines of chessboard.

    Then n lines, the first integer of ith line is m(m20), indicates the number of chesses on the ith line of the chessboard. Then m integers pj(1pj20) followed, the position of each chess.
    OutputFor each test case, output one line of “YES” if Alice can win the game, “NO” otherwise.Sample Input
    2
    1
    2 19 20
    2
    1 19
    1 18
    Sample Output
    NO
    YES

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,m,sg[1<<21],vis[21];
     4 int dfs(int x)
     5 {
     6      memset(vis,0,sizeof(vis));
     7      for(int i = 20;i>=0;i--)
     8      {
     9          if(x & (1<<i))
    10          {
    11              int temp = x;
    12              for(int j = i-1;j>=0;j--)
    13              {
    14                  if(!(x&(1<<j)))
    15                  {
    16                      temp ^= (1<<j)^(1<<i);
    17                      vis[sg[temp]]=1;
    18                      break;
    19                  }
    20              }
    21          }
    22      }
    23      for(int i = 0;i<=20;i++)
    24          if(!vis[i])
    25              return i;
    26      return 0;
    27 }
    28 int main()
    29 {
    30      memset(sg,0,sizeof(sg));
    31      for(int i = 0;i<(1<<20);i++)
    32          sg[i]=dfs(i);
    33      int T;
    34      scanf("%d",&T);
    35      while(T--)
    36      {
    37          int n;
    38          scanf("%d",&n);
    39          int ans = 0;
    40          for(int i = 0;i<n;i++)
    41          {
    42              int res = 0,temp;
    43              int q;
    44              scanf("%d",&q);
    45              while(q--)
    46                 scanf("%d",&temp),res|=1<<(20-temp);
    47              ans^=sg[res];
    48          }
    49          if(ans)
    50              printf("YES
    ");
    51          else
    52              printf("NO
    ");
    53      }
    54  
    55 }

    博弈练习题

    十年前读大学的时候,中国每年都要从国外引进一些电影大片,其中有一部电影就叫《勇敢者的游戏》(英文名称:Zathura),一直到现在,我依然对于电影中的部分电脑特技印象深刻。
    今天,大家选择上机考试,就是一种勇敢(brave)的选择;这个短学期,我们讲的是博弈(game)专题;所以,大家现在玩的也是“勇敢者的游戏”,这也是我命名这个题目的原因。
    当然,除了“勇敢”,我还希望看到“诚信”,无论考试成绩如何,希望看到的都是一个真实的结果,我也相信大家一定能做到的~

    各位勇敢者要玩的第一个游戏是什么呢?很简单,它是这样定义的:
    1、  本游戏是一个二人游戏;
    2、  有一堆石子一共有n个;
    3、  两人轮流进行;
    4、  每走一步可以取走1…m个石子;
    5、  最先取光石子的一方为胜;

    如果游戏的双方使用的都是最优策略,请输出哪个人能赢。

    Input输入数据首先包含一个正整数C(C<=100),表示有C组测试数据。
    每组测试数据占一行,包含两个整数n和m(1<=n,m<=1000),n和m的含义见题目描述。
    Output如果先走的人能赢,请输出“first”,否则请输出“second”,每个实例的输出占一行。Sample Input
    2
    23 2
    4 3
    Sample Output
    first
    second
     1 #include<stdio.h>
     2 int main()
     3 {
     4     int t,n,m;
     5     scanf("%d",&t);
     6     while(t--)
     7     {
     8         scanf("%d%d",&n,&m);
     9         if(n%(m+1)==0) 
    10             printf("second
    ");
    11         else
    12             printf("first
    ");
    13     }
    14     return 0;
    15 }
    有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
    Input
    输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。
    Output
    输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。
    Sample Input
    2 1
    8 4
    4 7
    Sample Output
    0
    1
    0
     1 #include<stdio.h>
     2 #include<math.h>
     3 #include<iostream>
     4 using namespace std;
     5 
     6 int main()
     7 {
     8     int n,m;
     9     while(~scanf("%d%d",&m,&n))
    10     {
    11         int a=min(n,m);
    12         int b=max(n,m);
    13         double k=(double)(b-a);
    14         int s1=(int)k*((1+sqrt(5))/2);
    15         if(s1==a)
    16         {
    17             printf("0
    ");
    18         }
    19         else
    20             printf("1
    ");
    21 
    22     }
    23     return 0;
    24 }
    1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".

    Input输入有多组.每组第1行是2<=n<2^31. n=0退出.
    Output先取者负输出"Second win". 先取者胜输出"First win".
    参看Sample Output.
    Sample Input
    2
    13
    10000
    0
    Sample Output
    Second win
    Second win
    First win
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 
     7 using namespace std;
     8 
     9 int main()
    10 {
    11     int n;
    12     while(scanf("%d",&n)!=EOF && n!=0)
    13     {
    14         int f[10010];
    15         f[1]=2;
    16         f[2]=3;
    17         for(int i=3; i<=48; i++)
    18         {
    19             f[i]=f[i-1]+f[i-2];
    20         }
    21         int flag=0;
    22         for(int i=1; i<=48; i++)
    23         {
    24             if(n==f[i])
    25                flag=1;
    26         }
    27         if(flag==1)
    28          printf("Second win
    ");
    29             else printf("First win
    ");
    30 
    31     }
    32     return 0;
    33 }
    大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此。当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考前的放松,所谓“张弛有道”就是这个意思。这不,Kiki和Cici在每天晚上休息之前都要玩一会儿扑克牌以放松神经。
    “升级”?“双扣”?“红五”?还是“斗地主”?
    当然都不是!那多俗啊~
    作为计算机学院的学生,Kiki和Cici打牌的时候可没忘记专业,她们打牌的规则是这样的:
    1、  总共n张牌;
    2、  双方轮流抓牌;
    3、  每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
    4、  抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
    假设Kiki和Cici都是足够聪明(其实不用假设,哪有不聪明的学生~),并且每次都是Kiki先抓牌,请问谁能赢呢?
    当然,打牌无论谁赢都问题不大,重要的是马上到来的CET-4能有好的状态。

    Good luck in CET-4 everybody!

    Input输入数据包含多个测试用例,每个测试用例占一行,包含一个整数n(1<=n<=1000)。Output如果Kiki能赢的话,请输出“Kiki”,否则请输出“Cici”,每个实例的输出占一行。
    Sample Input
    1
    3
    Sample Output
    Kiki
    Cici
     1 #include<stdio.h>
     2 #include<math.h>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     int n,m;
     8     while(~scanf("%d",&n))
     9     {
    10         if(n%3==0) printf("Cici
    ");
    11         else
    12             printf("Kiki
    ");
    13     }
    14     return 0;
    15 }
    Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can move one chess in one turn. If there are no other chesses on the right adjacent block of the moved chess, move the chess to its right adjacent block. Otherwise, skip over these chesses and move to the right adjacent block of them. Two chesses can’t be placed at one block and no chess can be placed out of the chessboard. When someone can’t move any chess during his/her turn, he/she will lose the game. Alice always take the first turn. Both Alice and Bob will play the game with the best strategy. Alice wants to know if she can win the game.

    InputMultiple test cases.

    The first line contains an integer T(T100), indicates the number of test cases.

    For each test case, the first line contains a single integer n(n1000), the number of lines of chessboard.

    Then n lines, the first integer of ith line is m(m20), indicates the number of chesses on the ith line of the chessboard. Then m integers pj(1pj20) followed, the position of each chess.
    OutputFor each test case, output one line of “YES” if Alice can win the game, “NO” otherwise.Sample Input
    2
    1
    2 19 20
    2
    1 19
    1 18
    Sample Output
    NO
    YES

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,m,sg[1<<21],vis[21];
     4 int dfs(int x)
     5 {
     6      memset(vis,0,sizeof(vis));
     7      for(int i = 20;i>=0;i--)
     8      {
     9          if(x & (1<<i))
    10          {
    11              int temp = x;
    12              for(int j = i-1;j>=0;j--)
    13              {
    14                  if(!(x&(1<<j)))
    15                  {
    16                      temp ^= (1<<j)^(1<<i);
    17                      vis[sg[temp]]=1;
    18                      break;
    19                  }
    20              }
    21          }
    22      }
    23      for(int i = 0;i<=20;i++)
    24          if(!vis[i])
    25              return i;
    26      return 0;
    27 }
    28 int main()
    29 {
    30      memset(sg,0,sizeof(sg));
    31      for(int i = 0;i<(1<<20);i++)
    32          sg[i]=dfs(i);
    33      int T;
    34      scanf("%d",&T);
    35      while(T--)
    36      {
    37          int n;
    38          scanf("%d",&n);
    39          int ans = 0;
    40          for(int i = 0;i<n;i++)
    41          {
    42              int res = 0,temp;
    43              int q;
    44              scanf("%d",&q);
    45              while(q--)
    46                 scanf("%d",&temp),res|=1<<(20-temp);
    47              ans^=sg[res];
    48          }
    49          if(ans)
    50              printf("YES
    ");
    51          else
    52              printf("NO
    ");
    53      }
    54  
    55 }
    Recently kiki has nothing to do. While she is bored, an idea appears in his mind, she just playes the checkerboard game.The size of the chesserboard is n*m.First of all, a coin is placed in the top right corner(1,m). Each time one people can move the coin into the left, the underneath or the left-underneath blank space.The person who can't make a move will lose the game. kiki plays it with ZZ.The game always starts with kiki. If both play perfectly, who will win the game?

    InputInput contains multiple test cases. Each line contains two integer n, m (0<n,m<=2000). The input is terminated when n=0 and m=0.

    OutputIf kiki wins the game printf "Wonderful!", else "What a pity!".
    Sample Input
    5 3
    5 4
    6 6
    0 0
    Sample Output
    What a pity!
    Wonderful!
    Wonderful!
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 
     7 using namespace std;
     8 
     9 int main()
    10 {
    11     int n,m;
    12     while(scanf("%d%d",&n,&m)!=EOF &&( n!=0 || m!=0))
    13     {
    14         if(n%2==0 || m%2==0) printf("Wonderful!
    ");
    15         else
    16             printf("What a pity!
    ");
    17     }
    18     return 0;
    19 }
    虽然不想,但是现实总归是现实,Lele始终没有逃过退学的命运,因为他没有拿到奖学金。现在等待他的,就是像FarmJohn一样的农田生涯。

    要种田得有田才行,Lele听说街上正在举行一场别开生面的拍卖会,拍卖的物品正好就是一块20亩的田地。于是,Lele带上他的全部积蓄,冲往拍卖会。

    后来发现,整个拍卖会只有Lele和他的死对头Yueyue。

    通过打听,Lele知道这场拍卖的规则是这样的:刚开始底价为0,两个人轮流开始加价,不过每次加价的幅度要在1~N之间,当价格大于或等于田地的成本价 M 时,主办方就把这块田地卖给这次叫价的人。

    Lele和Yueyue虽然考试不行,但是对拍卖却十分精通,而且他们两个人都十分想得到这块田地。所以他们每次都是选对自己最有利的方式进行加价。

    由于Lele字典序比Yueyue靠前,所以每次都是由Lele先开始加价,请问,第一次加价的时候,
    Lele要出多少才能保证自己买得到这块地呢?

    Input本题目包含多组测试,请处理到文件结束(EOF)。每组测试占一行。
    每组测试包含两个整数M和N(含义见题目描述,0<N,M<1100)
    Output对于每组数据,在一行里按递增的顺序输出Lele第一次可以加的价。两个数据之间用空格隔开。
    如果Lele在第一次无论如何出价都无法买到这块土地,就输出"none"。
    Sample Input
    4 2
    3 2
    3 5
    Sample Output
    1
    none
    3 4 5
     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 
     7 using namespace std;
     8 int ans[1100];
     9 int main()
    10 {
    11     int n,m;
    12     while(scanf("%d%d",&n,&m)!=EOF)
    13     {
    14         if(n%(m+1)==0) printf("none
    ");
    15         else
    16         {
    17             if(n%(m+1)==n)
    18             {
    19                 printf("%d",n);
    20                 for(int i=n+1;i<=m;i++)
    21                 {
    22                     printf(" %d",i);
    23                 }
    24             }
    25             else
    26             {
    27                 printf("%d",n%(m+1));
    28             }
    29             printf("
    ");
    30         }
    31 
    32     }
    33     return 0;
    34 }
    一年在外 父母时刻牵挂
    春节回家 你能做几天好孩子吗
    寒假里尝试做做下面的事情吧

    陪妈妈逛一次菜场
    悄悄给爸爸买个小礼物
    主动地 强烈地 要求洗一次碗
    某一天早起 给爸妈用心地做回早餐

    如果愿意 你还可以和爸妈说
    咱们玩个小游戏吧 ACM课上学的呢~

    下面是一个二人小游戏:桌子上有M堆扑克牌;每堆牌的数量分别为Ni(i=1…M);两人轮流进行;每走一步可以任意选择一堆并取走其中的任意张牌;桌子上的扑克全部取光,则游戏结束;最后一次取牌的人为胜者。
    现在我们不想研究到底先手为胜还是为负,我只想问大家:
    ——“先手的人如果想赢,第一步有几种选择呢?”

    Input输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000,i=1…M),分别表示M堆扑克的数量。M为0则表示输入数据的结束。
    Output如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。
    Sample Input
    3
    5 7 9
    0
    Sample Output
    1
     1 #include<cstring>
     2 #include<cstdio>
     3 
     4 using namespace std;
     5 
     6 int main()
     7 {
     8     int t,a[1100];
     9 
    10     while(scanf("%d",&t)!=EOF && t)
    11     {
    12         int sum=0;
    13        for(int i=1;i<=t;i++)
    14        {
    15            scanf("%d",&a[i]);
    16            sum^=a[i];
    17        }
    18        int ans=0;
    19 
    20        if(sum==0) printf("0
    ");
    21        else
    22        {
    23            int res;
    24            for(int i=1;i<=t;i++)
    25            {
    26                res=sum^a[i];
    27                if(res<a[i]) ans++;
    28            }
    29            printf("%d
    ",ans);
    30        }
    31     }
    32     return 0;
    33 }
    Aekdycoin and abcdxyzk are playing a game. They get a circle chain with some beads. Initially none of the beads is painted. They take turns to paint the chain. In Each turn one player must paint a unpainted beads. Whoever is unable to paint in his turn lose the game. Aekdycoin will take the first move.

    Now, they thought this game is too simple, and they want to change some rules. In each turn one player must select a certain number of consecutive unpainted beads to paint. The other rules is The same as the original. Who will win under the rules ?You may assume that both of them are so clever.

    InputFirst line contains T, the number of test cases. Following T line contain 2 integer N, M, indicate the chain has N beads, and each turn one player must paint M consecutive beads. (1 <= N, M <= 1000)OutputFor each case, print "Case #idx: " first where idx is the case number start from 1, and the name of the winner.Sample Input
    2 
    3 1 
    4 2
    Sample Output
    Case #1: aekdycoin 
    Case #2: abcdxyzk
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 
     5 #define MAXN 1010
     6 
     7 using namespace std;
     8 
     9 int T,N,M,sg[MAXN];
    10 int SG(int n)
    11 {
    12     if(sg[n]!=-1) return sg[n];
    13     if(n<M) return sg[n]=0;
    14     int vis[MAXN]= {0};
    15     //memset(vis,0,sizeof(vis));
    16     for(int i=0; i<=n-M-i; i++) vis[SG(i)^SG(n-M-i)]=1;
    17     for(int i=0;; i++) if(!vis[i]) return sg[n]=i;
    18 }
    19 int main()
    20 {
    21 
    22     scanf("%d",&T);
    23     int cas=0;
    24     while(T--)
    25     {
    26         scanf("%d%d",&N,&M);
    27         printf("Case #%d: ",++cas);
    28         memset(sg,-1,sizeof(sg));
    29         if(N<M)
    30         {
    31             printf("abcdxyzk
    ");
    32             continue;
    33         }
    34         if(SG(N-M)) printf("abcdxyzk
    ");
    35         else printf("aekdycoin
    ");
    36     }
    37     return 0;
    38 }
    任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的:
    F(1)=1;
    F(2)=2;
    F(n)=F(n-1)+F(n-2)(n>=3);
    所以,1,2,3,5,8,13……就是菲波那契数列。
    在HDOJ上有不少相关的题目,比如1005 Fibonacci again就是曾经的浙江省赛题。
    今天,又一个关于Fibonacci的题目出现了,它是一个小游戏,定义如下:
    1、  这是一个二人游戏;
    2、  一共有3堆石子,数量分别是m, n, p个;
    3、  两人轮流走;
    4、  每走一步可以选择任意一堆石子,然后取走f个;
    5、  f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8…等数量);
    6、  最先取光所有石子的人为胜者;

    假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢。

    Input输入数据包含多个测试用例,每个测试用例占一行,包含3个整数m,n,p(1<=m,n,p<=1000)。
    m=n=p=0则表示输入结束。
    Output如果先手的人能赢,请输出“Fibo”,否则请输出“Nacci”,每个实例的输出占一行。
    Sample Input
    1 1 1
    1 4 1
    0 0 0
    Sample Output
    Fibo
    Nacci
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 
     5 #define MAXN 1010
     6 
     7 using namespace std;
     8 int vis[10];
     9 int f[21];
    10 int sg[1010];
    11 void get_sg()
    12 {
    13     f[1]=1;
    14     f[2]=1;
    15     for(int i=3; i<=20; i++)
    16     {
    17         f[i]=f[i-1]+f[i-2];
    18 
    19     }
    20     for(int i=0; i<=1000; i++)
    21     {
    22         memset(vis,false,sizeof vis);
    23         for(int j=1; j<=20; j++)
    24         {
    25             if(f[j]<=i) vis[sg[i-f[j]]]=true;
    26             else break;
    27         }
    28 
    29         for(int j=0; j<=10; j++)
    30         {
    31             if(!vis[j])
    32             {
    33                 sg[i]=j;
    34                 break;
    35             }
    36         }
    37 
    38     }
    39 }
    40 
    41 int main()
    42 {
    43     get_sg();
    44     int m,n,p;
    45     while(~scanf("%d%d%d",&m,&n,&p) &&!(m==0 && n==0 && p==0))
    46     {
    47         int k=(sg[m]^sg[n]);
    48         int t=(k^sg[p]);
    49         if(t==0) printf("Nacci
    ");
    50         else printf("Fibo
    ");
    51     }
    52     return 0;
    53 }

    参见原博客:https://blog.csdn.net/ac_gibson/article/details/41624623,https://www.cnblogs.com/ECJTUACM-873284962/p/6921829.html

  • 相关阅读:
    Spring中使用存储过程
    使用mysql-connector-java.jar连接MySql时出现:Error while retrieving metadata for procedure columns: java.sql.SQLException: Parameter/Column name pattern can not be NULL or empty.
    Spring的JDBC示例
    使用JDBC连接MySql时出现:The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration
    Spring的JDBC框架概述
    数据库中的DDL/DML/DCL解释(转)
    沉默的螺旋--digest
    左边老师长征--性命、生命、使命
    柬埔寨旅游小结
    Spring Security 源码分析(四):Spring Social实现微信社交登录
  • 原文地址:https://www.cnblogs.com/weixq351/p/9473905.html
Copyright © 2020-2023  润新知