此题来至吴军的《信息论》
新研发的[0-63]号新药,64种新药里有一个序号的药会致命,无毒的药混吃没事,只要吃了致命毒药一天内必死,现在只剩一天时间。
要求:最少用多少只小鼠测试出致命毒药的序号。理解为最小成本的 64选1。
分析:信息量为 log64 ( 2^6 = 64) 最少用到 6 bit (6只小鼠)。
代码思路:
每个新药的序号都用二进制表示,不足6位的用0左补齐6位。
进制对照
十进制 | 二进制 |
0号 | 000000 |
1号 | 000001 |
...... | ...... |
62号 | 111110 |
63号 | 111111 |
64种新药用数据结构来表示
'0': 药序号
binaryList: [......] 药序号的二进制数组
flag: true 布尔值(只有一个毒药是 false)
{
'0': { binaryList: [ '0', '0', '0', '0', '0', '0' ], flag: true },
'1': { binaryList: [ '0', '0', '0', '0', '0', '1' ], flag: true },
'2': { binaryList: [ '0', '0', '0', '0', '1', '0' ], flag: true },
......
'38': { binaryList: [ '1', '0', '0', '1', '1', '0' ], flag: false },
......
'59': { binaryList: [ '1', '1', '1', '0', '1', '1' ], flag: true },
'60': { binaryList: [ '1', '1', '1', '1', '0', '0' ], flag: true },
'61': { binaryList: [ '1', '1', '1', '1', '0', '1' ], flag: true }
}
6只小鼠初始数据状态用 mouseStatus: [ '0', '0', '0', '0', '0', '0' ] 来表示。
mouseStatus 与 binaryList, 6 列 竖着对应起来。
3号:binaryList: [ '0', '0', '0', '0', '1', '1' ]
4号:binaryList: [ '0', '0', '0', '1', '0', '0' ]
鼠: mouseStatus : [ '0', '0', '0', '0', '0', '0' ]
从索引 0 开始 binaryList[0] 值为 0 时不吃该序号的药,为 1 就吃药。
吃了药时判断该序号的 flag 是否为 false(毒药),将小鼠的状态值 0 改为 1 表示该小鼠挂了。
最后小鼠的状态值(0为活,1为挂)转换为十进制得到毒药序号。
下面是 js 实现的 64选1
// 范围内随机数
const randomRange = (max, min = 0) => (
~~(Math.random() * (max - min) + min)
)
// 补足长度位
String.prototype.fillLeft = function (n, fill = 0) {
let str = this.toString()
if (str.length >= n) return str
return (Array(n - str.length + 1).join(fill) + str)
}
// 新药的序号生成二进制
const medicamentGroup = (num) => {
let medicamentObj = {}
, numBinaryLength = (num - 1).toString(2).length
;
for (let i = 0; i < num; i++) {
medicamentObj[i] = {
binaryList: (i).toString(2).fillLeft(numBinaryLength).split(''),
flag: true
}
}
return {medicamentObj, numBinaryLength}
}
// 测试新药
const makeDrugTest = (num) => {
let {medicamentObj, numBinaryLength} = medicamentGroup(num)
, mouseStatus = Array(numBinaryLength).fill(0)
, drug = randomRange(num)
;
// 打印出随机毒药序号
medicamentObj[drug]['flag'] = false
console.log(`drug: ${drug}`);
for (let index in mouseStatus) {
for (let item in medicamentObj) {
let medicament = medicamentObj[item]
, binaryList = medicament.binaryList
;
// 模拟 0 不吃药,1 吃药
if (parseInt(binaryList[index])) {
// 吃到毒药 小鼠挂了,状态改为 1
medicament.flag || (mouseStatus[index] = 1)
}
}
}
let drugTest = mouseStatus.join('')
// 二进制转十进制
return parseInt(drugTest, 2);
}
let num = 64
console.log(
makeDrugTest(num)
);
毒药的序号是随机的结果也是随机数,大家复制代码测试看结果。