博弈知识汇总



博弈知识汇总

来源:网络汇总和自己总结。

有兴趣可以看一下算法合集之《组合游戏略述——浅谈SG游戏的若干拓展及变形》这篇文章,写的很好,适于拓展学习。http://pan.baidu.com/s/1qWqJXne

有一种很有意思的游戏,就是有物体若干堆,可以是火柴棍或是围棋子等等均可。两个人轮流从堆中取物体若干,规定最后取光物体者取胜。这是我国民间很古老的一个游戏,别看这游戏极其简单,却蕴含着深刻的数学原理。下面我们来分析一下要如何才能够取胜。

(一)巴什博奕(Bash Game):只有一堆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)的倍数,就能最后获胜。这个游戏还可以有一种变相的玩法:两个人轮流报数,每次至少报一个,最多报十个,谁能报到100者胜。
(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。这种情况下是颇为复杂的。我们用(ak,bk)(ak ≤ bk ,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)。可以看出,a0=b0=0,ak是未在前面出现过的最小自然数,而 bk= ak + k,奇异局势有如下三条性质:

    1。任何自然数都包含在一个且仅有一个奇异局势中。由于ak是未在前面出现过的最小自然数,所以有bk > ak-1 ,而 bk= ak + k > ak + k-1 = bk-1 > ak-1 。所以性质1。成立。
    2。任意操作都可将奇异局势变为非奇异局势。事实上,若只改变奇异局势(ak,bk)的某一个分量,那么另一个分量不可能在其他奇异局势中,所以必然是非奇异局势。如果使(ak,bk)的两个分量同时减少,则由于其差不变,且不可能是其他奇异局势的差,因此也是非奇异局势。
    3。采用适当的方法,可以将非奇异局势变为奇异局势。假设面对的局势是(a,b),若 b = a,则同时从两堆中取走 a 个物体,就变为了奇异局势(0,0);如果a = ak ,b > bk,那么,从b中取走b– bk个物体,即变为奇异局
势;如果 a = ak ,b < bk ,则同时从两堆中拿走 ak–ab + ak个物体,变为奇异局势( ab–ak ,ab–ak+b– ak);如果a > ak ,b= ak + k,则从第一堆中拿走多余的数量a–ak 即可;如果a<ak,b= ak + k,分两种情况,第一种,a=aj (j < k),从第二堆里面拿走 b – bj 即可;第二种,a=bj (j < k),从第二堆里面拿走 b – aj 即可。

    从如上性质可知,两个人如果都采用正确操作(每次取都是对自己有利的),那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。那么任给一个局势(a,b),怎样判断它是不是奇异局势呢?我们有如下公式:ak =[k(1+√5)/2],k= bk-ak (也就是只需判断ak==[(bk-ak)*(1+√5)/2]是否成立,成立就是奇异局势,注意[]为取整)   (k=0,1,2,…,n 方括号表示取整函数)奇妙的是其中出现了黄金分割数(1+√5)/2 = 1.618…,因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a=aj+1,bj+1=aj+1+j+1,若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。

(三)尼姆博奕(Nimm Game):有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。这种情况最有意思,它与二进制有密切关系,我们用(a,b,c)表示某种局势,首先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是
(0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情形。计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(1,2,3)的按位模2加的结果:

1 =二进制01
2 =二进制10
3 =二进制11 (+)
———————
0 =二进制00 (注意不进位)

    对于奇异局势(0,n,n)也一样,结果也是0。

    任何奇异局势(a,b,c)都有a(+)b(+)c =0。

如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a(+)b,即可,因为有如下的运算结果: a(+)b(+)(a(+)b)=(a(+)a)(+)(b(+)b)=0(+)0=0。要将c 变为a(+)b,只要从 c中减去 c-(a(+)b)即可。
     例1。(14,21,39),14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。

    例2。(55,81,121),55(+)81=102,121-102=19,所以从121中拿走19个物品就形成了奇异局势(55,81,102)。

    例3。(29,45,58),29(+)45=48,58-48=10,从58中拿走10个,变为(29,45,48)。

例4。我们来实际进行一盘比赛看看:
        甲:(7,8,9)->(1,8,9)奇异局势
        乙:(1,8,9)->(1,8,4)
        甲:(1,8,4)->(1,5,4)奇异局势
        乙:(1,5,4)->(1,4,4)
        甲:(1,4,4)->(0,4,4)奇异局势
        乙:(0,4,4)->(0,4,2)
        甲:(0.4,2)->(0,2,2)奇异局势
        乙:(0,2,2)->(0,2,1)
        甲:(0,2,1)->(0,1,1)奇异局势
        乙:(0,1,1)->(0,1,0)
        甲:(0,1,0)->(0,0,0)奇异局势
        甲胜。

SG等于当前所有堆做异或运算。

下面由例题题说明

1.

Being a Good Boy in Spring Festival

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4829    Accepted Submission(s): 2884

Problem Description

一年在外 父母时刻牵挂
春节回家 你能做几天好孩子吗
寒假里尝试做做下面的事情吧

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

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

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

 

 

Input

输入数据包含多个测试用例,每个测试用例占2行,首先一行包含一个整数M(1<M<=100),表示扑克牌的堆数,紧接着一行包含M个整数Ni(1<=Ni<=1000000i=1…M),分别表示M堆扑克的数量。M0则表示输入数据的结束。

 

 

Output

如果先手的人能赢,请输出他第一步可行的方案数,否则请输出0,每个实例的输出占一行。

 

 

Sample Input

35 7 90

 

 

Sample Output

1

 

基础Nim博弈

如果SG=0时,那么当前就是奇异点(先手输),输出0,如果SG=0,那么就是非奇异点(后手赢)。当SG=0时,对当前每一堆扫描,如果a[i]>(a[i]^SG),就有sum++,先手最后就有sum种取法获胜。

 

#include<stdio.h>
#define MAX 1000000
int a[MAX+10];
int main()
{
	int N,i,SG,sum;
	while(scanf("%d",&N)&&N!=0)
	{
		for(i=0,SG=0;i<N;i++)
		{
			scanf("%d",&a[i]);
			SG^=a[i];
		}
		
		for(i=0,sum=0;i<N;i++)
		if(a[i]>(a[i]^SG))
		sum+=1;
        printf("%d\n",sum);
		
	}
	return 0;
}

2.

Be the Winner 

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 689    Accepted Submission(s): 350

Problem Description 

Let's consider m apples divided into n groups. Each group contains no more than 100 apples, arranged in a line. You can take any number of consecutive apples at one time.
For example "@@@" can be turned into "@@" or "@" or "@ @"(two piles). two people get apples one after another and the one who takes the last is the loser. Fra wants to know in which situations he can win by playing strategies (that is, no matter what action the rival takes, fra will win). 

 

Input 

You will be given several cases. Each test case begins with a single number n (1 <= n <= 100), followed by a line with n numbers, the number of apples in each pile. There is a blank line between cases. 

Output 

If a winning strategies can be found, print a single line with "Yes", otherwise print "No".

Sample Input 

2 2 

3

Sample Output 

No 

Yes

此题是Nim博弈变形(anti-nim)

题目大意:有n堆苹果,每堆有mi个。两人轮流取,每次可以从一堆苹果中取任意连续个苹果,最后取光者为输。Fra先,问是否可以获胜。 

算法如下:

这题与以往的博弈题的胜负条件不同,谁先走完最后一步谁输,但他也是一类Nim游戏,即为anti-nim游戏。 

定义anti-nim游戏)  

桌子上有N堆石子,游戏者轮流取石子。 

每次只能从一堆中取出任意数目的石子,但不能不取。 n 

取走最后一个石子者败。

【SJ定理】

先手必胜当且仅当:

1)所有堆的石子数都为1且游戏的SG值为0

2)有些堆的石子数大于1且游戏的SG值不为0

 

【证明】 

1. 若所有堆都为1且SG值为0,则共有偶数堆石子,故先手胜。 

2. 

i)只有一堆石子数大于1时,我们总可以对该石子操作,使操作后堆数为奇数且所有堆的石子数均为1; 

ii)有超过一堆的石子数1时,先手将SG值变为0即可,且总还存在某堆石子数大于1 

 

先手胜。 

 

此题用到的概念: 

【定义1】:若一堆中仅有一个石子,则被称为孤单堆。若大于1个,则称为充裕堆 

【定义2】:T态中,若充裕堆的堆数大于等于2,则称为完全利他态,用T2表示;若充裕堆的堆数等于0,则称为部分利他态。用T0表示。 

        孤单堆的根数异或智慧影响二进制的最后以为,但充裕堆会影响高位(非最后一位)。一个充裕堆,高位必有一位不为0,则所有根数异或不为0。故不会是T态。 

【定理1】:S0态,即仅有奇数个孤单堆,必败。T0态必胜。 

证明:S0态,其实就是每次只能取一根。每次第奇数根都由自己取,第偶数根都由对方取,所以最后一根必由自己取。所以必败。同理:T0态必胜。 

【定理2】:S1态,只要方法正确,必胜。 

证明:若此时孤单堆堆数为奇数,把充裕堆取完;否则,取成一根。这样,就变成奇数个孤单堆,由对方取。由定理1,对方必输,己必胜。 

【定理3】:S2态不可转一次变为T0态。 

证明:充裕堆数不可能一次由2变为0。 

【定理4】:S2态可一次转变为T2态。 

证明:因为对于任何一个S态,总能从一堆中取出若干个使之成为T态。又因为S1态,只要方法正确,必胜。S2态不可转一次变为T0态,所以转变的T态为T2态。 

【定理5】:T2态,只能转变为S2态或S1态。 

证明:因为T态,取任何一堆的若干根都将成为S态。由于充裕堆不可能一次由2变为0,所以此时的S态不可能为S0态。得证。 

【定理6】:S2态,只要方法正确,必胜。 

证明:方法如下: 

1. S2态,就把它变为T2态。(定理4); 

2. 

对方只能T2转变为S2态或S1态(定理5)。 

3. 

若转变为S2,则转向①。 

4. 

若转变为S1,这时己必胜(定理1)。 

5. 

【定理7】:T2态必输。 

证明:同定理6. 

综上所述:必输态有:T2S0;必胜态有:S2S1T0

代码如下:

#include<iostream>
using namespace std;
int main()
{
    int i,n,m;
    while(cin >> n)
    {
              int flag = 0; //判断是否是孤单堆
              int s = 0;
              for(i = 0;i < n;i++) 
              {
                    cin >> m;
                    s ^= m;
                    if(m > 1) 
                         flag = 1;
              }
              if(flag == 0)//是孤单堆
                      if(n % 2)
                           cout << "No\n";
                      else
                           cout << "Yes\n";
              else
                  if(s == 0)
                      cout << "No" <<endl;
                  else
                      cout << "Yes" <<endl;
    }
    return 0;
}


Simoncode如下:

#include<stdio.h>
int main()
{
	int N,i,j,sum,num;
	while(scanf("%d",&N)!=EOF)
	{
		for(i=0,sum=0,num=0;i<N;i++)
	    {
	    	scanf("%d",&j);
	    	sum^=j;
	    	if(j!=1)
	    	num+=1;
	    }
	    if(num==0&&sum==0||num>0&&sum!=0)//SJ定理 
	    printf("Yes\n");
	    else
	    printf("No\n");
	}
	return 0;
}


ACM课作业:(HDOJ)
1846 Brave Game
1847 Good Luck in CET-4 Everybody!
1848 Fibonacci again and again
1849 Rabbit and Grass
1850 Being a Good Boy in Spring Festival
2149 Public Sale 
2188 悼念512汶川大地震遇难同胞——选拔志愿者 
2147 kiki’s game 
1079 Calendar Game 
1514 A Multiplication Game 
1404 Digital Deletions 
1536 S-Nim   1944 S-Nim

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值