# 1033. To Fill or Not to Fill (25)

With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.

Input Specification:
Each input file contains one test case. For each case, the first line contains 4 positive numbers: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di (<=D), the distance between this station and Hangzhou, for i=1,…N. All the numbers in a line are separated by a space.

Output Specification:
For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print “The maximum travel distance = X” where X is the maximum possible distance the car can run, accurate up to 2 decimal places.

Sample Input 1:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300
Sample Output 1:
749.17
Sample Input 2:
50 1300 12 2
7.10 0
7.00 600
Sample Output 2:
The maximum travel distance = 1200.00

/*

很明显，这道题的思路是贪心，也就是要用尽可能少的钱，要去尽可能远的地方。
那么，像这种贪心的题目，怎么去思考呢？
首先，今天听到戴龙翱（ZJU大牛）提到的一点，对于贪心的题目，测试样例，必须自己去体会一遍，这样，很有可能会给我们带来不少启发。
那么，我们就一起来过一遍测试样例吧：

Sample Input 1:
50 1300 12 8
6.00 1250
7.00 600
7.00 150
7.10 0
7.20 200
7.50 400
7.30 1000
6.85 300

Sample Output 1:
749.17

1：起点，肯定是要加油的，不然跑都跑不起来，那么，问题来了——加多少？

2：通过1的分析，我们选择了加油站B。而且值得强调的是，我们在起点A加的油跑到B时是正好用完的状态。

B处的油价是7，显然，750之前的加油站有很多，油价有比7小的，比7大的，也有等于7的。那么，贪婪的你，一定不会傻到去选择一个油价贵的（如C、E）

so，我们选择了D（油价6.85），而且，D的油价比当前的便宜，所以我们加油只要够从B——>D就好，加多了就不符合我贪婪的本性了！
3：到了D之后，可以说是比较开心的，因为在他[300,300+600]的范围内这价是最便宜的，此时不加更待何时！？因为是最便宜的，所以，为了贪，必须加满！

4：和之前的情况有所不同的是，这次，我们到目的地的时候，还是有油剩余的（600-300<600），而且剩余的油够跑300（即可以跑到900）。

5：到了G之后，计算了此时邮箱还剩下的油狗刨200，也就是说，我们在贵的的地方G只需要加50（1250-1000-200），能到H即可，因为H的油价是最便宜（没有之一），

6：走到了H之后，就不用多想了，H之后也没有加油站了，而且加满能够到目的地I的油量就够了。

a:有比当前加油站的油价更便宜的加油站——加到恰好能到那个最近的油站的油量              【1】【2】【5】（注：1、如果有多个便宜的，还是要先选取最近的那个，而不是最便宜的那个；2、可能还有油剩余）
b:没有比当前加油站的油价更便宜的加油站——加满，然后在600范围内找到最便宜的加油站加油             【3】【4】

Sample Input 2:
50 1300 12 2
7.10 0
7.00 600

Sample Output 2:
The maximum travel distance = 1200.00

1：600的范围内（包括600），有加油站，而且比当前的油价要便宜，因此，属于情况3—a，故，我们加到恰好能到，这里比较特殊的是，只有加满才恰好能到，

2：600范围内，没有加油站，这里属于情况2，能跑多远跑多远，因为已经无法到达目的地了，只能尽可能地跑更远

1：起点没有加油站
2：起点即终点

1：到达当前加油站的油量——因为，你要计算还需要加多少油，所以，总共需要的油量—现有的油量=在当前加油站要加的油量
*/
#include<stdio.h>
#include<algorithm>
#include<iostream>
using namespace std;

typedef struct
{
double pos;
double price;
}gasstation;
gasstation gasst[502];

bool cmp(gasstation a,gasstation b)
{
if(a.pos<b.pos)
return true;
return false;
}

int main()
{
double Cmax,D,Davg;
int N;
scanf("%lf%lf%lf%d",&Cmax,&D,&Davg,&N);
int i;
for(i=0;i<N;i++)
scanf("%lf%lf",&gasst[i].price,&gasst[i].pos);
sort(gasst,gasst+N,cmp);
if(D==0)
{
printf("0.00\n");
return 0;
}
if(gasst[0].pos!=0)
{
printf("The maximum travel distance = 0.00\n");
return 0;
}
int curstnum=0;               //当前所处的油站编号,即当前的位置
double curgas=0;              //当前的油量
double curcost=0;                //当前的花费
bool flag=false;              //是否达到目的
double maxrundis=Cmax*Davg;        //邮箱加满最远能行驶的距离
while(!flag)
{
bool tag=false;            //最大距离内是否有加油站
bool ifcheaper=false;    //是否有便宜的
double cheapestprice=10000;    //找出最便宜的
int cheapestnum;        //没有更便宜的情况下，找出最便宜的
for(i=curstnum+1;i<N;i++)
{
if((gasst[i].pos-gasst[curstnum].pos)<=maxrundis)    //范围内
{
tag=true;         //有加油站
if(gasst[i].price<gasst[curstnum].price)        //情况3-a
{                                            //且有更便宜的
ifcheaper=true;
double dist=gasst[i].pos-gasst[curstnum].pos;
double needgas=dist/Davg-curgas;
curgas=0;
curcost+=(needgas*gasst[curstnum].price);
curstnum=i;
break;
}
if(gasst[i].price<cheapestprice)
{
cheapestprice=gasst[i].price;
cheapestnum=i;
}
}
else
break;
}
if(!ifcheaper&&(maxrundis>=(D-gasst[curstnum].pos)))   //说明已经可以到达目的地了,情况1
{
double dist=D-gasst[curstnum].pos;
double needgas=dist/Davg-curgas;
curcost+=needgas*gasst[curstnum].price;
printf("%.2lf\n",curcost);
return 0;
}
if(tag&&!ifcheaper)            //情况3-b
{
double needgas=Cmax-curgas;
curcost+=(needgas*gasst[curstnum].price);
double dist=gasst[cheapestnum].pos-gasst[curstnum].pos;
curgas=Cmax-dist/Davg;
curstnum=cheapestnum;
}
else if(!tag)                        //情况2
{
printf("The maximum travel distance = %.2lf\n",gasst[curstnum].pos+maxrundis);
return 0;
}
}
return 0;
}

• 本文已收录于以下专栏：

## 贪心算法

ACM算法之贪心算法 一般使用贪心算法要满足两个条件: a.贪心选择性质  —— 可通过做局部最优（贪心）选择来达到全局最优解。（贪心选择性质：这是贪心算法与动态规划的区别） b.最优子结构性质...

## 贪心算法

举报原因： 您举报文章：深度学习：神经网络中的前向传播和反向传播算法推导 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)