老鼠喝水——从 1000 杯水中找出有毒的那 1 杯水

问题描述

  有 1000 杯水,其中 1 杯水有毒。老鼠只要喝到有毒的一滴,2 小时后死亡。

假定每杯水有足够分量,而且提供充足的可用的取样设备。

如果要求只花费 2 个小时,请问需要至少几只老鼠才能找出哪杯水是有毒的?

问题分析1

  这个问题比较直观,还是比较好理解的,这个问题求解算法的好坏可以通过两个因素进行评估:时间花费以及老鼠花费

很明显问题对时间花费以及老鼠花费是有要求的,可以选择先找到直观的算法,再通过分析并改进直观的算法从而得到符合要求的算法。

  

问题初步抽象

        对于水:我从 0 开始给每 1 杯水进行编号,0 作为第 1 杯水的编号,999 作为第 1000 杯(最后 1 杯)水的编号。另外将 0 号杯水简写为 0 号水以便于描述,其他编号的每 1 杯水同理。

  对于老鼠:我从 0 开始给花费的每一只老鼠进行编号,0 作为第 1 只花费的老鼠的编号,其他编号的老鼠描述同理。

问题初步求解

  秉着循序渐进的原则,先不考虑时间的花费,也不考虑老鼠的花费。

于是问题可以变为如何花费一定数量的时间以及一定数量的老鼠从 1000 杯水中,找到那杯有毒的水。

这个问题相当直观,可以较为轻松的找到如下算法:

直观算法1

  1.使用 1 只老鼠从 第 1 杯水开始喝水,喝完水之后等待 2 小时

  2. 2 小时后如果老鼠死亡,那么老鼠 2 小时之前喝的那杯水就是有毒的,如果没死那么这只老鼠继续喝下 1 杯水,直至喝完最后 1 杯水或者死亡

直观算法2

  

  1.使用 1000 只老鼠,每只老鼠各自喝和自己编号相同的那杯水,喝完水后等待 2 小时

  2. 2 小时后死亡那只老鼠,所喝的那杯水就是有毒的

算法1评估

  最坏时间花费:  2000 小时(可以改进为 1998小时)

  老鼠数量花费:    1 只

算法2评估

  最坏时间花费:  2 小时

  老鼠数量花费:  1000只(当然可以改进为 999 只)

问题分析2

  上述 2 个算法都很直观,但并不高效。由于算法 2 相比算法 1 更为接近题目要求(时间上只花费了 2 小时),这里将着重分析并改进算法 2 。

        算法 2 之所以需要花费 1000 只老鼠,是因为每只老鼠只喝了 1 杯水,换句话说 1 只老鼠只存储了一杯水的是否有毒的信息。如果能让每只老鼠喝更多杯水,从而能存储更多杯水的是否有毒的信息,那么就能降低老鼠花费

         当有 4 杯水时,可以使用 2 只老鼠找出有毒的那杯水;0 号老鼠可以同时喝下 0 ,1 号水,1 号老鼠可以同时喝下 0,2 号水,可以根据 0 号以及 1 号老鼠的“反应”找到有毒的那杯水。具体就是:如果 2 只老鼠都死亡,那么有毒的那杯水是 0 号;如果 2 只老鼠都存活,那么有毒的那杯水就是 3 号; 如果 0 号老鼠存活且 1 号老鼠死亡,那么 2 号水是有毒的;如果 1 号老鼠都存活且 0 号老鼠死亡,那么 1 号水是有毒。由此可以得出结论:花费 2 只老鼠就可以找出 4 杯水中有毒的那 1 杯

        按照这样的方法,花费 500 只老鼠就解决这个问题!至此又得到 1 个新的算法,这里称为 算法3 !

       

算法3

        使用 500 只老鼠,2 只老鼠为 1 组,共计 250 组

        1. 0 号老鼠喝 0,1 号水;1 号老鼠喝 0,2 号水。

            2 号老鼠喝 4,5 号水;3 号老鼠喝 4,6 号水。

                ……

            直至,498 号老鼠喝 996,997 号水;499 号老鼠喝 996,998 号水

        2. 当有老鼠死亡时,结合这只老鼠所在组别的另一只老鼠的存活情况,就能找出有毒的那杯水

算法3评估

        最坏时间花费:  2 小时

        老鼠数量花费:  500只

问题分析3

         算法 3 任意一组老鼠存活情况,只能判断该组所喝的水是否有毒,对于其他编号的水帮不上忙。
       4 杯水的问题可以由 2 个老鼠组成 1 组进行解决。那么这里假设 1000 杯水的问题同样存在 N 只老鼠组成的 1 组进行解决,任意 1 杯水是否有毒,由这 N 只共同决定!

        

问题进一步抽象

        令老鼠喝水用 0 表示,不喝用 1 表示;

        生存用 1 表示,老鼠死亡用 0 表示,

        所有喝水情况以及生存情况都按老鼠编号从左至右排列;

        当有 4 杯水时,使用了 2 只老鼠。

        对于 0 号水,2 只老鼠都喝,定义为 0,0

        对于 1 号水,0 号老鼠喝,1 号老鼠不喝,定义为 0,1

        对于 2 号水,0 号老鼠不喝,1号老鼠喝,定义为 1,0

        对于 3 号水,0 号老鼠不喝,1 号老鼠也不喝,定义为 1,1

        

        可以将 0~3 号水,换作如下二进制形式:

        00,

        01,

        10,

        11

       

        老鼠喝水情况为:

                0 号老鼠喝 0,1 号水;

                1 号老鼠喝 0,2 号水;

        老鼠生存情况有以下 4 种:

                0 号老鼠死亡,1 号老鼠死亡;用 0,0 表示,此时 0 号水有毒。

                0 号老鼠死亡,1 号老鼠存活;用 0,1 表示,此时 1 号水有毒。

                0 号老鼠存活,1 号老鼠死亡;用 1,0 表示,此时 2 号水有毒。

                0 号老鼠存活,1 号老鼠存活;用 1,1 表示,此时 3 号水有毒。

        可以发现 2 只老鼠的生存情况和水的编号 一一对应。        

        这里可以将生存情况,当做二进制,将它转为 10 进制,此时它的值就是有毒的那杯水的编号

        当有 8 杯水时,根据上面的结论。使用 4 只老鼠可以找出有毒的那杯水,但不太可能是高效的方法,毕竟 8 杯水杯分成了 2 个单独组。那如果使用 3 只能找到吗?假定可以找到,这里按照 4 杯水的处理方式推导一下:

        对于 0 号水,0,1,2 号老鼠都喝,定义为 0,0,0

        对于 1 号水,0 号老鼠喝,1 号老鼠喝,2 号老鼠不喝,定义为 0,0,1

        对于 2 号水,0 号老鼠喝,1 号老鼠不喝,2 号老鼠喝,定义为 0,1,0

        对于 3 号水,0 号老鼠喝,1 号老鼠不喝,2 号老鼠不喝,定义为 0,1,1

        对于 4 号水,0 号老鼠不喝,1 号老鼠喝,2 号老鼠喝,定义为 1,0,0

        对于 5 号水,0 号老鼠不喝,1 号老鼠喝,2 号老鼠不喝,定义为 1,0,1

        对于 6 号水,0 号老鼠不喝,1 号老鼠不喝,2 号老鼠喝,定义为 1,1,0

        对于 7 号水,0,1,2 号老鼠都不喝,定义为 1,1,1

        

        老鼠喝水情况为:

                0 号老鼠喝 0,1,2,3 号水;

                1 号老鼠喝 0,1,4,5 号水;

                2 号老鼠喝 0,2,4,6 号水;

        老鼠生存情况有以下 8 种:

                0 号老鼠死亡,1 号老鼠死亡,2 号老鼠死亡;用 0,0,0 表示,此时 0 号水有毒。

                0 号老鼠死亡,1 号老鼠死亡,2 号老鼠存活;用 0,0,1 表示,此时 1 号水有毒。

                0 号老鼠死亡,1 号老鼠存活,2 号老鼠死亡;用 0,1,0 表示,此时 2 号水有毒。

                0 号老鼠死亡,1 号老鼠存活,2 号老鼠存活;用 0,1,1 表示,此时 3 号水有毒。

                0 号老鼠存活,1 号老鼠死亡,2 号老鼠死亡;用 1,0,0 表示,此时 4 号水有毒。

                0 号老鼠存活,1 号老鼠死亡,2 号老鼠存活;用 1,0,1 表示,此时 5 号水有毒。

                0 号老鼠存活,1 号老鼠存活,2 号老鼠死亡;用 1,1,0 表示,此时 6 号水有毒。

                0 号老鼠存活,1 号老鼠存活,2 号老鼠存活;用 1,1,1 表示,此时 7 号水有毒。

       至此 8 杯水问题,可以用 3 只老鼠解决。

        2 只老鼠的 4 种存活情况对应了 4 杯水的各自编号;

        3 只老鼠 8 种存活情况分别对应了 8 杯水各自编号。

        当有 N 只老鼠时,由于每只老鼠的存活情况有 0,1 两种,于是共有 2 的 N 次方种存活情况,可以解决大小为 2的N次方的问题。

        当 N 为 10 时,存活情况为 1024 种。

        至此,对于 1000 杯水,只需要花费 10 只老鼠就能找到有毒的那 1 杯水。

算法4

        对于 1000 杯水,使用 10 只老鼠,

        将 0~999 编号的每 1 杯水编号写作二进制形式

        从 0000000000 到 11111100111 对于每 1 杯水,将每 1 杯水编号的二进制的形式 10 位数字,从左到右的分别描述为第 1 位到第 10 位

        0 号老鼠喝 第 1 位为 0 的二进制编号所对应编号的水,

        1 号老鼠喝 第 2 位为 0 的二进制编号所对应编号的水,

        ……

        8 号老鼠喝 第 9 位为 0 的二进制编号所对应编号的水,

        9 号老鼠喝 第 10 位为 0 的二进制编号所对应编号的水,

        2 小时后,将表示存活情况的 10 位二进制数,转为 10 进制,就找到了有毒的水的编号

算法4评估

        最坏时间花费:  2 小时

        老鼠数量花费:  10 只

        

        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值