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
思路:
设汽车加满油可以驾驶的最大距离是maxrange
从第一个加油站开始,在maxrange范围内判断是否存在比当前加油站价格更小的加油站,若存在:则在当前油量下,加到刚好可以到达该价格更小的加油站。否则:将油加满,然后开到maxrange内最远的加油站。这样知道到达终点或者发现终点不可达。
坑点:
1、(2号测试点会卡这个)油箱刚开始是空的,所以要在对加油站按照距离排序后特判排序后第一个加油站距离杭州是否为0。
2、(3号测试点会卡这个)如果你的思路和我的类似,那么可能还有这个坑点供参考:
如下图所示,圆圈代表加油站,数字代表价格,x、y、z分别指代加油站之间的距离。(设油箱最大储油量为Cmax,当前油量为nowtank,每单位油可以跑的距离为Davg)
(为方便起见,下面直接用价格代指加油站)
在上图所示情况下,由于在6.5的加油站之后,maxrange内,没有比其价格更低的加油站,因此就应该判断从6.5的加油站可否直接到达终点。很多朋友肯定会有疑问,要是之后有比其价格更低的加油站还需要判断吗? 答案是不需要,因为只要出现了价格更低的加油站,那么就先跑到该加油站,这样消费才会最低。这里我们可以分两种情况讨论(前提:6.5加油站可以直接到达终点,而且之后有更低价格的加油站时):
1、若到达6.5后,还有油量剩余。
那么从6.5走到下一个价格较低的加油站处,不可能还剩有油量。我们以下图说明这个论断:(注意区分两个图里面的6.5)
假设路径是从6.5到7再到6.2。那么,从6.5到7可以有剩油,而从7到6.2必定没有剩油。因为:若从7到6.2还有剩油,必定可以直接从6.5到6.2。(没有明白的朋友可以在草稿纸上反证一下。)
明白了这个论断以后,我们回到我们讨论的情况中,若到达6.5以后有剩油,那么再到下一个价格比其更低的加油站时必定不可能剩油,这时如果从6.5可以直接到达终点,那么必定要以6.5的价格加到到达终点所需的油量。这样下来价格就会偏高,所以此时不能添加程序判断是否可以直接到达终点。
2、若到达6.5以后,没有油量剩余。利用上面讨论过的论断,我们可以很容易得到这种情况下也不能添加程序判断。
实现代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000;
struct node{
double price;
int dis;
};
node d[maxn];
bool cmp(node a,node b){
return a.dis<b.dis;
}
int main(){
int Cmax,D,Davg,N;
scanf("%d%d%d%d",&Cmax,&D,&Davg,&N);
for(int i=0;i<maxn;i++){
d[i].dis = 0x7FFFFFFF;
d[i].price = 0;
}
for(int i=0;i<N;i++){
scanf("%lf %d",&d[i].price,&d[i].dis);
}
d[N].price = 0x7FFFFFFF;
d[N].dis = D;
sort(d,d+maxn,cmp);
// 特判是否第一个加油站可达,因为刚开始没有油。。
if(d[0].dis!=0){
printf("The maximum travel distance = 0.0");
return 0;
}
int num=0,flag = 1;
double nowpos=0.0,sum_price = 0.0,storage = 0.0;
while(nowpos!=D && num<=N){
// 无法到达下一站
if(Cmax*Davg<d[num+1].dis-nowpos){
flag = 0;
nowpos += double(Cmax*Davg);
break;
}
// 在最大可达范围内寻找下一个最小价格加油站
int i = num+1;
while(d[i].dis-nowpos<=Cmax*Davg && i<=N){
if(d[i].price<=d[num].price){
break;
}
i++;
}
// 若最大可达范围内存在比目前加油站价格更低的加油站:
if(d[i].dis-nowpos<=Cmax*Davg && i<=N){
sum_price += storage<=(d[i].dis-nowpos)/Davg?(double(d[i].dis-nowpos)/Davg-storage)*d[num].price:0;
storage = storage<=(d[i].dis-nowpos)/Davg?0:storage-double(d[i].dis-nowpos)/Davg;
nowpos = d[i].dis;
num = i;
}else{
// 否则判断是否可直达终点
if(nowpos+Cmax*Davg>=D){
sum_price += storage<=(D-nowpos)/Davg?(double(D-nowpos)/Davg-storage)*d[num].price:0;
nowpos = D;
num = N;
break;
}
// 找到最大可到达的加油站
i =num+1;
while(d[i].dis-nowpos<=Cmax*Davg && i<=N){
i++;
}
// 如果下一个点就是终点(这里我在之前输入的数据后面添加了终点)
if(num+1 == N){
sum_price+= storage<=(D-nowpos)/Davg?(double(D-nowpos)/Davg-storage)*d[num].price:0;
storage=0;
}else{
sum_price += (Cmax-storage)*d[num].price;
storage = Cmax-double(d[i-1].dis-nowpos)/Davg;
}
nowpos = d[i-1].dis;
num = i-1;
}
}
if(flag){
printf("%.2f",sum_price);
}else{
printf("The maximum travel distance = %.2f",nowpos);
}
return 0;
}