Description
Input
Output
Sample Input
2 1
8 4
4 7
Sample Output
0
1
題目鏈接:http://poj.org/problem?id=1067
解法類型:威佐夫博奕
解題思路:就是一個經典的威作福博弈,知道公式就很水了。現給出我看到的一個很牛叉的證明:
-
簡單分析一下,容易知道兩堆石頭地位是一樣的,我們用餘下的石子數(a,b)來表示狀態,並畫在平面直角座標系上。
用之前的定理: 有限個結點的無迴路有向圖有唯一的核 中所述的方法尋找必敗態。先標出(0,0),然後劃去所有(0,k),(k,0),(k,k)的格點;然後找y=x上方未被劃去的格點,標出(1,2),然後劃去(1,k),(k,2),(1+k,2+k),同時標出對稱點(2,1),劃去(2,k),(1,k),(2+k,1+k);然後在未被劃去的點中在y=x上方再找出(3,5)。。。按照這樣的方法做下去,如果只列出a<=b的必敗態的話,前面的一些是(0,0),(1,2),(3,5),(4,7),(6,10),…
接下來就是找規律的過程了,忽略(0,0),記第n組必敗態爲(a[n],b[n])
命題一:a[n+1]=前n組必敗態中未出現過的最小正整數
[分析]:如果a[n+1]不是未出現的數中最小的,那麼可以從a[n+1]的狀態走到一個使a[n+1]更小的狀態,和我們的尋找方法矛盾。
命題二:b[n]=a[n]+n
[分析]:歸納法:若前k個必敗態分別爲 ,下證:第k+1個必敗態爲
從該第k+1個必敗態出發,一共可能走向三類狀態,從左邊堆拿走一些,從右邊堆拿走一些,或者從兩堆中拿走一些.下面證明這三類都是勝態.
情況一:由命題一,任意一個比a[k+1]小的數都在之前的必敗態中出現過,一旦把左邊堆拿少了,我們只要再拿成那個數相應的必敗態即可。
情況二(從右邊堆拿走不太多):這使得兩堆之間的差變小了,比如拿成了 ,則可再拿成 ;
情況二(從右邊堆拿走很多):使得右邊一堆比左邊一堆更少,這時類似於情況一,比如拿成了 (其中a[m] ;
情況三:比如拿成 ,則可再拿成 .
綜上所述,任何從 出發走向的狀態都可以走回核中.故原命題成立.
以上兩個命題對於確定(a[n],b[n])是完備的了,給定(0,0)然後按照這兩個命題,就可以寫出(1,2),(3,5),(4,7),…
這樣我們得到了這個數列的遞推式,以下我們把這兩個命題當成是(a[n],b[n])的定義。
先證明兩個性質:
性質一:核中的a[n],b[n]遍歷所有正整數。
[分析]:由命題一,二可得a[n],b[n]是遞增的,且由a[n]的定義顯然。
性質二:A={a[n]:n=1,2,3,…},B={b[n]:n=1,2,3,…},則集合A,B不交。
[分析]:由核是內固集,顯然。
看到這裏大家有沒有想到Beatty序列呢,實際上a[n]和b[n]就是一個Beatty序列。
,有 ,解方程
得 ,到此,我們找到了該必敗態的通項公式。
實際上這組Beatty序列還有一些別的性質,比如當一個數是Fibonacci數的時候,另一個數也是Fibonacci數;而且兩者的比值也越來越接近黃金比,這些性質在得到通項公式之後不難證明。
總的來說,這個問題給我們了哪些啓示呢?首先用定理所說的方法找核,然後給出核的規律(遞推,或是通項)並且證明。最後附上一張對應的必敗態圖.
PS:用圖來表示博弈過程,好想法啊。~
算法實現:
//STATUS:C++_AC_32MS_172k #include<stdio.h> #include<math.h> const double x=((sqrt(5.0)+1)/2); int main() { // freopen("in.txt","r",stdin); int a,b,k,ta; while(~scanf("%d%d",&a,&b)) { if(a>b){int t=a;a=b,b=t;} k=b-a; ta=(int)floor(k*x); printf("%d\n",ta==a?0:1); } return 0; }