有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。
输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。
2 1 8 4 4
Sample Output
0 1 0#include<stdio.h> #include<math.h> double g=(sqrt(5.0)+1)/2; int main() { int a,b,t; while(scanf("%d %d",&a,&b)==2) { if(a>b) { t=a; a=b; b=t; } int k=b-a; if(a==(int)(g*k)) { printf("0\n"); } else { printf("1\n"); } } return 0; }
分析
- (0,0) 先手必败,很明显他没得取了。
- (1,2) 先手必败。具体分析一下,先手有以下几种取法: 取第一堆的1个,后手取走第二堆的2个获胜。 从第一堆第二堆各取1个,后手取走第二堆剩下的1个获胜。 取第二堆的1个,后手从第一堆第二堆各取1个获胜。 取第二堆的2个,后手取走第一堆的1和获胜。 综上所述,先手必败。
- (3,5) 先手必败。 首先可以明确的一点是,先手不能把任意一堆取完,如果取完显然必败。 先讨论先手从第一堆中取的情况 先手可以从第一堆中取1个,后手从第二堆中取4个,转化为(1,2),先手必败。 先手可以从第一堆中取2个,后手从第二堆中取3个,转化为(1,2),先手必败。 再讨论先手从第二堆中取的情况 先手可以从第二堆中取1个,后手从两堆中各取2个,转化为(1,2),先手必败。 先手可以从第二堆中取2个,后手从两堆中各取3个,转化为(0,0),先手必败。 先手可以从第二堆中取3个,后手从两堆中各取1个,转化为(1,2),先手必败。 先手可以从第二堆中取4个,后手从第一堆中取2个,转化为(1,2),先手必败。 接着讨论先手从两堆中取的情况 先手可以从两堆中各取1个,转化为(2,4),此时情况较多 后手足够聪明,他从第二堆中取了1个,转化为(2,3),先手也足够聪明,他为了不直接输掉,从第一堆中取了1个(其他取法直接输掉了),转化为(1,3),此时后手从第二堆中取1个,转化为(1,2),先手必败。 先手可以从两堆中各取2个,后手从第二堆中取一个,转化为(1,2),先手必败。 综上所述,先手必败。
其他的先手必败局势 (4,7),(6,10),(8,13),(9,15),(11,18).
我们将先手必败局势的集合,称为奇异局势。
奇异局势的性质
- 任何自然数都包含在一个且仅有一个奇异局势中。
- 任意操作都可将奇异局势变为非奇异局势。
- 采用适当的方法,可以将非奇异局势变为奇异局势。
Betty定理
我们可以发现,将所有奇异局势按照第一堆的石子的数目从小到大排列,每个奇异局势的差值是自然数列。 进一步观察发现,对于一个奇异局势(A,B), A = 下取整[ (B-A) * 1.618 ],更准确的说,1.618 = (sqrt(5) + 1) / 2.
为什么会是这样的? 具体的证明涉及到Betty的定理,有兴趣的读者可以百度,这里不再赘述。
常见的几类问题
- 给出一个局面,判断先手输赢。 检查是否是奇异局势。
- 给出局面,判断先手输赢,若赢,求出首步取法。 由于差值是固定的,根据差值计算。