zoukankan      html  css  js  c++  java
  • 基础博弈

    前提:

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

    博弈:

    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;  
    
    }
  • 相关阅读:
    如何使用RabbitMQ实现事件总线
    一起学Vue:UI框架(elementui)
    一起学Vue:访问API(axios)
    一起学Vue:CRUD(增删改查)
    一起学Vue:路由(vuerouter)
    如何使用IMemoryCache实现内存缓存
    手把手教你AspNetCore WebApi:Nginx(负载均衡)
    一起学Vue:状态管理(Vuex)
    自我介绍
    牛客练习赛74AB
  • 原文地址:https://www.cnblogs.com/mozheaishang/p/11302436.html
Copyright © 2011-2022 走看看