《可怜的小猪》
看起来简单,但是没有头绪,我大意了啊,感觉自己有点猪,其实感觉这道题更像是自下而上的动态规划,过程的繁琐和最终的两行代码形成强烈的反差,涉及到的数学知识也非常简单,就是看你能不能想清楚每一步,本文拯救可怜的小猪,一道 brain teaser 的题目。
Beijing, 2020
作者:RaySue
题目描述
有 buckets 桶液体,其中 正好 有一桶含有毒药,其余装的都是水。它们从外观看起来都一样。为了弄清楚哪只水桶含有毒药,你可以喂一些猪喝,通过观察猪是否会死进行判断。不幸的是,你只有 minutesToTest 分钟时间来确定哪桶液体是有毒的。
喂猪的规则如下:
- 选择若干活猪进行喂养
- 可以允许小猪同时饮用任意数量的桶中的水,并且该过程不需要时间。
- 小猪喝完水后,必须有 minutesToDie 分钟的冷却时间。在这段时间里,你只能观察,而不允许继续喂猪。
- 过了 minutesToDie 分钟后,所有喝到毒药的猪都会死去,其他所有猪都会活下来。
- 重复这一过程,直到时间用完。
给你桶的数目 buckets ,minutesToDie 和 minutesToTest ,返回在规定时间内判断哪个桶有毒所需的 最小 猪数。
示例 1:
输入:buckets = 1000, minutesToDie = 15, minutesToTest = 60
输出:5
示例 2:
输入:buckets = 4, minutesToDie = 15, minutesToTest = 15
输出:2
示例 3:
输入:buckets = 4, minutesToDie = 15, minutesToTest = 30
输出:2
提示:
- 1 <= buckets <= 1000
- 1 <= minutesToDie <= minutesToTest <= 100
题目解析
先从最简单的情况入手,从一头猪并且时间只有一次,即minutesToTest / minutesToDie = 1,那么一只小猪只可以验证两桶水是否有毒,小猪尝试0,如果0有毒,结束;如果0没毒,那么1有毒,结束。
同样的有两头猪A、B,我们如何安排能够最有效呢?如下:
A - 0
B - 1
AB - 2
这样,两头猪就可以判断 4 桶水了,如果0有毒A挂,1有毒B挂,2有毒AB都挂,都没挂则3有毒,可以检测4桶
扩展到三头猪:A、B、C,安排:
A - 0, B - 1, C - 2
AB - 3, AC - 4, BC - 5
ABC - 6
这样,三头猪就可以判断8桶水了
数学好的小伙伴到这里已经发现了,如果有n头猪可以验证多少桶水呢?那就是
C n 1 + C n 2 + . . . + C n n + 1 = C n 0 + C n 1 + C n 2 + . . . + C n n = 2 n C_n^1 + C_n^2 + ... + C_n^n + 1 = C_n^0 + C_n^1 + C_n^2 + ... + C_n^n = 2^n Cn1+Cn2+...+Cnn+1=Cn0+Cn1+Cn2+...+Cnn=2n
这次实验中一只猪对应只可以验证 2 桶水,如果时间充裕,一头猪可以验证 3 桶水,那就是 3 n 3^n 3n,一次类推,那么一头猪可以验证多少桶水是如何决定的呢?即minutesToTest / minutesToDie + 1,时间给的最够多,只有一瓶毒药的情况下,一只猪可以验证无数桶水,
Code
int poorPigs(int buckets, int minutesToDie, int minutesToTest)
{
int x = minutesToTest / minutesToDie + 1;
return ceil(log(buckets) / log(x));
}