问题描述:
有N个人围成一圈,按顺序排号。从第一个人开始报数(从1开始),凡报到5的人退出圈子,问最后留下的是原来第几号的那位。
例如:9个人围成一圈,1号从第1开始报数,5号首先退出圈子。接着6号从1开始重新报数,1号退出圈子。接着2号从1开始重新报数,7号退出圈子。然后从8号开始重新报数,4号退出圈子。6号重新报数,3号退出圈子。依次类推,最后剩下原来的8号留下
- 已有文件in.txt。输入文件格式如下:
656
786
547
9
3423
- 文件里每一行为一个整数N,表示每一轮游戏有N个人参与报数。以回车换行。
- 输出最后留下的人员编号
解题:理解题目后发现,这是一个Josephus问题,总共包含n个人,从第k(K=1)个人开始数数,数m个之后退出,依次循环
首先需要将n个人映射到一个长度为n的数组中people[0]...people[n-1]对应[1,n],注意下标和编号的对应(编号1的下标为0),针对约瑟夫问题,两种方法:
1.数组标记方式:扫描数组,设置计数器,当数到m时,将对应的值设为0(退出),将计数器复位,进行下一轮的计数,直到剩下最后一个元素:
需要注意:经过几轮的访问之后,数组的下标可能已经超过了数组长度,需要将数组下标取模映射到原数组中
2.列表方式:扫描数组,如果数到m时,则将对应的数从列表中出列,直到数组长度变为1
#数组方式,n:数组长度,k:开始编号,m:数的个数; def josephus_A(n,k,m): people = list(range(1,n+1)) i = k - 1 for num in range(n): count = 0 #count:计数器 while count < m: if people[i] > 0: count += 1 if count == m: print(people[i],end=' ') #退出的人 people[i] = 0 #编号设为0 i = (i+1)%n if num < n - 1: print(", ",end="") elif num == n - 1: print("最后留下:",people[i]) else: print(" ") return def josephus_L(n,k,m): people = list(range(1,n+1)) num, i = n, k-1 for num in range(n-1,0,-1): i = (i+m-1)%num print(people.pop(i), end=(", " if num > 1 else "\n")) print("最后留下:",people[0]) return #测试 with open(filename,'r',encoding='utf-8') as fp: lines = fp.readlines() for line in lines: line = line.rstrip('\n') n = int(line) k = 1 m = 5 josephus_A(n,k,m)