百囚问题

国王招来100个囚犯,对他们说:你们犯的是死罪,本应该将你们统统杀掉,但我慈悲为怀,给你们一次求生的机会。15分钟以后,你们将被关进一个有100间隔离牢房的监狱里,每人一间牢房,都与外界隔绝,什么也听不见、看不到,连时间都没法计算,更别说获得外界的任何信息。(送饭除外,但也是不规律的送)

这所监狱有一个院子,每天会随机(注意是完全随机)打开一间牢房的门,让那个囚犯到院子里来放风。院子里有一盏路灯,放风的囚犯可以控制它的开关,将它打开或是关闭。除囚犯之外,其他人都不会去碰开关。这盏灯会永远有充足的能源供应,如果灯泡坏了或是电路出了故障会马上修好,当然修理人员不会改变灯的状态(开或关)。

除了开关这盏灯,放风的囚犯放风时留下的任何其它痕迹都会在夜晚被清除干净(包括在灯上作的任何记号)。

牢房是完全封闭的,院子里的灯光在牢房里看不到。只有放风出到院子里的人才能看到。

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

若干天以后,你们中只要有任何一个人能够向我证明所有的人都曾到院子里去过,你们就全体释放。当然要有证据!因为我只会给你们一次机会,如果向我证明的那个人无法自圆其说,你们就全部砍头。所以,要珍惜这次机会。如果你们永远做不到我的要求,你们就全部囚禁到死。

现在给你们15分钟商量你们的方案。15分钟以后,你们将被关进我刚才说的那个监狱,永远无法再交流。


请你帮助囚犯给出一个方案
|
|
|
|
|
|
|
|
|
|
|
|
|
|

看了下要求,毫无疑问要在灯上下功夫。
首先选定一个人甲计数,并制定以下规则:
1.甲:灯亮–>灭,如果灯是亮的,则甲将灯灭掉,其它状态保持。
2.其他人:灯灭–>亮,如果灯是灭的,则将灯亮,其它保持,执行且只执行1次。
但由于开始灯状态不定,做一下两种推理:
1.开始灯是灭的:
a.第一个人是其他人(当然,他并不知道他是第一个守夜人),守夜时看到灯是灭的,将灯调亮,若中间有其他人守夜,看到灯是亮的,保持不变,直到计数人甲守夜,将灯调灭,并计数。如此,当计数人甲计数到99时,所有人都已守夜。
b.第一个人是计数人,看到等灭保持不变,直到守夜人是其他人,接下来同1.a
2.开始灯是亮的:
a.若第一个人是其他人,保持不变(相当于开始灯灭将灯调亮,其实同1.a)
b.若第一个人是计数人,开始灯是亮的,甲将灯调灭并计数,这样多计数一次,接下来同1,这样当计数到99时,其实只有不包含自己的98个人守过夜。
**

以上不行。

**
考虑的2.b的情况,调整规则如下:
1.甲:灯亮–>灭,如果灯是亮的,则甲将灯灭掉,其它状态保持。
2.其他人:灯灭–>亮,如果灯是灭的,则将灯亮,其它保持,执行且只执行2次。
这样,对于上1.a、1.b、2.a的情况,计数到197次时就能保证所有人都守过夜(抽屉原理)。对于2.b,计数到198次时,就能保证所有人都守过夜(去掉多记了一次)。这样当计数到198次时,对于所有情况都可确定所有人都已守过夜。

/**
 * 灭-->亮:其他人(只执行2次,执行2次而不是1次是为了消除开始灯亮灭不定的影响)
 * 亮-->灭:计数人(执行并计数)
 * 1.定一人:开始灯灭可以,亮不行(那就2次)
 * @author Administrator
 *
 */
public class I00PrisonersProblems {

    //开始灯的亮灭随机
    public static boolean LIGHT_FLAG = Math.random() > 0.5 ? true : false;

    //囚犯人数
    public static final int PRISONERS_NUM = 100;

    public static void main(String[] args) {
        int[] prisoners = new int[PRISONERS_NUM];
        //计数人计数
        int count = 0;
        //天数
        int days = 0;
        while(count < (PRISONERS_NUM - 1) * 2){
            //随机守夜人
            int index = (int) (Math.random() * PRISONERS_NUM);
            //计数人守夜且灯亮
            if(index == 0 && LIGHT_FLAG){
                count ++;
                LIGHT_FLAG = false;
            }
            //其他人守夜、灯灭且计数小于2次
            if(index > 0 && !LIGHT_FLAG && prisoners[index] < 2){
                prisoners[index] ++;
                LIGHT_FLAG = true;
            }
            //天数
            days ++;
        }
        System.out.println("过了" + days/365 + "年" + days%365 + "天,100人都已守过夜。");
    }
}

算了10000次,平均大概要56年40天左右……
横竖是出不来了。万一说错当场就要死,还不如闭口不答。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值