POJ 2431 Expedition(贪心+优先队列)

来源:互联网 发布:淘宝买家如何开店 编辑:程序博客网 时间:2024/05/01 09:43

原题地址

http://poj.org/problem?id=2431

题意:一辆有P单位汽油的卡车,刚开始停在距离起点处,距离终点L单位距离,卡车每开一单位距离就要消耗一单位汽油。在途中一共有N个加油站,每个加油站有各自的位置和油量。假设卡车的燃料箱容量无限,请问最少需要加几次油到达终点。如果不能到达则输出-1。

解题思路

这道题需要一个切入点,有了这个思想,贪心的做法写起来就很简单了。

在卡车开往终点的途中,只有在加油站可以加油,转换一下思路,每经过一个加油站 i,就获得了一次在之后的任何时候都可以加 i 的油的权利,也就是把 i 作为了储备的油,之后需要加油的时候,就认为是在之前经过的加油站里加油就可以了(无疑是加满)。

因为希望停的次数尽可能少,所以当燃料为0了之后再进行加油、且选经过的油站里油量最大的加,是很好的办法。每次贪心取最大,数据结构上最合适的就是最大堆形式的优先队列啦。

实现时,先对所有油站的距离排序(给出的是距离终点的距离,先转换为距离起点的距离),每经过一个油站就把该油站的油量加入优先队列,当没油时,如果优先队列已经空了,说明之前的油都加完了,否则取出最大数值加油。

编码了两种实现,都可以AC:

  • 《挑战程序设计竞赛》书上给出的代码solve_book(),它以每次能否到达下一个加油站为判断标准(其实不是很懂?和它描述的思路不那么对应)。有个处理技巧,将终点也作为一个空的加油站,做循环的时候就不用再处理边界条件。
  • 自己按照思路实现的代码solve_mine()。每次把油耗尽之后再回头看是否还有油可以加,而不是判断能否到达下一个加油站。

AC代码

#include <iostream>#include <cstdio>#include <algorithm>#include <queue>using namespace std;const int maxn = 10005;typedef struct node{    int dist, fuel;    bool operator < (const node A) const //距离升序    {        return this->dist < A.dist;    }}NODE;int n, length, left_fuel;NODE stop[maxn];void solve_book() //书上代码:以能否到达下一个加油站为判断条件{    int pos = 0, pass = 0;    //把终点也当作一个空油站    stop[n].dist = length; stop[n].fuel = 0;    n++;    sort(stop, stop+n); //按距离排序    priority_queue<int> pq;    for(int i = 0; i<n; ++i)    {        int between =  stop[i].dist - pos; //距离下一个加油站        while (left_fuel < between) //到不了新的加油站        {            if (pq.empty()) //队列已空,没储备油可加            {                cout << -1 << endl;                return;            }            left_fuel += pq.top();            pq.pop();            ++pass; //加油次数+1        }        //到达新的加油站        pos = stop[i].dist;        left_fuel -= between;        pq.push(stop[i].fuel); //加入储备油站    }    cout << pass << endl;}void solve_mine() //自己实现:每次开到最远,再回头看油{    sort(stop, stop+n); //按距离排序    priority_queue<int> pq;    int pos = 0, index = 0, ans = 0; //index-1指向开过的最右边站点    while(1)    {        pos += left_fuel; //当前油量开到的最远点        if (pos >= length) //能开过终点        {            cout << ans << endl;            return;        }        while (stop[index].dist <= pos) //统计此次开过的站        {            pq.push(stop[index].fuel);            index++;        }        if (pq.empty()) //无油可加        {            cout << -1 << endl;            return;        }        //加队列里的最大油量        left_fuel = pq.top(); pq.pop();        ans++;    }}int main(){    //freopen("C:/Users/DELL/Desktop/a.txt", "r", stdin);    ios::sync_with_stdio(false);    cin >> n;    for (int i = 0; i<n; ++i)        cin >> stop[i].dist >> stop[i].fuel;    cin >> length >> left_fuel;    for (int i = 0; i<n; ++i) //转换为到起点的距离        stop[i].dist = length - stop[i].dist;    //solve();    solve_mine();    return 0;}

算法复杂度:O(n)
耗时:141ms

0 0
原创粉丝点击