(笔记)博弈论 公平组合游戏

博弈论

优化策略取得最大收益的理论方法。

公平组合游戏

玩家可以对局面进行全盘操作,该操作与轮到哪位玩家没有关系。如中国象棋、国际象棋、围棋等只能操纵己方棋子不能算是公平组合游戏。

领悟知识点:哦哦哦哦哦哦。

考题:我们充分发扬人类智慧,观察到二进制……异或……

考场:打表。

博弈图 有向图游戏 SG 函数

将游戏中的状态视为节点,分为必败态必胜态

每次操作可以转移到博弈图中的任意后继节点,如果没有后继就称为必败态。如果存在任意一个后继为必败态,那么一定可以通过移到这个后继使对手必败,则该状态为必胜态。反之如果所有后继都为必胜态,该状态就也是必败态

对于状态 \(x\),我们不妨让 \(\text{SG}(x)\) 表示该状态必胜还是必败。如果为 \(0\) 就是必败,大于 \(0\) 就是必胜。运算 \(\text{mex(S)}\) 表示后继集合 \(S\) 中不存在的最小自然数。显然转移 \(\text{SG}(x)=\text{mex}(S)\) 是一个合法的转移。

为什么不能直接设必胜态为 \(1\),必败态为 \(0\)?这样做也没错,但是会损失大量信息。在之后的性质定理中,我们推出了一个游戏局面只有走向 \(\text{SG}(x')<\text{SG}(x)\) 的后继 \(x'\) 才是有意义的,因为 \(\text{mex}\) 有一个很好的性质,\(\text{mex}=x(x>0)\) 说明后继中存在 \(0,1,...,x-1\)。走向 \(\text{SG}(x')>\text{SG}(x)\) 的后继就意味着 \(x'\) 的后继中一定存在 \(\text{SG}(i)=\text{SG}(x)\)\(i\),那么移到该节点就可以抵消上一次行动。

Nim 游戏

两位玩家,轮流行动,\(n\) 堆石子,每堆 \(a_i\) 个,每次行动选择任意一堆取任意石子,取完胜利。

这里延伸出了比较好的结论,按位异或表示为 \(\oplus\),那么当且仅当 \(\oplus_{i=1}^n a_i\neq 0\) 时处在必胜态。为什么?这是一个比较反直觉的结论,本质上其实是我们利用了题目的性质(只能使 \(a_i\) 变小),以及异或运算本身的特殊性(异或是异或的逆运算),因此我们用它来构造必胜态和必败态。

首先对于 \(\forall i,a_i=0\),该状态肯定为必败态,符合结论。

对于必胜态 \(\exist i,a_i\neq 0\),我们需要证明它的后继中至少有一个必败态,不妨令 \(\oplus_{i=1}^n a_i=k\neq 0\),需要更改的是 \(a_i\),那么更改后的 \(a_i'=a_i\oplus k\),我们需要清楚这个东西实际上是把 \(a_i\) 的一个为 \(1\) 的位变成了 \(0\),然后该位以下的位置重新打乱,定有 \(a_i'<a_i\),这是符合游戏规则的。接下来解释为什么是这样的,不妨令 \(k\) 有最高为 \(1\) 的位置 \(d\) 使得 \(2^d\le k < 2^{d+1}\),那么一定存在奇数个 \(a_j\) 使得 \(a_j\)\(d\) 位是 \(1\),从中任选一个发现其结构是比 \(d\) 更高的位与 \(k\) 异或后不变。

Proof:考虑反证法,如果改变说明:

  1. 存在更高位使得 \(a_j\) 在该位上为 \(0\)\(k\) 在该位上为 \(1\),与 \(k\) 的最高位为 \(d\) 矛盾。
  2. 存在更高位使得 \(a_j\) 在该位上为 \(1\)\(k\) 在该位上为 \(1\),与 \(k\) 的最高位为 \(d\) 矛盾。

所以任选一个 \(a_j\) 即可。

接下来证明 \(\oplus_{i=1}^n a_i = 0\) 无法达到必败态。显然要达到必败态也需要 \(\oplus_{i=1}^n a_i' = 0\),而根据异或运算改变的那个 \(a_i'=a_i\oplus 0=a_i\),没有改变,是不符合游戏规则的。

SG 定理

\(n\) 个有向图的组合游戏中,存在起点 \(s_1,...s_n\),当且仅当 \(\oplus_{i=1}^n\{\text{SG}(s_i)\}\neq 0\) 时处在必胜态。

Proof:考虑数学归纳法,由当前状态 \(x\) 及其集合 \(s_1,...,s_n\) 转移到后继状态 \(x'\) 及其集合 \(s_1',...,s_n'\),如果 \(x\) 合法能推出合法的 \(x'\) 那么定理成立。显然对于所有 \(\text{SG}(s_i)=0\)\(x\) 为必败态,这是成立的。

这时每步操作可以选取一个 \(s_i\),令其变大或变小(转移到更大或更小的 SG 值,对于 \(s_i>0\),仅在后继中不可能存在 \(i\),其他数都有可能存在,所以该转移合法)。

如果变大,那么由于 \(\text{mex}(S)=x(x>0)\) 说明后继中存在 \(0,1,...,x-1\)。走向 \(\text{SG}(x')>\text{SG}(x)\) 的后继就意味着 \(x'\) 的后继中一定存在 \(\text{SG}(i)=\text{SG}(x)\)\(i\),那么移到该节点 \(i\) 就可以抵消上一次行动,所以变大是无效的。

如果变小,这就变成了一个 Nim 游戏,参照前面的推论可以得到 SG 定理。

需要注意的是,SG 定理适用于一个游戏划分为若干个子游戏,且所有游戏都操作完才算游戏结束的局面。

Nim 游戏转化为有向图游戏

前面的 SG 定理是有向图游戏转化为 Nim 游戏,那么能否逆推?

我们把 Nim 游戏看成有向图游戏,每堆石子都可以转移到比自己小的状态,那么对于 \(x=0,\text{SG}(x)=0\)。对于 \(x>0\)\(\text{SG}(x)=\text{mex}_{i=0}^{x-1}i=x\),那么利用 SG 定理就可以得到 Nim 和的结论 \(\oplus_{i=1}^n\text{SG}(a_i)\neq 0\) 时处于必胜态,即 \(\oplus_{i=1}^na_i\neq 0\),反推得到了 Nim 和结论。

例题

P10501 Cutting Game

每次游戏都是一次状态分裂,看成分裂成 \(2\) 个有向图游戏,将长宽分别为 \(a,b\) 的网格视为状态 \((a,b)\),有转移如下:\(\text{SG}((a,b))=\text{mex}_{i,j}\{\text{SG}(a,j)\oplus \text{SG}(a,b-j)\cup \text{SG}(i,b)\oplus \text{SG}(a-i,b)\}(j\in[2,b-2],i\in[2,a-2])\)。然后直接 DP 或者记忆化搜索即可,时间复杂度 \(O(n^3)\)

本题实际上不符合经典公平组合游戏的模型,任意一个子游戏达到 \(1\times 1\) 就会结束游戏,但是我们很清楚其实如果达到了类似 \(2\times 2,3\times 3,2\times 3,3\times 2\),那么这些状态一定都是必败态,我们会选择去剪其它的网格,直到所有都剪完,这就又变成了经典模型。实现中由于保证了 \(2\le W,H\),不需要考虑 \(\text{SG}((x,y))\)\(x=1\lor y=1\) 的情况,因为无法到达,所以特判 \(\text{SG}((1,1))\) 无需写入程序也可以达到相同的效果。这样我们的最终边界就自动变成了上述四种情况

原理解释就是:只有所有子游戏都会变成 \(2\times 2,2\times 3,3\times 2,3\times 3\) 四个必败局面之一时先手才必败。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=205;
int SG[N][N],n,m;
int sg(int x,int y){
  if(SG[x][y]>=0)return SG[x][y];
  map<int,bool>mp;
  for(int i=2;i<=y-2;i++)
    mp[sg(x,i)^sg(x,y-i)]=1;
  for(int i=2;i<=x-2;i++)
    mp[sg(i,y)^sg(x-i,y)]=1;
  SG[x][y]=0;
  while(mp[SG[x][y]])SG[x][y]++;
  return SG[x][y];
}
int main(){
  for(int i=1;i<=200;i++)
    for(int j=1;j<=200;j++)
      SG[i][j]=-1;
  while(cin>>n){
    cin>>m;
    cout<<(sg(n,m)?"WIN\n":"LOSE\n");
  }
  return 0;
}

P2148 [SDOI2009] E&D

先打表找规律。注意不能使用 DP 因为可能出现类似 \((1,5)\leftarrow (2,3)\) 的转移。

用二进制表示集合 \(S\),找到对于所有 \(a+b=c\)\(c\),其 \(\text{SG}\) 值的集合为 \(c-1\) 的二进制表示。\(\text{SG}((a,b))\) 就是 \(a-1\) 按位或 \(b-1\) 的二进制表示下的最小为 \(0\) 的位置,具体证明移步题解区。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+5;
int n,s[N];
int mex(int x){
  int i;
  for(i=0;x;i++,x>>=1)
    if(!(x&1))return i;
  return i;
}
int main(){
  int T;scanf("%d",&T);
  while(T--){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%d",&s[i]);
    int ans=0;
    for(int i=1;i<=n;i+=2){
      ans^=mex((s[i]-1)|(s[i+1]-1));
    }
    if(ans)printf("YES\n");
    else printf("NO\n");
  }
  return 0;
}

P2594 [ZJOI2009] 染色游戏

Lemma1:一维和二维翻硬币游戏中,当前局面的 \(\text{SG}\) 值为所有硬币单独存在时的 \(\text{SG}\) 值异或和。

Proof:容易证明构造方案的充分性,定义 \(\text{SG}((x,y))\) 表示翻硬币 \((x,y)\) 且保证子矩形 \((1,1)\)\((x,y)\) 内除 \((x,y)\) 之外硬币正反面不变的 \(\text{SG}\) 值(如果已完成值为 \(0\))。那么通过把 \(cnt\) 个需要翻的硬币分离成 \(cnt\) 个有向图游戏即可,最终 \(\text{SG}\) 就是其异或和。

必要性不会证。很多翻硬币游戏的题都用到了这个结论但是没什么具体翔实的证明,建议网络搜索。

Theorem1

\[\begin{aligned} \text{SG}(i,j)= \begin{cases} \text{lowbit}(i+j-1) & i=1\lor j=1 \\2^{i+j-2} & \text{otherwise} \end{cases} \end{aligned} \]

Proof:考虑 SG 定理类似数学归纳法证明即可,请移步题解区。

最终使用 \(f_i\) 表示 \(\text{SG}\) 值第 \(i\) 位上是否为 \(1\),然后直接计算即可。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=105;
char s[N];
int SG[N][N];
bool f[N*2];
int main(){
  for(int i=1;i<=100;i++)
    SG[i][1]=SG[1][i]=log2(i&(-i));
  for(int i=2;i<=100;i++)
    for(int j=2;j<=100;j++)
      SG[i][j]=i+j-2;
  int T;scanf("%d",&T);
  while(T--){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=200;i++)f[i]=0;
    for(int i=1;i<=n;i++){
      scanf("%s",s+1);
      for(int j=1;j<=m;j++)
        if(s[j]=='T')f[SG[i][j]]^=1;
    }
    bool tf=0;
    for(int i=0;i<=200;i++)
      if(f[i])tf=1;
    if(tf)printf("-_-\n");
    else printf("=_=\n");
  }
  return 0;
}
posted @ 2025-08-02 11:39  TBSF_0207  阅读(41)  评论(0)    收藏  举报