原帖: 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
noe132 OP |
2
mikeguan 2021-04-21 01:21:50 +08:00 via Android
123 -1
234 -2 345 -3 456 -4 567 -5 678 -6 这样应该可以判断那两瓶有问题 |
4
mikeguan 2021-04-21 01:26:27 +08:00 via Android
感觉又可以的样子,算了不看了
|
6
snw 2021-04-21 02:29:04 +08:00 via Android
28 瓶中只有 1 瓶没毒,但 5 只老鼠每只至少要喝 2 瓶,那么结果总是全死啊,你怎么判断?
|
8
iceheart 2021-04-21 08:13:24 +08:00 via Android
两只老鼠就够了吧,不死就继续用
|
9
z1113456051 2021-04-21 09:35:18 +08:00
算上自己就够了
|
11
iceheart 2021-04-22 09:09:44 +08:00 via Android
有两瓶有毒,这个条件信息量有两个 bit 吗?我觉得不太可能。
化简: 三个瓶子两个有毒,一只老鼠测一次 |