问题描述
一个美国旅行代理商经常被要求去估计开车从一个城市旅行至另一个城市的最小费用。他有一个在通常路线上的大多数加油站的列表。列表包括了所有加油站的位置及当前每加仑汽油的价格。
为了简化估计费用的过程,代理商使用了以下的简化汽车驾驶员行为的规则:
● 除非汽车无法用油箱里的汽油达到下一个加油站(如果有的话)或目的地,在油箱里还有不少于最大容量一半的汽油时,驾驶员从不在加油站停下来。
● 在每一个停下的加油站,驾驶员总是将油加满。
● 在一个加油站停下之后,驾驶员将为旅程在快餐和糖果上花去2.00元。
● 在驶向加油站或目的地时,驾驶员不需要超过必须量的汽油。不需要“安全余量”。
● 驾驶员开始旅行时油箱总是满的。
● 每个加油站付款时四舍五入到分(1元等于100分)。
你必须写一个程序以估计驾驶员在旅程上至少要为汽油和食品付多少钱。
输入格式
开始的2行给出了出发地和目的地的信息。
数据的后继若干行代表了路线上的加油站,每个加油站用一行表示。下面是输入数据中数据项的精确格式及其含义。
第一行:一个实数——从出发地到目的地的距离(英里)。
第二行:三个实数及一个整数。
● 第一个实数是汽车油箱的最大的容量(加仑)。
● 第二个实数是汽车每加仑汽油可以行驶的英里数。
● 第三个实数是汽车在出发地城市加满油箱的费用(单位:元)。
● 整数(小于51)是路线上加油站的数目。
接下来的每一行:两个实数。
● 第一个实数是从出发地到加油站的距离(单位:英里)。
● 第二个实数是该加油站出售的汽油每加仑的价格(单位:分)。
数据项中的所有数据都是正的。一条路线上的加油站根据其到出发地的距离递增排列。路线上不存在这样的加油站,它到出发点的距离大于从出发点到目的地的距离。每条路线上的加油站都被适当的安排以使得任何汽车都能从出发地开到目的地。
输出格式
仅一个实数(保留两位小数),表示最小的花费(单位:元)。
样例输入
475.6
11.9 27.4 14.98 6
102.0 99.9
220.0 132.9
256.3 147.9
275.0 102.9
277.6 112.9
381.8 100.9
样例输出
27.31
这道题虽然很简单,但是那个条件想起来还是比较麻烦。
一开始WA80,是因为没有理解题意。
我是把终点当做了一个加油站,其实不能这样,因为这句话:
● 除非汽车无法用油箱里的汽油达到下一个加油站(如果有的话)或目的地,在油箱里还有不少于最大容量一半的汽油时,驾驶员从不在加油站停下来。
但是是可以有不少于容量一半的汽油到达终点。
所以应该枚举距离不超过油量限制的最后一个点,找到最小解。
#include <cstdio>
#define min(a,b) ((a)<(b)?(a):(b))
const double eps = 1e-8;
const double inf = 1e19;
double d[60];
double v[60];
double D,S,M,init;
long n;
double f[60];
int main()
{
freopen("oil.in","r",stdin);
freopen("oil.out","w",stdout);
scanf("%lf%lf%lf%lf%ld",&D,&S,&M,&init,&n);
for (long i=1;i<n+1;i++)
{
scanf("%lf%lf",d+i,v+i);
v[i] /= 100.0;
}
for (long i=1;i<n+1;i++)
f[i] = inf;
f[0] = init;
for (long i=1;i<n+1;i++)
{
for (long j=i-1;j>=0;j--)
{
if (d[i]-d[j] > M*S+eps)
break;
if (d[i]-d[j] > M*S/2+eps)
{
f[i] = min(f[i],f[j]+v[i]*((d[i]-d[j])/M)+2);
}
}
}
double ans = 1e19;
for (long i=n;i>=0;i--)
{
if (D - d[i] > M*S+eps)
break;
ans = min(ans,f[i]);
}
printf("%.2lf",ans);
return 0;
}