题目:1000 瓶无色无味的药水,其中有一瓶毒药,10只小白鼠拿过来做实验。喝了无毒的药水第二天没事儿,喝了有毒的药水后第二天会死亡。如何在一天之内(第二天)找出这瓶有毒的药水?
第一次看这个问题完全没思路,应该有很巧妙的解法吧,后来还是百度一下,才明白怎么回事。
思路就是用二进制,2^10=1024,也就是10只小白鼠最多能验出1024瓶药水,哪个有毒。小白鼠编号,1-10。瓶子也编号,1-1000,然后把瓶子的编号转变为二进制数。如果第几位是1,就把这瓶水给第几个小白鼠喝。最后大概每个小白鼠喝500瓶药水的混合液。如果还不懂,下面列几个数字解释一下。
瓶子编号 二进制数 第几个小白鼠喝
1 0000000001 1
2 0000000010 2
3 0000000011 1,2
4 0000000100 3
5 0000000101 1,3
大概就是这意思,再反过来,假如1号和3号小白鼠死了,死的小白鼠用1表示,再写成2进制数:0000000101,转化为十进制数是5,从上面列出来的也可以看出1,3都喝了5号瓶的水,所以就是第五瓶水有毒。
写出来距想明白还有那么一点差距,下面再附上我写的python代码,代码水平不是很高,只能算出每只小白鼠喝第几瓶水,请见谅。
#coding=utf-8
#十个列表,每个小白鼠一个
a=[]
b=[]
c=[]
d=[]
e=[]
f=[]
g=[]
h=[]
i=[]
j=[]
#
#1000瓶水标签0-1000
li=list(range(1,1001))
#取出一瓶水,把标签十进制数字转化为二进制
for x in li:
# 定义一个空列表,存储每次二进制数,存进列表里的二进制数是字符格式的
li1 = []
er=bin(x)
# print (er)
for y in er:
if y==b:
continue
else:
li1.append(y)
#把li1列表里的元素顺序反向排列
list.reverse(li1)
# print (li1)
#计算li1列表里元素个数,根据元素个数生成一个列表,每次从li1里拿元素用
n=list(range(len(li1)))
# print (n)
for y in n:
# print (y)
# print (li1[y])
# print (x)
# print (type(li1[y]))
#li1这个二进制列表里拿一个数,这个数为1的时候,就是把原十进制数对应水编号给y小白鼠喝
if li1[y]=='1':
# print (x)
# print (type(y))
# print (y)
if y==0:
# print (y)
a.append(x)
elif y==1:
# print (y)
b.append(x)
elif y==2:
c.append(x)
elif y==3:
d.append(x)
elif y==4:
e.append(x)
elif y==5:
f.append(x)
elif y==6:
g.append(x)
elif y==7:
h.append(x)
elif y==8:
i.append(x)
else:
j.append(x)
# else:
# continue
print ("1000瓶水打上标签,经过下面计算,每只小白鼠喝下下面计算的混合液。")
print ("第一只小白鼠喝下水瓶标签:",a)
print ("第二只小白鼠喝下水瓶标签:",b)
print ("第三只小白鼠喝下水瓶标签:",c)
print ("第四只小白鼠喝下水瓶标签:",d)
print ("第五只小白鼠喝下水瓶标签:",e)
print ("第六只小白鼠喝下水瓶标签:",f)
print ("第七只小白鼠喝下水瓶标签:",g)
print ("第八只小白鼠喝下水瓶标签:",h)
print ("第九只小白鼠喝下水瓶标签:",i)
print ("第十只小白鼠喝下水瓶标签:",j)
print ("如果第一只,第三只,第五只小白鼠死了,就是0b0000010101(二进制数,转化为十进制数是21),第21瓶水有毒。")
代码就放这么多,下面再放一张运行结果的图,1000瓶水太多了,简化为4只小白鼠,验15瓶药水。
四只小白鼠最多能验2^4=16瓶水,从这个结果可以看出,最好的情况,小白鼠都没死,就是第16瓶水有毒了,感觉如果出这个结果还是不错的。