博弈论

一、
NIM博弈:有n堆石子,从任意一堆石子中可以取任意颗石子,不能不取,最后谁取的时候没有石子了,谁就输了
结论:当 a 1 ⊕ a1\oplus a1 a 2 ⊕ a2\oplus a2 a 3 ⊕ a3\oplus a3 … \ldots = 0 =0 =0 时是先手必败态,其余先手必胜
证明:我们证明可以分以下三步(注意当移动的时候两者先后手发生了变化)
1:将全为0的状态判为先手必败
2:判为先手必胜的状态一定可以移动到一个先手必败的状态
3:判为先手必败的状态不能移动到先手必败的状态
第一个命题显然:0异或n个0是0
第二个命题 :先手必胜是a1^ a2 ^ a3 ^ …… an>0的状态,我们假设a1 ^ a2 ^ ……an=k,那么我们可以从中发现的是在所有的数一定有至少有一个数在k的最高位上的数字是1,那么这时ai ^ k< ai是一定成立的,我们将ai=ai ^ k。那么原式=k ^ k=0。
第三个命题:假设先手必败,那么a1 ^ a2 ^ …… ^ an=0,我们可以发现无论我们怎么改,一定会对各位数字上奇偶的数量发生变化,所以改变数字后,结果一定是不为0的。

这个其实也不叫证明,知识对于公式的验证,验证他是正确的。

二、
巴什博弈:有一堆物品共n个,两个人轮流取物,一次最少取1个,最多取m个,取走最后一个的胜。
分情况讨论:
当n<=m时,显然是先手必胜
当n=m+1时,显然是后手必胜
当n%(m+1)!=0时,先手可以取出n%(m+1),然后这时n%(m+1)=0,然后这时,无论后手如何操作,先手只需要将一份剩下的m+1取完,直到最后取完。这时,先手必胜
当n%(m+1)=0时,同上,此时后手必胜

三、
威佐夫博弈:两堆物品,两人轮流取,一次可以从一堆取至少一个,至多全部,或从两堆取相同数,取最后一个的人获胜。

思路:这个感觉不需要证明,只要记住结论即可:1.618(或是(sqrt(5.0)+1)/2)*(abs(b-a))=min(a,b)就是后手赢其余都是先手赢。用语言描述呢就是假设1.618乘以两个差值=较小的值,那么就是后手赢否则就是先手赢
奇偶性博弈:有 n n n堆石子,第 i i i堆石子有 a i a_i ai个,保证初始时 a i a_i ai ≤ \leq a i + 1 a_{i+1} ai+1(1 ≤ \leq i < < <n)。现在他们轮流对这些石子进行操作,每次操作人可以选择满足 a i a_i ai> a i − 1 a_{i-1} ai1 a 0 a_0 a0 0 0 0)的一堆石子,并从中取走一个。谁最后不能取了谁输。 A l i c e Alice Alice先手,他们都使用最优策略,判断最后谁会取得胜利。

证明:
1:首先很明显的就是只要是有石子就可以取,因为第一堆石子总比第0堆石子多。所以肯定是最终一定取完才可以分出胜负
2:这样的话就是奇数的话就是先手胜,偶数的话就是后手胜

也可以把上面的情况扩展到二维平面中,题目描述如下:
在一个 n ∗ n n*n nn的棋盘上有一个棋子,放置在 ( 1 , 1 ) (1,1) (1,1)这个位置,要求移动过的位置不能再被移动,最终不能被移动的人输。
我们可以发现一定不会出现就是一人被一人围住这种情况,因为我们可以发现只要被围住的时候一定会有一个人输,那么输的这个人一定会在被围住之前移到别处。
所以,所有的 n 2 − 1 n^{2}-1 n21个都会被走完,所以若其为奇数则先手赢,反之后手赢

四、
SG函数:
我们将nim游戏变得难一些,假设每次能够取的石子不是任意个了,我们假设第一堆可以取1,2,3,第二堆可以取偶数个,第三堆可以取奇数个,剩下的可以随便取。这样就不能用简单的nim来解决了,我们在这里就可以用SG函数来解决这个问题。

我们可以将一个博弈问题抽象成在有向无环图上一个的问题,假设图上的某一个顶点有一枚棋子,两个人分别移动这个棋子,最终无法移动的一个人输。这样的话任何一种局面我们可以看做一个顶点,用一条线连接他的子局面。

首先定义一个mex{}函数,他表示集合中不存在的最小的非负整数,mex{}=0,mex{1,2,0}=3,.mex{1,2,3}=0;

sg[x]=mex{sg(y)|y是x的后继}

我们可以给出sg函数的几个结论和结论的简单说明。

1:sg[x]=0表示x处于先手必败态(当然这个x状态需要具体问题具体分析,可能是1也可能是0或者其他 ),这个是由sg函数的定义决定的。我们可以做一个简单的说明:我们假设当前处于最后一个状态,那么下一个一定是空状态,这时候,sg[x]=0,即表示无法到达下一个状态了,这样一定是必败的。所以将sg[x]=0的状态设为必败态。
2:假设初始的情况下由很多种状态的时候,我们将sg[1] ^ sg[2] ^ sg[3] ^ ……=0的处于先手必胜,否则就是先手必败。

我们可以简单证明以下:这是类似于nim博弈的,sg函数的定义就是:我们可以达到的状态,假设sg[x]=k,那么表示可以将这x状态变成0,1,2,3,……,k-1,但是不能不变,所以这就和nim博弈联系起 来了,谁最后能拿完谁就胜,因为sg[x]存的是下一层sg函数的集合,所以也可以做这样的操作,最中化作有n堆石子的nim博弈问题。

注意:我们求mex得时候从最底层求,因为不同的题有不同的状态,而且层数也不同,所以不同的状态有不同的sg值

详细sg函数讲解参考博客:博客链接

下面是一道例题:戳我
这道题的SG就是找规律的。

我们要注意一个点就是mex{}里面的是一个一个子局面。

我们首先就是判断SG(1)=0,然后依次往上找即可。

但是要记住的是假设我们将8分成4个2,所以我们应该将所有的状态sg值异或起来就是原来的答案,这里我感觉用mex的话太复杂了,所以用sg值异或的方法比较好。

其实想想也是,如果我们将某一个数分成了几个相等的数,那么这就不是单独的状态了,这几个数共同构成一个状态,所以我们应该将他们的值求出来,然后把所有的值异或起来,得到的异或结果,构成这个分状态的值,下面是AC代码:(参考网上的代码,具体的可以网上搜一下题解)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int p[maxn], cnt;
int flag[maxn];

void prime()
{
    for(int i = 2; i < maxn; i++)
    {
        if(!flag[i]) p[cnt++] = i;
        for(int j = 0; p[j] < maxn / i; j++)
        {
            flag[p[j] * i] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

int sg(int x)
{
    int res = 0;
    for(int i = 0; i < cnt && p[i] <= x / p[i]; i++)
    {
        if(x % p[i] == 0)
        {
            if(p[i] == 2)
            {
                res++;
                while(x % p[i] == 0)
                    x /= p[i];
            }
            else
            {
                while(x % p[i] == 0)
                    x /= p[i], res++;
            }
        }
    }
    if(x > 1) res++;
    return res;

}

int main()
{
    prime();
    int t; scanf("%d", &t);
    while(t--)
    {
        int n; scanf("%d", &n);
        int res = 0;
        for(int i = 1; i <= n; i++)
        {
            int x; scanf("%d", &x);
            res ^= sg(x);
        }
        printf("%s\n", res ? "W" : "L");
    }
}

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值