博弈论

一.斐波那契博弈

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

Input

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

先取者负输出"Second win". 先取者胜输出"First win". 

Sample Input

2
13
10000
0

Sample Output

Second win
Second win
First win


解题思路:
从PN图入手,我们会发现如果是斐波那契数先手必输,后手胜利。

      2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20……

     p p n p n n p n  n    n   n   p    n   n   n   n    n   n   n……

我这里直接利用斐波那契博弈的结论,不能给出证明,下面是可以参考的
证明

https://blog.csdn.net/dgq8211/article/details/7602807

第二数学归纳法证明:

为了方便,我们将n记为f[i]。

1、当i=2时,先手只能取1颗,显然必败,结论成立。

2、假设当i<=k时,结论成立。

     则当i=k+1时,f[i] = f[k]+f[k-1]。

     则我们可以把这一堆石子看成两堆,简称k堆和k-1堆。

    (一定可以看成两堆,因为假如先手第一次取的石子数大于或等于f[k-1],则后手可以直接取完f[k],因为f[k] < 2*f[k-1])

     对于k-1堆,由假设可知,不论先手怎样取,后手总能取到最后一颗。下面我们分析一下后手最后取的石子数x的情况。

     如果先手第一次取的石子数y>=f[k-1]/3,则这小堆所剩的石子数小于2y,即后手可以直接取完,此时x=f[k-1]-y,则x<=2/3*f[k-1]。

     我们来比较一下2/3*f[k-1]与1/2*f[k]的大小。即4*f[k-1]与3*f[k]的大小,对两值作差后不难得出,后者大。

     所以我们得到,x<1/2*f[k]。

     即后手取完k-1堆后,先手不能一下取完k堆,所以游戏规则没有改变,则由假设可知,对于k堆,后手仍能取到最后一颗,所以后手必胜。

     即i=k+1时,结论依然成立。

那么,当n不是Fibonacci数的时候,情况又是怎样的呢?

这里需要借助“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。

关于这个定理的证明,感兴趣的同学可以在网上搜索相关资料,这里不再详述。

分解的时候,要取尽量大的Fibonacci数。

比如分解85:85在55和89之间,于是可以写成85=55+30,然后继续分解30,30在21和34之间,所以可以写成30=21+9,

依此类推,最后分解成85=55+21+8+1。

则我们可以把n写成  n = f[a1]+f[a2]+……+f[ap]。(a1>a2>……>ap)

我们令先手先取完f[ap],即最小的这一堆。由于各个f之间不连续,则a(p-1) > ap  + 1,则有f[a(p-1)] > 2*f[ap]。即后手只能取f[a(p-1)]这一堆,且不能一次取完。

此时后手相当于面临这个子游戏(只有f[a(p-1)]这一堆石子,且后手先取)的必败态,即先手一定可以取到这一堆的最后一颗石子。

同理可知,对于以后的每一堆,先手都可以取到这一堆的最后一颗石子,从而获得游戏的胜利。

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 using namespace std;
 5 const int N = 55;///参看斐波那契表,第50左右时已经超过2^32
 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)
30             puts("Second win");
31         else
32             puts("First win");
33     }
34     return 0;
35 }

二.威佐夫博弈(Wythoff Game)

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

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


解题思路:直接给出结论,没有给出证明。
若两堆物品的初始值为(x,y),且x<y,则另z=y-x;记w=(int)[((sqrt(5)+1)/2)*z  ];若w=x,则先手必败,否则先手必胜。
 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<stdlib.h>
 4 #include<math.h>
 5 using namespace std;
 6 int main()
 7 {
 8     int n,m,k,w,min;
 9     while(scanf("%d%d",&n,&m)!=EOF)
10     {
11         if(n>m)
12         {
13             k=n-m;
14             min=m;
15         }
16         else
17         {
18             k=m-n;
19             min=n;
20         }
21         w=(int)((sqrt(5)+1)/2*k);
22         if(w==min)
23         {
24             printf("0\n");
25         }
26         else
27         {
28             printf("1\n");
29         }
30 
31     }
32     return 0;
33 }

三.巴什博奕(Bash Game)

Tang and Jiang are good friends. To decide whose treat it is for dinner, they are playing a game. Specifically, Tang and Jiang will alternatively write numbers (integers) on a white board. Tang writes first, then Jiang, then again Tang, etc... Moreover, assuming that the number written in the previous round is X, the next person who plays should write a number Y such that 1 <= Y - X <= k. The person who writes a number no smaller than N first will lose the game. Note that in the first round, Tang can write a number only within range [1, k] (both inclusive). You can assume that Tang and Jiang will always be playing optimally, as they are both very smart students. 

InputThere are multiple test cases. For each test case, there will be one line of input having two integers N (0 < N <= 10^8) and k (0 < k <= 100). Input terminates when both N and k are zero. 
OutputFor each case, print the winner's name in a single line. 
Sample Input

1 1
30 3
10 2
0 0

Sample Output

Jiang
Tang
Jiang

 题目意思:唐和江两个人轮流在白板上写数,所写的数字在1-k之间,谁所写的数与之前所写的数的和先超过n,那么谁就会输。

 解题思路:巴什博奕的简单变形,原来的问题模型是:只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个,最后取光者得胜。

 解决思路:当n=m+1时,由于一次最多只能取m个,所以无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜,所以当一方面对的局势是n%(m+1)=0时,其面临的是必败的局势。所以当n=(m+1)*r+s,(r为任意自然数,s≤m)时,如果先取者要拿走s个物品,如果后取者拿走x(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。、变形:条件不变,改为最后取光的人输。

结论:当(n-1)%(m+1)==0时后手胜利。

posted @ 2018-04-29 19:59  王陸  阅读(458)  评论(0编辑  收藏  举报