據說著名猶太歷史學家 josephus有過以下的故事:在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了乙個自殺方式,41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下乙個重新報數,直到所有人都自殺身亡為止。
然而josephus 和他的朋友並不想遵從。首先從乙個人開始,越過k-2個人(因為第乙個人已經被越過),並殺掉第k個人。接著,再越過k-1個人,並殺掉第k個人。這個過程沿著圓圈一直進行,直到最終只剩下乙個人留下,這個人就可以繼續活著。
問題是,給定了和,一開始要站在什麼地方才能避免被處決?josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。
稍微改一下書中的題意,只求最後活下來的人
鍊錶節點
class
node()
:def
__init__
(self, val)
: self.val = val
self.
next
=none
問題求解
def
josephus
(head, m)
:if head is
none
or head.
next
== head or m <0:
return head
prev, cur =
none
, head
x =0while cur != prev:
if x == m-1:
prev.
next
= cur.
next
x =0else
: x +=
1next
= cur.
next
prev = cur
cur = cur.
next
return cur.val
測試
def
make_cycle_list
(l):
head, tail =
none
,none
for x in l:
node = node(x)
if tail is
none
: head = node
else
: tail.
next
= node
tail = node
tail.
next
= head
return head
deftest_josephus
(n, m)
: l =
for i in
range
(n):
head = make_cycle_list(l)
x = josephus(head, m)
print
(x)
遞迴求解:
n個人(編號[0, n-1]),從0開始迴圈報數,報到m-1被殺,直到剩下乙個,求最終剩下誰
假如n = 1,則肯定剩下編號為0的人即
f(1, m) = 0
n個人,從0報到m-1,
例如,n=6, m= 4, 6個人,報數到3,則第一次被殺的是3 = m-1 = (m-1) % n
序號:0, 1, 2, 3, 4, 5
報數:0, 1, 2, 3
n = 6, m = 9, 6個人,報數到8,第一次被殺的是 2 = (m-1) % n
序號:0, 1, 2, 3, 4, 5
報數:0, 1, 2, 3, 4, 5
報數:6, 7, 8
所以,無論m < n還是m >= n,第一次被殺的都可以表示為k = (m-1) % n
第二輪,還剩下n-1個人,從4開始報數,
序號:0, 1, 2, 3 ,4, 5
報數:0, 1, 2, 3,0, 1
報數:2, 3
而假設原始問題就是n=5, m= 4
序號:0, 1, 2, 3, 4
報數:0, 1, 2, 3
序號對應關係:
4, 5, 0, 1, 2
0, 1, 2, 3, 4
4 = 0+4
5 = 1+4
0 = (2+4) % 6
1 = (3+4) % 6
2 = (4+4) % 6
4,5後面%6 依然成立。
因此 f(4, 4) = (f(5, 4) + m) % n,
這樣我們把問題縮小到乙個更加簡單的問題,
類似地:
f(n, m) = (f(n-1, m) + m) % n
def
get_josephus_live
(n, m)
:if n ==1:
return
0return
(get_josephus_live(n-
1, m)
+ m)
% n
測試:
def
test_josephus2
(n, m)
: x = get_josephus_live(n, m)
;print
(x)if __name__ ==
'__main__'
:print
('5, 6'
) test_josephus(5,
6)test_josephus2(5,
6)print
('------------------------------'
)print
('6, 3'
) test_josephus(6,
3)test_josephus2(6,
3)print
('------------------------------'
)print
('16, 5'
) test_josephus(16,
5)test_josephus2(16,
5)print
('------------------------------'
)print
('6, 15'
) test_josephus(6,
15)test_josephus2(6,
15)print
('------------------------------'
)print
('500, 123'
) test_josephus(
500,
123)
test_josephus2(
500,
123)
print
('------------------------------'
)print
('500, 1234'
) test_josephus(
500,
1234
) test_josephus2(
500,
1234
)print
('------------------------------'
)
➜ 6_josephus python josephus.py5,
633-
----
----
----
----
----
----
----
-6,3
00--
----
----
----
----
----
----
----
16,55
5---
----
----
----
----
----
----
---6
,1533
----
----
----
----
----
----
----
--500,
1237575-
----
----
----
----
----
----
----
-500
,1234
477477--
----
----
----
----
----
----
----
環形單鏈表約瑟夫問題
乙個環形單鏈表,從頭結點開始向後,指標每移動乙個結點,就計數加1,當數到第m個節點時,就把該結點刪除,然後繼續從下乙個節點開始從1計數,迴圈往復,直到環形單鏈表中只剩下了乙個結點,返回該結點。思路 當鍊表為空或者鍊錶只有乙個節點或者m 1時,不做處理,直接返回原鍊錶即可。if head null h...
環形單鏈表的約瑟夫問題
輸入 乙個環形單鏈表的頭結點head和報數的值m。返回 最後生存下來的節點,且這個節點自己組成環形單向鍊錶,其他節點都刪掉。高階 如果鍊錶節點數為n,想在時間複雜度o n 時完成原問題的要求,該如何實現?public class josephuskill1 public node josephusk...
環形單鏈表的約瑟夫問題
題目 約瑟夫環 約瑟夫問題 是乙個數學的應用問題 已知n個人 以編號1,2,3 n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌只剩乙個人。解題思路 1 如果鍊錶為空,或者鍊錶節點數為1,retu...