Codeup——584 | 问题 C: To Fill or Not to Fill

题目描述

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.

输入

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.

输出

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.

样例输入

59 525 19 2
3.00 314
3.00 0

样例输出

82.89

提示

该题目所要解决的问题是:给定若干加油站信息,问能否驾驶汽车行驶一定的距离。如果能够行驶完全程,则计算最小花费。若不能行驶完全程,则最远能够行驶多长距离。

拿到这一题,首先判断汽车是否能够行驶到终点。什么情况下汽车无法行驶到终点呢?两种情况:起点根本就没有加油站,汽车无法启动;或者中途两个加油站之间的距离大于加满油后汽车能够行驶的最大距离。前者汽车行驶的最大距离为0.00,而后者最大距离为当前加油站的距离加上在这个加油站加满油后能够行驶的最大距离。在这里,需要将加油站按到杭州的距离从小到大排序。

接下来在能够行驶到终点的情况下计算最小花费。我们首先从路程来考虑,如果在路上,我们能够使用最便宜的汽油,当然就在那个加油站加油了。所以从起点开始遍历每个加油站。假设遍历到了第i个加油站,我们现在来判断在加油站i应该加多少油。设当前汽车离杭州的距离为curLen,当前加油站离杭州的距离为nodes[i].dis,加满油以后汽车能够行驶的最大距离为(dis=cmax*len)。这样就有node[i].dis <= curLen <= nodes[i].dis+dis,否则的话第i个加油站的油是不起作用的。于是在第i个加油站的作用范围内寻找有没有更为便宜的加油站,如果有,则下次使用这个加油站的油(j),这次汽车应该行驶到这个加油站,即touch=nodes[j].dis。如果没有找到更为便宜的加油站则可以在第i个加油站加满油,即touch=nodes[i].dis+dis。然后判断下次应该行驶到的距离与当前距离的关系,如果下次应当行驶到的距离大于当前距离,则汽车行驶,否则不动(也就是说上个加油站的油更便宜,后一个加油站也便宜,根本就不需要在当前加油站加油)。

思路:一开始做的时候我没有模拟加油的过程,而是直接计算从i站到k站的路费,后来怎么改都是错的,但是经过本人测试,和AC代码去的加油站是一样的,也就是说算法的大致思路是一样的,所以我推测应该是精度的问题,因此后来我模拟了加油的过程,最后代码AC。下面切入主题:
输入完数字之后,我们把加油站按照路程从小到大进行排序。在这里应该可以知道,如果第一个加油站的距离不为零,则到这就可以结束了,因为一开始车加不了油,所行驶的最大距离就是零。
如果第一个加油站的距离不为零,则先找到在最大行驶路程之内油价最便宜的那一家加油站,在遍历的过程中,假设第i个加油站的油价比当前所在站的油价还低,则直接去这个加油站,若不存在这样的加油站,我们就直接去相对其它站来说油价最低的那一个站就可以了。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

struct GasStation{
	double money;	//油价
	double distance;	//距离杭州的距离
}g[501];

bool cmp(struct GasStation a,struct GasStation b){
	if(a.distance==b.distance) return a.money<b.money;
	else return a.distance<b.distance;
}

int main()
{
	double c,distance,run,min;
	double d,m,maxdistance,oil;	//d:当前所有距离,m:最小的油费,oil;邮箱
	int n,i,j,k;
	while(scanf("%lf%lf%lf%d",&c,&distance,&run,&n)!=EOF){
		for(i=0;i<n;i++)
			scanf("%lf %lf",&g[i].money,&g[i].distance);
		sort(g,g+n,cmp);
		g[n].distance=distance;
		g[n].money=0;
		
		//如果第一站距离杭州的距离不是0
		if(g[0].distance!=0)
			printf("The maximum travel distance = 0.00\n");
		else{
			m=0;
			d=g[0].distance;
			maxdistance=run*c;//最大行程
			i=0;
			oil=0;//刚开始油箱为空
			while(1){
				k=-1;
				min=10000000000;//保证每次都有最低的油价

				//不用太在意该循环的意思,如果可以到达终点则是以j>n的条件退出的,如果到达不了终点则是以maxdistance<g[j].distance-d的条件退出的。
				for(j=i+1;j<=n&&maxdistance>=g[j].distance-d;j++){
					if(g[j].money<min){
						min=g[j].money;
						k=j;
						if(min<g[i].money)//如果存在比当前站的油价还低的站,直接结束循环去这一个站
							break;
					}
				}
				if(k==-1) break;//表示没有进入循环,说明已经到达终点,或者是最大行驶路程到不了下一站。
				double need_oil=(g[k].distance-d)/run;//到达k站所要的油
				if(min<g[i].money){
					if(oil<need_oil){//油量不够则加油至刚刚到达k站的油量
						m+=(need_oil-oil)*g[i].money;
						oil=0;//油量用完
					}
					else//油够的话就直接减去所需要的油量即可
						oil-=need_oil;
				}
				else{//如果没有比本站油价更便宜的站点,就在本站加满油,再去k站。
					m+=(c-oil)*g[i].money;//加满油
					oil=c-need_oil;
				}
				d=g[k].distance;
				i=k;
			}
			if(i!=n){
				d+=maxdistance;
				printf("The maximum travel distance = %.2lf\n",d);
			}
			else
				printf("%.2lf",m);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44888152/article/details/106789422