The Locker Puzzle
今天刷到一个很有趣的著名概率题,如果有和我一样闲的人可以一起看看。
Philippe Flajolet和Robert Sedgewick在2009年提出了“百囚犯问题(The Locker Puzzle)”。
问题描述
在监狱中有100名囚犯,被编号为1-100号。典狱长决定给囚犯们一次特赦的机会,条件是通过一项挑战。在一个房间中放着一个有100个抽屉的橱柜,里面随机放着与囚犯编号对应的1-100的号码牌。挑战开始后,每个囚犯依次进入该房间,打开不超过半数的抽屉,并从中找到与自己对应的号码则为成功,每名囚犯出去时该橱柜恢复原样。从第一名囚犯进入直至最后一名囚犯出来期间不允许有任何交流,任何一名囚犯挑战失败都会导致所有囚犯死亡,只有全部成功才能够特赦该100名囚犯。如果囚犯们都随机打开50个抽屉,他们的生存几率为1/(2^100,约等于0.0000000000000000000000000000008。所以囚犯们需要找到一个最佳策略,来提高生存率。
变态的思路
1.先打开自己的号码的抽屉。
2.如果这个抽屉里有他的号码,他就成功了。
3.否则,抽屉里会有另一个号码,然后他打开这个号码的抽屉。
4.不断重复第2步和第3步,直到他找到自己的号码或已经打开了50个抽屉(那就全体失败了)。
证明
太长了,懒得抄,自己看论文吧。
https://www.cl.cam.ac.uk/~gw104/Locker_Puzzle.pdf
好吧,其实这个论文我看不懂,上抖音学下证明吧。
Last
最后是C++的小模拟(百万次测试),rt;可见,结果基本就是标准计算概率:0.3118了。
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int box[N];
int pep[N];
int vb[N],vp[N];
const int n=100;
int suc;
const int tot=1e6;
int main(){srand(time(0));for(int i=1;i<=tot;i++){memset(vb,0,sizeof vb);memset(vp,0,sizeof vp);for(int i=1;i<=n;i++){int x=rand()%n+1;while(vb[x]){x=rand()%n+1;}vb[x]=1;box[i]=x;}for(int i=1;i<=n;i++){int x=rand()%n+1;while(vp[x]){x=rand()%n+1;}vp[x]=1;pep[i]=x;}int fin=0;for(int i=1;i<=n;i++){int x=pep[i];int k=50;while(k--){if(box[x]==pep[i]){fin++;break;}x=box[x];}}printf("Test %d : The number of the successful people: %d\n",i,fin); if(fin==n) suc++;}cout<<"------------------"<<endl;cout<<"The number of ALL_PEOPLE_OUT:"<<" "<<suc<<endl<<endl;double ans=suc*1.0/tot;printf("The odds is %0.8lf",ans*100);cout<<"%"<<endl;return 0;
}