密碼學課上老師介紹了這樣一個問題,囚徒問題(100 prisoners problem):一百個囚徒被關在牢房里,典獄長給他們最后一次機會,100人依次進入一個有100個抽屜的牢房,每個抽屜置亂放入1~100的號碼,每個人依次打開50個抽屜,如果每個人都能找到自己的號碼(0~100),則所有人被釋放,反之所有人都會被殺死。
典型的算法給出的被釋放概率幾乎為零,但是有這樣一種方法:第i號囚徒打開第i號抽屜,如果這個抽屜放的是自己的號碼牌,ok pass,如果不是,則打開該抽屜中號碼牌對應的抽屜,依次進行,直到找到自己的號碼牌或者失敗。
那么,這個方法的成功率有多少呢。使用python模擬的代碼如下:
import random
flag = 0 # 單次實驗是否成功flag
counter = 0 # 實驗成功次數counter
fcounter = 0 # 單個囚徒打開抽屜次數fcounter
N = 10000 # 設置試驗次數
A = list(range(100))
random.shuffle(A) # 抽屜置亂
for i in range(N):
flag = 1
# experiment begins
for j in range(100):
k = j
while(A[k] != j and fcounter < 50):
k = A[k]
fcounter += 1
if(fcounter >= 50):
flag = 0
fcounter = 0
break
fcounter = 0
if(flag == 1):
counter += 1
flag = 0
random.shuffle(A)
print('Success Rate: ' + str(counter/N))
最終的成功率是驚人的
Success Rate: 0.3117
這種方法的原理是什么呢,用置換的方法看,一次1~100置亂可以分解為若干個不相交的小循環。若所有小循環的階都小於50,則囚犯都可以找到自己的號牌。
囚徒遇到大於五十階循環的概率如左所示,則囚徒們成功的概率達到了驚人的0.3118
