約瑟夫環非遞迴演算法和遞迴演算法分析與實現(ZZ)

2021-08-31 22:20:22 字數 1412 閱讀 6881

【joseph問題描述】

n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。

【求解思路】

[size=medium][b]1.非遞迴演算法[/b][/size]

我們知道第乙個人(編號一定是m%n-1) 出列之後,剩下的n-1個人組成了乙個新的約瑟夫環(以編號為k=m%n的人開始):

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

並且從k開始報0。

現在我們把他們的編號做一下轉換:

k --> 0

k+1 --> 1

k+2 --> 2

......

k-2 --> n-2

k-1 --> n-1

變換後就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那麼根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎?!!變回去的公式很簡單,相信大家都可以推出來: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]+m)%i; (i>1)

有了這個公式,我們要做的就是從1-n順序算出f[i]的數值,最後結果是f[n]。因為實際生活中編號總是從1開始,我們輸出f[n]+1

由於是逐級遞推,不需要儲存每個f[i],程式也是異常簡單:

int main()

[size=medium][b]2.遞迴演算法[/b][/size]

當n個人時,退出的一定是報到m%n-1的人(有%是因為m可能大於n,經過迴圈才能報到m),由於所有人是乙個環,可以認為是從任何地方開始編號的,所以在m%n-1這個人之後的人可以認為編碼都大於他,那麼整個環的編號就是m%n-1到m%n-1+n-1(也就是m%n-1到m%n-2,實際上乙個編號是m還是m+n或者m+2n都無所謂,只要最終算出來的編號對n取模就是正確的編號了。)

那此人退出後他的下一位,也就是原來報m%n這位的編號將更新為0。相應的後面的編碼都會減少m%n,所以得出公式:

f[n] - m%n = f[n-1]

變形一下公式也就是:

f[n] = (f[n-1] + m) % n

由此公式得到遞迴演算法(注,要是跟非遞迴保持一致的話,可以將最後返回值+1)

int f(int n, int m)

約瑟夫環非遞迴演算法分析

joseph問題描述 n個人 編號0 n 1 從0開始報數,報到 m 1 的退出,剩下的人繼續從0開始報數。求勝利者的編號。求解思路 我們知道第乙個人 編號一定是m n 1 出列之後,剩下的n 1個人組成了乙個新的約瑟夫環 以編號為k m n的人開始 k k 1 k 2 n 2,n 1,0,1,2,...

約瑟夫環非遞迴演算法分析

joseph問題描述 n個人 編號0 n 1 從0開始報數,報到 m 1 的退出,剩下的人繼續從0開始報數。求勝利者的編號。求解思路 我們知道第乙個人 編號一定是m n 1 出列之後,剩下的n 1個人組成了乙個新的約瑟夫環 以編號為k m n的人開始 k k 1 k 2 n 2,n 1,0,1,2,...

約瑟夫環 遞迴演算法

假設下標從0開始,0,1,2 m 1共m個人,從1開始報數,報到k則此人從環出退出,問最後剩下的乙個人的編號是多少?現在假設m 10 0 1 2 3 4 5 6 7 8 9 k 3 第乙個人出列後的序列為 0 1 3 4 5 6 7 8 9 即 3 4 5 6 7 8 9 0 1 我們把該式轉化為 ...