• 博弈论


    一.典型的博弈模型:

    Nim博弈的一些思考:

    1.无法进行任何移动的局面(也就是 (terminal position) )是 (P-position)
    2.对于 (P-position),一定存在某种方式可以移动到 (N-position) 的局面;
    3.对于 (N-position),所有移动都导致 (P-position) 的局面。

    证明
    1.((0,0)) 为无法移动的状态,且为 (P-position)
    2.
    (t=a_1 igoplus a_2 igoplus ... igoplus a_n!=0),为当前状态。
    假设 (a_i o a_i^{'}),使得 (a_1 igoplus a_2 igoplus ...igoplus a_i^{'} igoplus ... igoplus a_n=0)
    必然会有一个 (a_i) 使 (t) 的二进制最高位是 (1),且 (a_i igoplus t<a_i)
    那么令 (a_i^{'}=a_i igoplus t),有
    (a_1 igoplus a_2 igoplus ...igoplus (a_i igoplus t) igoplus ... igoplus a_n=0)
    得证。
    3.
    (a_1 igoplus a_2 igoplus ...igoplus a_i igoplus ... igoplus a_n=0)
    假设 (a_i o a_i^{'}),则
    (a_1 igoplus a_2 igoplus ...igoplus a_i^{'} igoplus ... igoplus a_n=0)
    所以 (a_i=a_i^{'})
    当把 (a_i) 取走之后,剩余的数量的异或和等于 (a_i),为 (P-position)
    不满足要求。

    二.一般的博弈:

    1.(N/P)分析:

    (P)点:必败点,无论谁处于此位置,则在双方操作正确的情况下必败。
    (N)点:必胜点,处于此情况下,双方操作均正确的情况下必胜。
    必胜点和必败点的性质:
    1、所有终结点是 必败点 (P) 。(我们以此为基本前提进行推理,换句话说,我们以此为假设)
    2、从任何必胜点 (N) 操作,至少有一种方式可以进入必败点 (P)
    3、无论如何操作,必败点 (P) 都只能进入必胜点 (N)
      我们研究必胜点和必败点的目的时间为题进行简化,有助于我们的分析。通常我们分析必胜点和必败点都是以终结点进行逆序分析。这种分析方法可以帮助我们从以下题目中寻找到规律。
    例题:
    1.hdu1847
    2.hdu2147

    2.(SG)函数的运用:

    (Sprague-Grundy)定理((SG)定理)
      游戏和的 (SG) 函数等于各个游戏 (SG) 函数的 (Nim)和(各个数相异或的结果)。这样就可以将每一个子游戏分而治之,从而简化了问题。而 (Bouton) 定理就是 (Sprague-Grundy) 定理在(Nim)游戏中的直接应用,因为单堆的 (Nim) 游戏 (SG) 函数满足 (SG(x) = x)
    (SG)函数
      先定义 (mex(minimal excludant)) 运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。
    例如(mex{0,1,2,4}=3)
    对于任何状态 (x)(SG[x]=mex{S}),其中 (S)(x) 的后继状态的 (SG) 函数值的集合。比如 (x) 的后继状态有 (a,b,c),那么(SG[x]=mex{SG[a],SG[b],SG[c]})
    集合(f)表示到达其后继状态的途径。
    例子:
    比如有一堆石子 (n) 个,每次可以取({1,3,4})个,那么个数的(SG)函数值:
    (SG[0]=0),为最终态。
    (x=1) 时,(f={1}),后继状态:({0}),所以 (SG[1] = mex{ SG[0] }= mex{0} = 1);
    (x=2) 时,(f={1}),后继状态:({1}),所以 (SG[2] = mex{ SG[1] }= mex{1} = 0);
    (x=3) 时,(f={1,3}),后继状态:({0,2}),所以 (SG[3] = mex{SG[0],SG[2]}= mex{0,0} = 1);
    (x=4) 时,(f={1,3,4}),后继状态:({0,1,3}),所以 (SG[4] = mex{ SG[0],SG[1],SG[3] }= mex{0,1,1} = 2);
    求解 (SG)函数代码:

    //f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
    //SG[]:0~n的SG函数值
    //S[]:为x后继状态的集合
    int f[N],SG[MAXN],S[MAXN];
    void  getSG(int n){
        int i,j;
        memset(SG,0,sizeof(SG));
        //因为SG[0]始终等于0,所以i从1开始
        for(i = 1; i <= n; i++){
            //每一次都要将上一状态 的 后继集合 重置
            memset(S,0,sizeof(S));
            for(j = 0; f[j] <= i && j <= N; j++)
                S[SG[i-f[j]]] = 1;  //将后继状态的SG函数值进行标记
            for(j = 0;; j++) if(!S[j]){   //查询当前后继状态SG值中最小的非零值
                SG[i] = j;
                break;
            }
        }
    }
    

    例题:Fibonacci again and again HDU - 1848
    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=19;
    int fb[maxn],s[1005],sg[1005];
    void init()
    {
        fb[0]=1;
        fb[1]=1;
        for(int i=2;i<maxn;i++)
            fb[i]=fb[i-1]+fb[i-2];
    }
    int get_sg(int x)
    {
        memset(sg,0,sizeof(sg));
        for(int i=1;i<=x;i++)
        {
            memset(s,0,sizeof(s));
            for(int j=1;j<maxn&&fb[j]<=i;j++)
                s[sg[i-fb[j]]]=1;
            for(int j=0;j<=i;j++)
            {
                if(s[j]==0)
                {
                    sg[i]=j;
                    break;
                }
            }
        }
        return sg[x];
    }
    int main()
    {
        int m,n,p;
        init();
        while(scanf("%d%d%d",&m,&n,&p),m||n||p)
        {
            int a=get_sg(m);
            int b=get_sg(n);
            int c=get_sg(p);
            if((a^b^c)==0)
                printf("Nacci
    ");
            else
                printf("Fibo
    ");
        }
        return 0;
    }
    
    

    相关题目:
    POJ 2234 Matches Game【nim博弈模板题】
    HOJ 4388 Stone Game II
    POJ 2975 Nim
    HOJ 1367 A Stone Game
    POJ 2505 A multiplication game
    ZJU 3057 beans game
    POJ 1067 取石子游戏
    POJ 2484 A Funny Game
    POJ 2425 A Chess Game
    POJ 2960 S-Nim
    POJ 1704 Georgia and Bob
    POJ 1740 A New Stone Game
    POJ 2068 Nim
    POJ 3480 John
    POJ 2348 Euclid's Game
    HOJ 2645 WNim
    POJ 3710 Christmas Game
    POJ 3533 Light Switching Game

    三.(green)博弈/树链博弈:

    问题:
    给定一棵有根树,(A)(B)分别轮流删边,删边后不与根联通的子树也一并删去。

    先考虑一个简单的模型:如果这棵树是一条链,那么就跟取石子一样;
    再考虑一个复杂一点的,在根上再加一条链,那么,这就变成了取 (2) 堆石子的问题了。其(SG)值正是这 (2) 条链的异或,因此,我们可以将这 (2) 条链等效成长度为其(SG)值的异或值的链。
    进而我们利用这个性质,将一个个分支简化成一条条链,这样,一棵树最终会被等效成一条链。
    树链博弈
    直接推结论的做法:题解

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=1005;
    vector<int>pic[N];
    int depth[N],num[N],w[N],maxn;
    void dfs(int v,int p,int d)
    {
        depth[v]=d;
        if(w[v]==1)
            num[d]++;
        maxn=max(d,maxn);
        for(int i=0;i<pic[v].size();i++)
        {
            int u=pic[v][i];
            if(u==p)
                continue;
            dfs(u,v,d+1);
        }
    }
    int main()
    {
        int n,u,v;
        maxn=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            pic[u].pb(v);
            pic[v].pb(u);
        }
        dfs(1,0,0);
        int cnt=0;
        for(int i=0;i<=maxn;i++)
        {
            if(num[i]&1)
                cnt++;
        }
        if(cnt==0)
            printf("Second
    ");
        else
            printf("First
    ");
        return 0;
    }
    
    

    Gameia HDU - 6105
    BZOJ2819 Nim 博弈论+树链剖分
    参考博客

  • 相关阅读:
    Linux 磁盘挂载和mount共享
    Socket编程实践(8) --Select-I/O复用
    JavaScript 作用域链图具体解释
    扩展MongoDB C# Driver的QueryBuilder
    Gray Code
    Android网络编程Socket【实例解析】
    设计模式之:代理模式
    LOL英雄联盟代打外挂程序-java实现
    MySQL系列:innodb源代码分析之线程并发同步机制
    linux压缩打包
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/12521088.html
Copyright © 2020-2023  润新知