脑筋急转弯:小狗辨别毒药水
今天面试碰到一个较为有意思的题,通过写我的思路在此地方,若有优化的地方,后续会跟进优化,也欢迎大家一起讨论,找到更优解。
**题目描述:**假设有十瓶水,其中有一瓶毒药,目前有一只小狗(或者是其他动物哈,也可以是小白鼠,这里只是一个例子),通过小狗去尝水并辨别哪瓶水是毒药,毒药药效为2小时起作用,即2小时之后,小狗会因为喝完毒药而去世。求最少多少只小狗能够辨别出毒药的位置。
个人理解:其实并不难,但是当时面试的时候太紧张没有思路hh,其实就是一个编码和译码的过程,本文对十瓶水进行从0001~1010进行编码,然后具体的思路为:
-
将十瓶水进行分别编号:1~10
-
将编号转化为二进制,如10转化为1010.(可以推广,设置的编码位数为
ceil(log2(BottleNum)
),数学表达式为*⌈log2(BottleNum)⌉*) -
把小狗设置为监督位(或称测试位),对二进制编码中的每一个位置的瓶子进行饮用,如第1只狗喝下所有编码第一位为1的瓶子、第2只狗喝下所有编码第二位为1的瓶子…
-
重复以上步骤,当第*⌈log2(BottleNum)⌉*(此时对于十个瓶子对应的狗的个数为4)只小狗喝下编码的二进制表示最高位为1的瓶子。
-
等待两个小时,观察哪些小狗死亡,根据死亡的编号,可以确定含有毒药的瓶子的编号。(其实相当于译码啦,如第一只狗和第四只狗死亡,则对应编码1001,即第九个瓶子为装有毒药水的瓶子)
因此将该题目推广成
n
个瓶子的问题,设计的大致C++代码如下:
// 检查第index位是否为1 bool hasPoison(const bitset<10>& bottle, int index) { return bottle.test(index); } // 模拟小狗喝水,返回是否死亡 bool drinkWater(const bitset<10>& bottle, int index) { return hasPoison(bottle, index); } // 根据死亡的小狗编号确定含有毒药的瓶子编号 int findPoisonBottle(const vector<bool>& deadDogs) { int bottleNumber = 0; for (int i = 0; i < deadDogs.size(); ++i) { if (deadDogs[i]) { bottleNumber |= (1 << i); // 将死亡小狗编号转换为含毒药的瓶子编号 } } return bottleNumber; }
主函数的设计如下(可能有误,慢慢更新):
int main() { vector<bool> deadDogs(numBottles, false); // 标记小狗是否死亡,初始都为假 // 模拟让小狗喝水 for (int i = 0; i < numBottles; ++i) { bitset<10> bottle(0); // 初始化瓶子的编码,初始都为0 bottle.set(i); // 设置第i瓶水有毒 for (int j = 0; j < numBottles; ++j) { if (drinkWater(bottle, j)) { deadDogs[j] = true; // 标记死亡的小狗 } } } // 找到含有毒药的瓶子编号 int poisonedBottle = findPoisonBottle(deadDogs); cout << "含有毒药的瓶子编号是: " << poisonedBottle << endl; return 0; }
可能存在更优的方法,慢慢更新,先到此。