約瑟夫問題,也叫約瑟夫環。
問題描述:n(編號從0到n-1)個人圍成乙個圈,從0號人開始數(從1開始數),數到第m個人,這個人淘汰。又從下乙個人開始,從1開始數,一直迴圈淘汰到只剩一人,這個人勝出。求這個人的編號。
解法一:模擬
這個問題很多人第一眼看到就覺得不是很簡單嗎,直接模擬就行啊。的確是,用一些列表型別的資料結構模擬一下就很容易做出來了。做法也因人而異。不過這方法只適用於人數和步數很小的時候,數量級一大就沒辦法了。模擬嘛,就是每m步去掉乙個,一共要去掉n-1個,所以時間複雜度是o(nm)。這裡我的方法不用傻乎乎的非要一步步的走,直接m步走,取餘,就能得到要刪除元素的下標。但是消耗時間還是沒解法二快,也許是列表刪除元素需要花費挺多時間,時間複雜度是o(n^2)。就算換成鍊錶,也是耗時間,因為需要找對應下標才能刪除,鍊錶找下標也要很久。python**如下。
# 模擬法
defjosephus1
(n:int
, m:
int)
->
int:
l =list
(range
(n))
idx =
0for i in
range
(n -1)
: idx =
(idx + m -1)
%len
(l) l.pop(idx)
return l[
0]
解法二:公式法其實約瑟夫問題是有規律的。
乙個人數為n,步數為m的約瑟夫環(定義為c(n, m)),走了m步去掉這個人(編號為m % n - 1)之後,又從下乙個人(編號為m)起,重新從0開始編號,這樣就變成了另乙個約瑟夫環c(n-1, m)。
然後一直走m步去掉乙個,約瑟夫環就變成c(n-2, m),c(n-3, m)…c(1, m)。所以求c(n, m),就變成了求c(n-1, m)…求c(1, m),求乙個任務就等於求它的子任務。在這些不斷的縮小的約瑟夫環中,都存在乙個同樣的人,就是倖存者,該編號在不同的約瑟夫環中是不同的。
還有乙個規律,乙個約瑟夫環元素編號可以被下一級約瑟夫環元素編號推出來。比如上圖,我們把這一級的下標和下一級的下標進行對比。
3 — 0
4 — 1
5 — 2
…n-2 — n-5
n-1 — n-4
n — n-3
0 — n-2
1 — n-1
可以發現,兩個下標之間差了m=3步。子任務只要加上m(往左走)就等於原任務的下標了,嚴謹點還得取模。設原任務的下標為idx,子任務的下標為idx』,原任務的人數為n,則公式為:idx = ((idx』 + m) % n)。
通過這個公式就可以用子任務的下標推算出上一級任務的下標。而約瑟夫環c(1, m)中的倖存者明顯就是0,這個倖存者是一直存在於上級的每個子任務中的,編號也不同。所以通過這個公式就可以一直推到c(n, m)中倖存者的標號。
比如求c(10, 3)
c(1, 3) = 0
c(2, 3) = (c(1, 3) + 3) % 2 = 1
c(3, 3) = (c(2, 3) + 3) % 3 = 1
…c(10, 3) = (c(9, 3) + 3) % 3 = 3
python**如下:
# 公式法
defjosephus2
(n:int
, m:
int)
->
int:
idx =
0for i in
range(1
, n +1)
: idx =
(idx + m)
% i return idx
m =3
for i in
range(1
,11):
print
('c({}, {}) = {}'
.format
(i, m, josephus2(i, m)))
# c(1, 3) = 0
# c(2, 3) = 1
# c(3, 3) = 1
# c(4, 3) = 0
# c(5, 3) = 3
# c(6, 3) = 0
# c(7, 3) = 3
# c(8, 3) = 6
# c(9, 3) = 0
# c(10, 3) = 3
模擬圖如下:
約瑟夫問題 約瑟夫環
約瑟夫 問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死...
約瑟夫問題 約瑟夫環
約瑟夫問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也...
約瑟夫問題
這是17世紀的法國數學家加斯帕在 數目的遊戲問題 中講的乙個故事 15個教徒和15 個非教徒在深海上遇險,必須將一半的人投入海中,其餘的人才能倖免於難,於是想了乙個辦法 30個人圍成一圓圈,從第乙個人開始依次報數,每數到第九個人就將他扔入大海,如此迴圈進行直到僅餘15個人為止。問怎樣排法,才能使每次...