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

2023-11-29 21:15

本文主要是介绍每日一练:约瑟夫生者死者小游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

1. 问题描述

  约瑟夫问题(Josephus problem)是一个经典的数学和计算机科学问题,源于犹太历史学家弗拉维奥·约瑟夫斯(Flavius Josephus)的著作《犹太战记》。问题的描述如下:
  在这个问题中,有n个人站成一个圈,从1n编号。从第一个人开始,每次数m个人,数到第m个人就将其从圈中删除,然后从下一个人开始重新数,重复这个过程,直到所有人都被删除。问题是,最后剩下的那个人的编号是多少?
  为了解决约瑟夫问题,可以使用递归或迭代的方法。下面是一个简单的递归解法的伪代码:

function josephus(n, m):if n == 1:return 1else: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人为止,问剩下的人的编号?

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 人为止,问剩下的人的编号?

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 人为止,问剩下的人的编号?

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 人为止,问剩下的人的编号?

def josephus_with_custom_deletion(n, m, k, deletion_rule):people = list(range(1, n + 1))current = 0while 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) % lengthresult = josephus_with_custom_deletion(30, 9, 15, custom_deletion_rule)
print("剩下的人的编号是:", result)

在这里插入图片描述

4.参考:

https://www.runoob.com/python3/python-joseph-life-dead-game.html

在这里插入图片描述

这篇关于每日一练:约瑟夫生者死者小游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/434330

相关文章

poj3750约瑟夫环,循环队列

Description 有N个小孩围成一圈,给他们从1开始依次编号,现指定从第W个开始报数,报到第S个时,该小孩出列,然后从下一个小孩开始报数,仍是报到S个出列,如此重复下去,直到所有的小孩都出列(总人数不足S个时将循环报数),求小孩出列的顺序。 Input 第一行输入小孩的人数N(N<=64) 接下来每行输入一个小孩的名字(人名不超过15个字符) 最后一行输入W,S (W < N),用

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

每日一练7:简写单词(含链接)

1.链接 简写单词_牛客题霸_牛客网 2.题目 3.代码1(错误经验) #include <iostream>#include <string>using namespace std;int main() {string s;string ret;int count = 0;while(cin >> s)for(auto a : s){if(count == 0){if( a <=

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

PHP约瑟夫环问题

#循环 function circle($arr,$idx,$k){for($i=0;$i<$idx;$i++){$tmp = array_shift($arr);array_push($arr,$tmp);}$j = 1;while(count($arr) > 0){$tmp = array_shift($arr);if($j++%$k == 0){echo $tmp."\n";}else{a

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调

每日一题——第八十一题

打印如下图案: #include<stdio.h>int main() {int i, j;char ch = 'A';for (i = 1; i < 5; i++, ch++){for (j = 0; j < 5 - i; j++){printf(" ");//控制空格输出}for (j = 1; j < 2 * i; j++)//条件j < 2 * i{printf("%c", ch

每日一题,力扣leetcode Hot100之238.除自身以外数组的乘积

乍一看这个题很简单,但是不能用除法,并且在O(N)时间复杂度完成或许有点难度。 考虑到不能用除法,如果我们要计算输出结果位置i的值,我们就要获取这个位置左边的乘积和右边的乘积,那么我新设立两个数组L和R。 对于L来说,由于表达的是位置i左边的数的乘积,那么L[0]=1,因为第一个数字左边没数那么为了不影响乘积初始值就设置为1,那么L[1]=L[0]*nums[0],那么L[i]=L[i-1

英语每日一段 195

Promising economic indicators won’t instantly reverse the lingering impact of hard times for millions of families, workplace culture expert Jessica Kriegel said. “Perception and reality are sometimes