补给站最优花费问题|豆包Marscode AI刷题

114 阅读6分钟

1.问题

问题描述

小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

2.思路

贪心算法

每天都买一个,价格按照这几天里最少的价格去买。如果这天有补给站,将这天补给站的价格与之前的最小值相比,购买价格较小的,如果这天没有补给站,按之前的最低价格买。

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

2.1初始化变量

# 定义最小成本 和 当前最小成本
    min_cost = 0
    min_now = p[0][1]  # 让当前的最小值等于第0天的价格
  • min_cost:用于记录从第 0 天到第 M-1 天的总食物费用。
  • min_now:表示当前所能使用的最低价格,初始值为第 0 天补给站的价格(题目保证第 0 天一定有补给站)。

2.2遍历每一天

# 遍历每一天
    for day in range(m):
        # 遍历每一个补给站描述
        # 当有补给站时,计算最小价格
        if day in [station[0] for station in p]:   # day是二元数组p中的第一个数组中的第一个数字,代表第几天
            
            # 找到 p数组中,第 day天时,其对应的价格 并记录下来
            for station in p:
                if station[0] == day:
                    result = station[1]

            # 找最小值:判断第day天的价格 和 前几天的最小价格,哪个更小
            min_now = min(min_now, result) 
            min_cost += min_now
            
        # 当没有补给站时,令该天食物价格为之前的最小值
        else:
            min_cost += min_now
    return min_cost

3.代码

我的代码

def solution(m: int, n: int, p: list[list[int]]) -> int:
    # 最小花费
    min_cost = 0
    # 当前情况下补给站的最低价格,因第0天一定有补给站,所以初始值为第零天的价格
    min_now = p[0][1]
    # 遍历0到m-1天
    for day in range(m):
        for i, j in p:
            # 这天有补给站
            if i == day:
                # 通过比较,买当前最低价的补给
                min_cost +=  min(min_now, j)
        # 没有补给
        else:
            min_cost += min_now
    return min_cost

结果有误,首先是min_cost += min(min_now, j)后少了break,接着通过打印看一下错误原因。

样例一过程如下:

第0天,有补给站,购买价格为2的补给
第1天,有补给站,购买价格为2的补给
第2天,有补给站,购买价格为1的补给
第3天,有补给站,购买价格为2的补给
第4天,没有补给站,购买价格为2的补给
9

可以看到在第三天和第四天,最小价格并没有更新为1,这是因为min_cost += min(min_now, j)只进行了比较,并没有更新min_now的值。修改如下:

def solution(m: int, n: int, p: list[list[int]]) -> int:
    # 最小花费
    min_cost = 0
    # 当前情况下补给站的最低价格,因第0天一定有补给站,所以初始值为第零天的价格
    min_now = p[0][1]
    # 遍历0到m-1for day in range(m):
        for i, j in p:
            # 这天有补给站
            if i == day:
                # 通过比较,买当前最低价的补给
                min_now = min(min_now, j)
                min_cost +=  min_now
                print("第" + str(day) +"天,有补给站,购买价格为"+str(min_now)+"的补给")
                break
        # 没有补给
        else:
            print("第" + str(day) +"天,没有补给站,购买价格为"+str(min_now)+"的补给")
            min_cost += min_now
    return min_cost

if __name__ == "__main__":
    print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]]))
    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]])) 
    print(solution(4 , 3 ,[[0, 3], [2, 2], [3, 1]]) ) 

image.png

参考代码

def solution(m: int, n: int, p: list[list[int]]) -> int:
    # 动态规划问题(dp)
    # 思路:遍历每一天,若到达有补给站的那天,判断当天与之前的每天价格的大小,选择最小的值作为当日食物费用。
    # 定义最小成本 和 当前最小成本
    min_cost = 0
    min_now = p[0][1]  # 让当前的最小值等于第0天的价格
    
    # 遍历每一天
    for day in range(m):
        # 遍历每一个补给站描述
        # 当有补给站时,计算最小价格
        if day in [station[0] for station in p]:   # day是二元数组p中的第一个数组中的第一个数字,代表第几天
            
            # 找到 p数组中,第 day天时,其对应的价格 并记录下来
            for station in p:
                if station[0] == day:
                    result = station[1]

            # 找最小值:判断第day天的价格 和 前几天的最小价格,哪个更小
            min_now = min(min_now, result) 
            min_cost += min_now
            
        # 当没有补给站时,令该天食物价格为之前的最小值
        else:
            min_cost += min_now
    return min_cost

4.总结

因为之前做过一道类似的题,用了最小堆的方法,不是特别理解,所以遇到这道题会先入为主认为这道题应该用比较复杂的算法,如最小堆、dp等,但通过查找资料,发现这道题可以用一个比较巧妙且直观的方法去求解。

5.参考资料