旅行家的预算
题目复盘
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。 给定两个城市之间的距离D1、 汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、 出发点每升汽油价格P和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,……N)。 计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
输入格式
第一行为4个实数D1、C、D2、P与一个非负整数N;接下来N行,每行两个实数Di、Pi。
输出格式
如果可以到达目的地,输出一个实数(四舍五入至小数点后两位),表示最小费用;否则输出“No Solution”(不含引号)。
样例输入
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
样例输出
26.95
思路复盘
第一步审题,明确我们要做什么,输出从A到B的最少油费,油费是从每个加油站过来的,那我肯定得从能到达的加油站当中选择一个油费最少的,如果起点的油费就是最低的,那我就开到能开到的最远的加油站,再去那个加油站考虑下一步做什么。要是连能开到的加油站都没有,那就输出“No Solution”。从算法的角度来看,我们是在找局部最优,但局部最优不会影响最终结果。所以此题用贪心。
那么我们在有解的情况下,有两种情况:
第一种就是出发买油的站本身就是最便宜的油价
第二种是后面能到达的站中有比他便宜的油。
先说第二种情况,第二种只要保证到那个站点的油刚好用完就行了。
此题难点就在第一种的情况如何处理上。
这里容易犯的错误就是我们把想当然的就是把油加到能够让他开到最远的站点,但是请注意,还有一个更优的策略就是把油加满,如此一来,到最后一个站以后,我们剩下的油是用了更便宜的油价买的,请放心,这剩下的油是到不了下一站的,读者可以细心想一下是不是这么一回事,
在看了大佬的题解后,他们还考虑到 到了终点以后肯定要把油刚好用完才算不亏,于是乎把终点看成是最便宜的加油站,然后我们决策的时候就能让他剩下的油为0。也算是非常巧妙了。
明确了算法的方向以后,我们按照上述思路构造一个伪代码:
这是如何选择下一个买油的加油站的代码:
while(当前的站点<最后的站点)
{
for(当前站点+1;直到最后一个站点之前;++站点)
{
if(当前站点到下一个站点之间的距离>所有油用完的距离)
{
下一个花钱买的加油站=此情况的站点-1;
break;
}
if(当前能到达的站点比原先的站点的价格少)
{
下一个花钱买的加油站=此情况站点;
break;
}
}
}
两种决策的伪代码
if(在能到达的站点中存在一个站点的油价比原先的便宜)
{
买刚好能到达那个加油站的油
}
else
//原先的加油站最便宜
{
加满油
}
注:这里引入一个变量oil表示到达下一加油站时剩余的油量。
最后实现的源码
/*
Considering there Strategy:
1. No solution:
use this station's all petrol until over my car's capacity but can't access the next station.
2.compare the station's price I can access when full my car:
2.1 if the local station cheapest
then buy the most oil towards next_station
and then I access the netx_Station the left oil=capacity - distance/d2
2.2 if this station is not the cheapst one among all the accessible station
then I only buy the least petrol to make sure access the cheapest one.
and when I access the next_station,the left oil = 0
*/
#include<iostream>
using namespace std;
struct st{
double distance;
double price;
}a[10];
int n;
double d,d2,c,p,ans;
int main()
{
int flag=0;
cin>>d>>c>>d2>>p>>n;
a[0].distance=0;a[0].price=p;
a[n+1].distance=d;a[n+1].price=0;
for(int i=1;i<=n;i++)
{
cin>>a[i].distance>>a[i].price;
if(a[i].distance-a[i-1].distance>c*d2)
flag=true;
}
if(flag)
{
cout<<"No Solution"<<endl;
return 0;
}
int index=0;
int next_index=0;
double oil;
while(index<=n)
{
index=next_index;
for(next_index=index+1;next_index<=n+1;next_index++){
//Consider the local optimal solution
if(a[next_index].distance-a[index].distance>c*d2){
next_index = next_index-1;
break;
}
if(a[next_index].price<=a[index].price){
break;
}
}
if(a[next_index].price<=a[index].price)
{
//2.2
ans+=((a[next_index].distance-a[index].distance)/d2-oil)*a[index].price;
oil=0;
}
else{
//2.1
ans+=(c-oil)*a[index].price;
oil=c-(a[next_index].distance-a[index].distance)/d2;
}
}
printf("%.2lf\n",ans);
return 0;
}