1. 程式人生 > >1525 Euclid's Game (找規律型博弈)

1525 Euclid's Game (找規律型博弈)

題目 

主要思路

設題目給的兩個數中,較大的為 a,較小的為 b。顯然,如果 a\; mod\; b = 0,先手(Stan)一步操作穩贏。

再通過分析發現,當 a > 2 * b 時,也為先手(Stan)必勝態。

a < 2 * b 時,就會存在不同的情況了,繼續對這種情況進行分析:

若能一步操作後轉化為 a > 2 * b,接下來的後手(Ollie)必勝;[比如4和3:  (4,3) --S-> (3,1) --O-> (1,0)]

若經過兩步操作才能轉化為 a > 2 * b,則兩步操作後的Stan必勝;[比如5和3:  (5,3) --S-> (3,2) --O-> (2,1) --S-> (1,0)]

若經過三步操作才能轉化為 a > 2 * b,則三步操作後的Ollie必勝

...

規律呈現出奇偶特點,因此可以不斷進行題目的減操作,並設定一個計數器記錄操作次數,直到 a > 2 * b 。若為操作次數為奇數,就一定是其中一方獲勝,若為偶數,則一定是另一方獲勝。

(a = 2 * b 已經包含在 a\; mod\; b = 0 情況中)

題解

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie();
    
    int n, m;
    while (cin >> n >> m) {
        // 始終讓保持 n > m (a > b)
        if (n < m) swap(m, n);
        if (!n & !m)
            break;
        
        // 當 a % b == 0 或 a > 2 * b 時的情況
        if (n % m == 0 || m * 2 < n) {
            cout << "Stan wins" << endl;
            continue;
        }
    
        // 分析 a < 2 * b 的情況
        int cnt = 1;
        while (2 * (n - m) > m) {
            cnt++;
            n = n - m;
            swap(n, m);
        }
        if (cnt % 2 == 0)
            cout << "Stan wins" << endl;
        else
            cout << "Ollie wins" << endl;
    }
    
    return 0;
}