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-1天
for 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]]) )
参考代码
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等,但通过查找资料,发现这道题可以用一个比较巧妙且直观的方法去求解。