题目描述:
已知一条公路上,有一个起点与一个终点,这之间有n个加油站;已知从这n个加油站到终点的距离d与各个加油站可以加油的量 l,起点位置至终点的距离L与起始时刻油箱中汽油量P;假设使用1个单位的汽油即走一个单位的距离,油箱没有上线,最少加几次油,可以从起点开至终点?(如果无法到达,返回-1)
思考:
汽车经过n个加油站,对于这n个加油站,应该在哪个加油站停下来加油,最终既能到达终点,又使加油次数最少?
若按顺序遍历加油站,则面临:
如果在某个加油站停下来加油,可能是没有必要的,有可能不进行这次加油也能到达终点;
如果在某个加油站不停下来加油,可能由于汽油不够而无法到达终点或者后面要更多次的加油才能到达终点
贪心:
在油用光的时候加油最合适!
在油量最多的加油站加油最合适!
算法思路:
1、设置一个最大堆,用来存储经过加油站的汽油量
2、按照从起点至终点的方向,遍历各个加油站之间的距离
3、每次需要走两个加油站之间的距离d,如果发现汽油不够走距离d时,从最大堆中取出一个油量添加,直到可以足够走距离d
4、如果把最大堆的汽油都添加仍然不够进行距离d,则无法达到终点
5、当前油量p减少d
6、将当前加油站油量添加至最大堆
代码以及注释如下:
//L为起点到终点的距离
//p为起点初始的汽油量
//pair<每个加油站至终点的距离,每个加油站汽油量>
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <stdio.h>
using namespace std;
bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
return a.first > b.first;
}
int get_minimum_stop(int L, int p, std::vector<std::pair<int, int>>& stop)
{
priority_queue<int> Q; //储存油量的最大堆
int result = 0; //记录加过几次油的变量
stop.push_back(make_pair(0, 0)); //将终点作为一个停靠点,添加至stop数组
sort(stop.begin(), stop.end(), cmp); //以停靠点至终点距离从大到小进行排序
for (int i = 0; i < stop.size(); i++) { //遍历各个停靠点
int dis = L - stop[i].first; //当前要走的距离即为当前距终点距离L减去下一个停靠点至终点的距离
while (!Q.empty() && p < dis) {
p = p + Q.top();
Q.pop();
result++;
}
if (Q.empty() && p < dis) {
return -1;
}
p = p - dis; //储油量减去两个站点间消耗的油量
L = stop[i].first; //更新L为当前停靠点至终点的距离
Q.push(stop[i].second); //将当前停靠点的汽油量添加至最大堆
}
return result;
}
测试代码如下:
//测试程序
int main()
{
vector<pair<int, int>> stop;
int N;
int L;
int p;
int distance;
int fuel;
//VS认为scanf不安全,要用它定义地scanf_s
scanf_s("%d", &N);
for (int i = 0; i < N; i++) {
scanf_s("%d %d", &distance, &fuel);
stop.push_back(make_pair(distance, fuel));
}
scanf_s("%d %d", &L, &p);
printf("%d\n", get_minimum_stop(L, p, stop));
return 0;
}
输入测试数据和结果如下: