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

目录


斐波那契博弈(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} 2≤n≤1015。

说明

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


题解code:

python 复制代码
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
如果有更多问题或需要进一步的帮助,可以在评论区留言讨论哦!
如果喜欢的话,请给博主点个关注 谢谢

相关推荐
少司府几秒前
C++基础入门:vector深度解析(七千字深度剖析)
c语言·开发语言·数据结构·c++·容器·vector·顺序表
星空椰1 分钟前
Python 使用飞书 API 获取子部门列表接口信息
python·pandas·飞书
zhoupenghui1682 分钟前
如何设置PyTorch程序在 GPU上运行
人工智能·pytorch·python·gru·cuda
he___H3 分钟前
子串----
java·数据结构·算法·leetcode
05候补工程师1 小时前
【ROS 2 避坑指南】从 SLAM 实时建图到 Nav2 导航算法深度调优全过程
算法·ubuntu·机器人
Dlrb12111 小时前
C语言-函数传参
c语言·数据结构·算法
Betelgeuse762 小时前
Django 中间件 4 大钩子 & CBV vs FBV 对比实战
python·中间件·django
92year8 小时前
用Google ADK从零搭一个能调工具的AI Agent:Python实操全过程
python·ai·mcp
洛水水8 小时前
【力扣100题】18.随机链表的复制
算法·leetcode·链表
南宫萧幕9 小时前
规则基 EMS 仿真实战:SOC 区间划分与 Simulink 闭环建模全解
算法·matlab·控制