一道发散思维题,有1000个一模一样的瓶子,其中有999瓶是普通的水,有一瓶是毒........

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

最近在知乎上看到很火的一个问题,如何看待清华大学自动化系2020年大一c++大作业是写一个功能更强大的雨课堂(雷课堂)?

翻着翻着看到了腾讯给的一个面试题目,也就是上面那个。拿到题目那一刻,当时立马想到了用二分法。于是在本子上开始画,画着画着发现不对了,只有一周的时间。不能一个接一个去检测,那该咋做?说来惭愧,作为计算机专业的学生,实在是没想到好的方法解出来。 看了一下别人的思路说用二进制数来表示,每一个老鼠对应一位,最后看老鼠的存活情况(0死亡,1存活),就可以对应出是哪瓶有毒了。

!!秒啊!!

于是我开始从大脑里回忆我那残留的毛皮计算机组成原理的知识,想到了内存映射。突然发现我以前从来没有想过为什么使用二进制能刚好对应一个位置。 比如,101 对应10进制数 5,如果8个盒子摆在面前(编号0-7),怎么通过3位二进制去选到5号这个盒子呢?

盒子:0-1-2-3-4-5-6-7

假设将盒子分为两半,二进制0代表选前一半,1代表选后一半

以101为例,从左至右:

第一位是1,那么意味着我的目标定位到后4个盒子也就是(4,5,6,7);

第二位是0,选(4,5,6,7)的前一半(4,5)

第三位是1,选(4,5)后一半得到5

如此就刚好定位到5了。这里我们是通过二进制数来找对应位置。

那么回到题目,我们如何用二进制来找到毒药呢?

这道题目巧妙的就是用老鼠是否毒发来代表0,1,从数量反过来编码二进制。

分析题目:

第一只老鼠用来实验一半的水,假设为A.

第二只老鼠则确定A中的一半的水,所以是喝其中的A/2的水吗?

依此类推,第三只老鼠,第四只。。。。。

其中有个问题,这个A可能是所有水的前一半也可能是后一半,第一只老鼠毒发则确定在后半部分,存活则是在前半部分。第二只老鼠则要在对应半个部分再划分确定一半。由于A是不确定的,有两种可能,所以不能只在一半部分取,我们分别在前半部分和后半部分各取一半这样就可以定位到对应的位置了。不懂?见下面的例子!

假设8瓶水 0,1,2,3,4,5,6,7

#以下左边括号代表为二进制0,代表没有喂给老鼠的对应的水编号;右边代表二进制1,代表喝的水对应编号

1号老鼠:(0,1,2,3): 0<=||=>1 :(4,5,6,7)

2号老鼠:((0,1),(4,5))0<=||=>1 ((2,3),(6,7)  )   

2号找上面1号的一半的一半,比如,((2,3),(6,7)  )   对应了无论1号是否毒发,2号毒发的对应的瓶子。

3号老鼠:((0),(4),(2),(6))0<=||=>1 ((1),(5),(3),(7 ))   也就是2号的一半的一半,同理

其实原理和二分法类似,但是这里是确定了一半的同时另一半也要确定了下来,所以每只老鼠都会喝下一半的水。

我们模拟一下,假如1号毒发,则在(4,5,6,7)中确定;  1号毒发编码为1

2号喝了1号的对应后半部分(2,3),(6,7) ,如果2号也毒发了,根据上面1号毒发的情况在(4,5,6,7)中确定,我们就可以在((2,3),(6,7)  )  确定(6,7) ,没有毒发则在(0,1),(4,5))确定(4,5); 这里假设2号未毒发则在(4,5)中确定一个。  2号未毒发编码为0

三号老鼠则喝了二号对应的一半的一半((1),(5),(3),(7 )),假如3号也毒发,则在根据2号的情况((1),(5),(3),(7 ))中确定了(5)。3号也毒发编码为1

所以最后从上到下的编码就是101=5号

我想了想,其实这就是二叉树进行编码的例子(具体请看数据结构,类似哈夫曼编码),突然遇到这种实际情况的题目很难反应过来,要是直接告诉我:1000个数要用多少个二进制进行编码我肯定立马就想到了。

感觉还是得回去看看数据结构顺便得结合一些实例来看。

最后一个问题来了!一下喝500瓶水老鼠会不会涨死?  。。。。。。当然我们还是可以把水混合着喂。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章