zoukankan      html  css  js  c++  java
  • 浅谈博弈论中的两个基本模型——Bash Game&&Nim Game

    最近在数学这一块搞了蛮多题目,已经解决了数论基础,线性代数(只有矩阵,行列式待坑),组合数学中的一些简单问题。所以接下来不可避免的对博弈论这一哲学大坑开工。

    当然,由于我很,所以也只能从最基础最容易的部分讲起了。

    这次主要介绍两个基本模型:Bash Game&&Nim Game,还是比较经典的

    下面开始讲

    1.Bash Game

    Bash Game(巴什博弈)是一种零基础的入门题目,它的基本模型大概是这样的:

    一堆石子共n个,两人轮流从中取石子,规定每次至少取一个,最多取m个,最后取光者得胜。问两人博弈,他们都采用最聪明的策略,问最后谁可以必胜。

    首先我们从小开始分析:

    • 当m>=n时,先手可以一把抓完石子,这样先手必胜

    • 当n=m+1时,先手无论怎么抓,都会留下1~m个石子,这样后手一把就可以抓完,这样先手必败

    • 当m+1<n<2*(m+1)时,先手只要抓适当的石子就可以剩下m+1个石子,然后后手必输,那么先手必胜

    • 当n=2*(m+1)时,后手可以采取这种策略,当先手抓x个时,后手就抓m+1-x个,这样就会把m+1的情况送给先手,那么先手必败

    • ......

    所以通过上面的分析我们很容易得出:当n%(m+1)==0时,先手必败;否则先手必胜

    这个很简单吧,因为谁先面对k*(m+1)(k为正整数)这种局面就必定失败。因为一方可以每次让你们两个取得石子和为m+1导致另一方失败。

    这个问题还有一些变形,比较经典的就是:把一个数从0开始不断增加,每次增加的范围都是1~k,谁先让数增加到n就Win||Lose

    这个直接转化为Bash Game做一下即可

    这里给几道例题&&CODE(以下例题都来自HDU

    1846

    Bash博弈的板子题,直接上即可

    CODE

    #include<cstdio>
    using namespace std;
    int t,n,m;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); 
        read(t);
        while (t--)
        {
            read(n); read(m);
            puts(n%(m+1)?"first":"second");
        }
        return 0;
    }
    

    2149

    这就是那种变式的情况,我们转化一下在做转化个屁,至于输出方案的话特判一下即可

    CODE

    #include<cstdio>
    using namespace std;
    int n,m;
    inline void write(int x)
    {
        if (x/10) write(x/10);
        putchar(x%10+'0');
    }
    int main()
    {
        register int i;
        while (scanf("%d%d",&m,&n)!=EOF)
        {
            if (n>=m)
            {
                for (i=m;i<n;++i)
                write(i),putchar(' '); write(n); putchar('
    ');
            } else
            if (m%(n+1)) write(m%(n+1)),putchar('
    '); else puts("none");
        }
        return 0;
    }
    

    2138

    同上,Bash Game直接上即可

    CODE

    #include<cstdio>
    using namespace std;
    int t,n,m;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); 
        read(t);
        while (t--)
        {
            read(n); read(m);
            puts(n%(m+1)?"Grass":"Rabbit");
        }
        return 0;
    }
    

    4764

    这道题就注意一下大于等于n你就输了,所以n要减一

    CODE

    #include<cstdio>
    using namespace std;
    int n,m;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); 
        for (;;)
        {
            read(n); read(m);
            if (!n&&!m) break;
            puts((n-1)%(m+1)?"Tang":"Jiang");
        }
        return 0;
    }
    

    2.Nim Game

    这其实是Bash Game的进化版,但是思维深度上了好几个台阶

    首先我们看基本模型:

    地上有n堆石子,每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这n堆石子的数量,他想知道是否存在先手必胜的策略。

    这是不是很复杂,首先我们考虑数据小的情况:

    • 只有一堆石子时,除非没有石子,否则先手一把抓完即可

    • 有两堆石子时,后手只需要跟随先手的动作即可

    • ......(后面的根本分析不出来好吧)

    但是在我们之前已经有大神成功证明了一个神奇的结论

    当n堆石子的数量异或和等于0时,先手必败,否则先手必胜

    证明请移步至attack dalao's blog

    很懵逼对吗其实我也是,那么让我们来感性理解一下(以下的说明仅为个人理解,几乎没有任何理论依据,请选择阅读)

    首先由于全部都是0的时候就失败了,所以我们可以认为当它们的异或和为0就是必败态

    这样我们先手是如果异或和为0那么就输了

    如果不是呢,我们就可以通过一种猥琐的方法来获胜(就是上面讲的方法)

    我们可以形象地认为它与Bash Game中先手先取得只剩下k*(m+1)然后通过让和始终为m+1来取胜

    然后这就是神奇的Nim Game

    这里有一道模板题Luogu P2197 nim游戏

    由于就是裸的Nim Game,这里就直接上CODE了

    #include<cstdio>
    using namespace std;
    int t,n,x,tot;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch=tc();
        while (ch<'0'||ch>'9') ch=tc();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); 
        register int i; read(t);
        while (t--)
        {
        	for (read(n),tot=0,i=1;i<=n;++i)
    		read(x),tot^=x;
    		puts(tot?"Yes":"No");
    	}
        return 0;
    }
    

    当然这只是博弈论的入门,一些真正强力的东西如SG函数&&MINMAX等东西还是一脸懵逼

  • 相关阅读:
    Weex-语法笔记 一
    Entitlements (授权机制) 延伸
    FOUNDATION_EXPORT 延伸
    NS_ASSUME_NONNULL_BEGIN 延伸
    SSLPinning 延伸
    Socket.io 延伸
    UI_APPEARANCE_SELECTOR 延伸
    Modules和Autolinking
    代码块(Block)回调一般阐述
    数据库连接池配置错误导致OOM
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9104602.html
Copyright © 2011-2022 走看看