1. 程式人生 > >POJ-1067 取石子游戲(威佐夫博弈)

POJ-1067 取石子游戲(威佐夫博弈)

題目連結

POJ-1067 取石子游戲

題目大意

有兩堆石子,數量分別為\(a,b\),兩個人輪流取石子。每次有兩種不同的取法:一是可以在任意的一堆中取走任意多的石子;二是可以在兩堆中同時取走相同數量的石子。最後把石子全部取完者為勝者。現在給出初始的兩堆石子的數目,如果輪到你先取,假設雙方都採取最優策略,問最後你是勝者還是敗者?

Sample Input

2 1
8 4
4 7

Sample Output

0
1
0

思路

直接是:威佐夫博弈。
這個過於繁瑣,只能運用現成的結論。
設奇異局勢(必敗局勢)為(a[i],b[i]),則有a[0]=b[0]=0a[

k]=前面未出現的最小自然數,b[k]=a[k]+k
具體求解公式:a[k]=k1+52b[k]=a[k]+k=k3+52

奇異局勢的性質:
1.任何自然數包含在且僅包含在一個奇異局勢中
a[k]>a[k1]b[k]=a[k]+k>a[k1]+k1=b[k1]>a[k1],則任意奇異局勢中不存在相同的自然數(除了(0,0)),又a[k]前面未出現的最小自然數,則任何自然數均會出現在奇異局勢中
2.任意操作均為將奇異局勢變為非奇異局勢
①在一堆中取石子,由於另一堆中的數不會出現在其他奇異局勢中,則新局勢必定非奇異局勢
②在兩堆中同時取石子,由於兩堆石子差值不變,而序號為差值的奇異局勢唯一,則新局勢必定非奇異局勢
3.任意非奇異局勢可以通過特定操作轉化為奇異局勢
設當前局勢為(

a,b)
a==b時:同時從兩堆取走a個石子,轉化為(0,0)
a==a[k]&&b>b[k]時:從第二堆取走bb[k]個石子,轉化為(a,b[k])
a==a[k]&&b<b[k]時:同時從兩堆取走aa[ba]個石子,轉化為(a[ba],ba+b[ba])
a>a[k]&&b==b[k]時:從第一堆取走aa[k]個石子,轉化為(a[k],b)
a<a[k]&&b==b[k]時:若a==a[j] (j<k),則從第二堆取走bb[
j]
個石子,轉化為(a,b[j]);否則必有a==b[j](j<k),則從第二堆取走ba[j]個石子,轉化為(a[j],a)

程式碼

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

int a,b,aa;
double x;

int main() {
    x=(1.0+sqrt(5.0))/2.0;
    while(2==scanf("%d%d",&a,&b)) {
        if(a>b) {
            swap(a,b);
        }
        aa=floor((b-a)*x);//計算第b-a個奇異局勢
        printf("%d\n",a==aa?0:1);
    }
    return 0;
}