約瑟夫環問題

2021-10-08 22:26:34 字數 2218 閱讀 4123

數學分析

經典演算法–約瑟夫環問題的三種解法

問題描述:n個人圍成一圈,從第乙個人開始從1開始報數,報到m的人出圈,剩下的人繼續從1開始報數,報到m的人出圈;如此往復,直到所有人出圈。(模擬此過程,輸出出圈的人的序號)

迴圈的開始和結束:迴圈的結束取決於圈內是否還有「人」,可以用乙個變數alive表示初始人數,每一次出圈,alive - 1。判斷alive是否非0即可。

while(alive > 0)
每一次迴圈,就是「過」乙個人,但是,這個人有兩種不同的狀態:在圈內和不在圈內;在圈內就報數,number+1,不在圈內就不參與報數,number不變。

假設有n個int元素的陣列,每乙個int元素表示乙個「人」;並且,取值為0和1, 1表示在圈內,0表示不在圈內,所以,如果這個人在圈內,number + 1;如果這個人不在圈內,number + 0。那麼,在報數的時候,不需要考慮這個人在不在圈內(每乙個人都需要加1或加0,所以,可以在這塊優化一下程式)。

void

joseph

(int count,

int doom)

//與總人數count取餘,則可以使index在0~count-1之間 一直迴圈,達到迴圈陣列的目的

index =

(index +1)

% count;

}printf

("\n");

free

(circle)

;//結束後一定要釋放circle所申請的空間

}

初始情況

一共n個人(編號0,1,2… n-1),組成乙個環。第乙個人從1開始報數,報數到m的人出環,然後,下乙個人重新開始從1開始報數,直到環中只有乙個人。

分析:第乙個出環的人編號是 (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

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

1.遞迴:

#include

intjosephus

(int n,

int m)

else

}int

main()

scanf

("%d"

,&m)

;int result =

josephus

(n, m)

;printf

("%d\n"

, result+1)

;}return0;

}

2.迭代:

#include

intmain()

scanf

("%d"

,&m)

; result =0;

for(i =

2; i <= n; i++

)printf

("%d\n"

, result +1)

;}return0;

}

約瑟夫問題 約瑟夫環

約瑟夫 問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死...

約瑟夫問題 約瑟夫環

約瑟夫問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也...

約瑟夫環問題

約瑟夫環問題 問題描述 編號是1,2,n的n個人按照順時針方向圍坐一圈,每個人持有乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向的下乙個人開始重新從1報數,如此下去,直到所有人...