补给站最优花费问题
问题重述:
从地到地需要天,每过一天需要一份食物,食物可以从补给站购买,路上总共有个补给站,为每个补给站的描述,共两个数字和,第一个表示第天有一个补给站,并且该站每份食物价格为。
实际上是一个非常经典的加油站最优解问题。
思路:
从到共需要天,即份食物,由于每个站点可购买的食物不设置上限,那么我们只需要在每过一天在曾经经过的花费最少的站点购买食物,也即贪心算法。
如何取得获取花费最少的站点,我们可以通过一个最大堆来维护所经过的所有站点,由于此题站点食物不设上限,则可以优化为只需要记住最便宜的花费即可。
代码实现:
定义min_cost记录所经过的站点的最小值
定义sum记录最终结果
定义j遍历p列表元素
通过循环遍历每一天,每经过一天则需要购买一份食物
在每次遍历之前,判断当前天数是否有站点
若当前天数有站点则将其花费与min_cost进行比较更新
而后在最终结果sum上增加min_cost
代码如下
def solution(n, k, p):
# Edit your code here
min_cost = 1e9
sum = 0
j = 0
for i in range(0,n):
if i == p[j][0]:
min_cost = min(min_cost,p[j][1])
if j < k-1:
j+=1
sum+=min_cost
return sum
if __name__ == "__main__":
# Add your test cases here
print(solution(5, 4, [[0, 2], [1, 3], [2, 1], [3, 2]]) == 7)
时间效率:
空间效率:
细节
-
为什么使用
min_cost而不是min_cost[]?因为每个站点所能购买的食物不设上限,我们只需要一直在所经过的最优站点一直购买即可,所以无需使用最大堆存储其他站点的数据,只需要进行更新
-
if j < k-1:的作用:防止
j越界题目进阶:
如果每个站点的食物是有限个
题目做法则为经典的最大堆贪心
我们需要引入一个最大堆来维护所有站点
把每个经过的站点放入优先队列中,优先进行最小数值的花费,当最小花费的站点没有食物之后弹出队列
继续从队列的头部更新,优先队列会自行维护从小到大的顺序
优先队列:
对于python中的优先队列可以手动维护也可以引入库函数。
优先队列本质上是通过堆排序进行维护整个数据结构。
手动堆排序维护在此不再赘述。
讲解一下对于库函数的调用。
在
Python中需要引入queue中的PriorityQueue使用方法如下
from queue import PriorityQueue q = PriorityQueue() q.put((2, 'code')) q.put((1, 'eat')) q.put((3, 'sleep')) while not q.empty(): next_item = q.get() print(next_item) # 结果: # (1, 'eat') # (2, 'code') # (3, 'sleep')对于
c++则直接引入queue库即可在此给出例题
lc的871.最低加油次数
并在此附上本人的该题做法仅供参考
class Solution { public: int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) { priority_queue<int> pq; int nowFuel = startFuel; int stops = 0, i = 0; // 循环直到当前油量能够到达目的地 while (nowFuel < target) { // 将所有可以到达的加油站的燃料添加到最大堆中 while (i < stations.size() && stations[i][0] <= nowFuel) { pq.push(stations[i][1]); i++; } // 如果没有加油站可以利用,并且无法继续前进,返回 -1 if (pq.empty()) return -1; // 从最大堆中取出最多燃料的加油站 nowFuel += pq.top(); pq.pop(); stops++; // 加油一次 } return stops; } };