POJ2348 Euclid's Game(博弈&自由度)

Two players, Stan and Ollie, play, starting with two natural numbers. Stan, the first player, subtracts any positive multiple of the lesser of the two numbers from the greater of the two numbers, provided that the resulting number must be nonnegative. Then Ollie, the second player, does the same with the two resulting numbers, then Stan, etc., alternately, until one player is able to subtract a multiple of the lesser number from the greater to reach 0, and thereby wins. For example, the players may start with (25,7): 
         25 7

         11 7

          4 7

          4 3

          1 3

          1 0

an Stan wins.
Input
The input consists of a number of lines. Each line contains two positive integers giving the starting two numbers of the game. Stan always starts.
Output
For each line of input, output one line saying either Stan wins or Ollie wins assuming that both of them play perfectly. The last line of input contains two zeroes and should not be processed.
Sample Input
34 12
15 24
0 0
Sample Output
Stan wins
Ollie wins

題意:

讓我們看一下這個以輾轉相除法爲基礎的遊戲。

給定兩個整數a和b。Stan和Ollie輪流從較大的數字中減去較小數字的倍數。這裏的倍數指的是1倍、2倍等這樣的正整數倍,並且相減後的結果不能小於零。Stan先手,在自己的回合將其中一個數變爲零的一方獲勝。當雙方都採取最優策略時,誰會獲勝?


解題思路:

讓我們來找找看該問題中必勝態和必敗態的規律。首先,如果a>b則交換,假設a<b。另外,如果b已經是a的倍數了則必勝,所以假設b並非a的倍數。此時,a和b的關係,按自由度的觀點,可以分成以下兩類。

(1)b-a<a的情況

(2)b-a>a的情況

對於第一種情況,如果從b中減去a的2倍以上的數則變爲負數,所以只能從b中減去a,沒有選擇的餘地。相對的,對於第二種情況,有從b中減去a,減去2a,或更高的倍數等多種選擇。

對於第一種情況,要判斷必勝還是必敗是很簡單的。因爲沒有選擇的餘地,如果b減去a之後所得到的狀態是必敗態的話,它就是必勝態,如果得到的是必勝態的話,它就是必敗態。

例如,從(4,7)這個狀態出發就完全沒有選擇的機會,按照

(4,7)-->(4,3)-->(1,3)

的順序,輪到(1,3)的一方將獲勝, 所以有

(4,7)-->(4,3)-->(1,3)

必勝-->必敗-->必勝

可見(4,7)是必勝態。


接下來,我們來看一下第二種情況是必勝態還是必敗態。假設x是使得b-ax<a的整數,考慮一下從b中減去a(x-1)的情況。例如對於(4,19)則減去12。

此時,接下來的狀態就成了前邊講過的沒有選擇餘地的第一種情況。如果該狀態是必敗態的話,當前狀態就是必勝態。

那麼,如果減去a(x-1)後的狀態是必勝態的話,該如何是好呢?此時,從b中減去ax後的狀態是減去a(x-1)後的狀態唯一可以轉移到的狀態,根據假設,減去a(x-1)後的狀態是必勝態,所以該狀態是必敗態。因此,當前狀態是必勝態。

例如對於(4,17),由於從17中減去12得到的(4,5)就是必敗態,所以只要減去12就能獲勝。另一方面,對於(4,19),減去12得到的(4,7)是必勝態,因此(4,3)就是必敗態,只要減去16就能獲勝。

由此可知,第二種情況總是必勝的。所以,從初始狀態開始,最先到達有自由度的第二種狀態的一方必勝。


AC代碼:

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
	int a,b;
	while(~scanf("%d%d",&a,&b)&&a&&b)
	{
		bool f=true;
		for(;;)
		{
			if(a>b) swap(a,b);
			if(b%a==0) break;//b是a的倍數時必勝 
			if(b-a>a) break;//如果是第二種情況必勝 
			b-=a;
			f=!f;
		}
		if(f) printf("Stan wins\n");
		else printf("Ollie wins\n");
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章