任务
编写一个使用列表求解约瑟夫环的问题
背景
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中。
39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
约瑟夫问题可以这样描述:n个人按1,2,3,… ,n编号,并顺序围坐一圈。开始按照1,2,3,… ,m 报数,凡报到 m 的出列。直到所有人出列为止。
求解
法一
从列表头开始遍历,设置一个计数器c
,初始化设置为0
,每次判断,都是判断计数器,若c==k(设置的序号)
即表示当前数应当被剔除,剔除后计数器归0
,遍历继续,但是c
从头开始计数。具体思路如下图所示:
x=[]
n=eval(input("输入人数"))
k=eval(input("输入序号"))
x = [i for i in range(1,n+1)]
c = 0
# 当x不为空时进行循环
while x:
temp = x[0]
c = c + 1
if c == k:
print(temp)
c = 0
x.remove(temp)
else:
x.remove(temp)
x.append(temp)
法二
法一是把它想成是一个直直的列表,遍历一直往后进行,法二是绕圈遍历,遍历到了末尾又从列表头开始。
循环下标index
从0
开始,当列表只有最后一个元素时结束
第一个移除出列表的元素下标,len
表示当前列表的长度:(0+(k-1))%len
第二个移除出列表的元素下标:(0+(k-1)+(k-1))%len
其实,也就是每次移除的元素,在数组中的位置index = (index + (k-1))%len
两个注意点:
为什么要%len?
因为是循环遍历,到了末尾需要从头继续,如1号,2号,3号三个人,依次报数,循环报数,取报数5的人,即2号。
为什么是index+(k-1)?
虽然是往后数k个数,但是因为在前一阶段移除了1个符合要求的元素,所以在后一阶段符合要求的元素的下标其实只增长了k-1
x=[]
n=eval(input("输入人数"))
k=eval(input("输入序号"))
x = [i for i in range(1,n+1)]
index = 0
while True:
if len(x) == 1:
print(x[0])
break
index=(index+(k-1))%len(x)
print(lb[x])
del lb[x]