密碼學課上老師介紹了這樣一個問題,囚徒問題(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