1. 程式人生 > >約瑟夫環問題的遞迴實現

約瑟夫環問題的遞迴實現

約瑟夫環問題有很多實現方法,迭代啦,遞迴啦。

這裡主要介紹一下遞迴的方法。

假設:

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