V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
noe132
V2EX  ›  问与答

8 瓶水 2 瓶有毒 6 个耗子 的解

  •  
  •   noe132 · 2021-04-21 01:09:53 +08:00 · 1396 次点击
    这是一个创建于 1344 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原帖: https://www.v2ex.com/t/771969

    很抱歉在原帖 1 楼发了一个错误的答案,想的太快导致逻辑出了 bug 。

    8 选 2 一共 28 种可能的组合。由于毒药混合只要有一瓶是毒药,结果则是毒药,属于逻辑或运算,不符合二进制与的条件,所以我们不混合 8 选 2,而是混合选出来后剩下的 6 瓶,8 选 6 。这样混合出来的 28 瓶里只有 1 瓶是无毒的,再根据 5 位 2 进制编码,给 5 只老鼠喝,就能找到哪一瓶有毒了。

    下面是 js 写的一个验证。随机从 water 数组里投毒 2 瓶,然后根据上面的方式计算结果并 log 出来。可以直接在浏览器控制台运行。

    (() => {
      let water = [
        [0, false],
        [1, false],
        [2, false],
        [3, false],
        [4, false],
        [5, false],
        [6, false],
        [7, false],
      ]
    
      // 随机投毒 2 瓶
      let pCount = 0;
      while (pCount < 2) {
        const index = Math.floor(Math.random() * 8)
        if (!water[index][1]){
          water[index][1] = true
          pCount += 1
        }
      }
    
      const poisonous = water.filter(v => v[1]).map(v => v[0]).join(', ')
      console.log('投毒了: ', poisonous)
    
      const mix = []
      
      for (let no = 0, i = 0; i < water.length; i += 1) {
        for (let j = i + 1; j < water.length; j += 1) {
          mix.push({
            no,
            bottle: [water[i], water[j]],
            harmless: water[i][1] && water[j][1],
          })
          no += 1;
        }
      }
    
      const mix2 = []
    
      for (let i = 0; i < 5; i += 1) {
        const key = 2 ** i
        const mix2Item = mix.filter(v => Boolean(key & v.no))
        const isHarmless = mix2Item.some(v => v.harmless)
        mix2.push({
          i,
          isHarmless,
        })
      }
    
      const resultNumber = mix2.filter(v => v.isHarmless).map(v => 2 ** v.i).reduce((p, c) => p + c)
    
      const resultPoisonous = mix[resultNumber].bottle.map(v => v[0]).join(', ')
      console.log('计算出来投毒了: ', resultPoisonous)
    })()
    

    题外,可以思考一下,如果不是固定 2 瓶毒药,而是可能是 0/1/2 瓶,这个应该如何解?

    第 1 条附言  ·  2021-04-21 02:38:04 +08:00
    此解有问题。第一次混合出 28 瓶后,只有 1 瓶是无毒的。将 28 瓶再次混合成 5 瓶后,无论怎么混合 5 瓶都是有毒的。毒药不像二进制异或,两瓶毒药相加是还是毒药,而 1 加 1 模 2 的 结果是 0 。先休息了,明天再来研究
    11 条回复    2021-04-22 09:09:44 +08:00
    noe132
        1
    noe132  
    OP
       2021-04-21 01:10:38 +08:00
    @zxCoder @yxt @hm20062006ok @AndyVerne @Elethom
    抱歉又 @ 了一次~这次算是想明白了
    mikeguan
        2
    mikeguan  
       2021-04-21 01:21:50 +08:00 via Android
    123 -1
    234 -2
    345 -3
    456 -4
    567 -5
    678 -6
    这样应该可以判断那两瓶有问题
    mikeguan
        3
    mikeguan  
       2021-04-21 01:24:44 +08:00 via Android
    @mikeguan #2 想错了,这样不行
    mikeguan
        4
    mikeguan  
       2021-04-21 01:26:27 +08:00 via Android
    感觉又可以的样子,算了不看了
    noe132
        5
    noe132  
    OP
       2021-04-21 01:26:30 +08:00
    @mikeguan 这个不行的。简单的例子,13 有毒和 23 有毒按照你的混和后,结果都是 1 2 3 三瓶有毒。
    snw
        6
    snw  
       2021-04-21 02:29:04 +08:00 via Android
    28 瓶中只有 1 瓶没毒,但 5 只老鼠每只至少要喝 2 瓶,那么结果总是全死啊,你怎么判断?
    noe132
        7
    noe132  
    OP
       2021-04-21 02:38:46 +08:00
    @snw 是的,这个解有问题。
    iceheart
        8
    iceheart  
       2021-04-21 08:13:24 +08:00 via Android
    两只老鼠就够了吧,不死就继续用
    z1113456051
        9
    z1113456051  
       2021-04-21 09:35:18 +08:00
    算上自己就够了
    mzlzero
        10
    mzlzero  
       2021-04-21 15:32:10 +08:00
    @iceheart 要求单次出结果,就是只做一轮,6 只一起喝
    iceheart
        11
    iceheart  
       2021-04-22 09:09:44 +08:00 via Android
    有两瓶有毒,这个条件信息量有两个 bit 吗?我觉得不太可能。
    化简: 三个瓶子两个有毒,一只老鼠测一次
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1532 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:05 · PVG 01:05 · LAX 09:05 · JFK 12:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.