組合賽局

玩遊戲

組合賽局的定義

  • 資訊公開
  • 兩名玩家
  • 無運氣成分

資訊公開

所有玩家皆可看到整個遊戲的局勢
這排除了德州撲克、橋牌等
所有玩家皆可看到整個遊戲的局勢

兩名玩家

僅有兩名玩家輪流進行遊戲

無運氣成分

 操作時不帶任何機率成分 

這排除了擲骰子,以及(又是)德州撲克

組合賽局的分類

雙方操作

  • 無偏賽局(雙方可進行的操作相同)
  • 有偏賽局(雙方可進行的操作不同)
如象棋就是有偏賽局,因為雙方的棋子並非共用的

勝利條件

  • 標準賽局(最後操作者獲勝)
  • 匱乏賽局(最後操作者落敗)

重複可能

  • 無環賽局:不會重複觸發同個局面
  • 有環賽局:重複觸發同個局面

像是象棋或是西洋棋,能夠來回走重複觸發同個局面

尼姆遊戲(Nim Game)

撿石頭

會尼姆了沒有

媽媽媽媽,你看,有石頭

😭😭😭😭😭

會尼姆了沒有

有一堆石頭,玩家可從一堆中取任意數量,取到最後一顆者獲勝

我全都要就好了

兩堆呢?

輪到先手/後手時,拿取石頭維持兩堆石頭相等,直到取到最後一顆石頭

如果初始狀態為兩堆相等,則後手必勝,反之先手必勝

終止狀態

遊戲結束時的狀態稱為終止狀態

在上述的遊戲中,終止狀態即為兩堆石頭為0

並且終止狀態時兩堆石頭相等

先手/後手每次操作都能夠控制此狀態(使兩堆石頭相等)

持續控制此狀態直到抵達終止狀態即獲勝

多堆石頭

有   堆石頭,每堆數量可以不同

玩家可以從一堆中拿出至少一顆石頭(只能拿一堆中的石頭)

Normal:拿到最後一顆者勝

Misère:拿到最後一顆者敗

{n}

尼姆數

每一堆的數量做    計算,得到尼姆數,如:

 

尼姆數為 ,記做         
{2}
{xor}
{nim(2)}

Normal,Misère必勝條件

如果初始狀態時尼姆數不為0,則先手有必勝法,反之後手

 

Proof

遊戲終止狀態

每堆石頭為0,玩家無法拿取,落敗

這是一個P-position(前面一個移動的玩家獲勝)

每堆石頭為0,尼姆數也是0

P-position為nim(0)

必定有一個合法的操作使尼姆數變成0

令S為尼姆數的位數

尼姆數的第S位必定為1

且石頭堆裡必定至少有一堆石頭數的S位為1(設為      )

      ⊕      ⊕...⊕      =nim

      ⊕      ⊕...⊕      ⊕nim=nim⊕nim=   

    ⊕nim<   

故必定能將第i堆的數量減少至      ⊕nim,使得新的nim為  

{a_{i}}
{a_{0}}
{a_{1}}
{a_{n}}
{a_{0}}
{a_{1}}
{a_{n}}
{0}
{a_{i}}
{a_{i}}
{a_{i}}
{0}

無任何一個合法的操作使

尼姆數從0變成0

      ⊕      ⊕...⊕      =0

假設我要更改     至

必不等於

⊕      必不等於0

      ⊕      ⊕...⊕      (      ⊕      ) =0⊕(      ⊕      )≠0

無任何一個合法的操作使尼姆數從0變成0

{a_{0}}
{a_{1}}
{a_{n}}
{a_{i}}
{a^′ _{i}}
{a_{i}}
{a^′ _{i}}
{a^′ _{i}}
{a_{i}}
{a_{0}}
{a_{1}}
{a_{n}}
{a^′ _{i}}
{a_{i}}
{a^′ _{i}}
{a_{i}}

為何不用其他方法檢查狀態

不符合上述兩個特性

先手無法控制or後手可以控制

例題

Misère要怎麼操作

與normal一樣,直到場上只剩下一堆石頭>1的堆

取該堆石頭至0 or 1使得場上有奇數個堆

獲勝

Sprague-Grundy 定理

將Nim number推廣至所有無偏無環賽局上

Grundy數

如果一遊戲之初始狀態 Grundy 數是 0,則先手必敗局;反之必勝

聽起來很Nim

怎麼計算?

遞迴

G(原狀態)=mex({下一步狀態,下一步狀態,......})

mex({})為在此集合中,最小的,非負整數的,不在此集合中的數

會有一個終止狀態當作遞回終點

Grundy num=                                                         

     是指第i堆尼姆堆的狀態

{G(s_{0})⊕G(s_{1})⊕G(s_{2})....⊕G(s_{n})}
{s_{i}}

玩家變成一次只能取1,2,3顆石頭

怎麼用Grundy來解?

考慮各種狀況

0顆石頭,G(0)=0(終止狀態)

1顆石頭,G(1)=mex({G(0)})=1

2顆石頭,G(2)=mex({G(0),G(1)})=2

3顆石頭,G(3)=mex({G(0,G(1),G(2)})=3

4顆石頭,G(4)=mex({G(1),G(2),G(3)})=0

5顆石頭,G(5)=mex({G(2),G(3),G(4)})=1

6顆石頭,G(6)=mex({G(3),G(4),G(5)})=2

7顆石頭,G(7)=mex({G(4),G(5),G(6)})=3

你發現了甚麼

G(n)=n%4

你會了

好欸

甚至不用遞迴

AC code

#include <bits/stdc++.h>
using namespace std;

int main () {
    int t;
    cin>>t;
    while (t--) {
        int n;
        cin>>n;
        int ans=0,x;
        for(int i=0;i<n;i++){
            cin>>x;
            ans=ans^(x%4);
        }
        if(ans==0)cout<<"second\n";
        else cout<<"first\n";
    }
    return 0;
}

需遞迴的實作題

CSES2207 TLE+stack overflow code

#include <bits/stdc++.h>
using namespace std;
vector<int>dp(1e6+5,-1);
 
int G(int n){
    if(n==1||n==2)return 0;
    if(dp[n]!=-1)return dp[n];
    else{
        unordered_set<int>s;
        for(int i=1;i<n-i;i++){
            s.insert(G(i)^G(n-i));
        }
        int ans=0;
        while(s.count(ans))ans++;
        dp[n]=ans;
        return ans;
    }
}
int main () {
    dp[1]=0;
    dp[2]=0;
    int t;
    cin>>t;
    while (t--) {
        int n;
        cin>>n;
        if(!G(n))cout<<"second\n";
        else cout<<"first\n";
    }
    return 0;
}

          怎辦?

找規律?沒啥規律

找後手必勝的上限

{O(n^2)}

1~50000中,後手必勝時的n

1,2,4,7,......,929,932,1022

???1022之後怎麼沒東西了

猜測(通靈)1022以上先手必勝

所以判<=1022的case即可

CSES2207 AC code

#include <bits/stdc++.h>
using namespace std;
vector<int>dp(1000005,-1);
int G(int n){ 
    if(n==1||n==2)return 0;
    if(dp[n]!=-1)return dp[n];
    else{ 
        unordered_set<int>s;
        for(int i=1;i<n-i;i++){
            s.insert(G(i)^G(n-i));
        } 
        int ans=0; 
        while(s.count(ans))ans++; 
        dp[n]=ans; 
        return ans; 
    } 
} 
int main () {
    dp[1]=0; 
    dp[2]=0; 
    int t; 
    cin>>t; 
    while (t--) { 
        int n; 
        cin>>n;
        if(n<=1222){
            if(!G(n))cout<<"second\n";
            else cout<<"first\n";
        }
        else cout<<"first\n";
    } 
}

當然也可以用迴圈寫

甚至可以打表,後手必勝只有41種可能

謝謝大家

你會撿石頭

組合賽局

By 硼/Boron

組合賽局

  • 114