P1290 歐幾里德的遊戲(博弈,SG)
阿新 • • 發佈:2018-12-11
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; }