您的位置:首页 > 其它

【每天进步一点】毒药和老鼠的研究

2015-04-09 15:44 274 查看
之前碰到过毒药和老鼠,鸡蛋和称的问题,每次都拿笔在纸上推敲很久,这类问题今天终于有了完整的解决思路。

基础:

1.整数的二进制表达式

1000的二进制表达式是什么呢?

1000/2=500  --(余)--0
500/2=250   --(余)--0
250/2=125   --(余)--0
125/2=62    --(余)--1
62/2=31     --(余)--0
31/2=15     --(余)--1
15/2=7      --(余)--1
7/2=3       --(余)--1
3/2=1       --(余)--1
1/2=0       --(余)--1


1000的二进制表达式为 1111101000 = 29 + 28 + 27 + 26 + 25 + 23 = 512 + 256 + 128 + 64 +32 + 8

还需要其他的吗?不需要了,有上面的基础足矣。

二进制和上面的题目有什么关系呢?

在计算机基础里面,函数B2Uw表示Binary to Unsigned(长度为w的二进制到无符号整数),它能够被定义为一个映射:

B2Uw{0,1}w --> {0,1,...,2w-1}

也就是说表达0~2w-1的整数值,只需要w位的二进制即可。

再转换一下:w位的二进制可以表达(2w-1)+1=2w个整数值。

反应在我们的命题中,n个瓶子对应n个可能的结果,转换成二进制之后,只需要x位的0101就可以表达出来了。(n已知,x未知。x的求值参考上面的结论)

命题:8瓶水,其中一瓶有毒,中毒的老鼠会在一个星期之后死亡。给你一个星期,请问最少几只老鼠可以测试出哪瓶有毒?

步骤一:确定需要几只老鼠

8 = (二进制)1000 = 23。

即三位的二进制即可表达8种情况。

步骤二:为药品分配准备数据

将三位的二进制所有的情况罗列出来,剔除0的情况

计算机的整数(索引)从0开始,生活中的计数习惯从1开始。而实际的操作中,我们可以拿出一瓶不做测试,当所有老鼠都存活下来时,就说明拿出来的这一瓶是最后的结果。这里可以取个巧,将0理解为索引,映射到最后一个数字,在这里就是8;剔除0,也就是剔除了第8瓶水的情况。

┆  0  ┆  0  ┆  1 ┆  //1
┆  0  ┆  1  ┆  0 ┆  //2
┆  0  ┆  1  ┆  1 ┆  //3
┆  1  ┆  0  ┆  0 ┆  //4
┆  1  ┆  0  ┆  1 ┆  //5
┆  1  ┆  1  ┆  0 ┆  //6
┆  1  ┆  1  ┆  1 ┆  //7


从右往左,第一列对应的是1010101,其中1对应的数即为{1,3,5,7};第二列对应0110011=>{2,3,6,7};第三列对应0001111=>{4,5,6,7}

步骤三:提取上面的数字,得出喂食方案。

第一只老鼠给他喂食(1,3,5,7)瓶水的混合液,第二只老鼠喂食(2,3,6,7)的混合液,第三只老鼠喂食(4,5,6,7)的混合液。

Console.WriteLine("假设有毒瓶数为:");
int poisonOne = int.Parse(Console.ReadLine());
Console.WriteLine("死掉的老鼠有:" + string.Join(",", solution.Select((aa, idx) => aa.Contains(poisonOne) ? idx + 1 : -1).Where(idx => idx != -1)));
var resBinary = new string(solution.Select(aa => aa.Contains(poisonOne) ? '1' : '0').Reverse().ToArray());
Console.WriteLine("二进制表达式为:" + resBinary);
var res = Convert.ToInt32(resBinary, 2);
if (res == 0) res = poisonNum;
Console.WriteLine("测试结果为:第{0}瓶有毒", res);


View Code

发散的问题:6个质量相等的小球和1个质量稍重的球,不能用天平,只能用称,设计一种方法,只能量三次就找出稍重的球。

类似的问题,这里数量变成了7个。测试数据也从死掉变成了重和轻,不过一样可以转换成0和1。

如果你看懂了上面,不妨想想这个的答案。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: