博弈汇总

一、介绍概念:

 P点 即必败点,某玩家位于此点,只要对方无失误,则必败;

N点 即必胜点,某玩家位于此点,只要自己无失误,则必胜。

定理:

        (1) 所有终结点都是必败点P(上游戏中,轮到谁拿牌,还剩0张牌的时候,此人就输了,因为无牌可取);

        (2)所有一步能走到必败点P的就是N点;

        (3)通过一步操作只能到N点的就是P点;

首先来玩个游戏,引用杭电课件上的:

(1) 玩家:2人;

(2) 道具:23张扑克牌;

(3) 规则:

游戏双方轮流取牌;

每人每次仅限于取1张、2张或3张牌;

扑克牌取光,则游戏结束;

最后取牌的一方为胜者

    自己画下图(N-P图)看看。

    x :  0  1  2  3  4  5  6  7  8  9  10。。。

    posP   N N  N  P N  N  N  P N   N 。。。

    所以若玩家甲位于N点。只要每次把P点让给对方,则甲必胜;

    反之,若玩家甲位于P点,他每次只能走到N点,而只要乙每次把P点让给甲,甲必败;

   hdu  2147   2188   2149   1847

二、巴什博奕(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)的倍数,就能最后获胜。

hdu  1846   

AC代码如下:

 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 }
View Code

三、威佐夫博奕(Wythoff Game):

      有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。、

(此处先省略。。。。)

四、尼姆博奕(Nimm Game):

   有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

  1.有两个玩家;

  2. 有三堆扑克牌(比如:可以分别是    579张);

  3. 游戏双方轮流操作;

  4. 玩家的每次操作是选择其中某一堆牌,然后从中取走任意张;

  5.最后一次取牌的一方为获胜方;

  对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0,其中^表示位异或(xor)运算。


  参考博文:http://www.cnitblog.com/weiweibbs/articles/42734.html

            http://www.cnblogs.com/kuangbin/archive/2011/08/28/2156426.html
      证明:http://acm.hdu.edu.cn/forum/read.php?fid=9&tid=10617

任何奇异局势(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。

例:(14,21,39),14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。

    我们来实际进行一盘比赛看看:

        甲:(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)奇异局势
        甲胜。

   练习题:hdu  1849    1850

  hdu1849解题报告:

Nim游戏模型:有三堆石子,分别含有a、b、c个石子。两人轮流从某一堆中取任意多的石子,规定每次至少取一个,多者不限。最后取光者得胜。

定理1:Nim游戏的一个状态(a、b、c)是P状态,当且仅当a^b^c =0。

对应此题就是:共有m个棋子就是m堆石子,把每个位置的标号等价于该堆石子的数目,取走最后一颗石子的人获胜,就是最后一个回到0位置的人获胜。即Nim博弈问题。

   AC代码如下:

 1 #include<stdio.h>
 2 int main()
 3 {
 4     int n,i,Nim[1010];
 5     while(scanf("%d",&n)&&n!=0)
 6     {
 7         int sg=0;
 8         for(i=0;i<n;i++)
 9         {
10             scanf("%d",&Nim[i]);
11             sg^=Nim[i];
12         }
13         if(sg==0)
14             printf("Grass Win!
");
15         else
16             printf("Rabbit Win!
");
17     }
18     return 0;
19 }
View Code

hdu  1850解题报告

题意:有n堆石子,两个人轮流从n堆石子中取走至少1个石子问先手能否获胜,若能,输出先手可取的方案数

解法:

  1. 本题中每一堆都可以选任意个,所以每一堆的SG值都是所剩余的个数。 
  2. 最后结果是所有堆的SG值异或的结果。令sg = 所有堆的SG值异或的结果 
  3. 如果sg == 0,则是必败点。 
  4. 如果sg != 0,使取后结果为0的策略是必胜策略 
  5. 具体怎么取呢? if(sg^a[i]<a[i])  ans++  即可,为什么呢?
  6. 有n堆物品,最多有n个情况,因为一次只能拿一堆的物品,所以在这一堆拿多少受限于其他n-1堆,所以就可以枚举所有的奇异局势,看目前这一堆需要多少个物品才能满足奇异局势,(上面这些是针对开始时候是非奇异局势来说的),然后求出来这个值再与之比较
  7. 每一堆的数值与sg相异或,所得的结果就是这一堆取走物品后剩余的数量,即(a,b,c)-->(a,b,a^b), 因为sg=a^b^c,所以sg^c=a^b^(c^c)=a^b^0=a^b,故sg^c就是非奇异局势时 c 堆上取走一定的石子后剩余的数量,明显这要比原始的数量少才可行,所以要满足条件:sg^a[i]<a[i],只要满足这个条件就是一种可行方案了

AC代码如下:

 1 #include<stdio.h>
 2 int main()
 3 {
 4     int n,i,a[105];
 5     while(scanf("%d",&n)&&n)
 6     {
 7         int sg=0;
 8         for(i=0;i<n;i++)
 9         {
10             scanf("%d",&a[i]);
11             sg^=a[i];
12         }
13         int ans=0;
14         for(i=0;i<n;i++)
15             if((sg^a[i])<a[i])
16                 ans++;
17         printf("%d
",ans);
18     }
19     return 0;
20 }
View Code

五、SG函数

 参考博文:http://www.cnitblog.com/weiweibbs/articles/42735.html

SG即Sprague-Garundy函数,把博弈游戏抽象成有向无环图

(1) 有向无环图
(2) 玩家1先移动,起点是x0
(3) 两个玩家轮流移动
(4) 对于顶点x, 玩家能够移动到的顶点集记为F(x).
(5) 不能移动的玩家会输掉游戏

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

定义一个图的Sprague-Grundy函数(X,F)是定义在X上的非负函数g(x),并且满足:
       g(x) = mex{g(y) : yF(x)}

看到这里先好好理解一下sg值是怎么求的;

如果在取子游戏中每次只能取{1,2,3},那么各个数的SG值是多少?

x      0 1 2 3 4 5 6 7 8 9 10 11 12 13 14. . .
g(x) 0 1 2 3 0 1 2 3 0 1  2   3   0   1   2. . .
看看这个和上面那个图的规律:

  P-即令 g(x) = 0 的 点!
 N-即令 g(x) > 0 的 点!

最后看下组合博弈,就是把简单的游戏组合起来,比如3堆的可以看成3个一堆的游戏。

 定理:

假设游戏 GiSG函数是gi, i=1,…,n, 
G = G1 + … + Gn 的 SG函数是
g(x1,…,xn) = g1(x1)⊕…⊕gn(xn).

其中那个符合就是异或^

看看是不是和Nim游戏的结论差不多?

有关SG 函数的模板请参考:http://www.cnblogs.com/frog112111/p/3199780.html

原文地址:https://www.cnblogs.com/frog112111/p/3199073.html