n个人做成一圈,顺时针由1开始给他们编号,然后由第一个人进行报数,数到m的人出局,接着下一个人又从1开始报数,只剩最后一个人的时候求这个人的编号
特例:当m = 2的时候
① n = 2^k
如果只有2个人,显然剩余的为1号如果有4个人,第一轮除掉2,4,剩下1,3,3死,留下1 。如果是8个人,先除去2,4,6,8,之后3,7,剩下1,5,除去5,又剩下1了
递推,起始我们仔细分析也就是每次除去一半的元素,然后剩余的一半继续重复之前的策略,再除去一半。(可想到递归)
结合:J(2) = 1我知道两个数,从1开始,肯定是2先死,剩下1.
得到:j(2^k)= 1
②当 n != 2^k (n = 9 11)
n 不等于2^k时,就不存在这样的easy的规律了,重新分析:
假设n =9,这时候如图下:
能看出来,我们干掉第一个人也就是2,之后就只剩下8个人了,又回到J(2^k)上了,这时候我们需要的是找到当前的1号元素。
见图下:
这时候,我们从3号开始,就成了另外一个规模小1的约瑟夫问题(恰好为2^k的特例)。
这时候,我们可以把3号看成新的约瑟夫问题中的1号位置:
J(8) = J(2^3) =1,也就是说这里的1代表的就是上一个问题中的3号
So:J(9) =3
答案为3号
同理可知所有的非2^k的数都是这样:【找到新的1号】
假设n = 2^k +t,t可以随意取,比如1,2,3…….
假设n = 11,这时候n =2^3 + 3,也就是说t = 3,所以开始剔除元素直到其成为2^k问题的约瑟夫问题。
So,我们在剔除了t(3)个元素之后(分别是2,4,6),此时我们定格在2t+1(7)处,并且将2t+1(7)作为新的一号,而且这时候的约瑟夫环只剩下2^3,也就是J(2^3+ 3) = 2*3 + 1 = 7,答案为7
总结一下这个规律:
J(2^k + t) = 2t+1
3.当q不等于2的情况下:
当q≠ 2:
我们假定:
- n —n人构成的约瑟夫环
- q —每次移除第q个人
约定:
-Jq(n)表示n人构成的约瑟夫环,每次移除第q个人的解
- n个人的编号从0开始至n-1
我们沿用之前特例的思想:能不能由Jq(n+1)的问题缩小成为J(n)的问题(这里的n是n+1规模的约瑟夫问题消除一个元素之后的答案),Jq(n)是在Jq(n+1)基础上移除一个人之后的解。也就是说,我们能由Jq(n)得到Jq(n+1)。
规律:Jq(n+1) = (Jq(n) + q ) / (n+1)
【
初始情况: 0, 1, 2......n-2, n-1 (共n个人)
第一个人(编号一定是(m-1)%n,设之为(k-1),读者可以分m<n和m>=n的情况分别试下,就可以得出结论) 出列之后,
剩下的n-1个人组成了一个新的约瑟夫环(以编号为k==m%n的人开始):
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ...,k-3, k-2
现在我们把他们的编号做一下转换:
x'-> x
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 -->n-2
k-1 -->n-1
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗!
x ->x'?(这正是从n-1时的结果反过来推n个人时的编号!)
0 -> k
1 -> k+1
2 -> k+2
...
...
n-2 -> k-2
变回去的公式x'=(x+k)%n
那么,如何知道(n-1)个人报数的问题的解?只要知道(n-2)个人的解就行了。(n-2)个人的解呢?只要知道(n-3)的情况就可以了---- 这显然就是一个递归问题:
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果就是f[n]
递推公式
f[1]=0;
f[i]=(f[i-1]+k)%i =(f[i-1] +m%i) % i = (f[i-1] + m) % i ; (i>1)
】
class Joseph:
def getResult(self, n, m):
# write code here
res = self.Josephus(n,m)
return res + 1
def Josephus(self,n,m):
if n == 1:
return 0
else:
return (self.Josephus(n-1,m)+m)%n