博弈论

一.典型的博弈模型:

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 \bigoplus a_2 \bigoplus ... \bigoplus a_n!=0\),为当前状态。
假设 \(a_i\to a_i^{'}\),使得 \(a_1 \bigoplus a_2 \bigoplus ...\bigoplus a_i^{'} \bigoplus ... \bigoplus a_n=0\)
必然会有一个 \(a_i\) 使 \(t\) 的二进制最高位是 \(1\),且 \(a_i \bigoplus t<a_i\)
那么令 \(a_i^{'}=a_i \bigoplus t\),有
\(a_1 \bigoplus a_2 \bigoplus ...\bigoplus (a_i \bigoplus t) \bigoplus ... \bigoplus a_n=0\)
得证。
3.
\(a_1 \bigoplus a_2 \bigoplus ...\bigoplus a_i \bigoplus ... \bigoplus a_n=0\)
假设 \(a_i\to a_i^{'}\),则
\(a_1 \bigoplus a_2 \bigoplus ...\bigoplus a_i^{'} \bigoplus ... \bigoplus 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\n");
        else
            printf("Fibo\n");
    }
    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\n");
    else
        printf("First\n");
    return 0;
}

Gameia HDU - 6105

BZOJ2819 Nim 博弈论+树链剖分

参考博客

posted @ 2020-03-19 18:14  xzx9  阅读(250)  评论(0编辑  收藏  举报