SG函数&&SG定理&&游戏的和&&公平组合游戏

本文探讨了公平组合游戏的概念,包括必胜点和必败点,并介绍了SG函数及其在解决此类游戏中的应用。SG定理说明了游戏和的SG函数值是子游戏SG函数值的异或。通过实例展示了如何利用这些理论解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

公平组合游戏(Impartial Combinatorial Games)

条件:

1.两名选手交替进行操作

2.两名选手局面移动的权力相同

3.当前选手的合法移动集合至于当前的局面有关,与轮到哪名选手操作、以前的任何操作、骰子的点数或者其它什么因素无关

4.如果当前选手的合法移动集合为空,则判此选手负

用状态图来理解就是:将一个游戏中的所有可能出现的状态看作是图的节点,如果一个状态可以一步转移到另一个状态,则这两个状态之间有一条有向边,设初始棋子在任意一节点上,通过有向边两名选手交替移动棋子,直至棋子不能再被移动结束。

例如:n=6,m=3的巴什博弈状态图如下:

以下讨论的是游戏的状态图为有向无环图的情况,即不存在平局

必胜点和必败点的概念:

P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败。

N点:必胜点,同上

性质:

1.P点的所有后继点都是N点

2.N点得后继点中存在P点

3.终结点一定是P点

SG函数:(针对解决公平组合游戏,不存在平局,即无环)

对于任意状态x,

                SG(x)=mex{ SG(y) |  y为x的所有后继状态 }

如果知道一个状态的SG值,我们就可以快速判断出它是P点还是N点

如果SG值等于0,那么是P点,否则是N

证明上述结论的链接:https://blog.youkuaiyun.com/philipsweng/article/details/48395375

游戏的和:

我们可以定义有向无环图游戏的和(Sum of Graph Games):设G1、G2、……、Gn是n个有向图游戏,定义游戏G是G1、G2、……、Gn的和(Sum),游戏G的移动规则是:任选一个子游戏Gi 并移动上面的棋子。

SG定理:

     SG(G)=SG(G1)^SG(G2)^…^SG(Gn)

游戏的和的SG函数值是它的所有子游戏的SG函数值的异或

证明上述结论的链接:https://blog.youkuaiyun.com/philipsweng/article/details/48395375

应用:

运用游戏的和,SG函数,SG定理我们可以将一个游戏分解为若干子游戏,分别求解若干子游戏的SG函数值,再将它们异或起来,得到总游戏的SG值。例如下面这个例子:

n堆石子,每次可以从第1堆石子里取1颗、2颗或3颗,可以从第2堆石子里取奇数颗,可以从第3堆及以后石子里取任意颗…… 我们可以把它看作3个子游戏,第1个子游戏只有一堆石子,每次可以取1、2、3颗,很容易看出x颗石子的局面的SG值是x%4。第2个子游戏也是只有一堆 石子,每次可以取奇数颗,经过简单的画图可以知道这个游戏有x颗石子时的SG值是x%2。第3个游戏有n-2堆石子,就是一个nim游戏。对于原游戏的每 个局面,把三个子游戏的SG值异或一下就得到了整个游戏的SG值。

经典题:

poj1848

 #include<bits/stdc++.h>
 using namespace std;
 #define maxn 1010
 #define N 20
 int S[maxn];
 int SG[maxn];
 int f[N];

 void getSG()
 {
     memset(SG,0,sizeof SG);
     for(int i=1;i<=maxn;i++)
     {
         memset(S,0,sizeof S);
         for(int j=0;f[j]<=i&&j<=N;j++)
           S[SG[i-f[j]]]=1;
         for(int j=0;;j++)
         {
             if(!S[j])
             {
               SG[i]=j;
               break;
             }
         }
     }
     return;
 }

 int main()
 {
     int m,n,p;
     f[0]=1;
     f[1]=1;
     for(int i=2;i<=20;i++)
     {
         f[i]=f[i-1]+f[i-2];
     }
     getSG();
     while(scanf("%d%d%d",&m,&n,&p),m||n||p)
     {
         if(SG[m]^SG[n]^SG[p])
            printf("Fibo\n");
         else
            printf("Nacci\n");
     }
     return 0;
 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值