約瑟夫環的O n 演算法

2021-06-14 03:52:29 字數 1193 閱讀 4744

問題描述:

已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。從編號為1的人開始報數,數到m的那個人出列;他的下乙個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列,求最後乙個出列人的編號。

為了討論方便,先把問題稍微改變一下,並不影響原意:問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求最後乙個人的編號。

第乙個出列人的編號一定是(m-1)%n,他出列之後,剩下的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

.....

n-1 --> n-1-k

0--> n-k   

... 

...   

k-3 --> n-3

k-2 --> n-2

從前面幾個數可以發現轉換後貌似都減了k,看到後面發現光減k不行,因為可能會出現負數,所以其實是先減去k再加上n最後對n取模。

變換後又從0開始報數,即就完完全全成為了(n-1)個人報數的子問題,假如我們知道這個子問題(即(n-1)個人報數的子問題)的解:例如x是最終出列的人,那麼根據上面這個表把這個x變回去就正好是n個人報數最後出列的人的編號x':

∵ k=m%n;   

∴ x' = x+k = x+ m%n ; 而 x+ m%n 可能大於n

∴x'= (x+ m%n)%n = (x+m)%n   得到 x『=(x+m)%n

如何知道(n-1)個人報數的問題的解?對,只要知道(n-2)個人的解就行了。(n-2)個人的解呢?當然是先求(n-3)的情況 ---- 這顯然就是乙個倒推問題!好了,思路出來了,下面寫遞推公式:

令f表示i個人玩遊戲報m退出最後出列者的編號,最後的結果自然是f[n].

遞推公式:   f[1]=0;   f[i]=(f[i-1]+m)%i; (i>1)

#includeusing namespace std;

int main()

printf("%hd\n", s+1);

return 0;

}

參考:

約瑟夫環演算法

約瑟夫環是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。2b求解 private void myjosf int teamle...

演算法 約瑟夫環

已知n個人 以編號1,2,3 n分別表示 圍坐在一張圓桌周圍 使用 list 來模擬環結構,不被淘汰則將其加入到 list 尾部,淘汰的直接移除。需注意,以編號 k 為第乙個報數的人,需要調整其在報數正式開啟前到 list 的頭部。param n 人的總數 param k 開始報數的序號,1 k n...

演算法設計 約瑟夫環

本科系列課程參見 軟體學院那些課 約瑟夫 joeph 問題的一種描述是 編號為1,2,n的n個人按順時針方向圍坐一圈,每人持有乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始按順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向上...