HDU 2117 取(2堆)石子游戏【wzf博弈】

题意:威佐夫博弈原型,除了输出先手能不能胜,还要输出先手的第一手选择。

思路:预处理出1000000以内的所有奇异局势。对于每个自然数,其必然是某一个奇异局势的a或者b。故对于一个非奇异局势,必定有一个且一个只取一堆石子的操作使得当前局势变成奇异局势。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<iostream>
using namespace std;
int a[400000],b[400000];
void init(){
    for(int i=0;;i++){
        a[i]=i*(1+sqrt(5.0))/2;
        b[i]=a[i]+i;
        if(b[i]>1000000){
            break;
        }
    }
}
int main(){
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m)&&n){
        if(n>m)    swap(n,m);
        int t=(m-n)*(1+sqrt(5.0))/2;
        if(n==t){
            printf("0
");
            continue ;
        }
        puts("1");
        int ans[2][2]={0},js=0;
        for(int i=0;;i++){
            if(a[i]>n||b[i]>m)    break;
            if(n-a[i]==m-b[i]){
                ans[0][0]=ans[0][1]=n-a[i];
                js++;
            }
            if(a[i]==n){
                ans[1][1]=m-b[i];
                js++;
            }
            if(b[i]==n){
                ans[1][1]=m-a[i];
                js++;
            }
            if(a[i]==m){
                ans[1][0]=n-b[i];
                js++;
            }
            if(b[i]==m){
                ans[1][0]=n-a[i];
                js++;
            }
            if(js==2)    break;
        }
        if(ans[0][0])    printf("%d %d
",n-ans[0][0],m-ans[0][1]);
        if(n!=m)n-=ans[1][0],m-=ans[1][1];
        else    n-=ans[1][0];
        if(n>m)    swap(n,m);
        printf("%d %d
",n,m);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/L-King/p/5762405.html