约瑟夫环 JosephusProblem

Posted -ackerman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了约瑟夫环 JosephusProblem相关的知识,希望对你有一定的参考价值。

问题描述:n个人 ( 编号0~(n-1) ),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。 

最直白的方法就是用链表去模拟整个过程就好了,但是这个的复杂度有点高,算不上一个非常优秀的做法。

 

下面进行推导,看是否能够推出一个通用的公式这样就可以直接得出答案:

初始情况: 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 


现在我们把他们的编号做一下转换:

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

 

递推公式

 f [1] = 0; 
 f [ i ] = ( f [i -1] + m) % i; (i>1) 

 

递归写法:

int josephus(int n,int m) {
    if (n == 1)
        return 0;
    else 
        return (josephus(n-1,m) + m) % n;
}

 

迭代写法:

int f[maxn];
int josephus(int n,int m) {
    if (n < 1 || m < 1)
        return -1;
    for (int i = 2;i <= n;i++)
        f[i] = (f[i-1] + m) % i;
}

以上是关于约瑟夫环 JosephusProblem的主要内容,如果未能解决你的问题,请参考以下文章

约瑟夫环(超好的代码存档)--19--约瑟夫环--LeetCode面试题62(圆圈最后剩下的数字)

约瑟夫环(超好的代码存档)--19--约瑟夫环--LeetCode面试题62(圆圈最后剩下的数字)

约瑟夫环 代码

约瑟夫环

python类约瑟夫环原创问题求解 求大神

java中约瑟夫环代码实现