开始更新博客啦~   计划每周研究一道算法问题,并给出解决方案和代码实现(python),欢迎大家提出看法和意见,有更优的解决方案更是强烈欢迎。

这次的问题是几天前看到的一个算法问题,先是自己想了半天,找到一个解决方案,然后和朋友讨论并找到了一个更优解,网上没有搜到几条比较相关的解决方法,所以发出来和大家分享一下。

问题描述:

监狱中关着100名囚犯,每人在一个独立的房间里,且无法用任何方式相互通信;每天会有随机一人被选出来放风,放风的地方有一盏灯,囚犯可以打开或关闭它,其他没有任何人会去动这个灯,其他囚犯不知道是谁被选中放风,也无法看到灯。

某一天国王召集所有囚犯开了一个会,向他们说:如果某一天有人说所有的囚犯都已经放过风了,且情况属实,则所有人都会被释放,如果说错了则所有人都要被处死,然后给了囚犯20分钟讨论时间。

不考虑灯损坏或犯人意外死亡的理想情况下,他们能找出办法让所有人都被释放吗?

大家可以先尝试思考一下,题中很明确只能通过开关灯和灯的亮灭传递消息,所以不要走进死胡同想别的通信方式了,就是设计一个算法,能只通过灯就知道是否所有人都放过风了。

1、发出信息的方式就是开灯或关灯,获取信息的方式就是灯亮着或灭着;2、囚犯除了处理灯以外,还可以计数,比如遇到过多少次亮灭;3、必须要有人做统计,知道有多少人已经放过风了才能汇报。

这里是思路提示

#有个人我们假设是A,A说:“你们如果放风的时候看到灯亮着,就关掉它,但是每个人只关一次。然后我去打开它。”#这样的话,A每次见到灯灭着,就说明有放过风的人数增加了1个,然后他打开灯。当他开了99次灯之后,说明所有人都已经放过风了。#理论最短耗时为198天,即其他人不重复的依次放风,A隔一天放一次风计数一次。BACADAEA......

#那么实际需要多少天才能完成目标呢?我们用python模拟一下:

importrandom#先创建一个99人的囚犯字典,值为False,代表还没放过风(没关过灯)

prisonerDict = dict.fromkeys(range(99), False)#再添加计数君A进去,值为0,代表已知0个人放过风

prisonerDict['A'] =0#天数

day =0#初始灯是亮的

light =True#然后开始我们漫长的循环之旅吧~

whileTrue:#新的一天开始了,我们随机选了一位囚犯出来放风

day += 1user=random.choice(prisonerDict.keys())#如果是A,看到灯灭了,则打开灯,并在人数上累加1

if (user == 'A'):if notlight:

light=True

prisonerDict[user]+= 1

#当A发现其他99个人都放过风了,则汇报上去,跳出循环

if (prisonerDict[user] == 99):break

else:#其他囚犯如果发现灯亮着而且这个囚犯没关过灯,就关掉它,囚犯状态改为True

if (light and notprisonerDict[user]):

light=False

prisonerDict[user]=True#简单计算一下天数(年数)

print day/365

这里是基本解法

#如果大家觉得A这个人不靠谱,每个人都想当最后汇报结果的人呢?那么我们就选拔出一个人吧:第一个重复放风的人成为计数君#基本解里,即使是一群欧皇(人品帝)理想模式下仍需要198天才能出去,能不能缩短下呢?让所有人都出去过的第二天,计数君就能汇报结果#优化后方案如下,分为2个阶段:

#1、计数君选拔阶段(前101天):每个人第一次放风的时候不处理灯,当第二次出去的时候关掉灯;那么第一个关灯的人就是计数君A,最多需要101天#2、计数阶段(102-):所有人按照基本解里的操作来执行。

#优化后的方案好处是缩短了理想情况的时间,当所有人依次放一次风后,第101天放风的人发现灯还是亮的,知道前100天没有人重复,就可以汇报了,耗时101天;(其实第100个人判断这100天都没重复就可以汇报了)#代码模拟如下:

#!/usr/bin/python#-*- coding: -*-

importrandom#创建一个100人的囚犯字典,值为[0, 0, None],代表还没放过风(没关过灯)且未开始计数且没有身份,没有使用dict.fromkeys是由于它产生的字典,所有值指向了同一个内存,无法分别计算

prisonerDict ={}for i in range(100):

prisonerDict[i]=[0, 0, None]#天数

day =0#初始灯是亮的

light =True#仍然是开始我们漫长的循环之旅~

whileTrue:#新的一天开始了,我们随机选了一位囚犯出来放风

day += 1user=random.choice(prisonerDict.keys())#前101天我们先选一个计数君,每次自己放风次数+1,灯亮着并且自己第二次出来则关掉灯

if (day < 102):

prisonerDict[user][0]+= 1

if (light and prisonerDict[user][0] == 2):

light=False#此处为标识计数君,将放风次数始终为负数,为保证始终有效,将放风次数置为-102

prisonerDict[user][2] = 'count'

else:#101天之后,如果是计数君,看到灯亮了,则关掉灯,并在人数上累加1

if (prisonerDict[user][2] == 'count'):iflight:

light=False

prisonerDict[user][1] += 1

#当A发现其他99个人都放过风了,则汇报上去,跳出循环

if (prisonerDict[user][1] == 99):break

else:#其他囚犯如果发现灯灭着而且这个囚犯没开过灯,就打开它,囚犯状态改为True

if (not light and not prisonerDict[user][2]):

light=True

prisonerDict[user][2] =True#简单计算一下天数(年数)

print day/365

这里是优化解

经过多次执行模拟的代码,可以看出来耗时在30年上下波动,也比较符合上述算法经过数学计算的10000天左右

C语言100个囚徒和灯泡,经典算法问题其一:百日囚徒问题相关推荐

  1. C语言计算日期间隔天数的经典算法解析

    C语言计算日期间隔天数的经典算法解析 网上看到一个计算日期间隔的方法,很高深,很巧妙.代码如下: #include <stdio.h> #include <stdlib.h> ...

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

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

  3. C#经典算法实践,回顾往生,更是致敬《算法导论》

    该文章的最新版本已迁移至个人博客[比特飞],单击链接 C#经典算法实践,回顾往生,更是致敬<算法导论> | .Net中文网 访问. 概述 本系列博文将会向大家介绍本人在钻研<算法导论 ...

  4. c语言经典算法大全pdf,c语言经典算法100例pdf版.pdf

    c语言经典算法100例pdf版 C 语言经典算法 100 例 C 语言编程经典 100 例 A:[程序1] 题目:有1.2.3.4 个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程 ...

  5. C语言经典算法100道实战题

    [C语言经典算法100道实战题]适合具备C语言基础语法的同学学习,提高编写程序的逻辑思维能力和算法设计能力专门精心设计.100个经典的算法供大家练习及配套对应的录播视频.为我们今后学习其它的编程语言和 ...

  6. c语言100道经典例题详解

    ** c语言100道经典例题 ** [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 1.程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所 ...

  7. C语言经典算法 21-30

    目录 21 一个有序的数组插入一个数 22 将一个数组逆序输出 23 报号 求最后是谁 24 写一个统计字符串长度的函数 25 八进制转换为十进制 26 判断一个素数能被几个 9 整除 27 输入一组 ...

  8. C语言经典算法 11-20

    C语言经典算法 11-20 十一.求最大公约数和最小公倍数 十二.统计字符串数字,字母,符号的各个数量 十三.2+22+222+..... 十四.完数 十五.小球反弹问题 十六.猴子吃桃问题 十七.求 ...

  9. C语言经典算法 1-10

    目录 一.排列组合题 二.区间题 三.判断平方数相关 四.给你一个年月日判断是第几天 五.将3个数由小到大排序 六.九九乘法表 七.兔子繁殖数列 八.判断素数 九.水仙花数 十.因数分解 一.排列组合 ...

最新文章

  1. linux windows c system 函数简介
  2. python发送文件到钉钉群_iOS python 自动化打包,并在钉钉群里发通知
  3. 通过简单的线性回归理解机器学习的基本原理
  4. 线性代数学习资料汇编
  5. [转]你不需要jQuery
  6. 给Ubuntu 16.04更换更新源
  7. 数据结构(复习)--------关于平衡二叉树(转载)
  8. 面试八股文:你写过自定义任务调度器吗?
  9. c语言spi测试代码,spi_test.c的spi跟踪(spi 数据传送流程)
  10. 运行wpf_在WPF中一种较好的绑定Enums数据方法
  11. Kubernetes学习总结(18)—— Kubernetes 容器网络
  12. python-学生管理系统--8-排序功能模块
  13. mysql 前缀索引_MySQL前缀索引
  14. 土地利用转移矩阵图怎么做_如何用Arcgis做土地利用转移矩阵?求教各位..._土地估价师_帮考网...
  15. Selenium初级 | 使用navigate系列方法操作网页
  16. 在不知道密码情况下卸载企业版360
  17. 为Python程序添加桌面快捷方式
  18. 克鲁斯卡尔算法_修路问题
  19. 前京东AI掌门人周伯文入局ChatGPT,亲手创立的衔远科技获天使轮融资数亿元!
  20. 以排印为本,从内容出发

热门文章

  1. php获取附近的商家
  2. windows命令行关闭已占用的端口
  3. android仿小米指南针
  4. 输出图案-平行四边形
  5. Please specify a program using absolute path or make sure the program is available in your PATH syst
  6. 电脑突然经常死机?(ubuntu系统如何检查原因)
  7. Unity 基础常用的脚本(一)
  8. win10自带远程桌面连接linux系统时崩溃的问题
  9. android手机blhx素材提取
  10. 15/18位身份证号码验证的正则表达式总结(详细版)