環形鍊錶的約瑟夫問題 高階

2021-10-08 16:45:52 字數 1523 閱讀 4457

環形鍊錶的約瑟夫問題(高階)

據說著名猶太歷史學家 josephus 有過以下故事:在羅馬人占領喬塔帕特後,39 個猶太人與 josephus 及他的朋友躲到乙個洞中,39 個猶太人決定寧願死也不要被敵人抓到,於是決定了一種自殺方式,41 個人排成乙個圓圈,由第 1 個人開始報數,報數到 3 的人就自殺,然後再由下乙個人重新報 1,報數到 3 的人再自殺,這樣依次下去,直到剩下最後乙個人時,那個人可以自由選擇自己的命運。這就是著名的約瑟夫問題。現在請用單向環形鍊錶得出最終存活的人的編號。

輸入描述:

一行兩個整數 n,m,n 表示鍊錶的長度,m 表示每報數到 m 就自殺。

輸出描述:

輸出最後存活的人的編號(編號從 1 開始到 n)。

示例1輸入

5 2
輸出
3
備註:

1 ≤n

,m≤5

∗106

1 \leq n,m \leq 5*10^6

1≤n,m≤

5∗10

6題解:

觀察一下資料,在前面一篇 環形鍊錶的約瑟夫問題 中,資料範圍較小,可以以 o(n

∗m

)o(n*m)

o(n∗m)

的時間複雜度進行模擬,但是本題的資料範圍意味著我們需要考慮 o(n

)o(n)

o(n)

時間複雜度的演算法。之前的模擬是因為我們不知道到底哪個會活下來,所以通過不停的刪除來淘汰無關節點,直到剩下乙個節點。如果我們可以不用一直刪除的方式,而是直接通過 n 和 m 計算哪個節點會活下來,然後找到該節點的編號即可。那麼怎麼找到呢?考慮如下問題:

1個人:fun(1) = 1;

2個人:fun(2);

n-1個人:fun(n-1);

n個人:fun(n)。

我們已經知道 fun(1) = 1 ,如果能確定 fun(i-1) 和 fun(i) 之間的關係,就可以通過遞迴求出 fun(n) 了。

假設 n 和 m 分別為 5 和 3,假設編號為 a 的人報的是 b ,則 a 和 b 的對應關係如下:ab

1122

3341

52上面假設了 n 和 m 分別是 3 和 5 ,第乙個被殺掉人的編號為 3 ,在殺掉 3 後,對剩下的人重新編號,如下:

a_old

a_new13

243x

4152

x 表示人已經被殺掉,從上表中可以看到,編號之間的關係為:old = (new + 3 - 1) % 5 + 1,改寫一下公式就是:old = (new + m - 1) % i + 1,i 表示有 i 個人。至此,我們找到了 fun(i-1)->new 和 fun(i)->old 之間的關係。

那麼剩下的就是寫**了,由於每個狀態只和前乙個狀態有關,可以通過迴圈實現,不需要用遞迴,見**:

**:

#include

using

namespace std;

intmain

(void

)

環形鍊錶 約瑟夫問題

問題描述josephu問題 設編號為1,2,3 n的n個人圍坐成一圈,約定編號為k的人從1開始報數,數到m的那個人出列,他的下一位從1開始報數,數到m那個人又出列,直到所有人都出列為止,由此產生乙個出佇列編號的序號。解決方法 建立乙個輔助指標helper,指向頭指標的前乙個節點 當小孩報數的時候,f...

Java環形鍊錶 約瑟夫問題

n個小孩圍成圈,丟手帕,從第start個小孩開始丟,每到第step個小孩出局 接著從下乙個小孩開始,直到最後乙個小孩為止,遊戲結束。author jiaozl cyclink cyclink new cyclink cyclink.setlen 5 cyclink.createlink cyclin...

約瑟夫問題 單向環形鍊錶

約瑟夫問題的示意圖 josephu 問題 josephu 問題為 設編號為 1,2,n 的 n 個人圍坐一圈,約定編號為 k 1 k n 的人從 1 開始報數,數到 m 的那個人出列,它的下一位又從 1 開始報數,數到 m 的那個人又出列,依次類推,直到所有人出列為止,由此 產生乙個出隊編號的序列。...