博弈题目模型总结

12 篇文章 0 订阅
9 篇文章 0 订阅

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

 判断方法:法(1)从1到m枚举s,若(n-s)%(m+1)==0,则break,先取者胜,如果没有一个s满足前面的式子,则后取者胜

                  法(2)可选步数为1-m的连续整数,SG(x) = x % (m+1),判断SG值是否为奇异局势即可

(二)威佐夫博奕(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同
时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

定义奇异局势为先手必败点

对于第k个奇异局势(m(k),n(k))来说,m(k)是前面没有出现过的最小自然数,n(k)=m(k)+k

判断一个点是不是奇异局势的公式与黄金分割有关,为:

m(k) = k * (1 + sqrt(5))/2

n(k) = m(k) + k

给出m、n,k=n-m,若m=floor(k*(1+sqrt(5.0))/2),则该局面为奇异局势,先手必败,否则先手必胜

 

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

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

给出a,b,c,若不为奇异局势,则先手胜

 

(四)今有若干堆火柴,两人依次从中拿取,规定每次只能从一堆中取若干根,
可将一堆全取走,但不可不取,最后取完者为胜,求必胜的方法。

和(三)尼姆博弈相似
若所有火柴数异或为0,即奇异局势,先手必败,否则,先手必胜。

若要求出如果先手能胜利,先手有多少种方案取胜,即要求出有多少种方法能使一个非奇异局势变为奇异局势:

法一:可以枚举每堆火柴,若其他火柴异或得出的结果小于这堆火柴,则方案数加一。

 法二:如果先手能胜利,则每堆火柴异或结果不为0,设第i堆火柴数为A(i),设为c = A(1) xor A(2) xor … xor A(n) > 0,把c表示成二进制,记它的二进制数的最高位为第p位,则必然存在一个A(t),它二进制的第p位也是1,那么设x = A(t) xor c,则得到x < A(t)。。所以求出有多少个A(i)xor c<A(i),即求出了有多少方案数,因为当x=A(t) xor c<A(t),从A(t)堆中取出 A(t) – x 根火柴后能讲非奇异局势变为奇异局势。

 

(五)今有若干堆火柴,两人依次从中拿取,规定每次只能从一堆中取若干根,
可将一堆全取走,但不可不取,最后取完者为负,求必胜的方法。
若一堆中仅有根火柴,则被称为孤单堆。若大于1个,则称为充裕堆

先手胜当且仅当①所有堆火柴数都为1且游戏的SG值(所有火柴数异或所得值)为0;②存在某堆火柴数大于1且游戏的SG值不为0.

 

博弈题目的王道:

/*求SG值模版:
计算从1-n范围内的SG值。
Array(存储可以走的步数,Array[0]表示可以有多少种走法)
Array[]需要从小到大排序
1.可选步数为1-m的连续整数,直接取模即可,SG(x) = x % (m+1);
2.可选步数为任意步,SG(x) = x;
3.可选步数为一系列不连续的数,用GetSG(计算)*/
int SG[MAX], hash[MAX];
void GetSG(int Array[], int n = MAX-1)
{
    int i, j;
    memset(SG, 0, sizeof(SG));
    for(i = 0; i <= n; i++)
    {
        memset(hash, 0, sizeof(hash));
        for(j = 1; Array[j]<=i; j++)
            hash[SG[i - Array[j]]] = 1;
        for(j = 0; j <= n; j++)
        {
            if(hash[j] == 0)
            {
                SG[i] = j;
                break;
            }
        }
    }
}



 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值