There are buckets
buckets of liquid, where exactly one of the buckets is poisonous. You have minutesToTest
minutes to determine which bucket is poisonous. If a pig drinks from the poisonous bucket, it will die after minutesToDie
minutes. The goal is to determine the minimum number of pigs needed to find the poisonous bucket within the allotted time. Pigs can drink from multiple buckets simultaneously, and multiple pigs can drink from the same bucket.
For example:
If buckets = 4
, minutesToDie = 15
, and minutesToTest = 15
, return 2.
If buckets = 4
, minutesToDie = 15
, and minutesToTest = 30
, return 2.
Constraints:
1 <= buckets <= 1000
1 <= minutesToDie <= minutesToTest <= 100
A brute-force approach would involve testing each bucket individually. With only minutesToTest
and minutesToDie
available, we can perform tests = minutesToTest / minutesToDie
tests. If buckets
is less than or equal to tests
, we only need one pig. Otherwise, we need multiple pigs. The problem is that the number of pigs we would need quickly goes up. This approach doesn't scale at all.
The core idea is to use pigs as 'digits' in a base system where the base is the number of times we can test within the given time. Each pig can represent one dimension in this base system. The number of possible states dictates how many buckets the pigs can differentiate.
tests = minutesToTest / minutesToDie
. If tests
is 1, it means we can only run one test.p
such that (tests + 1)^p >= buckets
. This translates to finding the base tests + 1
logarithm of buckets
and rounding up to the nearest integer.minutesToDie
is equal to minutesToTest
, then we only have one chance to test. Each pig can only provide two results: die or survive, which can represent 2 buckets at max.buckets = 1000
, minutesToDie = 15
, minutesToTest = 60
tests = 60 / 15 = 4
We need to find the minimum p
such that 5^p >= 1000
.
5^1 = 5
5^2 = 25
5^3 = 125
5^4 = 625
5^5 = 3125
So, p = 5
pigs are needed.
import math
def poorPigs(buckets: int, minutesToDie: int, minutesToTest: int) -> int:
if buckets == 1:
return 0
tests = minutesToTest // minutesToDie
return math.ceil(math.log(buckets, tests + 1))