HDU 1527 (POJ 1067) 取石子游戏 Wythoff Game

题目大意:
就是Wythoff Game的原型, 每次可以拿其中一堆的任意数量或者两堆同时拿一样的任意数量, 拿走最后一颗石子的人胜

大致思路:
首先可以参考这篇Wythoff Game的论文:
Wythoff Game
其中提到了一个Beatty Theorem(贝蒂定理):
如果 a b 都是无理数, 且 1a+1b=1 , 那么 {a,2a,3a...} {b,2b,3b...} 两个集合之间没有相同元素且他们并组成正整数集 ( a 表示向下取整)

另外Wythoff Game当中一个重要的表:

The Sequence of Safe Pairs (A, B)

n 0 1 2 3 4 5 6 7 8 9 10
A 0 1 3 4 6 8 9 11 12 14 16
B 0 2 5 7 10 13 15 18 20 23 26

这里我们是不妨假设了 AB
其中 (A,B) P 点的条件是 A=ϕn,B=A+n 是 第n个 P 点, 当然 Bϕ2n
其中 ϕ 是黄金比例 ϕ=1+52

上表中的一些性质
将第 i 列的 A B 记做 A[i],B[i] 的话, B[i]=A[i]+i , 并且, 如果第 i 列是 (A[i],B[i]) , 那么第 B[i] 列一定满足 A[B[i]]=A[i]+B[i]
对于每一个 A[k] , A[k] 一定是前面 (A[i],B[i]) 中没有出现过的最小自然数, 并且任何一个自然数都包含在一个且仅有的一个 P 点中(也有文章称为奇异局势), 这里我们只考虑了 A[i]B[i] 的局势
那么接下来说明任意操作都可以将奇异局势( P 点)变成非奇异局势( N 点)
如果 (A[k],B[k]) 是奇异局势( P 点), 如果只改变其中一个数, 那么得到的分量不可能在其他奇异局势中( P 点), 因为每个奇异局势中的自然数是唯一的, 如果将两个数同时减少, 由于两个数的差不变, 不可能是其他奇异局势的差, 因为第i个奇异局势的差是 B[i]A[i]=i , 于是从奇异局势( P 点)只能变成非奇异局势( N 点)
对于一个非奇异局势( N 点),记为 (a,b) , 如果 b=a 可以变为 (0,0) 的奇异局势, 那么 a<b 时 如果 a=A[k],b>B[k] , 那么可以变为奇异局势 (A[k],B[k])
如果 a=A[k],b<B[k] , 那么两堆同时拿走 A[k]A[bA[k]] , 很明显由于 B[k]>b>a>A[k] , 这里取走 A[k]A[bA[k]] bA[k]<B[k]A[k]=k , 所以肯定是可取的, 那么这样就变成了 (A[bA[k]],bA[k]+A[bA[k]]) , 也就是 (A[bA[k]],A[bA[k]]+(bA[k])) , B[bA[k]]=A[bA[k]]+(bA[k]) 所以变成了奇异局势( P 点)
如果 a>A[k],b=B[k]=A[k]+k , 那么从第一队中拿走多余的即可变为 (A[k],B[k)
如果 a<A[k],b=A[k]+k=B[k]
那么当 a=A[j] (j<k) 从第二堆拿走 bB[j] 即可
a=B[j] (j<k) , 从第二堆拿走 bA[j] 即可
以上两种一定包含了所有情况, 因为之前找到的性质: A[i] 是前面没有出现的最小自然数

以上是学习到的所有Wythoff Game相关的东西了, 这里了一下:

接下来就是代码了, 利用黄金分割来判断是否是(A[i], B[i])即可
代码如下:
Result : Accepted Memory : 1576 KB Time : 31 ms

/* * Author: Gatevin * Created Time: 2015/5/8 10:14:35 * File Name: Rin_Tohsaka.cpp */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

const double gold_ratio1 = (1 + sqrt(5.)) / 2;
const double gold_ratio2 = (sqrt(5.) - 1) / 2;
int a, b;

int main()
{
    while(scanf("%d %d", &a, &b) != EOF)
    {
        if(a > b) swap(a, b);
        int t = floor(a*gold_ratio2);
        if(floor(t*gold_ratio1) != a)
        {
            if(a + t + 1 == b) puts("0");
            else puts("1");
        }
        else
        {
            if(a + t == b) puts("0");
            else puts("1");
        }
    }
    return 0;
}

你可能感兴趣的:(威佐夫博弈,hdu-1527,Wythoff)