仓鼠毒药问题
几个月前,同裴阳和李天翼去吉野家吃饭,收到女友发来短信:
有1000个一模一样的瓶子,其中仅有1瓶是毒药,余下的是纯净水。任何喝下毒药的生物都会在一星期之后死亡。现在,你只有10只小白鼠和一星期的时间,如何检验出哪个瓶子里有毒药?
这类题目的下场只有一个——被秒杀。为了增加共进晚餐的快乐程度,我提出了如下问题:
有1000个一模一样的瓶子,其中仅有2瓶是毒药,余下的是纯净水。任何喝下毒药的生物都会在一星期之后死亡。现在,你需要几只仓鼠才能在一星期的时间内检验出哪些瓶子里有毒药?请尽可能给出较优的方案,即用尽可能少的仓鼠。
对于这个问题寻找非显然的方案似乎是困难的,回到寝室后,五六个数院同学一起想了好一会都没有比较理想的结果。今天下午不知为何又旧事重提,和金睿璋讨论了好一会,找到一个似乎不错的结果。
为了和原问题(老鼠毒药问题)区分,我们命名新问题为仓鼠毒药问题。
首先我们来看老鼠毒药问题的一个“显然”解答:让一只老鼠每隔一秒就尝一个瓶子里的东西再按死亡时间来计算。这样的解答让题目变得很无趣,所以我们需要对实验的方法进行严格的约定:
- 只能通过小白鼠服用药水的方式进行实验,药水可以混合后服用,毒性将不因稀释后而改变。
- 小白鼠在服用药水后的一周内随时可能毒发身亡,所以无法从时间的先后获取任何信息。
在这样的假设下,老鼠毒药问题可以用精确的数学语言刻画:
试构造一个10行1000列的布尔矩阵(取值为0或1的矩阵),使得每列互不相同。
这与原问题等价(请读者自行思考,提示第$i$行$latex j$列为1当且仅当第$i$只小白鼠服用含有第$j$瓶药水的混合药水),由于 $2^{10}\geq 1000$,所以总是可以构造出这样的矩阵,例如在第$j$列写上$j$的二进制表示,二进制表示不足10位的需要补零。通过这样的转换也可以说明更少的小白鼠是无法完成任务的,因为$2^9< 1000$。
回到仓鼠毒药问题,先看一个具有启发性的解决方案:
- 准备工作:将1000瓶药水用1至1000的二进制编号,并通过在首位前补零的方式补成10位数,你可以想象我们将这些二进制的10位编号做成标签贴到瓶子上(注意是想象,谁会真去贴呢!)。
- 随后提问:如何才能确定两瓶毒药在编号的哪一位不同了呢?举个例子:假设标签编号为0001010010, 0010010010的两瓶是毒药,那你可以回答他们在第3位不同。当然回答可能有多种,你只需要告诉我一个。啊哈!为了完成这个任务我们需要使用9对仓鼠夫妇,第$i$对仓鼠夫妇分别服用(1)所有第$i$位为0的混合药水(2)所有第$i$位为1的混合药水。假设第$i$对仓鼠夫妇一同为拯救人类的光荣事业而牺牲了,就说明两瓶毒药的编号在第$i$位发生了分歧。否则,每对仓鼠夫妇中都有一位幸存(并忍受丧偶痛苦……太残忍了!这是什么狗血剧情),说明两瓶毒药的编号在个位(也就是第10位)发生了分歧。
- 最后判定:在知道了两瓶毒药在第几位发生分歧的基础上,不妨设两瓶毒药的编号在个位是不同的,再多需要9对仓鼠敢死队就可以确定两瓶毒药的编号了。方法是分别让第$i$对仓鼠敢死队分别妇服用(1)所有标签编号第$i$位为0且个位为1的药水的混合药水(2)所有标签编号第$i$位为1且个位为0的药水的混合药水。
这样我们需要36只仓鼠就能完成任务了,但可能你已经发现这个解决方案的问题所在了。没错!第三步是建立在第二步的结果之上的,我们只有一次机会!
没有关系,只需要将第三步稍加改造就可以了,我们对仓鼠敢死队进行扩招:对于不相等两个自然数$i$与$j$(取值范围1至10),调配所有标签编号第$i$位为0且第$j$位为1的药水的混合药水,这样我们就有了90瓶混合药水,将仓鼠敢死队扩招至90只,逐一服用混合药水即可。这样在步骤2的结果出来之后,我们只需要关心90只仓鼠中的某18就足够了。
最后,金睿璋指出实际上不需要步骤2中的9对仓鼠夫妇,因为仓鼠敢死队的讯息已经足以回答步骤2中的问题(请读者自行思考)。
开放问题(广义仓鼠毒药问题):
有$n$个一模一样的瓶子,其中仅有$m$瓶是毒药,余下的是纯净水。任何喝下毒药的生物都会在一星期之后死亡。现在,你最少需要几只仓鼠才能在一星期的时间内检验出哪些瓶子里有毒药?记这个最小值为$H(m,n)$,其中$0< m\leq n$。
总结之前的结论,我们有部分结果:
$$H(1,n)=\lceil \log_2{n}\rceil, H(2,n)\leq O\left((\log n)^2\right)$$值得尝试的子问题:证明或者否定
$$H(m,n)=O\left((\log n)^m\right), (n\rightarrow\infty)$$