博客园 首页 私信博主 显示目录 隐藏目录 管理

约瑟夫环问题的递归实现

约瑟夫环问题有很多实现方法,迭代啦,递归啦。

这里主要介绍一下递归的方法。

假设:

初始情况: 0, 1, 2 ......n-2, n-1 (共n个人)

 第一个人(编号一定是(m-1)%n,设之为(k-1) ) 出列之后,

剩下的n-1个人组成了一个新的约瑟夫环(以编号为k==m%n的人开始):

 k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ...,k-3, k-2 


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


x' -> x      (x‘代表新编号,x代表原编号   k==m%n

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[n]=(f[n-1]+k)%n = (f[n-1] +m%n) % n = (f[n-1] + m) % n ;  (n>1)

当然,当n==1时,直接返回0即可

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int Josephus(int n,int m){
 5     if(n>1){
 6         return (m+Josephus(n-1,m))%n;
 7     }
 8     else{
 9         return 0;
10     }
11 }
12 int main()
13 {
14     int n,m;
15     scanf("%d %d",&n,&m);
16     int result=Josephus(n,m);
17     printf("%d",result+1);
18 
19     return 0;
20 }

 

有些目标看似很遥远,但只要付出足够多的努力,这一切总有可能实现!
posted @ 2018-12-08 23:25  Brave_WTZ  阅读(891)  评论(0编辑  收藏  举报