首页 > 代码库 > [原博客] POJ 1067 取石子游戏
[原博客] POJ 1067 取石子游戏
题目链接
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。(中文题面,感动ing)
但是这道题实在是呵呵。
开始没啥思路,根据必胜状态必败状态的定义,n^3
打了个表,看起来是这样的。
图为100x100,已经缩小,左上角是状态(0,0)
,右下角状态为(100,100)
,黄色标出的是必败状态。(哇,博客还能传图,真好~)
嗯,对称是显然的吧,因为这两堆可以直接交换,而且看起来很有规律的样子。
T_T找不到规律。
后来知道这个叫“威佐夫博奕(Wythoff Game)”。百科
这个问题中必败状态叫奇异局势(奇异~),然后可以有公式去算,好像还与黄金分割有半毛钱关系,具体看百科证明吧。
规律摘抄如下:
- 任何自然数都包含在一个且仅有一个奇异局势中。
- 任意操作都可将奇异局势变为非奇异局势。(必败状态)
- 采用适当的方法,可以将非奇异局势变为奇异局势。(必胜状态)
- 如果用
(ak,bk)
表示一个状态,设ak<=bk
,则有a0=b0=0
,ak是未在前面出现过的最小自然数,且bk=ak+k
。
公式:ak =[k(1+√5)/2],bk= ak + k
(k=0,1,2,...,n 方括号表示取整函数)。
做法:如果对于(a,b)是奇异局势的话,应该有k=b-a
,然后根据k计算出a等不等于ak即可,若相等,该状态为奇异局势,必败输出0,否则输出1。
*涨姿势。
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>//by zrt//problem:using namespace std;typedef long long LL;const int inf(0x3f3f3f3f);const double eps(1e-9); int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif double sqrt5=sqrt(5.0); int a,b; while(~scanf("%d%d",&a,&b)){ if(a>b) swap(a,b); int j=b-a; int tmp=(int)(j*(1+sqrt5)/2.0); if(tmp==a) puts("0"); else puts("1"); } return 0;}
[原博客] POJ 1067 取石子游戏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。