51nod 2636 卡车加油

题目链接:http://class.51nod.com/Challenge/Problem.html#problemId=2636

一、题目描述

一辆卡车,初始时距离终点L,油量为P,在起点到终点途中有n个加油站,每个加油站油量有限,而卡车的油箱容量无限,卡车在行车途中,每走一个单位的距离消耗一个单位的油量,给定n个加油站距离起点的距离A[i]以及油存储量B[i]。问卡车是否能到达终点,如果可达,最少需要加多少次油,否则输出-1。输入不保证有序。

1 <= n <= 10000; 1 <= L <= 1000000; 1 <= P <= 1000000;1≤A[i]<L,1≤B[i]≤100。

输入

第一行三个数L,P,n,以空格隔开,分别表示起点到终点的距离、现在的油量、中途加油站数;
之后n行,每行两个数A[i]和B[i],以空格隔开,表示该加油站到起点的距离和油存储量。

输出

输出一个数,表示最少的加油次数。

样例输入

100 15 2
15 75
90 25

样例输出

2

二、思路描述

在卡车开往终点的图中,只有在加油站才可以加油。

但是如果转换成“在到达加油站i时,就获得了一次在之后任何时候都可以加B[i]单位汽油的权利”,在解决问题上是一样的。

我们可以把每次到加油站的油量都存到优先队列里。

那么,想要加油的次数尽可能少,当燃料用完之后再去看加哪个B[i]应该是最优的,在燃料为0时,应该选油量B[i]最大的加油站。

由此可见,需要一直动态的维护一个最大油量,就应用到了优先队列的性质。

那么算法的步骤如下:

1、当经过加油站时,将B[i]加入优先队列中。

2、如果燃料为0

3、如果优先队列为空,则表示无油可加,无法到达终点

4、否则取出优先队列中最大的元素,用来给卡车加油

那么现在有个问题:如果我要到最大的供油加油站就得使用几个油箱中的油。可是我最后最大的供油加油站却可以供从起点开到终点的油。

我最后就输出1了,实际上还有一些数字没有算进去。这要怎么解决呢?

可以定义一个v数组,v[a]=b代表位置a处有一个油量为b的加油站,输入a,b的时候就做这个操作。

遍历路的时候,就判断这个i上面有没有加油站(无:v[i]=0),if ( v[i] != 0 ) q.push(v[i]) 这个应该在if(p==0)前面写

三、复习优先队列

四、代码

#include<queue>
#include<cstdio>
#include<iostream>
using namespace std;

priority_queue <long long> q;
long long l, p, n, a, b, ans=0, v[1000005];

int main(){
    cin >> l >> p >> n;
    for(long long i = 1;i <= n;i++){
        cin >> a >> b;
        v[a] = b;
    }
    for(long long i = 1;i < l;i++){
        p--;
        if(v[i]){
            q.push(v[i]);
        }
        if(p == 0){//如果暂且选择的油箱空了 
            if(q.empty()){//如果没有可以用的油箱了 
                ans = -1;//不能满足题目要求,最后输出-1
                break;
            }
            else{//还有可以选择的油箱 
                p = q.top();//从大往下取油箱 
                ans++;//选择的油箱数量+1
                q.pop(); 
                //最大的油箱已经选过了,后面不能数了,去掉这个数 
            }
        }
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/elisa02/p/12879021.html