优先队列的使用——Expedition

一、题目描述

你需要驾驶一辆卡车行驶L单位距离。最开始时,卡车上有P单位的汽油。卡车每开1单位距离需要消耗1单位的汽油。如果在途中车上的汽油耗尽,卡车就无法继续前行,因而无法到达终点。中途共有N个加油站,第i个加油站距离终点Ai单位距离,最多可以给卡车加Bi单位汽油。假设卡车的燃料箱的容量是无限大的,无论加多少油都没有问题。那么请问卡车是否能到达终点?如果可以,最少需要加多少次油?如果不可以输出-1。(1 ≤ N ≤ 10000,1 ≤ L ≤ 1000000,1 ≤ P ≤ 1000000,1 ≤ Ai ≤ L,1 ≤ Bi ≤ 100)

二、问题分析

由于加油站的数量非常大,必须像一个高效的解法。

在卡车开往终点的途中,只有在加油站才可以加油。我们换一种思考方式,如果认为“在到达加油站时i时,再次之后的任何时候都获得了加Bi油的权利”。因为希望到达终点的加油次数尽可能地少,我们可以加经过地加油站的加油量放入优先队列,当油量不足以到达下一站,则取出优先队列中的最大值,其实就是贪心算法,取所有权力中的最大值,最坏的情况时,每次油量都不够,需要从队列中取,此时时间复杂度O(nlogn).

三、代码实现

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<queue>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 
 8 const int maxn = 10000 + 10;
 9 struct Station
10 {
11     int pos;
12     int fuel;
13     bool operator < (const Station &n)const {
14         return (pos < n.pos);
15     }
16 }sta[maxn];
17 int n, L, P;
18 
19 void slove()
20 {
21     //把终点也认为是一个加油站,写起来更加方便
22     sta[n].pos = L;
23     sta[n].fuel= 0;
24     n++;
25 
26     priority_queue<int>que;
27     int ans = 0,pos = 0, tank = P; //pos表示当前位置,tank表示当前油量
28 
29     sort(sta, sta + n);            //使各加油站的位置从小到大排列
30 
31     for (int i = 0; i < n; i++)
32     {
33         int d = sta[i].pos - pos;
34 
35         //油量不够则加油
36         while (tank - d < 0)
37         {
38             if (que.empty())
39             {
40                 printf("-1\n");
41                 return;
42             }
43             tank += que.top();
44             que.pop();
45             ans++;
46         }
47         tank -= d;
48         pos = sta[i].pos;
49         que.push(sta[i].fuel);
50     }
51     printf("%d\n", ans);
52 }
53 int main()
54 {
55     scanf("%d", &n);
56     for (int i = 0; i < n; i++)
57         scanf("%d%d", &sta[i].pos, &sta[i].fuel);
58     scanf("%d%d", &L, &P);
59     for (int i = 0; i < n; i++)
60         sta[i].pos = L - sta[i].pos;
61     
62     slove();
63     return 0;
64 }

四、总结

熟练应用优先队列能很好的解决许多问题。

猜你喜欢

转载自www.cnblogs.com/lfri/p/9457689.html