今天写编程作业的时候,遇到了一个【轮流出列】的问题(助教非常贴心地将m和n的数字设置为了模拟方法刚好可以通过的大小……)。
题目如下:
编号为n的人围成一个圈,轮流从1开始报数,报到m的人出列,然后从下一个人开始继续从1开始报数。求最后剩下的人的编号。
这是一个典型的约瑟夫环问题。
解法为从人数为1开始,逐步递推回人数为n的情况。我们先假设下标从0开始,这样方便后面的计算。当人数为1时,剩下的人的编号显然为0,于是返回1.注意到这一轮中编号0的人,一定是上一轮中编号为m % i的人,所以这一轮中报res的人,在上一轮中的编号为(res + m)% i,我们知道最后一轮中剩下的人一定是编号为0的,这样就可以逐步倒推回此人在第一轮中的编号了(记得要加上1,因为从1开始编号,而我们的推导是从0开始编号)。
代码如下:
def out_queue(n, m):
res = 0
for i in range(2, n + 1):
res = (res + m) % i
return res + 1
最后,这个问题的关键在于弄明白这样一个问题:
这一轮中报res的人,在上一轮中的编号是多少?
这样我们知道当最后只剩一个人的时候,若继续报数,则此人一定报0.那么逐渐递推回去,就是这个问题的答案。