當前位置: 華文星空 > 心靈

圓桌上 100 個人輪流開槍,最可能活下來的是幾號?

2024-12-30心靈

省流版本:在100000次的模擬中,100,78,95名列前三;分別存活了1097,1093,1089次,最大存活率在1.1%左右;27,18和12最危險,都只存活了868,903和909次。

如下圖所示,其中藍色線段為100000次的模擬數據,黃色線段為 @張雄騏 大佬的解析解的結果,我們可以看出二者是十分吻合的 [1] 。解析解指出1號將具有最大的生存率,實際上如果我們把1號視作最後接受槍擊的101號的話,我們也能自然地看出『 序號越大後生存機率越大 』的特點。


經典的約瑟夫問題的變形,引入了左輪賭局這個隨機變量。我們這裏假設每次開槍意味著有六分之一的機率死亡,那麽我們就可以先模擬一下。

首先,我們先生成一個標準的 迴圈連結串列

class Node(object): def __init__(self, value): self.value = value self.next = None def create_linkList(n): head = Node(1) pre = head for i in range(2, n+1): newNode = Node(i) pre.next= newNode pre = newNode pre.next = head return head

如果開槍成功,我們就將當前Node從 迴圈連結串列 中移出,直到整個迴圈連結串列中只剩下一個Node時遊戲結束。

def test(): head = create_linkList(100) pre = None cur = head while cur.next != cur: pre = cur cur = cur.next # 引入判定條件 if randint(1,6) == 1: pre.next = cur.next cur.next = None cur = pre.next return cur.value

之後我們再模擬10000次,再排序就出現結果了。

然後是上述模擬程式的可能的誤差來源。

首先是用於生成隨機數 randint 函式,此函式的隨機性由Mersenne Twister演算法保證,理論上的隨機數周期為 2^{19937}-1 ,以目前的迴圈次數來看,還是 不需要考慮因隨機數迴圈導致的取樣偏差的

評論區中給出了另外一種理解題意的方式,即『 若槍未發射,則繼續傳遞,所以下一發射出的機率應該增加 』。從個人角度來說,我認為這兩種情況在統計結果上應該是等價的。就類似與開獎先後的順序實際上不會影響獲獎機率的。


update

上述解法給出的是『每位都有六分之一的機率死亡』的模擬,這一點和題目中所謂的『傳遞手槍』的說明並不完全相同。以下給出『 傳遞手槍 』的解法:

def test_same_gun(n): head = create_linkList(n) pre = None cur = head bullet_pos = randint(1,6) while cur.next != cur: # 傳遞手槍 for _ in range(bullet_pos): pre = cur cur = cur.next bullet_pos = randint(1,6) pre.next = cur.next cur.next = None cur = pre.next return cur.value

可以料想,『傳遞手槍』實際上相當於給所有人分組了,比如2-7號,其中必定至少會有一人被射擊。

參考

  1. ^https://www.zhihu.com/question/8225556361/answer/67650588974