文章目录
- 题目
- 解析
- 香农熵公式
- 样例具体分析
- 代码
题目
有 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));}
};