兩位玩家給定兩正整數 a, b。每回合將較大數減去較小數的任意正整數倍(結果不得為負)。先將任一數減至 0 者獲勝。這是經典的 Euclid's Game,其解法深刻體現了數論與博弈論的結合。
設 a ≥ b,定義 win(a, b) 為當前玩家是否必勝:
由於 a, b 嚴格遞減,遞歸深度為 O(log max(a,b)),極為高效。迭代版本更簡潔:
bool stanWin = true; // 先手 Stan
while (true) {
if (a < b) swap(a, b);
if (a % b == 0 || a / b >= 2) break; // 當前玩家必勝
a = a - b; // 唯一移動
stanWin = !stanWin; // 交換玩家
}
// stanWin 為 true 則先手勝
#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
long long a, b;
while (scanf("%lld%lld", &a, &b) == 2) {
if (a == 0 && b == 0) break;
bool stan = true;
while (true) {
if (a < b) swap(a, b);
if (a % b == 0 || a / b >= 2) break;
a -= b;
stan = !stan;
}
printf("%s wins\n", stan ? "Stan" : "Ollie");
}
return 0;
}
本質上,遊戲走勢對應歐幾里得算法的商序列。若某步商 ≥ 2,當前玩家可決定勝負;若所有商均為 1,則對應斐波那契數列,勝負取決於步數奇偶。這與威佐夫遊戲、黃金分割比例有深層聯繫。
Euclid's Game 是理解「遞歸博弈」、「不變量」與「數論結構」的絕佳教材,掌握其核心邏輯有助於解決更複雜的組合遊戲問題。