1. 程式人生 > >P1290 歐幾里德的遊戲(博弈,SG)

P1290 歐幾里德的遊戲(博弈,SG)

P1290 歐幾里德的遊戲

  • 題目描述 歐幾里德的兩個後代Stan和Ollie正在玩一種數字遊戲,這個遊戲是他們的祖先歐幾里德發明的。給定兩個正整數M和N,從Stan開始,從其中較大的一個數,減去較小的數的正整數倍,當然,得到的數不能小於0。然後是Ollie,對剛才得到的數,和M,N中較小的那個數,再進行同樣的操作……直到一個人得到了0,他就取得了勝利。下面是他們用(25,7)兩個數遊戲的過程:

Start:25 7

Stan:11 7

Ollie:4 7

Stan:4 3

Ollie:1 3

Stan:1 0

Stan贏得了遊戲的勝利。

現在,假設他們完美地操作,誰會取得勝利呢?

  • 輸入格式: 第一行為測試資料的組數C。下面有C行,每行為一組資料,包含兩個正整數M, N(M, N不超過長整型).
  • 輸出格式: 對每組輸入資料輸出一行,如果Stan勝利,則輸出“Stan wins”;否則輸出“Ollie wins”

思路:感覺這題很像尼姆博弈的變形,同樣都是n堆石子任意拿,但是尼姆博奕是在任意一堆拿石子,而這個必須一堆一堆地拿,拿完這一堆才能拿下一堆. 然後我們這樣想,假設當前堆誰拿了最後一個誰就必輸,那麼肯定希望把最後一個留給對方.所以假如我是先手,假如當前堆只有1個,那麼我只能乖乖地拿了,必輸.假如有兩個,我肯定只拿一個,假如有三個我肯定拿兩個, 這一點又很像巴什博奕,所有隻要大於一個我就能贏.同理假如當前堆誰拿了最後一個誰就必贏,我是先手的話我肯定一次就拿完,所以無論有多少堆,只要當前堆大於一個先手必勝. 那麼怎麼知道當前堆拿最後一個是贏還是輸,遞迴求解即可,假如n/m == 1,那麼SG(n,m) = !SG(m,n%m),而SG(m,n%m)又能繼續按照此規則判斷,假如n/m> 1,則直接為必勝態.

程式碼:

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 2e5+5;
const double eps = 1e-12;
const int inf = 0x3f3f3f3f;
map<int,int>::iterator it;

ll a,b;

int get_sg(ll x,ll y)
{
	if(y == 0) return 0;
	if(x/y> 1) return 1;
	return !get_sg(y,x%y);
}

int main()
{
	int t;
	cin>>t;
	
	while(t--)
	{
		scanf("%lld %lld",&a,&b);	
		if(a< b) swap(a,b);
		
		int f;
		if(a/b> 1) f = 1;
		else f = !get_sg(b,a%b);
		
		if(f)
			printf("Stan wins\n");
		else
			printf("Ollie wins\n");
	}
	
	return 0;
}