經典的威佐夫博弈:有兩堆石子,數量分別為 a、b(a ≤ b)。雙方輪流操作,每次可選擇:
取走最後石子者獲勝。給定初始 (a, b),先手是否必勝?若必勝,輸出第一步最優操作後的剩餘石子數 (x, y)(x ≤ y);若同時有「取同量」與「取單堆」兩種獲勝策略,優先輸出取同量的方案。
威佐夫博弈的必敗態(P-position)為:
(⌊k·φ⌋, ⌊k·φ²⌋) 或對稱位置,其中 φ = (1+√5)/2 ≈ 1.618,k = 0,1,2…
等價判斷:令 a ≤ b,k = b - a。若 a = ⌊k·φ⌋,則為必敗態,先手輸(輸出 0);否則先手贏(輸出 1)。
贏的情況下,需找到一步操作使對手進入必敗態。兩種操作類型:
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
long long a, b;
const double phi = (sqrt(5.0) + 1) / 2.0;
while (cin >> a >> b && (a || b)) {
if (a > b) swap(a, b);
long long k = b - a;
if ((long long)(k * phi) == a) {
cout << "0\n";
continue;
}
cout << "1\n";
// 優先嘗試同時取同量
for (long long i = 1; i <= a; ++i) {
if ((long long)(k * phi) == a - i) {
cout << a - i << ' ' << b - i << '\n';
break;
}
}
// 再嘗試單堆取石
for (long long i = b - 1; i >= 0; --i) {
long long na = min(a, i), nb = max(a, i);
long long nk = nb - na;
if ((long long)(nk * phi) == na) {
cout << na << ' ' << nb << '\n';
break;
}
}
}
return 0;
}