补给站最优花费问题解析 | 豆包MarsCode AI刷题

156 阅读6分钟

学习笔记:补给站最优花费问题解析 | 豆包MarsCode AI刷题

题目解析

问题描述

小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,小U每天都需要消耗一份食物。在路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,且每个补给站的食物价格各不相同。

小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费最少的钱顺利完成这次旅行。

  • M:总路程所需的天数。
  • N:路上补给站的数量。
  • p:每个补给站的描述,包含两个数字 A 和 B,表示第 A 天有一个补给站,并且该站每份食物的价格为 B 元。

保证第0天一定有一个补给站,并且补给站是按顺序出现的。


测试样例

样例1:

输入:m = 5 ,n = 4 ,p = [[0, 2], [1, 3], [2, 1], [3, 2]]
输出:7

样例2:

输入:m = 6 ,n = 5 ,p = [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]
输出:6

样例3:

输入:m = 4 ,n = 3 ,p = [[0, 3], [2, 2], [3, 1]]
输出:9

题目分析

我们需要帮助小U规划她的徒步旅行补给计划,目标是以最低成本购买所需的食物。题目给出的条件包括:

  1. 旅行天数 M:小U需要进行 M 天的徒步旅行。
  2. 补给站数量 N:途中有 N 个补给站。
  3. 补给站信息 p:每个补给站包含两部分数据,第 A 天的补给站,和每份食物的价格 B。

小U每天都需要消耗一份食物,我们需要确保她每天都有足够的食物供给,同时总花费最少。


思路解析

本问题需要规划一种策略,以最低花费购买 M 天所需的食物。为了解决这个问题,我们可以使用贪心策略为核心的算法,以下是解题的核心思路:

  1. 每日需求

    • 小U每天都需要一份食物,因此问题可以简化为:每天选择一个有效补给站,购买最便宜的食物。
  2. 贪心选择策略

    • 贪心算法的核心在于局部最优解:每天都从当前可用的补给站中选择价格最低的补给站购买。
    • 由于补给站只能在当天及之前开放,因此每天的选择范围受到限制。
  3. 实现步骤

    • 按天循环,从第 0 天开始,到第M-1 天结束。
    • 对每一天,查找当天及之前开放的所有补给站,选择价格最低的一个补给站购买食物。
    • 累加花费并更新到下一天,直至完成所有 M 天的补给。

图解示意

以下通过图表详细说明样例 1 的求解过程:

输入数据

  • M=5, N=4, p=[[0,2],[1,3],[2,1],[3,2]]。

图解过程

天数当前可用补给站选择最优补给站(价格)当天花费累计总花费
0[0 (2)]0 天补给站(2 元)2 元2 元
1[0 (2), 1 (3)]0 天补给站(2 元)2 元4 元
2[0 (2), 1 (3), 2 (1)]2 天补给站(1 元)1 元5 元
3[0 (2), 1 (3), 2 (1), 3 (2)]2 天补给站(1 元)1 元6 元
4[0 (2), 1 (3), 2 (1), 3 (2)]2 天补给站(1 元)1 元7 元

最终输出:7。

图解表明,贪心算法通过逐天选择最低价格的补给站,能够以最小成本完成旅行。

代码详解

以下代码基于贪心算法逐天选择最优价格的补给站:

def solution(M, N, p):
    total_cost = 0  # 总花费
    current_day = 0  # 当前天数
    
    while current_day < M:
        # 找到当前天数及之前的最便宜的补给站
        min_price = float('inf')  # 初始设为正无穷大
        for station in p:
            if station[0] <= current_day:  # 仅考虑当天及之前的补给站
                min_price = min(min_price, station[1])
        
        # 购买食物并更新总花费
        total_cost += min_price
        current_day += 1
    
    return total_cost

if __name__ == "__main__":
    # 测试样例
    print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]]))  # 输出: 7
    print(solution(6, 5, [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]))  # 输出: 6
    print(solution(4, 3, [[0, 3], [2, 2], [3, 1]]))  # 输出: 9

代码运行逻辑

  1. 初始化

    • total_cost:记录总花费,初始值为 0。
    • current_day:记录当前天数,从 0 开始。
  2. 查找最低价格

    • 遍历补给站列表 p,筛选出当前天数 currentdaycurrent_day 及之前的补给站。
    • 使用 min() 函数实时更新最低价格。
  3. 更新状态

    • 累加当天购买食物的花费到 total_cost
    • 递增 current_day 进入下一天。
  4. 循环结束条件

    • 循环 current_day 至 M-1,完成所有 M 天的补给。

样例测试

if __name__ == "__main__":
    print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]]))  # 输出: 7
    print(solution(6, 5, [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]]))  # 输出: 6
    print(solution(4, 3, [[0, 3], [2, 2], [3, 1]]))  # 输出: 9

性能分析

  • 时间复杂度

    • 外层循环执行 M 次,内层循环遍历 N 个补给站,总复杂度为 O(M⋅N)。
  • 空间复杂度

    • 仅使用常量空间存储总花费和当前天数,复杂度为 O(1)。

优化与扩展

  1. 优化数据结构

    • 可使用优先队列(最小堆)维护当前可用补给站的价格,使得查询最小价格的复杂度降低为 O(log⁡N)。
  2. 扩展问题

    • 考虑补给站食物数量有限的情况,增加动态规划以处理更复杂的需求。

知识总结

新知识点

  1. 贪心算法的应用

    • 贪心策略的核心是局部最优解。
    • 本题中,每天都选择价格最低的补给站来达到最低总花费。
  2. 浮点数的无穷大表示

    • float('inf') 用于初始化最小值或最大值,在比较过程中逐渐更新。
  3. 输入数据处理

    • 理解题目时要准确提取输入格式(如补给站的时间和价格)。

学习总结

通过本题的解析,我们学习了如何应用贪心算法解决实际问题。局部最优策略在类似优化问题中非常高效。理解问题的本质,结合贪心策略和清晰的逻辑实现,是完成这类问题的关键。通过对题目的解析与总结,我们不仅能够提升解题能力,还能系统性地巩固算法知识。

学习心得

  1. 从样例入手理解题目:可以从通过样例数据进行分析,手动计算一次,帮助分析潜在的规律和逻辑。

  2. 刚开始刷题时,可能会遇到没有思路无从下手,或者有思路没有办法转化为代码的问题,这时候可以通过豆包MarsCode AI进行对话,从中获取一部分的思路或代码,读懂理解后再进行刷题,这一定程度上提高了我的学习效率。

  3. 最后一定要动手实践代码:理解代码逻辑后,一定要亲自实现,不能眼高手低,重新编程实现,这样可以检验自己是否真正掌握了这个算法的核心要点,同时也可以发现遗漏的细节或优化点。