问题描述
题目分析
1、若在前一个油站把油加满都不能到下一个油站,则无法到达目的地。否则,一定可以到达目的地。
2、因为在任何一个油站都可以把油箱加满,所以当我们到达加油站i时,油站i之前的油站不再考虑,只需要考虑此时油箱里的油 和 油站i后面的油站。
3、也是因为在任何一个油站都可以把油箱加满,所以当我们到达加油站i时,只需要考虑从油站i要去往哪个油站,而不用考虑再去往哪个油站等其他后续问题。
4、假设油箱容量无上限,从现在的位置,我们希望跑到一个比现在位置油价更便宜的油站。用更便宜的油价加油继续往下跑。而且加油前,油箱里的价格更贵的油恰好用完。
5、在油箱容量有限的前提下,如果能跑到一个比现在位置油价更便宜的油站,那就跑过去。油价相等的地方也行,相当于扩充邮箱容量。如果能跑到的油站都比现在的油价贵,假设目的地无限远,那就在当前油站加满油,跑到能跑到的油价最低的油站。因为目的地无限远,所以加满油也跑不完,所以不用考虑会剩下油。
6、将目的地也看做一个油站,油价无穷小。那么上一条就不会出现剩油的情况。因为在到达目的地前的最后一次加油,不会出现“能跑到的油站都比现在的油价贵”的情况。
7、倘若出现多个油站油价相同,那么如果出发点油价<到达点油价,则去尽可能远的那个。如果出发点油价>到达点油价,则去尽可能近的那个。
思路
1、对除了目的地的每个油站判断,若在该油站加满都不能到下一个油站,结束。
2、若在当前油站加满油,能到达油价比它低的油站,则去油价比它低的最近的油站。
3、即使在当前油站加满油,也不能到达油价比它低的油站,则去它能到的油价最低的油站,若这样的油站有多个,则去最远的那个。
代码
#include<stdio.h>
const double eps=1e-8;
int n;//油站个数
double m,C,d,p[9],dis[8];
// m总距离 C油箱容量 d每升汽油能行驶的距离
//p[]每个位置的油价 dis[]每个位置距离出发点的距离
int i,j;
int now,to;//now当期在哪个油站 to要去的油站
double need,sum,have;
//need从now到to需要的油量 sum总花费 have邮箱剩余油量
double abs(double a) //计算绝对值函数
{
if(a>0) return a;
if(a<0) return -a;
}
void read()
{
scanf("%lf%lf%lf%lf%d",&m,&C,&d,&p[0],&n);
for(i=1;i<=n;++i) scanf("%lf%lf",&dis[i],&p[i]);
dis[n+1]=m;
p[n+1]=-1; //目的地看做第n+1个油站
p[n+2]=501; //留一个油价无限大的位置,后面计算油价最小的油站时作初始值
//因为题目说数据范围<=500,所以501相当于一个极大值。油价不为负,-1相当于一个极小值
}
int no_solution() //判断无解
{
for(i=0;i<=n;++i)
if(C*d<dis[i+1]-dis[i])
{
printf("No Solution");
return 1;
}
return 0;
}
void find()
{
j=n+2;
for(i=now+1;i<=n+1;++i)
{
if((dis[i]-dis[now])/d>C) break; //超出能跑的范围
if(p[i]<p[now] || abs(p[i]-p[now])<eps) //找到一个比当前油站油价便宜或相等的油站
{
j=i;
break;
}
if(p[i]<p[j] || abs(p[i]-p[j])<eps) j=i; //找油价最低的油站
}
to=j;
}
void price()
{
need=(dis[to]-dis[now])/d;
if(p[to]<p[now] || abs(p[to]-p[now])<eps) //出发点油价<=到达点,恰好跑到到达点,油箱不剩油
{
sum+=(need-have)*p[now];
have=0;
}
else //出发点油价>到达点,油箱加满
{
sum+=(C-have)*p[now];
have=C-need;
}
now=to;
}
int main()
{
read();
if(no_solution()) return 0;
while(now<=n)
{
find();//找下一个要去的油站
price();//计算这一段的价格
}
printf("%.2lf",sum);
return 0;
}