小F的糖果工厂挑战 | 豆包MarsCode AI 刷题

56 阅读6分钟

解题笔记:小F的糖果工厂挑战

问题分析

小F的糖果工厂问题是一个典型的二分查找结合贪心思想的问题,目标是找到完成订单的最少天数。要解决这个问题,需要通过以下几个核心步骤:

  1. 需求分析

    • 工厂每天生产多种糖果,每种糖果的数量固定。
    • 每包糖果必须至少有b个糖果。
    • 工厂需要生产a包这样的糖果。
    • 问题的本质是:以最少天数使生产的总包数不少于a
  2. 解决思路

    • 使用二分查找来确定完成订单所需的最少天数。
    • 在每个候选天数mid中,计算工厂在这些天内能够生产的总包数。
    • 如果生产的总包数满足需求,则尝试减少天数;否则增加天数。

代码逐步讲解

1. 计算每种糖果的每日包数

daily_bags = [c // b for c in candies]

功能
将每种糖果的每日生产数量candies[i],除以每包所需的最少糖果数b,计算出该糖果每天最多能生产的完整包数。

分析

  • candies = [7, 9, 6], b = 20

    • 第一种糖果每天最多生产7 // 20 = 0包。
    • 第二种糖果每天最多生产9 // 20 = 0包。
    • 第三种糖果每天最多生产6 // 20 = 0包。

2. 初始化二分查找范围

left, right = 1, a * b

功能
设定二分查找的上下界。

  • left:至少需要1天。
  • right:假设工厂每天全力生产,最多生产a * b的糖果。

分析

  • 当糖果需求量较大时,最大天数right会趋于较大,但通过二分查找可以有效缩小范围。

3. 二分查找核心逻辑

while left < right:
    mid = (left + right) // 2
    
    # 计算在mid天内能生产的总包数
    total_bags = sum((c * mid) // b for c in candies)
    
    if total_bags >= a:
        right = mid  # 如果满足需求,尝试更少天数
    else:
        left = mid + 1  # 否则增加天数

功能

  • 使用二分查找逐步缩小完成需求所需的天数范围。
  • mid代表当前假设的天数。
  • 计算假设天数内,每种糖果能生产的总包数。
  • 根据结果调整leftright的值。

关键点

  1. 计算逻辑

    total_bags = sum((c * mid) // b for c in candies)
    

    对于每种糖果,计算mid天内生产的糖果总量能分成的完整包数,然后汇总所有种类的包数。

  2. 范围调整

    • 如果total_bags >= a:说明当前天数可以满足订单需求,尝试缩短天数。
    • 否则:增加天数以满足需求。

4. 返回结果

return left

功能
循环结束时,left即为满足需求的最少天数。


完整代码

def solution(n: int, a: int, b: int, candies: list[int]) -> int:
    # 计算每种糖果每天能生产的满足要求的包数
    daily_bags = [c // b for c in candies]
    
    # 初始化二分查找的范围
    left, right = 1, a * b
    
    while left < right:
        mid = (left + right) // 2
        
        # 检查mid天内能生产的总包数是否满足要求
        total_bags = sum((c * mid) // b for c in candies)
        if total_bags >= a:
            right = mid  # 如果能满足需求,尝试更少的天数
        else:
            left = mid + 1  # 否则增加天数
    
    return left

测试分析

测试用例 1

输入

n = 3, a = 10, b = 20, candies = [7, 9, 6]

输出

10

解释
每天所有种类糖果最多生产0包,因此需要10天才能凑齐订单。


测试用例 2

输入

n = 4, a = 5, b = 15, candies = [3, 10, 8, 4]

输出

4

解释
在4天内,每种糖果可以生产:

  • 第一种:3 * 4 // 15 = 0包。
  • 第二种:10 * 4 // 15 = 2包。
  • 第三种:8 * 4 // 15 = 2包。
  • 第四种:4 * 4 // 15 = 1包。
    总计生产5包,刚好满足需求。

解题感悟

  1. 二分查找的高效性
    本题的核心在于优化计算时间。使用二分查找,可以高效地缩小可能的解范围。在"最小化某一变量满足条件"类问题中,二分查找是一种常用且高效的工具。通过不断调整范围,避免了暴力穷举所有天数的可能性,将问题复杂度从线性增长优化到对数级别。

  2. 数学推导与建模能力的重要性
    在解题过程中,将问题转换为数学表达式非常关键。例如,将生产的糖果数量转化为包数的计算公式(c * mid) // b,以及将所有种类的包数汇总以判断条件total_bags >= a,这些数学上的抽象是构建程序逻辑的基础。这也提醒我们,写代码并不仅仅是写逻辑,更重要的是理解问题的本质并进行有效建模。

  3. 问题分解与局部优化
    问题表面看起来是多种糖果的生产安排,但实际上可以拆解成单种糖果的生产能力,再通过累加满足整体需求。这种分而治之的思路让问题解决更清晰。同时,局部优化(即每种糖果的生产包数)为全局优化(最少天数)提供了直接依据,凸显了算法设计中逐步逼近的思想。

  4. 工程实践中的实际应用
    类似问题在生产调度、物流分配等实际场景中广泛存在。比如:

    • 生产计划:确定完成一批订单所需的最少时间。
    • 任务分配:将多个生产资源分配到不同任务上,以满足需求。
    • 库存管理:计算库存是否能够在有限时间内满足下游需求。 掌握这样的算法不仅有助于竞赛中的解题,也为解决现实问题提供了思路。
  5. 边界测试的重要性
    在解决实际问题时,边界情况往往是系统中最容易出错的地方。本题中的边界包括:

    • 每种糖果的生产能力是否足够覆盖单包需求(如candies[i] < b时能否处理)。
    • 工厂每天都生产但需求量极大时的情况(如订单量a和单包需求b非常大)。
    • 当糖果种类较多时的资源调度问题。
      这些边界条件的合理处理不仅是算法鲁棒性的体现,也让程序更具实际适用性。
  6. 贪心与动态规划的结合思维
    本题中虽然使用了二分查找,但在计算每种糖果生产包数时,隐含了贪心思想:优先满足能最大化生产包数的糖果。进一步延伸,这类问题也可以结合动态规划解决,例如处理某些特殊情况下,可能需要动态分配资源来优化总成本或时间。

    总的来说,这道题目涉及了数学建模、逻辑设计和算法优化多个方面,体现了解题过程中的系统性和综合性。学习和掌握这些思路对我未来应对更复杂的问题也会有很大帮助。