(博弈论合集)巴什今天不想博弈,尼姆也不想,威佐夫听完默默的放下了手中的石子

前言

对于当前正在行动的一方来说,能使之获胜的称为非奇异局面(先手必胜)
反之,不能使之获胜的成为奇异局面(先手必败)

巴什博弈(Bash Game)

内容及讲解:

内容:一堆n个物品,两人轮流取,每次取1至m个,最后取完者胜。
1,假设我们先手,当m>=n时,肯定是先手必胜,没什么好说的
继续分析,当n=m+1的时候呢,这时,我们可以取的物品数范围是[1,m]这是题目给出的已知条件,相减一下,剩余物品数最多为m个,最少为1个,也就是说不管我们现在怎么取,当对方操作的时候他都可以一次取完。好,这样就得出结论:n=m+1时先手必败
2,如果n=m+2呢?我们取走一个的话,对方操作的时候就面临m+1的局面了,轮到他必输了,也就是说 n=m+2局面就是先手必胜了,同理n=m+3,取走2个,n=m+4,取走3个…一直到同理到n=m+1+m=2m+1。
3,当n=2m+2=2(m+1)这个局面的时候,我们根据递归的思想,不论我们取多少个,都会将局面变成上面第2点中说到的那些局面中的一种,那这个时候对手如果将物品数控制m+1这个局面我们就必输了。
好,n=2(m+1)对于我们来说使必输局面
4,这样递归下去,最终可以得出结论当我们面临的局面是n=k(m+1)(k=0.1.2.3…)的时候,我们必输,否则我们必胜。
那最终结论就出来了嘛!
结论:对于总数n和每次可以取的最大物品数m,如果n%m=0先手必败,否则先手必胜

例题:取石子游戏I

题目描述:
一堆石子有n个,两人轮流取.每次取最少取1个,最多取m个。取完者胜.先取者负输出"Second win".先取者胜输出"First win"
输入:
多组测试数据。

每组测试数据包含2个正整数n,m。(n,m<=10000000)
输出:
对于每组测试数据,输出谁获胜.
输出样例:

2 1
3 2
3 1

输出样例:

Second win
Second win
First win

解题代码:

#include <iostream>

using namespace std;

int main()
{
    int n,m;
    while(cin>>n>>m)
    if(n%(m+1)==0)
        cout<<"Second win"<<endl;
    else
        cout<<"First win"<<endl;
    return 0;
}

尼姆博弈(Nim Game)

内容及讲解:

内容:有若干堆物品,每堆物品的数量都是有限的,合法的移动是“选择一堆物品并拿走若干个(不能不拿)”,拿走最后一件物品的人赢。
首先,先细品一下“一堆物品”这个词,一堆物品~~,我们每次只能动一堆物品。
我们如果将每堆物品的数量异或起来那我们得到的结果就只有1和0两种(这不是废话吗)
那我们就可以用这个结果来表示当前的局面,结果为1,1局面,为0,0局面。那有没有可能正好对应了输赢这两种可能呢,首先看这两个情况。
一 .如果2堆(n,n)这个局面,异或一下,0,当前操作的一方必输。
二 .如果2堆(n,不为n的其他数),异或一下,1当前操作的一方必输
再想想,如果现在是0局面,当前方操作一下,之后另一方面对的也是0局面,这种情况,它河里吗?
如果你把每一个物品数转成二进制再对应起来,你会发现,如果异或结果不为0,是可以选择从数量最多的那一堆里取走一定数量的物品使得结果为0的,而当结果为0的时候,不管你怎么取都会使取完之后的异或结果不为0.
也就是说,1局面操作完必为0局面,反之亦然。
那么如果一开始,任意一方面临的是什么局面(1局面,0局面),那之后就永远都是这个局面了(胜负从一开始就决定了)
最后随着石物品越来越少,总会到只有两堆的情况,这时也就是上面一开始说过的两种情况之一了,再结合之前的理论,如果游戏一开始的一方面临的是1局面,那他最后就会面临上面说过的二这个情况,反之他最后将面临一这个情况。
最后,破案了,得出结论。
(参考博客:尼姆博弈的证明
结论:将每一堆的物品数ni和异或操作(+),如果n1(+)n2(+)n3(+)…ni =0,则先手比败,否则先手必胜。

例题:洛谷P2197 【模板】nim游戏

https://www.luogu.com.cn/problem/P2197

#include <iostream>

using namespace std;

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int r;
        for(int i=0; i<n; i++)
        {
            int x;
            cin>>x;
            if(!i)
                r=x;
            else
                r=x^r;

        }
        if(r==0)cout<<"No";
        else cout<<"Yes";
        cout<<endl;
    }
    return 0;
}

威佐夫博弈(Wythoff Game)

内容:首先有两堆物品,博弈双方每次可以取一堆物品中的任意个,不能不取,或者取两堆物品中的相同个。先取完者赢。
(参考博客:威佐夫博弈详解
结论:设两堆物品的物品数分别为(a,b),规定其中a<b,并设k为黄金比例约为1.618,如果(b-a)*k==a则先手比输,反之先手必赢。

例题:取石子游戏II

题目描述:
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

输入:
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

输出:
输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。

输出样例:

2 1
8 4
4 7

输出样例:

0
1
0

解题代码:

#include<bits/stdc++.h>
using namespace std;
#define p 1.618
int main()
{
    int a,b;
    while(cin>>a>>b)
    {
        if((int)(abs(a-b)*p)==min(a,b))
            cout<<0<<endl;
        else
            cout<<1<<endl;
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值