- 注册时间
- 2007-12-26
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 12449
- 在线时间
- 小时
|
发表于 2009-6-18 21:21:01
|
显示全部楼层
以前用计算机模拟过,最终是需要相当长的时间才能出来。-
- /*
- 有100个无期徒刑囚徒,被关在100个独立的小房间,互相无法通信。
- 每天会有一个囚徒被随机地抽出来放风,随机就是说可能被抽到多次。
- 放风的地方有一盏灯,囚徒可以打开或者关上,除囚徒外,没有别人会去动这个灯。每
- 个人除非出来防风,是看不到这个灯的。
-
- 一天,全体囚徒大会,国王大赦,给大家一个机会:如果某一天,某个囚徒能够明确表
- 示,所有的囚徒都已经被放过风了,而且的确如此,那么所有囚徒释放;如果仍有囚徒
- 未被放过风,那么所有的囚徒一起处死!
-
- 囚徒大会后给大家20分钟时间讨论,帮囚徒们能找到方法。
-
- 答案:?
- 囚徒们这样商定好:凡是第一次出来放风的囚徒就把灯点燃,凡不止是第一次出来放风的囚徒出来放风,就把点燃的灯熄灭。
- 这样一来,当某一个囚徒第二次出来放风时,如果他发现灯是亮着的,
- 那么他就可以确定:前一天出来的那个囚徒一定是到目前为止第一次出来放风的。
- 这样下去,当这个囚徒第N次出来放风时,如果他第九十九次
- (注意:N≥99,表示他可能在某些次出来发现灯关掉了。)发现灯是亮着的,那么他就可以宣布:所有的囚徒均已经放过风。
-
- 答案:?
- 假设希望寄托在第一个人身上,他出去后看到灯是关着的,不管它
- 第二个出去的人把灯打开,后面出去的人看到灯是开的不要管
- 等第一个人有机会被抽到第二次出去,将灯关掉
- 此时下一个出去的人看到灯是关的,他如果没有开过灯,打开;开过,不要管
- ………………
- ………………
- 以此类推,也就是遵循以下原则:
- 1 只有第一个出去的人有权力关灯
- 2 每个人只有一次开灯机会
-
- 这样等第一个人第99次关灯时,就可以证明全部都放过风了
-
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
-
- #define _PRINT_ 0
-
- const long MAX_JAILBIRD=100;
-
- typedef struct
- {
- long count; //放风次数
- long on; //发现灯为开的次数(对于第二方案是开灯次数)
- long off; //发现灯为关的次数(对于第二方案是关灯次数)
- bool first; //是否是第一个被叫出去防风
- } JAILBIRD; //囚徒类
- bool light; //灯的开关状态,1-开,0-关
- long days; //经过的天数
- JAILBIRD jb[MAX_JAILBIRD]; //100个囚徒
- bool ok; //所有的囚徒都已经被放过风了
-
- /*
- 初始化函数
- */
- void init(void)
- {
- light=0;
- days=0;
- ok=false;
- randomize();
- for(long i=0; i < MAX_JAILBIRD; i++)
- {
- jb[i].count=0;
- jb[i].on=0;
- jb[i].off=0;
- jb[i].first=false;
- }
- }
-
- /*
- 放风函数
- */
- void ff1(void)
- {
- long v;
- v=rand() % MAX_JAILBIRD; //随机抽一个囚徒
- days++;
- #if (_PRINT_)
- printf("第%ld天开始,囚徒%d已经放风%ld次,灯为开%ld次,灯为关%ld次,灯%d。\n",
- days,
- v,
- jb[v].count,
- jb[v].on,
- jb[v].off,
- light);
- #endif
- jb[v].count++;
- if(light) //如果灯是开的,计数
- {
- jb[v].on++;
- }
- else
- {
- jb[v].off++;
- }
-
- if(jb[v].on == 99) //第99次发现灯为开,结束
- {
- ok=true;
- }
-
- if(jb[v].count == 1) //如果是第一次出来放风
- {
- if(!light) //将关的灯打开
- {
- light=true;
- }
- }
- else //如果不是第一次出来放风
- {
- if(light) //将开的灯关上
- {
- light=false;
- }
- }
-
- #if (_PRINT_)
- printf("第%ld天结束,囚徒%d已经放风%ld次,灯为开%ld次,灯为关%ld次,灯%d\n",
- days,
- v,
- jb[v].count,
- jb[v].on,
- jb[v].off,
- light);
- #endif
- }
-
- /*
- 放风函数
- */
- void ff2(void)
- {
- long v;
- v=rand() % MAX_JAILBIRD; //随机抽一个囚徒
- days++;
- #if (_PRINT_)
- printf("第%ld天开始,囚徒%d已经放风%ld次,开灯%ld次,关灯%ld次,灯%d。\n",
- days,
- v,
- jb[v].count,
- jb[v].on,
- jb[v].off,
- light);
- #endif
- if(days == 1)
- {
- jb[v].first=true; //记下第一个出来放风的囚徒
- #if (_PRINT_)
- printf("第一个出来放风的囚徒是%d号\n", v);
- #endif
- }
-
- jb[v].count++;
- if(jb[v].first) //如果是第一个出来放风的囚徒
- {
- if(light) //如果灯是开的
- {
- light=false; //关灯
- jb[v].off++; //关灯次数计数
- #if (_PRINT_)
- printf("第一个出来放风的囚徒第%ld次关灯\n", jb[v].off);
- #endif
- }
- }
- else //如果不是第一个出来放风的囚徒
- {
- if(!light) //如果灯是关的
- {
- if(jb[v].on == 0) //如果他没有开过灯
- {
- light=true; //开灯
- jb[v].on++; //开灯次数计数
- }
- }
- }
-
- if(jb[v].first && jb[v].off == 99) //第一个放风的囚徒第99次关灯,结束
- {
- ok=true;
- }
-
- #if (_PRINT_)
- printf("第%ld天结束,囚徒%d已经放风%ld次,开灯%ld次,关灯%ld次,灯%d\n",
- days,
- v,
- jb[v].count,
- jb[v].on,
- jb[v].off,
- light);
- #endif
- }
-
- /* */
- int main(void)
- {
- init();
- while(!ok)
- {
- ff2();
- }
-
- printf("\n共%ld天,以下是每个囚徒出来放风的次数\n", days);
- for(long i=0; i < MAX_JAILBIRD; i++)
- {
- printf("%ld\t", jb[i].count);
- }
-
- printf("\n");
-
- return 0;
- }
复制代码 |
|