博弈论进阶——Anti-SG

时间:2021-08-30
本文章向大家介绍博弈论进阶——Anti-SG,主要包括博弈论进阶——Anti-SG使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

博弈论进阶——\(Anti\)-\(SG\)

博弈\(——\)多年以后,\(Bob\)仍然爱慕着\(Alice\)的容颜

\(SG\)函数的拓展\(——Anti\)-\(SG\)游戏

感谢贾志豪《组合游戏略述——浅谈SG游戏的若干拓展及变形》一文

一、\(Anti-Nim\)游戏

\(n\)堆石子,两个人可以从任意一堆石头中拿走任意颗石头,拿走最后一个石头的失败
这与我们之前处理的\(Nim\)游戏有所不同,即两人胜利的条件发生了改变,与\(Nim\)游戏相反,所以被称之为\(Nim\)游戏

结论

先手必胜当且仅当满足下面两种情况的一种:
(1)任意堆的石子数都为\(1\)且游戏的\(SG\)值为\(0\)
(2)存在堆的石子数大于\(1\)且游戏的\(SG\)值不为\(0\)

证明:
假设有\(n\)堆石子。

  1. 每堆只有一个石子
    之前我们就证明过每一堆石子的\(SG\)值显然是这堆石子的个数。每一堆的石子数均为\(1\)
    很容易看出:
    当有偶数堆时,也就是\(SG\)值为\(0\)时,先手必胜
    当有奇数堆时,也就是\(SG\)值为\(1\)时,先手必败
  2. 至少两堆石子数大于\(1\)
    考虑两种情况,当\(SG\)\(0\)\(SG\)不为\(0\)的情况。
  • \(SG\) 不为 \(0\)
    若还有至少两堆石子的数目大于 \(1\),则先手将 \(SG\) 值变为 \(0\) 即可;若只有一堆石子数大于 \(1\),则先手总可以将状态变为有奇数个 \(1\)。所以,当 \(SG\) 不为 \(0\) 时先手必胜。
  • \(SG\)\(0\)
    至少有两堆石子的数目大于 \(1\),则先手决策完之后,必定至少有一堆的石子数大于 \(1\),且 \(SG\) 值不为 \(0\),由上段的论证我们可以发现,此时,无论先手如何决策,都只会将游戏带入先手必胜局,所以先手必败。
    (说实话感觉大佬贾志豪这段的证明有点问题)
    另外一种证明方式

二、\(Anti-SG\)

\(Anti-SG\)游戏与\(SG\)游戏不同的点仅仅在于\(Anti-SG\)是最后一个进行操作的输。

\(SG\)函数存在这样一个性质:
\(SG\)\(0\)的局面不一定为终局局面。(定理一的反命题)
基于这个性质我们可以知道\(Anti-Nim\)的结论并不能直接套用在\(Anti-SG\)上面。

对于这个问题,贾志豪给出了\(SJ定理\)\((Sprague Grundy——Jia Zhihao定理)\)

\(SJ\)定理
规定当局面中所有的单一游戏\(SG\)值为\(0\)时,游戏结束,则先手必胜当且仅当

  1. 游戏\(SG\)值不为\(0\)且游戏中某个单一游戏的\(SG\)函数大于\(1\)
  2. 游戏\(SG\)函数为\(0\)且游戏中没有单一游戏的\(SG\)函数大于\(1\)

证明(全文照搬):

我们只需要证明:

  1. 所有的终止局面为先手必胜局。(这一点显然,证明中略去)
  2. 游戏中的任何一个先手必败局一定只能够转移到先手必胜局;
  3. 游戏中的任何一个先手必胜局一定能够转移到至少一个先手必败局。

情况一:局面的 SG 函数为 0 且游戏中某单一游戏的 SG 函数大于1。

∵当前局面的 SG 函数值为 0
又∵SG 函数性质
∴它所能转移到的任何一个局面的 SG 函数值不为 0 ①
∵当前局面的 SG 函数值为 0 且游戏中某个单一游戏的 SG 函数大于1。
∴当前局面中必定至少有 2 个单一游戏的 SG 函数大于 1。
又∵每次至多只能更改一个单一游戏的 SG 值
∴它所能转移到的任何一个局面都至少有一个单一游戏的 SG 值大于1。②
由①②得,情况一所能转移到的任何一个局面都为先手必胜局。

情况二:局面的 SG 函数不为 0 且游戏中没有单一游戏的 SG 函数大于 1。

显然,当前局面一定有奇数个游戏的 SG 函数值为 1,其余游戏的 SG函数值为 0。

  1. 将某个单一游戏的 SG 值更改为大于 1 的数。
    ∵转移前没有单一游戏的 SG 值大与 1,转移将某个单一游戏的 SG值更改为大于 1 的数。
    ∴转移后的局面一定有且只有一个单一游戏的 SG 值大于 1。 ③
    ∴后继局面的 SG 值一定不为 0。 ④
    由③④得,后继局面一定为先手必胜局。
  2. 将某个单一游戏的 SG 值更改为 0 或 1。
    ∵转移是将某个 SG 值为 0 的单一游戏改成 SG 值为 1 的单一游戏,或将某个 SG 值为 1 的单一游戏改成 SG 值为 0 的单一游戏。
    ∴转移后的局面一定有偶数个 SG 值为 1 的单一局面且不含有 SG 值大于 1 的局面。
    ∴后继局面一定为先手必胜局。

情况三:局面的 SG 函数不为 0 且游戏中某个单一游戏的 SG 函数大于 1

  1. 局面中只有 1 个单一游戏的 SG 值大于 1。
    我们选择更改 SG 值最大的单一游戏,我们可以选择将其更改成 0 或1 来保证转移后的局面有且只有奇数个 SG 值为 1 的单一游戏。
    则通过这种方式转以后的局面为先手必败局。
  2. 局面中有至少两个单一游戏的 SG 值大于 1。
    根据 SG 函数性质(2),总存在一种决策可以将后继局面的 SG 函数值变为 0 ⑤
    ∵局面中有至少两个单一游戏的 SG 值大于 1
    又∵每次最多只能更改一个单一游戏的 SG 值
    ∴后继局面中至少有一个游戏的 SG 值大于 1 ⑥
    由⑤⑥得,后继局面为先手必败局。

情况四:局面的 SG 函数为 0 且游戏中没有单一游戏的 SG 函数大于1。

当局面中所有单一游戏的 SG 值为 0 时,游戏结束,先手必胜。
否则,局面有且仅有偶数个 SG 值为 1 的单一游戏,其余游戏的 SG
值为 0。
我们只需将其中的某一个 SG 值为 1 的单一游戏的 SG 值变为 0,游戏
中即可出现奇数个 SG 值为 1 的单一游戏,到达先手必败局。

一道模板题
code

```cpp
#include <bitset>
#include <vector>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
#include <map>
#include <unordered_map>
using namespace std;
using namespace std;
#define lowbit(x) x&-x
#define ll int
#define pll pair<ll,ll>
#define dob double
#define For(i,s,n) for(ll i = s;i <= n;i++)
#define mem0(a) memset(a,0,sizeof a)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a/gcd(a,b)*b
#define abs(x) x>=0?x:-x
const int N = 1e5+5;
const double eps = 1e-6;
const ll mod =  1000000007;
const ll inf = 1e9+50;

int main(){
    ios::sync_with_stdio(false);
    ll t;cin>>t;
    while(t--){
        ll n;cin>>n;
        ll sum = 0,cnt = 0;
        for(ll i = 1;i <= n;i++){
            ll x;cin>>x;
            if(x>1)cnt++;
            sum^=x;
        }
        if((sum == 0 && cnt == 0)||(sum && cnt)) cout<<"John\n";
        else cout<<"Brother\n";
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Paranoid5/p/15207289.html