1. 程式人生 > >POJ 2348 Euclid's Game(輾轉相除博弈+自由度分析)

POJ 2348 Euclid's Game(輾轉相除博弈+自由度分析)

main -1 發現 轉移 pro b- color 思路 span

題目鏈接:http://poj.org/problem?id=2348

題目大意:給你兩個數a,b,Stan和Ollie輪流操作,每次可以將較大的數減去較小的數的整數倍,相減後結果不能小於0,誰先將其中一個數字變成0誰就獲勝。

解題思路:看了挑戰程序設計上的,這裏我們先假設a<b,當b是a的整數倍是必勝態。我們討論以下b不是a的整數倍,此時a,b的關系按照自由度的觀點(第一次聽說),可以分為以下兩種情況:

     ①b-a<a

     ②b-a>a

那麽對於①,玩家只有從b中減去a這一個選擇。如果b-a得到的狀態是必敗態,那當前就是必勝態,反之,就是必敗態。例如從(4,7)出發,只有(4,7)->(4,3)->(1,3)這一條路,(4,7)是必勝態。

但是對於②,有從b中減去a,2a或者更高的倍數等多種選擇。假設x是使得b-a*x<a,我們考慮一下兩種情況:

    1)將b-a*(x-1),得到狀態①。

    2)將b-a*x,不能確定是狀態①還是②。

並且我們可以發現,b-a*x是b-a*(x-1)唯一能轉移到的狀態,如果b-a*(x-1)是必勝態,那就執行b-a*(x-1),但如果是必敗態呢,那b-a*x是就是必勝態。所以無論如何只要到了狀態②就肯定會贏。

所以我們得到了結論:從初始狀態開始最先到達自由度的第二種狀態或者得到b是a的整數倍的一方必勝。

代碼:

 1 #include<cstdio>
 2
#include<algorithm> 3 using namespace std; 4 5 int main(){ 6 int a,b; 7 while(~scanf("%d%d",&a,&b)&&(a||b)){ 8 int cnt=0; 9 while(1){ 10 cnt++; 11 if(a>b) 12 swap(a,b); 13 if(b%a==0
) 14 break; 15 if(b-a>a) 16 break; 17 b-=a; 18 } 19 if(cnt&1) puts("Stan wins"); 20 else puts("Ollie wins"); 21 } 22 }

POJ 2348 Euclid's Game(輾轉相除博弈+自由度分析)