前几天在网上看到了一个有趣的问题,就是 国王和100个囚犯 的问题。第一次看到这个问题时,当时也懵了,这是什么鬼?你确定你题出的木有问题?当时就是这感觉…

但仔细思索后还是想到了解决方法,让我们一起来看看这个有趣的问题吧。

题目如下:

国王招来100个囚犯,对他们说:你们犯的是死罪,但我给你们一次求生的机会。15分钟以后,你们将被关进一个有100间隔离牢房的监狱里,每人一间牢房,都与外界隔绝,什么也听不见看不到,连时间都没法计算,无法获得外界的任何信息。

这所监狱有一个院子,每天只少随机(注意是完全随机)打开一间牢房的门,让一个囚犯到院子里来放风。院子里有一盏灯,放风的囚犯可以控制它的开关,将它打开或是关闭。除囚犯之外,其他人都不会去碰开关。这盏灯会永远有充足的能源供应,灯泡和电路不会出故障。
  

除了开关这盏灯,放风的囚犯放风时留下的任何其它痕迹都会在夜晚被清除干净(包括在灯上作的任何记号)。牢房是完全封闭的,院子里的灯光在牢房里看不到。只有放风到院子里的人才能看到。

国王:好了现在我向你们提出一个要求,只要你们做到了,就可以全部获得释放:

给你们15分钟商量你们的方案。15分钟以后,你们将被关进我刚才说的那个监狱,永远无法再交流,被关若干天后,你们中间如果任何一个人能够向我证明你们每个人都至少放风了一次,我就把你们放了,不然永远别想再出来。

如果你们有谁现在可以告诉我这个方法,也就是能够证明你们每人至少放风一次的方法,我就放掉你们!

其中一个囚犯想了几分钟,回答了这个问题,国王听后,如自己所说的把他们全部给放了。请问那个囚犯是用什么方法证明的?

大致的解题思路(建议思考后再看):

还赶紧用你的2.4G赫兹的4核CPU大脑思考下,该如何解决?

100个囚犯商量选出一个囚犯作为计数员(PrisonerCounter),**普通囚犯(Prisoner)**每次出去,如果自己没有打开过灯,并且灯是灭的,则打开灯;其它情况均不操作。计数员每次出去,如果灯是亮的就自己计数一次,并把灯关掉,其它情况什么也不干。一直到计数员计数到100,则全部囚犯都出去过至少打过一次灯。

再来细化化下每个角色的职责:

  • 计数员: 如果灯亮,计数一次,并关灯。如果灯灭,啥事不干。
  • 普通囚犯:如果自己没有开关灯,并且现在灯灭,就打开灯;如果自己以前开过灯或现在灯亮,则什么也不做。
  • 灯:能开、能关

看到这里,你应该有一种虎躯一震的感觉,还有这骚操作…

来看看代码具体怎么实现的吧

对象:阿拉丁神灯(这个灯好像不太神,只能开与关,但却掌握着100人的生与死)

    /*** 阿拉丁神灯* @Author: danding* @Date: 2019/8/30*/public class Light {//灯的状态(true-开,false-关)private Boolean state;public Light() {this.state = false;//默认为关}public Boolean getState() {return state;}public void setState(Boolean state) {this.state = state;}}

对象:普通囚犯

/*** 囚犯* @Author: danding* @Date: 2019/8/30*/
public class Prisoner {//囚犯编号private int id;//是否打开过灯private Boolean isOpenLight = false;//院子里的灯protected Light light;public Prisoner(int id) {this.id = id;}/*** 放风时要干的事件* @return 普通囚犯返回值无意义*/public boolean doSomeThing(){if(light==null){return false;}//如果这个囚犯放风时,打开过灯,则这次出去什么也不做if(isOpenLight==true){System.out.println(String.format("囚犯编号:%d,大爷的,怎么又是我,我已经开过灯了....",id));return false;}//如果出去发现灯的亮的,则什么也不做if(light.getState()==true){System.out.println(String.format("囚犯编号:%d,大爷的,第一次出来,灯竟然被占用了...",id));return false;}//如果这个囚犯被放风还没有开过灯:if(light.getState()==false){//如果出去发现灯的灭的,他就打开灯System.out.println(String.format("囚犯编号:%d,我终于出来放风了,还是第一次呢,有点小鸡冻(激动)呢!!!",id));light.setState(true);this.isOpenLight = true;}return false;}/*** 赋予或移除灯* @param light*/public void setLight(Light light) {this.light = light;}
}

对象:囚犯计数员(比普通囚犯多一个计数功能)

/*** 囚犯计数人* @Author: danding* @Date: 2019/8/30*/
public class PrisonerCounter extends Prisoner{//已开灯的人数(自己不计算在内)private int prison_out_count = 1;public PrisonerCounter(int id) {super(id);}/*** 囚犯计数者每次放风:* 如果灯亮,则计数一次,并把灯关了* 如果灯灭,不作任何操作* @return true-全部人都打开过灯一次,false-还有其它人没有开过灯*/public boolean doSomeThing(){if(super.light==null){return false;}if(super.light.getState()==false){return false;}this.prison_out_count++;System.out.println(String.format("当前第%d个囚犯打开了灯",this.prison_out_count));if(this.prison_out_count>=100){return true;}super.light.setState(false);return false;}
}

对象:上帝(主宰一切,什么都是我说了算)

import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;/*** 上帝,掌握着一切* @Author: danding* @Date: 2019/8/30*/
public class God {public static void main(String[] args){//所有囚犯集合List<Prisoner> prisonerList = new ArrayList<>();//初始化1个计数者Prisoner prisoner = new PrisonerCounter(0);prisonerList.add(prisoner);//初始化99个囚犯for(int i=1;i<100;i++){prisoner = new Prisoner(i);prisonerList.add(prisoner);}//初始化一个院子里的灯Light light = new Light();Random random = new Random();int day = 0;boolean isOver;do{day++;//计天数//每天随机抽一个囚犯int index = random.nextInt(prisonerList.size());prisoner = prisonerList.get(index);//出去放风,这个时候这个囚犯拥有控制灯的权限prisoner.setLight(light);//干约定好的事件isOver = prisoner.doSomeThing();//回老方,没收控制灯的权限prisoner.setLight(null);}while(!isOver);System.out.println(String.format("经历了%d天,所有囚犯都出去开过至少一次灯",day));}
}

代码完了,让我们一起来看看这100个囚犯大概多久能出来吧

...
...省略部分
...
囚犯编号:88,我终于出来放风了,还是第一次呢,有点小鸡冻(激动)呢!!!
囚犯编号:72,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:50,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:86,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:53,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:48,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:23,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:4,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:17,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:35,大爷的,怎么又是我,我已经开过灯了....
囚犯编号:99,大爷的,怎么又是我,我已经开过灯了....
当前第100个囚犯打开了灯
经历了10483天,所有囚犯都出去开过至少一次灯


什么?这不得等上将近30年…随间歇菜…
想来也对,因为每天放风的囚犯都是随机的,至于多少天能出来,完全看运气了。
以上运行结果并没有什么参考意义,因为你每次运行的结果都不一样,并且差别应该也不小。

运气绝对好,至少需要多少天?

作为高逼格的蜗牛哥绝不能就达此结束了,我们得想想他们运气绝对好,每次都能中彩票一等奖,这种情况下,他们最快多少天能出来呢?

给你5分钟思考时间

如果运气绝对好,那么他们的出场顺序应该是这样的:

第01天:囚犯01号
第02天:囚犯计数员
第03天:囚犯02号
第04天:囚犯计数员
第05天:囚犯03号
第06天:囚犯计数员
......
第195天:囚犯98号
第196天:囚犯计数员
第197天:囚犯99号
第198天:囚犯计数员

也就是说他们运气绝对好,至少需要198天就可以全部出狱了,这个结果还是让人满意的,也就大半年时间。

到这里就该真的结束了,希望通过这个趣味小实验,能让你从中学到些什么,哪怕有一丁点的帮助,小蜗牛在此也欣慰了。


关注公众号:「Java 知己」,每天更新Java知识哦,期待你的到来!

  • 发送「1024」,免费领取 30 本经典编程书籍。
  • 发送「Group」,与 10 万程序员一起进步。
  • 发送「JavaEE 实战」,领取《JavaEE 实战》系列视频教程。
  • 发送「玩转算法」,领取《玩转算法》系列视频教程。

趣味算法:国王和100个囚犯相关推荐

  1. 国王和100个囚犯还有1盏灯

    版权归作者所有.任何形式转载须联系作者获得授权. 作者:好难搜 来源:正解网 链接:https://www.zhengjie.com/question/0E582F52 国王招来100个囚犯,对他们说 ...

  2. 100个囚犯和灯泡C语言,关于国王和100个囚犯

    大概在去年,朋友问过过我这个问题. 方案比较简单: 首先,第一天出来的人,担当"计数者",它把灯开起来(原来开着就不必动了) 然后每天出来一个囚犯. 如果他不是"计数者& ...

  3. 100个囚犯的脱狱问题

    问题: 话说有一国王找到100个囚犯,每个人都剃了光头.     国王对他们说:一会儿有人会在你们头上写上1-100之间的随机数.你们只要有一个人能说对大家头上所有数字的和,就都放了.否则统统赠送给芙 ...

  4. 19【C趣味算法 却是用Python解决】国王的失算(数量级太大Dev-C++中无法得出结果),考虑用Python实现

    这道题是一个较为简单的问题(但是还是挺经典的哈!),因此若是不感兴趣的朋友可以忽略哦~ Contents 一.Review 二.New Problem 2.1 Description of the p ...

  5. 趣味c语言编程100例(一)

    Technorati 标签: 趣味,c语言,编程,100例 经典c程序100例==1--10 [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分 ...

  6. C语言100个囚犯和灯泡,一百个囚犯和一个灯泡

     这是一个策略设计博弈谜题.说的是"囚犯与灯泡"的问题. 有100个囚犯分别关在100间牢房里.牢房外有一个空荡荡的房间,房间里有一个灯泡,以及控制这个灯泡的开关.初始时,灯是关 ...

  7. python迭代法求解方程_第一部分:趣味算法入门;第六题牛顿迭代法求一元三次方程的根...

    100个不同类型的python语言趣味编程题 在求解的过程中培养编程兴趣,拓展编程思维,提高编程能力. 第一部分:趣味算法入门:第六题SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键 ...

  8. python计算存款_第一部分:趣味算法入门;第七题:最佳存款方案

    这里将告诉您第一部分:趣味算法入门:第七题:最佳存款方案,具体完成步骤:100个不同类型的python语言趣味编程题 在求解的过程中培养编程兴趣,拓展编程思维,提高编程能力. 第一部分:趣味算法入门: ...

  9. 三天打鱼两天晒网python_趣味算法入门;第三题:三天打鱼两天晒网

    100个不同类型的python语言趣味编程题 在求解的过程中培养编程兴趣,拓展编程思维,提高编程能力. 第一部分:趣味算法入门:第三题 ''' 3.三天打鱼两天晒网:某人从1990年1月1日起开始'三 ...

最新文章

  1. mysql5.7与8.0用那个_MySQL 5.7 vs 8.0,哪个性能更牛?
  2. Conan and Agasa play a Card Game
  3. java线程的内存模型_java多线程内存模型
  4. Android实现退出提示的功能
  5. 一段时间以来的SEO优化结果
  6. 未来的地下世界?《明日之后》打造专属半感染者的“未来都市”
  7. SAP UI5 new sap.ui.commons.Button trigger component load
  8. ensp静态路由的配置及分析
  9. Node Express4.x 片段视图 partials
  10. redis 学习笔记(1)-编译、启动、停止
  11. python shell运行当前程序、可以按下_Python下调用Linux的Shell命令的方法
  12. 连数据都读不懂,你凭什么说会数据分析?
  13. 【报告分享】中国数据智能应用趋势报告:解码数据中台最佳实践,企业数字化转型新引擎.pdf(附下载链接)...
  14. ue4渲染速度太慢_推介飞向月球纪录片基于Unreal实时渲染引擎的三维流程化制作...
  15. HTML5 Canvas渐进填充与透明(摘自 http://blog.csdn.net/jia20003/article/details/9251893)
  16. 基于EEG信号的文献记录01(0719)-特征选择和分类算法在基于脑电信号的睡眠阶段分类中的比较研究
  17. 机器学习系列(16)_怎样找到一份深度学习的工作(附学习材料,资源与建议)
  18. php捉迷藏,查看“蘑菇捉迷藏!”的源代码
  19. manjaro安装搜狗拼音输入法
  20. C++ RALL机制浅谈

热门文章

  1. React学习笔记(八)--- HooK
  2. 【Linux共享内存】
  3. 来自灵魂的拷问——知道什么是SQL执行计划吗?
  4. 深入理解散列函数和散列表
  5. b站网页版没有html播放,网页b站能小窗口播放吗?怎么播放?最新版本bilibili小窗口播放器...
  6. lsm mysql_一文了解数据库索引:哈希、B-Tree 与 LSM
  7. Graylog之Grok解析
  8. 电压有效值电容和电感的电压电流相位关系以及电抗和容抗值推导
  9. Riemann积分和Lebesgue积分角度下一积分不等式的等号成立充要条件的研究
  10. 同步以太网-SyncE介绍