hdu 2516 取石子游戏(FIB博弈)

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26672

准确的说,这个FIB博弈,叫Fibonacci Nim。
大约是这么个模型:
1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完。以后每次取的石子数不能超过上次取子数的2倍。取完者胜。

和之前的给的巴什勃♂弈,差别很大。因为,去的策略变得动态了。之前的博弈,其策略都相对固定。(就是套路痕迹很重)

话说回来,既然叫斐波那契博弈,肯定和斐波那契数列有很大关系。
强行假装不知道斐波那契博弈模型:
首先拿到题目,肯定很难马上想到必败点的递推式的。所以我们先需要膜一发。
n = 2时 后手赢;
n = 3时 后手赢;
n = 4时,先手想获胜就必须先拿1个,剩余的石子数为3,则无论第二个人如何取,第一个人都能赢,输出先手;
n = 5时,先手不可能获胜,因为先手拿2时,后手直接取掉剩下的3个就会获胜,当他取1时,这样就变成了n为4的情形,所以输出的是后手;
n = 6时,先手只要去掉1个,就可以让局势变成n为5的情形,所以输出的是先手;
n = 7时,先手取掉2个,局势变成n为5的情形,故先手赢,所以输出的是先手;
n = 8时,当先手取1的时候,局势变为7的情形,第二个人可赢,先手取2的时候,局势变成n为6得到情形,也是后手赢,取3的时候,后手直接取掉剩下的5个,所以n = 8时,输出的是后手;

可以看到,2为最小必败点,然后3,5,8、、、、看看这像什么。
斐波那契。
数论里边应该会常用的:任何一个正整数都可以用若干个不连续的斐波那契数之和表示。
顺带:这里有很多经典数论: xuzengqiang大

那么我们就可以把n写成 n = f[a1]+f[a2]+……+f[ai]。(a1>a2>……>ai)
我们令先手先取完f[ai],即最小的这一堆。由于各个f[]之间不连续,则a(i-1) > ai + 1,则有f[a(i - 1)] > 2 * f[ai]。即后手只能取f[a(i-1)]这一堆,且不能一次取完。

后手处在只有f[a(i - 1)]这一堆石子,且后手先取的子游戏的必败态,即先手一定可以取到这一堆的最后一颗石子。

同理可知,对于以后的每一堆,先手都可以取到这一堆的最后一颗石子,从而获得游戏的胜利。

后边会附上FIB博弈的证明。(无聊时候做的,喜欢的自取)
代码:

#include
using namespace std;
int fib[50];
int main(){
    fib[0]=1;fib[1]=2;
    for(int i=2;i<45;i++)
        fib[i]=fib[i-1]+fib[i-2];
    int n;
    while(scanf("%d",&n)!=EOF&&n){
        int i=0;
        for(i=0;i<45;i++)
            if(fib[i]==n)
                break;
        if(i<45)
            puts("Second win");
        else
            puts("First win");
    }
    return 0;
}

愚蠢的数学证明:
设i=n,为必败态。
i=2 , 这是最小必败态。
那么i=2,显然成立。

假设当i<=n时,结论成立
那么i = n+1时,肯定有f[i+1]=f[i]+f[i-1]成立。
那么,石子就分成了两堆,f[i] , f[i-1]。
对于f[i-1]堆,由假设可知,不论先手怎样取,后手总能取到最后一颗。下面我们分析一下后手最后取的石子数x的情况。

若先手第一次取的石子数y>=f[i-1]/3,则这小堆所剩的石子数小于2*y,后手可以直接取完,x=f[i-1]-y,则x<=2/3*f[i-1]。

1/2*f[i]>2/3*f[i-1],所以我们得到,x<1/2*f[i]。

后手取完f[i-1]堆后,先手不能一下取完f[i]堆,所以游戏规则没有改变,则由假设可知,对于i堆,后手仍能取到最后一颗石头,后手必胜。

i=n+1时,结论依然成立。
综上,证毕。

你可能感兴趣的:(「ac妹」博弈)