• HDU 2516 取石子游戏 斐波纳契博弈


    斐波纳契博弈:

    有一堆个数为n的石子,游戏双方轮流取石子,满足:

    1)先手不能在第一次把所有的石子取完;

    2)之后每次可以取的石子数介于1到对手刚取的石子数的2倍之间(包含1和对手刚取的石子数的2倍)。

    约定取走最后一个石子的人为赢家,求必败态。

    证明 FBI数为必败局:

    1.对于任意一个FBI数 FBI[K]=FBI[K-1]+FBI[K-2],我们可以将FBI[K]看成石子数目分别是FBI[K-1],FBI[K-2]的两堆(一定可以这样分,因为FBI[K-1] > FBI[K-2]*2,若先手取的数目大于等于FBI[K-2],则后手可以一次拿完)

    2.将FBI[K-2],FBI[K-1],再次拆分,无论先手如何取,后手总能取走最后一个石子

    证明 非FBI数为必胜局:

    1.由齐肯多夫定理知道,任意一个整数,可以被拆分成几个不连续的FBI数相加的形式:n=FBI(ak)+FBI(ak-1)+FBI(ak-2)+……+FBI(a1)

    2.因为式子中的FBI数不连续,所以FBI(a) > 2FBI(a-1)

    3.先手取走FBI(a1)个石子,那么后手只能在FBI(a1+1)堆中取,且不能一次性取完。依旧是说对于任意一堆,总是先手取走最后一个石子!

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<math.h>
    #include<iostream>
    #include<algorithm>
    #define INF 0x3f3f3f3f
    #define MAXSIZE 100005
    
    using namespace std;
    
    int fib[MAXSIZE];
    
    int Game(int n)
    {
        for(int i=1;i<=46;i++)
        {
            if(fib[i]==n)
                return 0;
        }
        return 1;
    }
    
    int main()
    {
        int n;
        fib[1]=1;
        for(int i=2;i<=46;i++)
            fib[i]=fib[i-1]+fib[i-2];
        while(scanf("%d",&n),n)
        {
            int op=Game(n);
            if(op==0)
                printf("Second win
    ");
            else
                printf("First win
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    防火墙2
    SVN:多版本库环境的搭建
    安装SVN服务端
    springContext
    linux centos7安装 mysql-5.7.11
    ajax struts2 前后台 交互
    Spring的 classpath 通配符加载配置文件
    使用甘特图实现服务计划的可视化
    条形码软件开发包Dynamic .NET TWAIN v5.0提供WPF功能
    快来玩“Gift大转盘”百分百赚好礼
  • 原文地址:https://www.cnblogs.com/alan-W/p/6286595.html
Copyright © 2020-2023  润新知