背景:故事源自著名犹太历史学家Josephus,在罗马人占领乔塔帕特后,39个犹太人与Josephus以及他的朋友躲进了一个山洞中,39个犹太人决定宁死不屈,于是决定了一个自杀方式,41个人排成一个圈,由第一个人开始报数,每数到3此人就自杀,然后由下一个重新报数,直到所有人都自杀为止。然而Josephus和他的朋友并不想这就死去,于是Josephus让他的朋友和他佯装遵从,他偷偷将朋友和自己安排在第16个和31个位置,最终逃过了这场死亡游戏。
以上就是经典的约瑟夫环问题,简单转换:
有n个人围成一圈(1~n),从第1号开始进行1、2、3报数,凡报3者就退出,下一个人又从1开始报数......直到所有人退出圈子为止。输入整数n,请按顺序输出退圈顺序
解题思路:可参考b站:约瑟夫问题,讲成这样,应该80老大爷都能听懂了_哔哩哔哩_bilibili
该up讲的非常清楚,但是源代码是C++,自己转换了一下为Python,其中遇到bug一直陷在了死循环,最后发现是while循环条件出错,基本代码和up的差不多,只是改动了一个条件
(定义如果圈里有人的位置即为1,无人的位置即0;引入一个模拟裁判,设定mouth为数数,手指finger作为指针同时进行数数,当mouth数到3,指针停止,指针finger指到的位置赋值0)
#定义如果圈里有人的位置即为1,无人的位置即0;引入一个模拟裁判,设定mouth为数数,手指finger作为指针同时进行数数,当mouth数到3,指针停止,指针finger指到的位置赋值0
import numpy as np
game = np.zeros((20,), dtype=int) #创建一个长度为20的全零数组
res = [] #存储输出顺序的数字
n = 10 #圈里共有10个人
m = 3 #依据题目数到3退圈
for i in range(n): #为全零数组的前十个位置赋值为1(0~9)
game[i] = 1
finger = 0
mouth = 0
#游戏开始到结束
count = n
while count !=1: #小心这里应该为1,若为0会死循环在第一个while跳不出来,当输出最后一个人退圈时,count只到1
finger += 1
mouth += 1
#当循环完第一圈时会有位置赋0,所以当指针finger指到为0的位置需要再跳一个即+1往下
while game[finger] == 0:
finger += 1
if finger > n: finger = 1 #这里当循环到finger大于n时应该指回原来圈圈的第一位其下标在数组为0,但是当我们进入循环时finger已经先+1,所以finger=1时指向了1号,所以这时返回finger=1才是等于原来的1号
if mouth == m:
res.append(finger)
count -= 1
game[finger] = 0
mouth = 0 #这里为0是因为在返回循环时mouth先+1,为了符合数数从1开始,这里应该为0
print(res)