[博弈論]hiho#1173 : 博弈遊戲·Nim遊戲·三

首先給出基本定義:

對於一個遊戲可能發生的局面x,我們如下定義它的sg值:
(1)若當前局面x爲終結局面,則sg值爲0。
(2)若當前局面x非終結局面,其sg值爲:sg(x) = mex{sg(y) | y是x的後繼局面}。
mex{a[i]}表示a中未出現的最小非負整數。舉個例子來說:
mex{0, 1, 2} = 3, mex{1, 2}=0, mex{0,1,3}=2

sg定理:
對於多個單一遊戲,X=x[1..n],每一次我們只能改變其中一個單一遊戲的局面。則其總局面的sg值等於這些單一遊戲的sg值異或和。
即:
sg(X) = sg(x[1]) xor sg(x[2]) xor … xor sg(x[n])
要證明這一點我們只要證明:
(1) 假設sg(x[1]) xor sg(x[2]) xor … xor sg(x[n]) = A,對於任意一個0 <= B < A,總存在一個X的後續局面Y,使得sg(Y) = B。
(2) 假設sg(x[1]) xor sg(x[2]) xor … xor sg(x[n]) = A,不存在一個X的後續局面Y,使得sg(Y) = A。

這是hiho裏給出的解釋,首先給出了定理,然後解釋了定理並證明了,然後結合問題分析了問題應該怎麼做。標準的中國式例題講解思維。確實這樣的邏輯會比較符合大多數人的思維。但是這裏面是否又有些值得深思的呢?

代碼就是依據定理來寫的,求出所有的sg[].
另外,對於這個題每個sg值就有兩種可能:
(1)不分堆:石子數量爲k’=0..k-1,則sg(k’)
(2)分堆:石子變爲2堆,數量爲(1,k-1),(2,k-2),…,(k-1,1)。設第一堆的石子數量爲i,則sg值爲sg(i) xor sg(k-i)。(這裏用到了sg定理)
那麼可以推算出sg(k) = mex{sg(0), sg(i), sg(i) xor sg(k - i) | i = 1..k-1}。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#define read freopen("q.in","r",stdin)
#define LL __int64
#define maxn 20004
#define inf 10000000
#define mod 142857
using namespace std;
int sg[maxn],a[maxn];
bool vis[maxn];
void Accepted()
{
    int i,j;
    sg[0]=0;

    for(i=1;i<=maxn;i++)
    {
        memset(vis,0,sizeof(vis));
        for(j=0;j<i;j++)
        {
            int t=sg[j]^sg[i-j];
            vis[sg[j]]=1;
            vis[t]=1;
        }
        for(j=0;j<maxn;j++)if(!vis[j])
        {
            sg[i]=j;
            break;
        }

    }
}
int main()
{
   int n,i,j,x;
   Accepted();
   scanf("%d",&n);
   int res;
   scanf("%d",&x);
   res=sg[x];
   for(i=1;i<n;i++)
   {
       scanf("%d",&x);
       res^=sg[x];
   }
   if(!res)cout<<"Bob"<<endl;
   else cout<<"Alice"<<endl;

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章