一个古老的取石子游戏:有两堆石子,数量为(n, m),规则为:一、每次从任一堆取任意多个;二、每次从两堆中取同样多个。最后取完石子的为胜者,即最后不能取的为败者。
Any position in the game can be described by a pair of integers (n, m) with n ≤ m, describing the size of both piles in the position. The strategy of the game revolves around cold positions and hot positions: in a cold position, the player whose turn it is to move will lose with best play, while in a hot position, the player whose turn it is to move will win with best play. The optimal strategy from a hot position is to move to any reachable cold position.
The classification of positions into hot and cold can be carried out recursively with the following three rules:
For instance, all positions of the form (0, m) and (m, m) with m > 0 are hot, by rule 2. However, the position (1,2) is cold, because the only positions that can be reached from it, (0,1), (0,2), and (1,1), are all hot. The cold positions (n, m) with the smallest values of n and m are (0, 0), (1, 2), (3, 5), (4, 7), and (6, 10).
<引自>http://en.wikipedia.org/wiki/Wythoff%27s_game
将游戏的所有局面分成两种,cold position 和 hot position;
cold position 即:必败局面
hot position 即:必胜局面
假设没有和局:则在双方都足够聪明的情况下,对于任一个局面,即状态(n, m),结果都是确定的。
容易推出,cold positon符合某些规律:(0, 0), (1, 2), (3, 5), (4, 7), (6, 10)......
Wythoff 发现了这个规律,
用(ak, bk)(k=0,1,2...)表示所有的cold position, ak = floor(k×Φ), bk = ak+k, Φ = (1+sqrt(5))/2,即黄金分割, floor为向下取整。
给定一个局面(a,b),怎样来判断是否是cold position?
我们假设a<=b, 令ak = a, 求得 k, 然后再代入验证,看k,k+1哪个是符合条件的k,然后求bk.
这只是最原始的问题,对于一些变形,我们可以用类似的方法,找出cold positon符合的规律。
最原始版本。
// Wythoff's game(取石子游戏)
#include < stdio.h >
#include < math.h >
#define PHI (1+sqrt(5.0))/2
#define SWP(x,y,t) {t=x;x=y;y=t;}
int main()
{
int a, b, t;
int k, ak, ak1;
while (scanf( " %d%d " , & a, & b) != EOF) {
if (a > b) SWP(a, b, t)
k = ( int )((sqrt( 5.0 ) - 1 ) / 2 * a);
ak = ( int )(k * PHI);
ak1 = ( int )((k + 1 ) * PHI);
if (ak == a && b == a + k
|| ak1 == a && b == a + k + 1 ) {
printf( " 0\n " );
} else printf( " 1\n " );
}
return 0 ;
}
先找出必败态的规律,然后求所有的必败态。
// wythoff's game
// cold position is (0,0), (1,2), (3,3), (4,5), (6,6)...
#include < stdio.h >
#define SWP(x,y,t) {t=x;x=y;y=t;}
inline int GCD( int a, int b)
{
while (b) {
int t = a;
a = b;
b = t % b;
}
return a;
}
int main()
{
int n, m;
int t, d;
while (scanf( " %d%d " , & n, & m) != EOF) {
if (n > m) SWP(n,m,t);
int a = n / 3 * 3 ;
if (n % 3 == 1 && n < m) a ++ ; // key
else if (n % 3 == 2 ) a += 2 ;
d = GCD(n * m, a);
printf( " %d/%d\n " , a / d, n * m / d);
}
return 0 ;
}
描述:一堆土豆,每次可以吃1,4,16(4的幂)。
必败态的规律:0,2,5,7,10,12,15,17......