您的位置:首页 > 其它

[博弈论]hiho#1173 : 博弈游戏·Nim游戏·三

2015-06-04 22:01 225 查看
首先给出基本定义:

对于一个游戏可能发生的局面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
)

要证明这一点我们只要证明:

(1) 假设sg(x[1]) xor sg(x[2]) xor … xor sg(x
) = A,对于任意一个0 <= B < A,总存在一个X的后续局面Y,使得sg(Y) = B。

(2) 假设sg(x[1]) xor sg(x[2]) xor … xor sg(x
) = 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}。

[code]#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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: