曖殇

博客园 首页 联系 订阅 管理

前提:

足够聪明,所以,条件注定了胜败。

博弈:

1.巴什博弈(Bash Game) 一堆石头两个人取,最多取m最少取1,取光者胜。

2.威佐夫博奕(Wythoff Game) 两堆石头轮流取,从一堆中取k个或者同时取k个,取光者胜。

3.尼姆博弈论(Nimm Game) n堆石头 n堆石头,每次取一堆,无限制,取光者胜。

 

 

两个状态:

P-position P指的是Previous上一个

N-position N指的是next下一个

position位置

定义:

上一个想赢,所以这个位置的人必输,即先手必输。为p状态(奇异局势)

相对于上一个人,他的下一个就是当前位置的,当前位置想赢,就是先手必赢。为N状态(非奇异局势)

 

 

.巴什博弈(Bash Game)

n%(m+1)=0;先手必输(足够聪明)

else

先手取n%(m+1),后手必输。

 

 

.威佐夫博奕(Wythoff Game)

必输局势(0,0)

所以相对于他,有(1,0)(2,0)(1,1)(2,2)等必赢

那么相对于这个,加上一个一次性取不完的条件(1,2)那么必输,不管怎么取都会回到上步比赢的状态。

然后递推:必输的状态有(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)

得出规律公式(百度百科有证明)

ak=[k*(1+√5)/2],bk=ak+k;

满足黄金分割,威佐夫博弈又叫黄金分割博弈

所以

a:b=√5-1:2时先手必输。

else

先手必赢

.尼姆博弈论(Nimm Game)

很简单的取,假设有三堆石头(1,1,0),先手取1个,后手取另一个就一定能赢(先手必输策略)。同理假设有三堆石头(1,2,3)就可以分成(1,10,10,1)又是先手必输,很明显的可以看出来这就是异或关系“^”,当所有堆的石头异或为零时,就存在,相对应的,相同的石头个数。同理,假设异或结束后不为零,先手取掉这些就好了,这样异或就为零后手必输了。

 

 

.斐波那契博弈(Fibonacci Nim Game)

一堆石子,两人轮流取,先取者第1次可以取任意多个,但不能全部取完,以后每次取的石子数不能超过上次取子数的2倍。取完者胜。

自行百度

主要是变形:

引入定理:

Sprague-Grundy定理(SG定理,又叫SG函数)

首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数,很迷。

1堆n个的石子,每次只能取{ 1, 3, 4 }个石子,先取完石子者胜利,那么各个数的SG值为多少?

 

SG[0]=0,f[]={1,3,4},

 

x=1 时,可以取走1 - f{1}个石子,剩余{0}个,所以 SG[1] = mex{ SG[0] }= mex{0} = 1;

 

x=2 时,可以取走2 - f{1}个石子,剩余{1}个,所以 SG[2] = mex{ SG[1] }= mex{1} = 0;

 

x=3 时,可以取走3 - f{1,3}个石子,剩余{2,0}个,所以 SG[3] = mex{SG[2],SG[0]} = mex{0,0} =1;

 

x=4 时,可以取走4-  f{1,3,4}个石子,剩余{3,1,0}个,所以 SG[4] = mex{SG[3],SG[1],SG[0]} = mex{1,1,0} = 2;

 

x=5 时,可以取走5 - f{1,3,4}个石子,剩余{4,2,1}个,所以SG[5] = mex{SG[4],SG[2],SG[1]} =mex{2,0,1} = 3;

 

以此类推.....

X        0  1  2  3  4  5  6  7  8....

SG[x]    0  1  0  1  2  3  2  0  1....

 

 

 

步骤:

1、预处理 f 数组(当前通过哪些操作后可得到的状态)

2、使用另一个数组标记后继状态。

3、模拟 mex 运算,找最小值,赋给SG

4、重复2-3,完成过程。

 

 

什么意思呢,假设有一堆5个的石头,5可以变成4,2,1那种形式,连续的sg就是0,1,2,如果它想赢,那么他为什么不把他拿后的状态让对面输呢,因为他的SG有0啊,可以取到对面输。这样看,SG函数只有0,1,就应该够了,当然,这是因为只有一堆,如果是多堆:

继续看样例,

假设有三堆,3,4,5

SG[3]=1

SG[4]=2

SG[5]=3

想要赢怎么赢,让这些SG全部转化为0,不就赢了,然后是不是好熟悉,三堆,1,2,3,可以任意取,全取为0。这样就成了nimm博弈了。

 

一个计算SG函数的实例:

/*输入n,从1开始,每次乘以2~9的数,谁最先达到n谁胜*/

#include<iostream>  

#include<cstdio>  

#include<cstring>  

#include<set>  

#define mem(a,x) memset(a,x,sizeof(a))  

using namespace std;  

typedef long long ll;  

const int N = 100000;   

int sg[N+4];  

void solve()  

{  

    sg[1] = 0;   //败态

    for (int i = 2;i <= N;++i)  

    {  

        set<int>s;  

        for (int j = 2;j <= 9;++j)  

        {  

            int to = i/j;  

            if (i%j)to++;  

            s.insert(sg[to]);//i>=j*to 所以如果存在to态则i可转化为to态 (同时记录sg[]出现的值用于求mex)/到达i可以超过i

        }

        int g = 0; // (若to态没有必败态,则i必败)或者一直到(最小的不属于这个集合的非负整数)即sg[]没出现的那个值

        while (s.count(g)){

         ++g;

}

        sg[i] = g;  

    }  

    for (int i = 0;i <= 9000;++i)   

    {  

        cout<<i<<" "<<sg[i]<<endl;  

    }   

}  

int main()  

{  

solve();

    return 0;  

}

 

posted on 2019-08-05 13:15  曖殇  阅读(145)  评论(0编辑  收藏  举报