1.题目
问题描述
小明的蛋糕工厂每天可以生产的蛋糕数量是由工厂中的机器和工人的数量决定的,即 ( m * w )。现在他收到了一个大订单,需要尽快生产出 ( n ) 个蛋糕。为了提升生产速度,小明可以使用每天生产的蛋糕去购买额外的机器或工人,每台机器或每个工人的成本是 ( p ) 个蛋糕。
例如,如果工厂起始时有 1 台机器和 2 个工人,每次扩大产能的成本是 1 个蛋糕,为了生产 60 个蛋糕,小明可以这样操作:
- 第一天:生产 2 个蛋糕,买入 2 台机器(总机器数变为 3)。
- 第二天:生产 6 个蛋糕,买入 3 台机器,3 个工人(机器数 6,工人数 5)。
- 第三天:生产 30 个蛋糕。
- 第四天:再生产 30 个蛋糕,完成订单。
你的任务是帮助小明计算最快多少天能完成订单。
测试样例
样例1:
输入:m = 3, w = 1, p = 2, n = 12
输出:
3
样例2:
输入:m = 10, w = 5, p = 30, n = 500
输出:
8
样例3:
输入:m = 3, w = 5, p = 30, n = 320
输出:
14
2.思路
核心算法
-
循环条件: 只要当前生产的蛋糕数 (
cake) 少于目标蛋糕数n,就需要继续生产。每生产完一天的蛋糕后,考虑是否有足够的蛋糕来购买机器或工人来提高生产能力。 -
步骤计算:
- 通过
(p - cake) // (m * w)计算出可以用当前生产的蛋糕数去买多少台机器或工人。p是每台机器或工人所需的蛋糕数,cake是当前生产的蛋糕数,m * w是当前生产能力。step是购买机器后,生产能力提升后,需要多少天来完成生产。 - 如果
step <= 0,表示当前蛋糕数足够用于购买机器或工人,就进行购买,并通过step = 1重新计算生产天数。 - 更新天数: 每次生产后,根据当前生产能力和目标蛋糕数更新生产天数
passes。 - 防止溢出: 如果计算出的蛋糕数超过最大值(
float('inf')),则跳出循环。
- 通过
结束条件
- 当
cake(当前生产的蛋糕数)达到或超过n时,停止生产。 - 需要计算出最小的生产天数,通过
min(passes, run)来返回最终答案。
3.代码
def solution(m, w, p, n):
# Please write your code here
passes = 0 # 记录天数
cake = 0 # 当前生产出的蛋糕数
run = float('inf') # 记录最小的完成时间(初始化为无穷大)
while cake < n: # 只要蛋糕数还没达到目标,就继续生产
# 计算当前机器和工人一起生产的蛋糕数量
if m > float('inf') / w:
step = 0 # 防止溢出
else:
step = (p - cake) // (m * w) # 计算能生产多少天才能买得起一个新机器或工人
if step <= 0: # 如果今天就可以买新机器或工人
mw = cake // p # 计算最多可以买多少台机器或工人
# 平衡增加机器和工人的数量,优先保持两者接近
if m >= w + mw:
w += mw # 增加工人数量
elif w >= m + mw:
m += mw # 增加机器数量
else:
total = m + w + mw # 计算总数
m = total // 2 # 让机器和工人尽量均衡
w = total - m # 剩下的分配给工人
cake %= p # 购买后剩下的蛋糕数
step = 1 # 购买后至少再经过 1 天
passes += step
# 计算生产蛋糕数量,防止溢出
if step * m > float('inf') / w:
cake = float('inf')
else:
cake += step * m * w
# 计算剩余蛋糕数达到目标所需的最小天数,并更新 `run`
run = min(run, passes + ((n - cake + m * w - 1) // (m * w)))
return min(passes, run)
if __name__ == "__main__":
# You can add more test cases here
print(solution(3, 1, 2, 12) == 3 )
print(solution(10, 5, 30, 500) == 8 )
print(solution(3, 5, 30, 320) == 14 )
if m > float('inf') / w:
step = 0 # 防止溢出
else:
step = (p - cake) // (m * w) # 计算能生产多少天才能买得起一个新机器或工人
-
if m > float('inf') / w:用于检查m * w的乘积是否会溢出。
-
step代表了在当前的生产能力下,我们能在多久后生产足够的蛋糕以购买新的机器或工人。也就是说,step的值是需要多少天才能用当前的蛋糕数量购买至少一个机器或工人。-
step <= 0:- 如果
step <= 0,表示当前的生产能力已经足够生产出足够的蛋糕去购买机器或工人,因此我们可以进行购买并提升生产能力。 - 在这种情况下,
step被设置为 1,表示当天可以进行购买,且至少还需要经过 1 天(即至少需要 1 天的生产来积累蛋糕)。
- 如果
-
step > 0:- 如果
step > 0,表示还需要step天才能积累足够的蛋糕进行购买。 - 这时候,
passes(天数)会增加step天,生产蛋糕直到可以进行购买。
- 如果
-
# 平衡增加机器和工人的数量,优先保持两者接近
if m >= w + mw:
w += mw # 增加工人数量
elif w >= m + mw:
m += mw # 增加机器数量
else:
total = m + w + mw # 计算总数
m = total // 2 # 让机器和工人尽量均衡
w = total - m # 剩下的分配给工人
else 用于在无法单独增加机器或工人的情况下,进行机器和工人的数量均衡调整。
run = min(run, passes + ((n - candy + m * w - 1) // (m * w)))
passes + ((n - cake + m * w - 1) // (m * w)):
这个表达式计算了当前已经生产过的天数(passes)和剩余需要生产的蛋糕数量所需的天数。
passes:已经过去的天数。n - cake:剩余需要生产的蛋糕数量。n是总的蛋糕需求量,而cake是当前已经生产的蛋糕数量。m * w:每一天能够生产的蛋糕数量。m是机器数量,w是工人数量,它们的乘积表示生产能力。(n - cake + m * w - 1) // (m * w):计算完成剩余蛋糕所需要的天数。这里使用了整数除法(//),并加上m * w - 1进行向上取整的效果。这个技巧确保即使有剩余蛋糕的部分,也能多加一天。
return min(passes, run)
这里返回的是 passes 和 run 中的最小值。passes 是当前的天数(实际的生产天数),run 是通过计算得到的最快生产天数。