当前位置: 首页 > article >正文

【算法】经典博弈论问题——斐波那契博弈 + Zeckendorf 定理 python

目录

  • 斐波那契博弈(Fibonacci Nim)
  • 齐肯多夫(Zeckendorf)定理
  • 示例分析
  • 实战演练


斐波那契博弈(Fibonacci Nim)


先说结论:当初始石子数目 n 是斐波那契数时,先手必败;否则,先手有策略获胜。

证明概要:
当n=2时,先手只能取1颗石子,后手直接取剩下的1颗石子获胜,因此先手必败。
假设对于所有小于等于某个斐波那契数 f[k]的情况,结论都成立。
归纳:
对于f[k+1]=f[k]+f[k-1]的情况,可以把这一堆石子看成两堆,分别有f[k]和[k-1]颗石子。
根据归纳假设,无论先手怎么取,后手总能取到最后一个石子。
特别地,如果先手取的石子数大于等于f[k-1],则后手可以直接取完f[k],因为f[k]<2*f[k-1]。



齐肯多夫(Zeckendorf)定理


任何正整数都可以表示成若干个不连续的斐波那契数之和。

证明略



非斐波那契数的情况:
使用齐肯多夫定理(Zeckendorf’s theorem),任何正整数可以表示为若干个不连续的斐波那契数之和。
将n分解为若干个不连续的斐波那契数之和,然后通过适当的策略让先手每次都能取到最后一颗石子,从而获胜。



示例分析


假设有一个 n=85 的石子堆,我们首先将85分解为斐波那契数之和:
85 = 55 + 30
30 = 21 + 9
9 = 8 + 1
所以,85=55+21+8+1。

根据上述结论,先手可以通过以下策略获胜:
1.先手先取1颗石子,剩下84颗。
2.因为84不是斐波那契数,后手无法直接应用斐波那契博弈的必败态。
3.接下来,先手可以根据后手的动作,逐步减少石子数,并确保每次后手面对的是非斐波那契数,最终达到胜利。



实战演练


[COCI 2010/2011 #4] HRPA https://www.luogu.com.cn/problem/P6487


题目描述

n n n 枚石子。两位玩家定了如下规则进行游戏:

  • Mirko 先取一次,Slavko 再取一次,然后 Mirko 再取一次,两人轮流取石子,以此类推;
  • Mirko 在第一次取石子时可以取走任意多个;
  • 接下来,每次至少要取走一个石子,最多取走上一次取的数量的 2 2 2 倍。当然,玩家取走的数量必须不大于目前场上剩余的石子数量。
  • 取走最后一块石子的玩家获胜。

双方都以最优策略取石子。Mirko 想知道,自己第一次至少要取走几颗石子最终才能够获胜。

输入格式

输入一行一个整数 n n n,表示石子的数量。

输出格式

输出一行一个整数,表示 Mirko 最少取多少石子可以保证获胜。

样例输入 #1

4

样例输出 #1

1

样例输入 #2

7

样例输出 #2

2

样例输入 #3

8

样例输出 #3

8

提示

样例 1 解释

对于这个样例,Mirko 第一次可以取 1 / 2 / 3 / 4 1/2/3/4 1/2/3/4 个。虽然他取 4 4 4 个会直接赢得比赛,但这并不是最少的。最少的方案是取走 1 1 1 个。这样 Slavko 只能取走 1 1 1 个或者 2 2 2 个。无论选择哪种,Mirko 下一步都能取走所有的石子并获胜。

数据规模与约定

对于 100 % 100\% 100% 的数据,保证 2 ≤ n ≤ 1 0 15 2\le n\le 10^{15} 2n1015

说明

题目译自 COCI2010-2011 CONTEST #4 T6 HRPA


题解code:

n = int(input())


def solve(n):
    if n == 1:
        return 1
    if n == 2:
        return 2
    a, b = 1, 2  # 初始化前两个斐波那契数
    while True:
        c = a + b  # 计算下一个斐波那契数
        if c == n:
            return n  # 当前n是斐波那契数,先手必败
        elif c > n:
            break  # 当前c大于n,退出循环
        a, b = b, c  # 更新a和b为下一个斐波那契数

    # 当前n不是斐波那契数,减去b并继续判断
    return solve(n - b)


print(solve(n))


END
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢


http://www.kler.cn/a/524112.html

相关文章:

  • Visual Studio Code修改terminal字体
  • 关联传播和 Python 和 Scikit-learn 实现
  • Mybatis是如何进行分页的?
  • ResNeSt: Split-Attention Networks 参考论文
  • ubuntu 更新24LTS中断导致“系统出错且无法恢复,请联系系统管理员”
  • 用WinForm如何制作简易计算器
  • 中文输入法方案
  • CH32V303RCT6使用RTOS的选择对比
  • 深入理解 C 语言函数指针的高级用法:(void (*) (void *)) _IO_funlockfile
  • 对游戏宣发的粗浅思考
  • LabVIEW开发故障诊断
  • 虚幻基础06:cast to
  • 讲解QoS队列调度算法
  • 【算法应用】基于A*-蚁群算法求解无人机城市多任务点配送路径问题
  • 用HTML、CSS和JavaScript实现庆祝2025蛇年大吉(附源码)
  • A星算法两元障碍物矩阵转化为rrt算法四元障碍物矩阵
  • SIPp的使用-SIPp的教程
  • INCOSE需求编写指南-第4节:需求和要求陈述以及需求和要求集的规则
  • 【Leetcode 每日一题】119. 杨辉三角 II
  • 06_改善播放效果--优先级与阻塞
  • Java定时任务实现方案(五)——时间轮
  • C++基础(1)
  • 处理 .gitignore 未忽略文件夹问题
  • 我的2024年终总结和2025年展望
  • DeepseekMath:超强开源数学模型(论文详解)
  • linux开启samba共享文件夹