码迷,mamicode.com
首页 > 其他好文 > 详细

约瑟夫环 JosephusProblem

时间:2020-01-08 22:39:47      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:组成   复杂度   ++   lse   直接   turn   答案   back   nbsp   

问题描述: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

标签:组成   复杂度   ++   lse   直接   turn   答案   back   nbsp   

原文地址:https://www.cnblogs.com/-Ackerman/p/12169034.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!