找回密码
 欢迎注册
查看: 58146|回复: 13

[提问] 一个囚徒问题

[复制链接]
发表于 2009-6-18 13:57:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?欢迎注册

×
精华
有100个无期囚徒,被关在100个独立的小房间,互相无法通信。 每天会有一个囚徒被随机地抽出来放风,随机的意思说每个囚徒可能被抽到多次。 放风的地方有一盏灯,囚徒可以打开或者关上,除囚徒外,没有别人会去动这个灯。每个人除非出来防风,是看不到这个灯的。 一天,全体囚徒大会,国王大赦,给大家一个机会:如果某一天,某个囚徒能够明确表示,所有的囚徒都已经被放过风了,而且的确如此,那么所有囚徒释放;如果仍有囚徒未被放过风,那么所有的囚徒一起处死! 囚徒大会后给大家20分钟时间讨论,囚徒们能找到方法么?
我加一问:如果能找到方法,那么按你的方法,囚徒到被释放平均还需要做多长时间的牢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 15:02:56 | 显示全部楼层
我觉得是没办法的,只有一个灯,两个状态。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 20:18:18 | 显示全部楼层
是可以的。 取其中一个状态作为囚徒是否放风的标志,然后统计总数是否足够即可。 这样需要事先设定一个专员对标志状态复位并统计。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 20:41:27 | 显示全部楼层
具体为: 推选一个固定的囚犯,其任务是复位并计数。 其他人放风时,当灯是关闭状态且自己从未开灯时,就把灯点亮;否则不要碰灯; 而那个指定的囚犯,则是负责给大家关灯的,每关一次就累加一下, 如果灯初始状态是关的,当达到99次时,则表明全部囚犯均放过风。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 20:46:36 | 显示全部楼层
考虑到节能,以及灯的寿命, 最好是将状态颠倒一下:点灯仅由指定的人去完成;而由其他人则是去关灯。 此时要求灯初始状态是关闭的。计数满100则表明全部都放过风。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 20:51:29 | 显示全部楼层
一个新的问题: 假定每次放风有且仅一人(随机的),放风时长固定,中间无间断(或固定间隔时长), 那么:用 4# 或 5# 的方案,哪个更节能?节能多少?(假设灯是长命灯,且功率固定)
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 21:21:01 | 显示全部楼层
以前用计算机模拟过,最终是需要相当长的时间才能出来。
  1. /*
  2. 有100个无期徒刑囚徒,被关在100个独立的小房间,互相无法通信。
  3. 每天会有一个囚徒被随机地抽出来放风,随机就是说可能被抽到多次。
  4. 放风的地方有一盏灯,囚徒可以打开或者关上,除囚徒外,没有别人会去动这个灯。每
  5. 个人除非出来防风,是看不到这个灯的。
  6. 一天,全体囚徒大会,国王大赦,给大家一个机会:如果某一天,某个囚徒能够明确表
  7. 示,所有的囚徒都已经被放过风了,而且的确如此,那么所有囚徒释放;如果仍有囚徒
  8. 未被放过风,那么所有的囚徒一起处死!
  9. 囚徒大会后给大家20分钟时间讨论,帮囚徒们能找到方法。
  10. 答案:?
  11. 囚徒们这样商定好:凡是第一次出来放风的囚徒就把灯点燃,凡不止是第一次出来放风的囚徒出来放风,就把点燃的灯熄灭。
  12. 这样一来,当某一个囚徒第二次出来放风时,如果他发现灯是亮着的,
  13. 那么他就可以确定:前一天出来的那个囚徒一定是到目前为止第一次出来放风的。
  14. 这样下去,当这个囚徒第N次出来放风时,如果他第九十九次
  15. (注意:N≥99,表示他可能在某些次出来发现灯关掉了。)发现灯是亮着的,那么他就可以宣布:所有的囚徒均已经放过风。
  16. 答案:?
  17. 假设希望寄托在第一个人身上,他出去后看到灯是关着的,不管它
  18. 第二个出去的人把灯打开,后面出去的人看到灯是开的不要管
  19. 等第一个人有机会被抽到第二次出去,将灯关掉
  20. 此时下一个出去的人看到灯是关的,他如果没有开过灯,打开;开过,不要管
  21. ………………
  22. ………………
  23. 以此类推,也就是遵循以下原则:
  24. 1 只有第一个出去的人有权力关灯
  25. 2 每个人只有一次开灯机会
  26. 这样等第一个人第99次关灯时,就可以证明全部都放过风了
  27. */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <time.h>
  32. #define _PRINT_ 0
  33. const long MAX_JAILBIRD=100;
  34. typedef struct
  35. {
  36. long count; //放风次数
  37. long on; //发现灯为开的次数(对于第二方案是开灯次数)
  38. long off; //发现灯为关的次数(对于第二方案是关灯次数)
  39. bool first; //是否是第一个被叫出去防风
  40. } JAILBIRD; //囚徒类
  41. bool light; //灯的开关状态,1-开,0-关
  42. long days; //经过的天数
  43. JAILBIRD jb[MAX_JAILBIRD]; //100个囚徒
  44. bool ok; //所有的囚徒都已经被放过风了
  45. /*
  46. 初始化函数
  47. */
  48. void init(void)
  49. {
  50. light=0;
  51. days=0;
  52. ok=false;
  53. randomize();
  54. for(long i=0; i < MAX_JAILBIRD; i++)
  55. {
  56. jb[i].count=0;
  57. jb[i].on=0;
  58. jb[i].off=0;
  59. jb[i].first=false;
  60. }
  61. }
  62. /*
  63. 放风函数
  64. */
  65. void ff1(void)
  66. {
  67. long v;
  68. v=rand() % MAX_JAILBIRD; //随机抽一个囚徒
  69. days++;
  70. #if (_PRINT_)
  71. printf("第%ld天开始,囚徒%d已经放风%ld次,灯为开%ld次,灯为关%ld次,灯%d。\n",
  72. days,
  73. v,
  74. jb[v].count,
  75. jb[v].on,
  76. jb[v].off,
  77. light);
  78. #endif
  79. jb[v].count++;
  80. if(light) //如果灯是开的,计数
  81. {
  82. jb[v].on++;
  83. }
  84. else
  85. {
  86. jb[v].off++;
  87. }
  88. if(jb[v].on == 99) //第99次发现灯为开,结束
  89. {
  90. ok=true;
  91. }
  92. if(jb[v].count == 1) //如果是第一次出来放风
  93. {
  94. if(!light) //将关的灯打开
  95. {
  96. light=true;
  97. }
  98. }
  99. else //如果不是第一次出来放风
  100. {
  101. if(light) //将开的灯关上
  102. {
  103. light=false;
  104. }
  105. }
  106. #if (_PRINT_)
  107. printf("第%ld天结束,囚徒%d已经放风%ld次,灯为开%ld次,灯为关%ld次,灯%d\n",
  108. days,
  109. v,
  110. jb[v].count,
  111. jb[v].on,
  112. jb[v].off,
  113. light);
  114. #endif
  115. }
  116. /*
  117. 放风函数
  118. */
  119. void ff2(void)
  120. {
  121. long v;
  122. v=rand() % MAX_JAILBIRD; //随机抽一个囚徒
  123. days++;
  124. #if (_PRINT_)
  125. printf("第%ld天开始,囚徒%d已经放风%ld次,开灯%ld次,关灯%ld次,灯%d。\n",
  126. days,
  127. v,
  128. jb[v].count,
  129. jb[v].on,
  130. jb[v].off,
  131. light);
  132. #endif
  133. if(days == 1)
  134. {
  135. jb[v].first=true; //记下第一个出来放风的囚徒
  136. #if (_PRINT_)
  137. printf("第一个出来放风的囚徒是%d号\n", v);
  138. #endif
  139. }
  140. jb[v].count++;
  141. if(jb[v].first) //如果是第一个出来放风的囚徒
  142. {
  143. if(light) //如果灯是开的
  144. {
  145. light=false; //关灯
  146. jb[v].off++; //关灯次数计数
  147. #if (_PRINT_)
  148. printf("第一个出来放风的囚徒第%ld次关灯\n", jb[v].off);
  149. #endif
  150. }
  151. }
  152. else //如果不是第一个出来放风的囚徒
  153. {
  154. if(!light) //如果灯是关的
  155. {
  156. if(jb[v].on == 0) //如果他没有开过灯
  157. {
  158. light=true; //开灯
  159. jb[v].on++; //开灯次数计数
  160. }
  161. }
  162. }
  163. if(jb[v].first && jb[v].off == 99) //第一个放风的囚徒第99次关灯,结束
  164. {
  165. ok=true;
  166. }
  167. #if (_PRINT_)
  168. printf("第%ld天结束,囚徒%d已经放风%ld次,开灯%ld次,关灯%ld次,灯%d\n",
  169. days,
  170. v,
  171. jb[v].count,
  172. jb[v].on,
  173. jb[v].off,
  174. light);
  175. #endif
  176. }
  177. /* */
  178. int main(void)
  179. {
  180. init();
  181. while(!ok)
  182. {
  183. ff2();
  184. }
  185. printf("\n共%ld天,以下是每个囚徒出来放风的次数\n", days);
  186. for(long i=0; i < MAX_JAILBIRD; i++)
  187. {
  188. printf("%ld\t", jb[i].count);
  189. }
  190. printf("\n");
  191. return 0;
  192. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2009-6-18 21:31:59 | 显示全部楼层
7# 风云剑 这两种方案平均起来哪个更优?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-6-19 07:59:50 | 显示全部楼层
昨天想了想,这个问题还是比较有意思的,又查了查,下面是网上查的几种方法 [zt] 第一天出來的這個囚徒負責關燈,以後出來的囚徒: 1)當燈是關著的時候,如果他沒有開過燈,那他可以打開燈,否則他不能開燈; 2)當燈是開著的時候,他不動燈。 3)第一個囚徒在他放風的時候,如果發現燈是開的,那麼他就關閉燈。這時他就把放過風的囚徒數加一。 當第一個囚徒的計數達到99的時候(加上他自己是100),他就可以宣佈所有的囚徒都放過風啦,按平均計算100×99=9900天,就是27年呀! [zt] 第二個方法分兩個階段: 階段一:前100天決定誰來計數。 1)第1-99天,初始燈關著,第一個兩次放過風的人將成為計數者,並將燈關上。設其為第K天第2次放風,則他知道已經有k-1個人放過風,做為100天後計數的初始值。 2)第100天放風的人如果看見等關著,則宣佈所有人都放過風;否則把燈關上 階段二:100天後 1)如果計數者放風看見燈開著,則將放過風的人數加1,到100時宣佈勝利 2)其他人如果以前沒放過風,並且燈關著,則開燈,否則不動 此方法期望年數為24.42年 [zt] 第三種方法提示如下:分為一個基本記數者和N個2級記數者,基本記數者的獨立記數上限Cp和2級記數的獨立計數上限Cs,時間由長度為S1和S2的兩段交替組成.在S1階段,計數者計數直到達到其獨立計數上限,在S2階段,達到計數上限的2級計數者將通過開燈方法告訴基本計數者直到基本計數者得到所有2級計數者完成任務並加上自己計數為100時宣佈自由. 此方法通過計算機模擬優化可在10年左右完成.
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2009-6-19 08:08:21 | 显示全部楼层
上面几种方法都比较巧妙 第一种和4#一样,我们分析一下: 设系统还有x个没开过灯的囚徒,没开过灯的某个囚徒被防风的概率是 x/100 ,所以期望时间是 100/x,然后等统计者出来关灯计数,此期望时间是100,于是总的期望为 $\sum_(i=1)^99{100+100/i} =10418天=28.5年$
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-11-22 12:59 , Processed in 0.033881 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表