每日一练:约瑟夫生者死者小游戏

1. 问题描述

约瑟夫问题(Josephus problem)是一个经典的数学和计算机科学问题,源于犹太历史学家弗拉维奥·约瑟夫斯(Flavius Josephus)的著作《犹太战记》。问题的描述如下:

在这个问题中,有n个人站成一个圈,从1n编号。从第一个人开始,每次数m个人,数到第m个人就将其从圈中删除,然后从下一个人开始重新数,重复这个过程,直到所有人都被删除。问题是,最后剩下的那个人的编号是多少?

为了解决约瑟夫问题,可以使用递归或迭代的方法。下面是一个简单的递归解法的伪代码:

python 复制代码
function josephus(n, m):
    if n == 1:
        return 1
    else:
        return (josephus(n - 1, m) + m - 1) % n + 1

这个递归函数的基本思想是:假设已知n-1个人的问题的解,那么在这个基础上,考虑第n个人加入的情况。在每一轮中,我们实际上将问题规模缩小为n-1个人。

注意,这里的编号是从1开始的,因为在问题的原始描述中,人的编号是从1到n的。在某些变体中,编号可能从0开始,因此在实现时需要注意这一点。

2. 解题思路

解决约瑟夫问题的一般思路是通过模拟每一轮的删除过程,不断更新当前位置,并在满足终止条件时停止模拟。下面是一种基于迭代的解题思路和设计:

解题思路

  1. 初始化: 创建一个包含n个人初始编号的列表,并初始化一个变量表示当前位置。
  2. 循环删除过程:
  • 在当前位置开始数m个人。
  • 计算出要删除的人的位置。
  • 从列表中删除该位置的人。
  • 更新当前位置为删除位置。
  1. 终止条件: 当剩下的人数满足终止条件时,停止循环。
  2. 返回结果: 根据具体要求返回结果。在约瑟夫问题中,通常是返回最后剩下的一个人的编号或一组编号。

3. 代码实现

3.1 代码实现一

30 个人在一条船上,超载,需要 15 人下船。于是人们排成一队,排队的位置即为他们的编号。报数,从 1 开始,数到 9 的人下船。如此循环,直到船上人不能数到9人为止,问剩下的人的编号?

python 复制代码
def josephus(n, m):
    # 创建一个列表,表示n个人的初始编号
    people = list(range(1, n + 1))
    
    # 初始化变量,表示当前位置
    current = 0
    
    # 循环,直到剩下8个人
    while len(people) > 8:
        # 计算下一个要删除的人的位置
        current = (current + m - 1) % len(people)
        
        # 删除当前位置的人
        del people[current]
    
    # 返回剩下的最后一个人的编号
    return people

# 示例:有30个人,每次数9个人
result = josephus(30, 9)
print("最后剩下的人的编号是:", result) 

运行效果:

3.2 代码实现二

题目修改为:

30 个人在一条船上,超载,需要 15 人下船。于是人们排成一队,排队的位置即为他们的编号。报数,从 1 开始,数到 9 的人下船。如此循环,直到船上仅剩 15 人为止,问剩下的人的编号?

python 复制代码
def josephus(n, m, k):
    # 创建一个包含n个人初始编号的列表
    people = list(range(1, n + 1))
    
    # 初始化变量,表示当前位置
    current = 0
    
    # 循环,直到剩下的人数满足终止条件
    while len(people) > k:
        # 在当前位置开始数m个人,计算出要删除的人的位置
        current = (current + m - 1) % len(people)
        
        # 从列表中删除该位置的人
        del people[current]
    
    # 返回剩下的人的编号
    return people

# 示例:有30个人,每次数9个人删除,直至剩下15个人
result = josephus(30, 9, 15)
print("剩下的人的编号是:", result)

3.3 代码实现三

题目修改为:

30 个人在一条船上,超载,需要 15 人下船。于是人们排成一队,排队的位置即为他们的编号。报数,从 5 开始,数到 9 的人下船。如此循环,直到船上仅剩 15 人为止,问剩下的人的编号?

python 复制代码
def josephus_with_start(n, m, k, start):
    people = list(range(1, n + 1))
    current = start - 1  # 起始位置
    while len(people) > k:
        current = (current + m - 1) % len(people)
        del people[current]
    return people

# 示例:有30个人,每次数9个人删除,直至剩下15个人,起始位置为5
result = josephus_with_start(30, 9, 15, 5)
print("剩下的人的编号是:", result)

3.4 代码实现四

题目修改为:

30 个人在一条船上,超载,需要 15 人下船。于是人们排成一队,排队的位置即为他们的编号。报数,从 1 开始,数到 9 的人下船,但是每隔一轮人才下船。如此循环,直到船上仅剩 15 人为止,问剩下的人的编号?

python 复制代码
def josephus_with_custom_deletion(n, m, k, deletion_rule):
    people = list(range(1, n + 1))
    current = 0
    while len(people) > k:
        current = deletion_rule(current, m, len(people))
        del people[current]
    return people

# 示例:有30个人,每次数9个人删除,直至剩下15个人,但是每隔一轮删除一个人
def custom_deletion_rule(current, m, length):
    return (current + m) % length

result = josephus_with_custom_deletion(30, 9, 15, custom_deletion_rule)
print("剩下的人的编号是:", result)

4.参考:

https://www.runoob.com/python3/python-joseph-life-dead-game.html
相关推荐
枫叶丹43 分钟前
【Qt开发】多元素类控件(二)-> QTableWidget
开发语言·qt
bin91534 分钟前
当AI开始‘映射‘用户数据:初级Python开发者的创意‘高阶函数‘如何避免被‘化简‘?—— 老码农的函数式幽默
开发语言·人工智能·python·工具·ai工具
Nebula_g26 分钟前
Java哈希表入门详解(Hash)
java·开发语言·学习·算法·哈希算法·初学者
努力努力再努力wz28 分钟前
【C++进阶系列】:万字详解unordered_set和unordered_map,带你手搓一个哈希表!(附模拟实现unordered_set和unordered_map的源码)
java·linux·开发语言·数据结构·数据库·c++·散列表
励志不掉头发的内向程序员32 分钟前
【STL库】哈希表的原理 | 哈希表模拟实现
开发语言·c++·学习·散列表
万粉变现经纪人38 分钟前
如何解决 pip install -r requirements.txt 私有仓库认证失败 401 Unauthorized 问题
开发语言·python·scrapy·flask·beautifulsoup·pandas·pip
量子炒饭大师1 小时前
收集飞花令碎片——C语言字符函数与字符串函数
c语言·开发语言
懂得节能嘛.1 小时前
【设计模式】Java规则树重构复杂业务逻辑
java·开发语言·设计模式
syt_biancheng1 小时前
Qt--命名,快捷键及坐标系
开发语言·qt