问题描述:
小U计划进行一场从地点A到地点B的徒步旅行,旅行总共需要 M 天。为了在旅途中确保安全,小U每天都需要消耗一份食物。在路程中,小U会经过一些补给站,这些补给站分布在不同的天数上,且每个补给站的食物价格各不相同。
小U需要在这些补给站中购买食物,以确保每天都有足够的食物。现在她想知道,如何规划在不同补给站的购买策略,以使她能够花费最少的钱顺利完成这次旅行。
M:总路程所需的天数。N:路上补给站的数量。p:每个补给站的描述,包含两个数字A和B,表示第A天有一个补给站,并且该站每份食物的价格为B元。
保证第0天一定有一个补给站,并且补给站是按顺序出现的。
测试样例:
输入:m = 5 ,n = 4 ,p = [[0, 2], [1, 3], [2, 1], [3, 2]] 输出:7
输入:m = 6 ,n = 5 ,p = [[0, 1], [1, 5], [2, 2], [3, 4], [5, 1]] 输出:6
输入:m = 4 ,n = 3 ,p = [[0, 3], [2, 2], [3, 1]] 输出:9
解题过程:
分析完题干后,可以认为这道题是一个典型的贪心问题,每一步都选择当前已知最优解,就能得出最终的题解。
具体到这道题的话,因为题目有明确的时间先后关系,所以在以天为单位前向遍历的过程中,还未碰到的补给站都不能参与选择,那么就只能在已经出现过的补给站中选择最便宜的一个购买。
首先按照人的思考方式看一下样例1,我们知道未来可能遇到的补给站价格分别是 2,3,1,2,最便宜的补给站在旅行的第二天才能碰到,所以在这之前需要有两天的食物,那么就可以在出发前选择买两份花费为 2 的食物,然后到第二天的时候再一次性买完剩余三天的食物,总共花费 7。
但是怎么用代码的方式表达上述过程呢?上述思路的核心逻辑是“当前最优解”,那么只要在遍历每一天的时候,与之前出现过的价格作比较,选择最小的那一个计入总花销即可。还是用样例1来举例,刚开始的时候只有0号补给站,所以先记下该补给站的价格,然后计入总花销,因为无论如何都至少需要在0号补给站购买一份食物。然后到1号补给站,先将这里的价格与记录中的价格比较,选择更便宜的一个价格覆盖之前的记录,并计入总花销,以此类推。具体实现如下:
def solution(m: int, n: int, p: list[list[int]]) -> int:
# Edit your code here
cost = [0] * (m + 1)
for i in range(n):
cost[p[i][0]] = p[i][1]
for i in range(1, m + 1):
if(cost[i] == 0 or cost[i] > cost[i - 1]):
cost[i] = cost[i - 1]
return sum(cost) - cost[-1]
在上述代码中,我用到了两个for循环,第一个for循环用于将题目中 p 的数据取出来,我这里其实是先默认每天都会在对应补给站购买食物,然后第二个for循环中,每一天都会和前一天作比较,用更便宜的价格覆盖今天的价格。同时,我也考虑到了没有遇到补给站的时候,这种情况直接计入当前最便宜的价格即可。
另外,在我初始化 cost 变量时分配了 m + 1 个空间,这是因为出发前有一个补给站,后续可能每天都遇到补给站,所以额外分配一个空间就不会出现特殊问题。但是在最后返回总花销的时候要将最后一天的数据剔除掉,因为按照题目的意思,每一天吃掉的食物都是前一天提前买好的,所以实际上最后一天有没有补给站并不影响最终答案。