Python 约瑟夫生者死者小游戏
30 个人在一条船上,超载,需要 15 人下船。
于是人们排成一队,排队的位置即为他们的编号。
报数,从 1 开始,数到 9 的人下船。
如此循环,直到船上仅剩 15 人为止,问都有哪些编号的人下船了呢?
实例
people={}
for x in range(1,31):
people[x]=1
# print(people)
check=0
i=1
j=0
while i<=31:
if i == 31:
i=1
elif j == 15:
break
else:
if people[i] == 0:
i+=1
continue
else:
check+=1
if check == 9:
people[i]=0
check = 0
print("{}号下船了".format(i))
j+=1
else:
i+=1
continue
执行以上实例,输出结果为:
9号下船了 18号下船了 27号下船了 6号下船了 16号下船了 26号下船了 7号下船了 19号下船了 30号下船了 12号下船了 24号下船了 8号下船了 22号下船了 5号下船了 23号下船了
Python3 实例
奇卡
ycz***18qijian@qq.com
参考方法:
peple =[] for i in range(1,31): person = 'person%d'%i peple.append(person) c = 0 max =30 t = 0 while max >15: god = [] for pe in peple: c += 1 if c % 9 == 0: print(c,pe,'离开') max -= 1 god.append(pe) for pe in god: peple.remove(pe) print('留下人员',peple)奇卡
ycz***18qijian@qq.com
看看python有多优雅
189***03000@189.cn
参考方法:
liver = list(range(1, 31)) index = 1 list_index = index - 1 while True: if len(liver) <= 15: break else: if index == 9: print('{0}号下船了'.format(liver[list_index])) liver.remove(liver[list_index]) index = 1 else: index += 1 list_index += 1 if list_index == len(liver): list_index = 0看看python有多优雅
189***03000@189.cn
fanzhao
732***338@qq.com
参考方法:
people = range(1,31) tempList = list() timer = 1 flag = True while flag: for x in people: if people.index(x) in tempList: continue if timer == 9: tempList.append(people.index(x)) timer = 0 if len(people) - len(tempList) == 15: flag = False break timer += 1 for x in tempList: print(x+1,end=" , ")fanzhao
732***338@qq.com
百川
pos***163.com
约瑟夫环是很经典的题目。以下代码充分利用 Python 数据结构的特性,以求尽可能简洁。
people=list(range(1,31)) while len(people)>15: i=1 while i<9: people.append(people.pop(0)) i+=1 print('{:2d}号下船了'.format(people.pop(0)))百川
pos***163.com
shohan
532***493@qq.com
上面写的有点复杂了,其实可以很简单的几行代码,如下直接定义成函数调用吧:
def yuesefu(nums, step, stay): #参数 nums:人数,step: 数到几的步数,stay: 最后留下多少人 lists = list(range(1, nums+1)) check = 0 while len(lists) > stay: for i in lists[:]: check += 1 if check == step: check = 0 lists.remove(i) print("{}号下船了".format(i)) return lists stays = yuesefu(30, 9, 15) print("最后留下的人:", stays)shohan
532***493@qq.com
逆光追梦
303***66@qq.com
a=[x for x in range(1,31)] b=[] for x in range(135): #x最少要数9*15次才能数够15名下船人数 if (x+1)%9==0: b.append(a[x-len(b)]) #把a里面被淘汰的人加入到b列表中 y=len(b)-1 #列表b里面每增加一个元素,a里面对应的人员就会自动往前面进一位后面前进的位数刚好是列表b的长度-1 a.remove(a[x-y]) #同时册除列表a里面被点中的人 else: a.append(a[x-len(b)]) #把没有被点中的人重新加入到列表a 的后面 print(b)运行的结果:
逆光追梦
303***66@qq.com
随遇而安
109***9506@qq.com
这个问题的关键在于每次循环只选出一个人。因为当留在船上的人数大于报数最大值的2倍时,若每次循环选出所有的可能数,则会造成结果中留在船上人少于目标值。将问题定义成函数如下:
def JosephDeathGame(total, onboard, step): peoples = list(range(1, 31)) x = 0 #下船人数计数 y = 1 #报数计数 z = 0 #索引计数 while x < total - onboard: if z > len(peoples)-1: z = 0 if y == step: print("{0}号下船了!".format(peoples.pop(z))) z -= 1 y = 0 x += 1 y += 1 z +=1 JosephDeathGame(30, 15, 9)随遇而安
109***9506@qq.com
Python小白
141***7026@qq.com
把前面两位大神的代码简单综合了一下,更加简单且适用各种情况的是。
def yuesefu(nums,step,stay): #nums:总人数 step:步长 stay:剩余的人数 lists = list( range(1,nums+1) ) #check = 0 while len(lists) > stay: i = 1 while i<step: lists.append(lists.pop(0)) #print(lists) i+=1 #print(i) print("{:2d}号要下船了".format(lists.pop(0))) stays = yuesefu(30,9,15)Python小白
141***7026@qq.com
realmesir
rea***sir@126.com
people = list(range(1, 31)) i = 0 while len(people) > 15: i += (9 - 1) if i >= len(people): i -= len(people) print("{}号下船了".format(people[i])) del people[i]realmesir
rea***sir@126.com
季修梵
tim***o@outlook.com
GitHub上看到的解决方法,代码简单易懂,参考下。
def main(): persons = [x for x in range(1, 31)] # 统计下船的人数 dropped = 0 while (dropped < 15): print('下船的号数为:', persons[8]) # 对列表进行切片操作,每次截取前9位后的数据和前8位的数据 persons = persons[9:] + persons[0:8] # print('截取后的列表数据为:',persons) dropped += 1 print ('剩余的号数为:') print (sorted(persons)) if __name__ == '__main__': main()季修梵
tim***o@outlook.com
Deng
chh***g@hotmail.com
用从字典里移除键值的方法来解决这个问题:
people={} for x in range(1,31): people[x]="p{}".format(x) c = 0 pn = 30 skip = [] while pn >15: for i in range(1,31): if i not in skip: # 跳过在移除人员列表中的键值 c += 1 # 累计数的次数 if c%9 == 0: # 当数到9的整数倍时 print("{:2d}".format(i) + " " + "号下船了") skip.append(i) # 创建移除人员列表 pn -= 1 # 人员名单长度因移除而缩短1 people.pop(i) # 移除相应人员 print ('\n留下人员', people)Deng
chh***g@hotmail.com
waipcat
wai***t@126.com
跟上边有几位同学的思路差不多,不过应该是最短的了,5 行:
sum = list(range(1,31)) while len(sum) > 15: print('{}号下船了'.format(sum.pop(8))) for i in range(8): sum.append(sum.pop(0))waipcat
wai***t@126.com
Deng
chh***g@yahoo.com
紧跟上一位同学的思路:
sum = list(range(1,31)) while len(sum) > 15: print('{}号下船了'.format(sum.pop(8))) sum +=sum[0:8] del sum[0:8]Deng
chh***g@yahoo.com
Deng
chh***g@hotmail.com
将上一个稍作调整:
people = [p for p in range(1,31)] left = [] while len(people) > 15: left.append(people[8]) people.extend(people[0:8]) del people[0:9] print("下了船的人员名单是: {0};\n留在船上的人员名单是:{1}".format(sorted(left), sorted(people)))Deng
chh***g@hotmail.com
Eric
nus***h@sina.com
利用切片,每次生成一个新的序列:
s=list(range(1,31)) for i in s: if len(s)>15: print(s[8]) s=s[9:]+s[:8]Eric
nus***h@sina.com
camsun
ken***enjian@outlook.com
参考:
people=list(range(1,31)) position=0 while len(people)>15: position=(position+8)%len(people) print("{}号下船了".format(people.pop(position))) print("船上最后剩下:{}".format(people))camsun
ken***enjian@outlook.com
学海无牙
yua***iu@gmail.com
参考方法:
def check_count(count1, count2, list): if count1 == 9: count1 = 1 if count2 == len(list): count2 = 0 else: count2 = count2 else: count1 += 1 if count2 == len(list) - 1: count2 = 0 else: count2 += 1 return count1, count2 num_ppl = int(input('Key in the number of people: ')) list = [] for i in range(1, num_ppl+1): list.append(i) print(list) count1 = 1 count2 = 0 while len(list) > 15: if count1 == 9: print('No.' + str(list.pop(count2)) + ' jump into the river!') count1, count2 = check_count(count1, count2, list) else: count1, count2 = check_count(count1, count2, list) print('Survivors:', end = ' ') print(list)学海无牙
yua***iu@gmail.com
Rounie
rou***jane@163.com
方法一:
#约瑟夫环问题,n=30,报数为9的下船,最终船上剩下15人 li=list(range(30)) countNum=1 #下船人数计数 取值1-15 while countNum<=15: i=1 #排序计数,取值1-9 while i<9: li.append(li.pop(0)) #每遍历一个元素,把当前元素追加到列表末尾,这样做是为了方便循环遍历 i+=1 print('{}号下船了'.format(li.pop(0)+1)) countNum += 1思想就是:队列从头开始按顺序报 1-9 之间的数,报完数的人站到队列末尾,报数是 9 的成员下船,如果有人下船,则下一个人从 1 开始报数,循环继续,直至下船人数达到 15 人停止。
所以该方法特点:第一、报数的人一定站在队列首位,当然下船的人也是在首位。第二、每下船一人,队列长度减一。第三、下船人号码正好是初始序列号码,在编程中表现即是下船号码是列表索引加 1。
方法二:
借鉴前几楼思路,使用列表切片来生成新的队列,并且改进之前的初始生成序列 0-29 为 1-30。
#利用切片来生成新的队列 li=list(range(1,31)) countNum=1 for i in li: if countNum<=15: print('{}号下船了'.format(li[8])) li=li[9:]+li[:8] countNum += 1Rounie
rou***jane@163.com
Alyna
aly***cai@163.com
使用队列(先进先出原理),代码如下:
from queue import Queue N = 30 q = Queue(N) #建立一个长度为30的堆栈 for i in range(1, N + 1): #给堆栈赋值1~30 q.put(i) #print(q.get()) check = 0 #报数检测9 leaveN = 0 #下船人数记录 while leaveN < 15: check += 1 temp = q.get() #前进先出 if check == 9: print(f'{temp}号下船') check = 0 leaveN += 1 else: q.put(temp) #进入队列Alyna
aly***cai@163.com