加油站

来源:互联网 发布:淘宝运营专才认证 编辑:程序博客网 时间:2024/04/27 19:26

加油站

题目描述

奶牛们开车到郊外旅游,由于驾驶技术不行,不小心撞到了石头,油箱漏油了。现在汽车每走一单位距离,油箱就损耗和漏掉共一单位油。
为了修车,必须把车开到最近的小镇(不会超过10,000,000单位距离),到小镇的路可以认为是在一条直线上。从现在的位置到小镇途中, 共有 N (1 <= N<= 50,000) 个加油点,第i个加油点位于距离小镇有D_i (1 <= D_i < L)单位距离的地方,该加油站储油F_i (1<= F_i <= 100)单位.由于路途艰险,奶牛们想尽量把加油的次数减到最少.汽车的油箱可以认为是无穷大. 汽车现在为于距离小镇L个单位距离的地方,并且有P单位的油(1<= P <= 10,000,000).请你计算最少要加多少次油才能到达小镇,或者汽车根本开不到小镇. 注意:在同一地点,可能有多个加油站,但是,在计算时,它们是独立的,认为是两个不同的加油站。

输入格式 1854.in

*第1行: 三个整数: N、 L、P.
* 第 2..N+1行: 两个整数: D_i 、 F_i. 对应着一个加油站。

输出格式 1854.out

*一行:到达小镇需要的最少的加油次数,如果无法到达小镇, 输出-1.

输入样例 1854.in

4 25 10
4 4
5 2
11 5
15 10

输出样例 1854.out

2
【输入解释】
汽车现在在距离小镇25个单位距离的地方,汽车有10个单位的汽油. 
在途中, 有 4 个加油站,他们分别位于距离小镇: 4、 5、 11、15个单位距离的地方。(可以看出,它们跟汽车现在位置的距离分别是:21、20、14、10) 。 这4个加油站的储油量分别是: 4、 2、 5、10。

【输出解释】
汽车开10单位距离后, 停车加10单位的油, 再开4单位距离,停车加5单位的油, 然后就可以开到小镇了。


    这题非常地经典,贪心思想妙极了~

    如果我们在开到某个加油站的时候,就随意决定到底要不要在那里加油,那这肯定是错误的。因为你不能确定在此处加油是否是全局的最优解,那怎么办呢?

    稍微转换一下思路,可以这样想:有一个加油站,实际上意味着在后面有一次加这么多油的机会。然后,可以提出一种后悔的机制:汽车可以一直开,不加油。直到它不够油了,再反悔,加一些油。为了使得加油次数尽可能少,反悔时,肯定选油量大的加油站。因此,可以用一个最大堆来存储路上所有加油站的油量。每次加油都选取堆中的最大值即可。

    需要注意的是,可能存在即使加了油也不够油的情况,需要输出-1。注意,不仅仅是从加油站到加油站有可能翻车,从起点到第一个加油站,从第n个加油站到终点,都是有可能输出-1的。这些细节不可忽略!

    这题,是贪心思想的一个典型例子。它提供了一种思路:后悔机制。实际上,网络流中的增广路也正是以这种后悔思想,建立反向边,从而贪心获得最优解。“后悔”这种策略,具有完美的正确性,具有很好的借鉴意义。

    代码如下:

#include#include#include#includeusing namespace std;const int MAXN=50005;int n,l,p,x,y,ans;struct wyy{    intdis,value;}a[MAXN];priority_queueq; bool cmp(wyy x,wyy y){    returnx.dis>n>>l>>p;    for(inti=1;i<=n;i++)    {       cin>>x>>y;       a[i].dis=l-x;       a[i].value=y;    }    sort(a+1,a+1+n,cmp);    a[n+1].dis=l;    long longleft=p;    for(inti=1;i<=n+1;i++)    {       left-=a[i].dis-a[i-1].dis;       while((!q.empty())&&left<0)       {           left+=q.top();           q.pop();           ans++;       }       if(left<0)       {           ans=-1;           break;       }       q.push(a[i].value);    }    cout<


原创粉丝点击