【博弈论】斐波那契博弈

斐波那契博弈

简介

一堆有 n n n个物品,如果有甲乙两个人。甲和乙轮流从这对物品中选取物品,第一次可以取 1 ∼ n − 1 1\sim n-1 1n1个物品,后一个人能取的物品数范围是 1 1 1到前一个人取的物品数 2 2 2倍,最后取光物品的人获胜。

思路

若甲先手,设当前物品数为 r r r

r ≤ 3 r\le 3 r3时,甲无法取胜,甲必败。

r = 4 r=4 r=4时,甲取 1 1 1,乙剩 3 3 3个无法取胜,故甲必胜。

r = 5 r=5 r=5时,甲若取 2 2 2个及以上乙必胜。甲若取 1 1 1个,乙取 1 1 1个又变成了 r = 3 r=3 r=3的情况,乙胜。

根据上述过程,不难发现要想自己赢必须尽可能保证对方拿到斐波那契数。

也就是说,甲先手获胜需要满足 n n n不是斐波那契数。

算法模板

首先我们需要能计算斐波那契数

  1. 递归法
long long fib(int k){
    if(k<=1) return 1;
    else return fib(k-1)+fib(k-2);
}
  1. 递推法
long long fib(int k){
    fib[0]=fib[1]=1;
    for(int i=2;i<=k;i++){
        fib[i]=fib[i-1]+fib[i-2];
    }
    return fib[k];
}

模板

由于递推法的线性复杂度,所以采取递推来实现斐波那契博弈。

bool fibG(int n){//这里返回的是先手玩家是否可以获胜
    fib[0]=fib[1]=1;
    for(int i=2;fib[i-2]<=n;i++){
        if(fib[i-2]==n) return false;
        fib[i]=fib[i-1]+fib[i-2];
    }
    return true;
}

例题

hdu2516

大概概括一下,就是 n n n表示物品数,输出第一个人先手时哪个人能获胜,输出获胜的人(First win or Second win),输入 0 0 0表示结束。

#include <iostream>
using namespace std;
int fib[1001]; 
bool fibG(int n){//这里返回的是先手玩家是否可以获胜
    fib[0]=fib[1]=1;
    for(int i=2;fib[i-2]<=n;i++){
        if(fib[i-2]==n) return false;
        fib[i]=fib[i-1]+fib[i-2];
    }
    return true;
}
int main(){
    int n;
    while(cin>>n,n!=0){
        if(fibG(n)) cout<<"First win\n";
        else cout<<"Second win\n";
    }
    return 0;
}

尝试推广

如果规定先取完的人输,再看一下策略。

因为甲可以取 1 ∼ n − 1 1\sim n-1 1n1个,那么甲直接取 n − 1 n-1 n1个,留下 1 1 1个给乙,则乙必输。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cout0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值