openjudge 6266取石子游戲 博弈論 c++
描述
有兩堆石子,兩個人輪流去取.每次取的時候,只能從較多的那堆石子裡取,並且取的數目必須是較少的那堆石子數目的整數倍.最後誰能夠把一堆石子取空誰就算贏.
比如初始的時候兩堆石子的數目是25和7
25 7 –> 11 7 –> 4 7 –> 4 3 –> 1 3 –> 1 0
選手1取 選手2取 選手1取 選手2取 選手1取
最後選手1(先取的)獲勝,在取的過程中選手2都只有唯一的一種取法。
給定初始時石子的數目,如果兩個人都採取最優策略,請問先手能否獲勝。
輸入
輸入包含多數資料。每組資料一行,包含兩個正整數a和b,表示初始時石子的數目。
輸入以兩個0表示結束。
輸出
如果先手勝,輸出”win”,否則輸出”lose”
樣例輸入
34 12
15 24
0 0
樣例輸出
win
lose
提示
假設石子數目為(a,b)且a >= b,如果[a/b] >= 2則先手必勝,如果[a/b]<2,那麼先手只有唯一的一種取法.
[a/b]表示a除以b取整後的值.
這道題被noi題庫放到了搜尋裡,但其實他更像是一個滲透著輾轉相除法的遞迴。
首先,讓我們假設兩人分別為x,y,並且括號中的數總是前一個大於後一個,我們想到這個遊戲只有3種情況那就是:
1.大的一堆比 小的一堆的二倍 還大即a>b*2
此時x是必勝的:首先假設a=b*n+c。那麼我們假設x取b*n個,那麼現在就由(a,b)變成(b,c)。如果(b,c)必輸的話,現在是y面對(b,c),那麼x就直接贏了。如果(b,c)必勝的話,那麼x可以不拿b*n個而拿去b*(n-1),於是y面對(b+c,b)因為c肯定< b,所以y只能取在b+c中取一個b,於是x面對的就變成了(b,c)。所以無論怎麼樣x都可以決定是自己面對(b,c)還是對手面對(b,c),必勝。
2.大的是 小的的倍數
x直接贏
3.大的小於 小的的二倍
那麼這種情況就需要呼叫遞迴,由於大的小於小的的二倍,所以只有一種取法,就是由(a,b)–>(b,a-b)在將(b,a-b)放到這三種情況中判斷就行了。
#include<cstdio>
using namespace std;
int n,m;
bool xht(int n,int m)
{
if (n%m==0)
return(true);
if (n/m==1)
return(!xht(m,n-m));
if (n>=2*m)
return(true);
}
int main()
{
scanf("%d%d",&n,&m);
while (n!=0&&m!=0)
{
if (n<m)
{
int t;
t=n;
n=m;
m=t;
}
if (xht(n,m))
printf("win\n");
else
printf("lose\n");
scanf("%d%d",&n,&m);
}
}