文章目录
- 题目
- 解析
- 香农熵公式
- 样例具体分析
- 代码
题目
有 n 桶液体,其其中 正好 有一桶含有毒药,其装的都是水。它们从外观看起来都一样。为了弄清楚哪只水桶含有毒药,你可以喂一些猪喝,通过观察猪是否会死进行判断,实验对象的反应时间为 d 。不幸的是,你只有 t 时间来确定哪桶液体是有毒的。
解析
香农熵公式
根据题意,最大测试次数为 num = ∣td∣\vert\frac{t}{d}\vert∣dt∣
只测试一轮:
考虑 num=1 时,也就是只进行一轮测试,容易想到可以使用与水同等数量的小猪来进行测试,n 个小猪喝 n 桶液体,哪个死翘翘哪一桶水有问题。
但这样的测试方式效率过低,我们其实可以结合二进制,让每个小猪同时测试多桶液体。这样祸害的小猪会少一点,更人道一些~
具体来说,我们需要 k 只小猪,k 满足 2k≥n{2^k} \geq n2k≥n。举个例子,当 n=5 时,可得 k = 3,即 3 只小猪即可一轮测出哪一桶是毒药,具体做法:
- 我们以 x1x2x3x_1 x_2 x_3x1x2x3 的形式表示
5桶液体的 二进制 编号,如:第一桶液体二进制编号为001。 - 我们让第
i只小猪喝二进制编号 xix_ixi 为1的液体。即:- 第一只小猪需要喝的桶二进制编号为:100、101
- 第二只小猪需要喝的桶二进制编号为:010、011
- 第三只小猪需要喝的桶二进制编号为:001、011、101
- 经过反应时间
d后,观察所有小猪的状态,第i只小猪死亡则代表含毒的水桶其 编号第i位为1,幸存则代表 编号第i位为0。从而得到含毒的水桶的编号。举例:第二、三只小猪死亡,说明第三桶液体含毒;第一、三只小猪死亡,说明第五桶液体含毒……
测试 num 轮:
- 只测试一轮时我们用二进制为水桶编号,因此测试
num轮时,我们用num+1进制为水桶编号。 - 小猪数量
k需满足 (num+1)k≥n{(num+1)^k} \geq n(num+1)k≥n,即k为num+1进制的长度。 - 若某桶水的
num+1进制中的第x位为i(0<=i<=num),则代表将该水在第i轮喂给编号为x的小猪。
这样我们就得到了著名的 香农熵 公式:H(X)=−∑xP(x)log2[P(x)]H(X)=−\displaystyle \sum_{x}{P(x)log}_2 [P(x)]H(X)=−x∑P(x)log2[P(x)]
P(x) 代表随机事件 x 的发生概率。
本题中,记随机事件 A 为 n 桶液体中哪一个桶有毒,概率为 1n\frac{1}{n}n1 。
记随机事件 B 为在测试轮数为 num 时,所有实验对象的最终状态,每个实验对象的状态共有 num+1 种(一开始都是活的状态,每测一轮多一种状态的可能性——死 or 继续活),即 k 只小猪共有 C=(num+1)kC=(num+1)^kC=(num+1)k 种最终结果,可近似看做等概率 1C\frac{1}{C}C1 。
我们需要求得在满足 H(A)<=H(B)H(A)<=H(B)H(A)<=H(B) 前提下的最小 k 值。即:log2nlog2(num+1)<=k\frac{log_2{n}}{log_2(num+1)} <= klog2(num+1)log2n<=k
样例具体分析
假设:总时间 minutesToTest = 60,死亡时间 minutesToDie = 15,pow(x, y) 表示 x 的 y 次方,ceil(x) 表示 x 向上取整。
那么:
- 当前有
1只小猪的话,最多可以喝num = minutesToTest / minutesToDie = 4次水 - 最多可以喝
4次水,能够携带base = times + 1 = 5个的信息量,也就是:- 喝 1 号死去,1 号桶水有毒
- 喝 2 号死去,2 号桶水有毒
- 喝 3 号死去,3 号桶水有毒
- 喝 4 号死去,4 号桶水有毒
- 喝了上述所有水依然活蹦乱跳,5 号桶水有毒
- 反推得,当
buckets ≤ 5时,小猪数量answer = 1。
- 那么
2只小猪可以验证的范围最多到多少呢?我们把每只小猪携带的信息量(能测多少桶液体)看成是base,2只小猪的信息量就是 pow(base,2)=pow(5,2)=25pow(base, 2) = pow(5, 2) = 25pow(base,2)=pow(5,2)=25,所以当 5≤buckets≤255 ≤ buckets ≤ 255≤buckets≤25 时,anwser = 2。 - 那么可以得到公式关系:pow(base,ans)≥bucketspow(base, ans) ≥ bucketspow(base,ans)≥buckets,取对数后即为:ans≥log(buckets)log(base)ans ≥ \frac{log(buckets)}{log(base)}ans≥log(base)log(buckets),因为
ans为整数,所以 ans=ceil(log(buckets)log(base))ans = ceil(\frac{log(buckets)}{log(base)})ans=ceil(log(base)log(buckets))
代码
class Solution {
public:int poorPigs(int buckets, int minutesToDie, int minutesToTest) {int num = minutesToTest/minutesToDie;return (int)ceil(log(buckets) / log(num+1));}
};