首页 > 代码库 > 老鼠试毒 两轮试验

老鼠试毒 两轮试验

大家应该都听说过这个老题目:有 1000 个一模一样的瓶子,其中有 999 瓶是普通的水,有一瓶是毒药。任何喝下毒药的生物都会在一星期之后死亡。现在,你只有 10 只小白鼠和一星期的时间,如何检验出哪个瓶子里有毒药?

  这个问题的答案也堪称经典:把瓶子从 0 到 999 依次编号,然后全部转换为 10 位二进制数。让第一只老鼠喝掉1到1000所有二进制数右起第一位是 1 的瓶子,让第二只老鼠喝掉所有二进制数右起第二位是 1 的瓶子,等等。一星期后,如果第一只老鼠死了,就知道毒药瓶子的二进制编号中,右起第一位是 1 ;如果第二只老鼠没死,就知道毒药瓶子的二进制编号中,右起第二位是 0 ……每只老鼠的死活都能确定出 10 位二进制数的其中一位,由此便可知道毒药瓶子的编号了。
现在,有意思的问题来了:
1、如果你有两个星期的时间(换句话说你可以做两轮实验),为了从 1000 个瓶子中找出毒药,你最少需要几只老鼠?注意,在第一轮实验中死掉的老鼠,就无法继续参与第二次实验了。

答案:7 只老鼠就足够了。事实上,7 只老鼠足以从 3^7 = 2187 个瓶子中找出毒药来。首先,把所有瓶子从 0 到 2186 编号,然后全部转换为 7 位三进制数。现在,让第一只老鼠喝掉所有三进制数右起第一位是 2 的瓶子,让第二只老鼠喝掉所有三进制数右起第二位是 2 的瓶子,等等。一星期之后,如果第一只老鼠死了,就知道毒药瓶子的三进制编号中,右起第一位是 2 ;如果第二只老鼠没死,就知道毒药瓶子的三进制编号中,右起第二位不是 2,只可能是 0 或者 1 ……也就是说,每只死掉的老鼠都用自己的生命确定出了,三进制编号中自己负责的那一位是 2 ;但每只活着的老鼠都只能确定,它所负责的那一位不是 2 。于是,问题就归约到了只剩一个星期时的情况。在第二轮实验里,让每只活着的老鼠继续自己未完成的任务,喝掉它负责的那一位是 1 的所有瓶子。再过一星期,毒药瓶子的三进制编号便能全部揭晓了。

类似地,我们可以证明, n 只小白鼠 t 周的时间可以从 (t+1)^n 个瓶子中检验出毒药来。

2、有700瓶水,一瓶有毒,小白鼠喝一点点,20小时内死翘翘,那么至少用多少只小白鼠一定可以在50小时内找到哪瓶水有毒?
    先看一个比这题简单点的题目:如果只给你20小时找出那瓶有毒的药水,该用多少只老鼠?
    分析:20小时只能做一轮实验。一只老鼠在喝了任意一瓶药水后的状态只可能有两种:死or没死,显然,死=喝了毒药,没死=没喝毒药。按照信息论,一只小白鼠做一次实验的信息量为I1=log2(2)=1bit,而700瓶药水中找到一瓶毒药所需之信息量为I2=log2(700),故需要的小白鼠数量为I2/I1=log2(700),向上取整后为10,即理论上至少需要10只小白鼠。但具体怎么找出这一瓶毒药呢?
   算法:将10只小白鼠排成一列,每一只相当于二进制数的一位,其中可设0=没死=没喝毒药,1=死了=喝了毒药。10只小白鼠可以表示的状态数为2^10=1024>700,所以足够了。将700个瓶子按照二进制依次编号,按照其编号,将对应位为1的瓶子里的药水给表示对应位的小白鼠喝。比如6号瓶的二进制编码为110,故从右到左第1位小白鼠不喝,而第2、3位小白鼠都要喝一口。如果20小时以后,第1位小白鼠木有挂,而第2、3位小白鼠挂了,说明毒药的编号就是110,即6号瓶。
 
  回到原题,原题与上题的区别在于50个小时,可以做两轮实验。当然,如果第一轮实验就挂掉的小白鼠是无法做第二轮实验的,但这无妨,可以用同样的方法解决。理论上,一只小白鼠做两轮实验,可能有三种状态:第一轮就挂了、第一轮木有挂而第二轮挂了、从头到尾都木有挂。所以,一只小白鼠做两轮实验的信息量为I1=log2(3),而700瓶中找出一瓶毒药所需之信息量仍然是I2=log2(700),故所需小白鼠为I2/I1=log3(700),向上取整为6只小白鼠。
   至于具体的算法也是一样的,只是这次所用的编码为3进制,我们可以设0=从头到尾都没死,1=第一轮没死第二轮死了,2=第一轮就死了。将对应位为2的瓶子给对应位的小白鼠喝。20小时后,如果有小白鼠死了,则可确定毒药瓶子的编号某些位为2,而剩下的位可能是1,也可能是0,于是第二轮实验便是上题一样的二进制了,可以将对应位为2的瓶子全部留下,再重新编号做实验。理论上剩下的小白鼠的数量足以完成实验。 

老鼠试毒 两轮试验