[博弈论]

巴什博弈:

只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。

显然,如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)*(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。

正确解法:

若 n%(m+1)==0 的话,一定是后手赢。

其他的话,就是先手赢。

kiki's game

Description

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?

Input

Input 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.

output

If kiki wins the game printf "Wonderful!", else "What a pity!".

Examples

Input

5 3

5 4

6 6

0 0

Output

What a pity!

Wonderful!

Wonderful!

正确解法:

输入n和m,在一张n*m上的棋盘上,棋子刚开始在(1,m)上。

棋子可以走 左边,下边,左下边的空白处。

kiki先走,若kiki必赢,则输出 “Wonderful!”,否则输出  ”What a pity! “

因为棋子现在在(1,m)处,它最起码要走(n-1)或 (m-1)步

若其中有一个是奇数,那么kiki必赢。

则n和m中有一个是偶数,那么就赢了。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
const int N=100000+100;
const int M=9999999;
const ll mod=1000000000+7;
int main()
{
    int n,m;
    while(scanf("%d %d",&n,&m))
    {
        if(n==0)    break;
        if(n%2==0||m%2==0)
            printf("Wonderful!\n");
        else
            printf("What a pity!\n");
    }


    return 0;
}
View Code

 

斐波那契博弈

有一堆个数为n的石子,游戏双方轮流取石子,满足:

1)先手不能在第一次把所有的石子取完;

2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。

约定取走最后一个石子的人为赢家,求必败态。

这个和之前的Wythoff’s Game 和取石子游戏 有一个很大的不同点,就是游戏规则的动态化。之前的规则中,每次可以取的石子的策略集合是基本固定的,但是这次有规则2:一方每次可以取的石子数依赖于对手刚才取的石子数。

这个游戏叫做Fibonacci Nim,肯定和Fibonacci数列:f[n]:1,2,3,5,8,13,21,34,55,89,… 有密切的关系。如果试验一番之后,可以猜测:先手胜当且仅当n不是Fibonacci数。换句话说,必败态构成Fibonacci数列。

就像“Wythoff博弈”需要“Beatty定理”来帮忙一样,这里需要借助“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。

取石子游戏

Description

1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".

Input

输入有多组.每组第1行是2<=n<2^31. n=0退出.

output

先取者负输出"Second win". 先取者胜输出"First win". 
参看Sample Output.

Examples

Input

2

13

10000

0

Output

Second win

Second win

First win

正确解法:

是斐波那契数列的话,那就是后手赢。不是的话就先手。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
const int N=100000+100;
const int M=9999999;
const ll mod=1000000000+7;
int main()
{
    ll f[50];
    int n;
    f[0]=2; f[1]=3;
    for(int i=2;i<=50;i++)
        f[i]=f[i-1]+f[i-2];
    while(scanf("%d",&n))
    {
        if(n==0)    break;
        int flag=0;
        for(int i=0;i<=50;i++)
        {
            if(f[i]==n)
            {
                flag=1;
                printf("Second win\n");
                break;
            }
            if(f[i]>n)
                break;
        }
        if(flag==0)
            printf("First win\n");
    }

    return 0;
}
View Code

 

威佐夫博弈(Wythoff's game)

有两堆各若干个物品,两个人轮流从某一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
这种情况下是颇为复杂的。我们用(a[k],b[k])(a[k] ≤ b[k] ,k=0,1,2,...,n)(表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。注:k表示奇异局势的序号, 第一个奇异局势k=0。
可以看出,a[0]=b[0]=0,a[k]是未在前面出现过的最小自然数,而 b[k]= a[k] + k。
 

取石子游戏

Description

有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

Input

输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

output

输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。

Examples

Input

2 1
8 4
4 7

Output

0
1
0

正确解法:

如果(a,b)是奇异数列,那么一定是后手赢。否则先手赢。

怎么判断是奇异数列呢?

若(b-a)*((sqrt(5)+1)/2)==a的话,那么就是奇异数列。

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=0x7fffffff;
const int N=100000+100;
const int M=9999999;
const ll mod=1000000000+7;
int main()
{
    int a,b;
    while(scanf("%d %d",&a,&b)!=EOF)
    {
        if(a>b) swap(a,b);
        int c=floor((b-a)*((sqrt(5)+1)/2));
        if(a==c)    cout<<0<<endl;
        else cout<<1<<endl;
    }

    return 0;
}
View Code

 

Good Luck in CET-4 Everybody!

Description

大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的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”,每个实例的输出占一行。

Examples

Input

1 
3

Output

Kiki
Cici

正确解法:

sg函数!

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 typedef long long ll;
13 const int inf=0x7fffffff;
14 const int N=100000+100;
15 const int M=9999999;
16 const ll mod=1000000000+7;
17 int a[15],n;
18 int sg[1005];
19 int mex(int x)
20 {
21     if(sg[x]!=-1)   return sg[x];
22     int bok[1005];
23     memset(bok,0,sizeof(bok));
24     for(int i=0;i<10;i++)
25     {
26         int temp=x-a[i];
27         if(temp<0)  break;
28         sg[temp]=mex(temp);
29         bok[sg[temp]]=1;
30     }
31     for(int i=0;;i++)
32         if(!bok[i])
33          {   sg[x]=i;
34             break;
35          }
36     return sg[x];
37 
38 }
39 int main()
40 {
41     a[0]=1;
42     for(int i=1;i<10;i++)
43         a[i]=a[i-1]*2;
44     //memset(sg,-1,sizeof(sg));
45     while(scanf("%d",&n)!=EOF)
46     {
47       memset(sg,-1,sizeof(sg));
48         if(mex(n))  printf("Kiki\n");
49         else
50             printf("Cici\n");
51 
52     }
53 
54     return 0;
55 }
View Code
 1 int mex(int x)
 2 {
 3     if(sg[x]!=-1)   return sg[x];
 4     int bok[1005];
 5     memset(bok,0,sizeof(bok));
 6     for(int i=0;i<10;i++)
 7     {
 8         int temp=x-a[i];
 9         if(temp<0)  break;
10         sg[temp]=mex(temp);
11         bok[sg[temp]]=1;
12     }
13     for(int i=0;;i++)
14         if(!bok[i])
15          {   sg[x]=i;
16             break;
17          }
18     return sg[x];
19 }

 

硬币游戏

Description

给定K个数字 a1,a2—ak ,有x个硬币,Alice 和Bob 交替拿走硬币,拿走的个数只能在 ai 中选,求最后谁赢了。

Input

x   「1,10000」

k  「1,100」

ai  「1,x」

output

如果Alice能赢的话,请输出“Alice”,否则请输出“Bob”,每个实例的输出占一行。

Examples

Input

9
2
1 4

Output

Alice

正确解法:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<string>
 4 #include<cstring>
 5 #include<map>
 6 #include<set>
 7 #include<vector>
 8 #include<queue>
 9 #include<algorithm>
10 #include<cmath>
11 using namespace std;
12 typedef long long ll;
13 const int inf=0x7fffffff;
14 const int N=1000000+100;
15 const int M=9999999;
16 const ll mod=1000000000+7;
17 int x,k,a[110];
18 int sg[110];
19 int mex(int x)
20 {
21     if(sg[x]!=-1)   return sg[x];
22     bool flag[110];
23     for(int i=1;i<=k;i++)
24     {
25         int temp=x-a[i];
26         if(temp<0)  break;
27         sg[temp]=mex(temp);
28         flag[sg[temp]]=1;
29     }
30     for(int i=0;;i++)
31     {
32         if(flag[i]==0)
33         {
34             sg[x]=i;
35             break;
36         }
37     }
38     return sg[x];
39 }
40 int main()
41 {
42     scanf("%d",&x);
43     scanf("%d",&k);
44     for(int i=1;i<=k;i++)
45         scanf("%d",&a[i]);
46     memset(sg,-1,sizeof(sg));
47     if(mex(x)==0)
48         cout<<"Bob"<<endl;
49     else
50         cout<<"Alice"<<endl;
51 
52 
53 
54     return 0;
55 }
View Code

 

 

 

 

posted @ 2019-04-03 10:14  kaike  阅读(340)  评论(0编辑  收藏  举报