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: C​max​​ (≤ 100), the maximum capacity of the tank; D (≤30000), the distance between Hangzhou and the destination city; D​avg​​ (≤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: P​i​​, the unit gas price, and D​i​​ (≤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

 吾思:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct station
{
	double price, dist;
};

bool cmp1(station a, station b)
{
	return a.dist < b.dist;
}

const double inf = 999999.0;

int main()
{
	
	//freopen("in.txt", "r", stdin);
	double Cmax, d, Davg, cost = 0.0;
	int n;
	scanf("%lf%lf%lf%d", &Cmax, &d, &Davg, &n);
	vector<station> stations(n + 1);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf %lf", &stations[i].price, &stations[i].dist);
	}

	sort(stations.begin(), stations.end(), cmp1);

	if (stations[1].dist != 0)//初始没油,如果第一个站dist不是0,一点油也没法加。
	{// 测试点2
		printf("The maximum travel distance = 0.00");
		return 0;
	}


	int i = 2, k, over = 0;
	double tankleft = 0.0, nowPrice = stations[1].price, maxdis = Cmax * Davg, nowDist = 0.0,preprice;
	while (nowDist < d)
	{

		double minPrice = inf;
		int flag = 0;
		if (nowDist + tankleft * Davg >= d)//油箱里剩的油能跑到终点
		{
			cost = cost - (tankleft - (d - nowDist) / Davg)*preprice;
			printf("%.2lf", cost);
			return 0;
		}
		//if (nowDist+maxdis>=d)//加满油能跑到终点
		//{
		//	cost += ((d - nowDist) / Davg - tankleft)*nowPrice;
		//	break;
		//}

		for (; i <= n && stations[i].dist <= nowDist + maxdis; i++)
		{
			if (stations[i].price < nowPrice)//有比当前低的,直接去那个低的就行了
			{
				if ((stations[i].dist - nowDist) / Davg >= tankleft)//剩的油不够跑到下一个便宜的站
				{
					cost += (((stations[i].dist - nowDist) / Davg) - tankleft)* nowPrice;
					preprice = nowPrice;
					//cout << "cost  " << cost << endl;
					tankleft = 0.0;
				}
				else//剩的油足够跑到下个站了
				{
					tankleft = tankleft - (stations[i].dist - nowDist) / Davg;
				}
				nowPrice = stations[i].price;
				nowDist = stations[i].dist;
				//cout << "now " << nowDist << endl;

				k = i;
				flag = 1;
				break;
			}
			if (stations[i].price < minPrice)//都比当前高,找个最低的
			{
				minPrice = stations[i].price;
				k = i;
			}
		}
		if (flag == 0 && minPrice != inf)//跑到的站都比当前价高,加满油去跑得到的站中最低的
		{
			if (nowDist + maxdis >= d)
			{//跑得到的站都比当前高,但是加满油能到终点
				cost += ((d - nowDist) / Davg - tankleft)*nowPrice;
				preprice = nowPrice;
				printf("%.2lf", cost);
				return 0;
			}
			else//加满油还到不了终点,只好去那个跑得到的站中最低的
			{
				cost += (Cmax - tankleft)*nowPrice;
				preprice = nowPrice;
				//cout << "cost" << cost << endl;
				tankleft = Cmax - (stations[k].dist - nowDist) / Davg;
				nowDist = stations[k].dist;
				//cout << "now " << nowDist << endl;
				nowPrice = minPrice;
			}


		}
		if (flag == 0 && minPrice == inf)//不考虑首尾,加满油都没跑到下一个站,因为flag和minPrice都没有变,说明没满足for循环的条件。
		{
			nowDist += maxdis;
			printf("The maximum travel distance = %.2f", nowDist);
			//over = 1;
			return 0;
		}
		i = k + 1;
		if (k == n)
		{
			if (stations[n].dist + Cmax * Davg < d)//最后一个加油站,满也到不了目的地
			{//测试点1
				printf("The maximum travel distance = %.2lf", stations[n].dist + Cmax * Davg);
				return 0;
			}
			else
			{
				cost += ((d - nowDist) / Davg - tankleft)*nowPrice;
				preprice = nowPrice;
				//cout << "lastcost " << ((d - nowDist) / Davg - tankleft)*nowPrice <<" "<< cost<<endl;  //调试用的,输出值,看看咋回事儿
				printf("%.2lf", cost);
				return 0;
			}
		}

	}

	printf("%.2lf", cost);
	return 0;
}

 测试点5不过:

 

 柳的思维是把终点当作一个price为0,dist为d 的油站加进去:我只是用i去记录实际到达的站的下标并直接用油箱剩余解决贪心关键(加满油):加满油而没用空油箱的遗留问题。贪心关键是趁油价便宜加满油。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct station
{
	double price, dist;
};

bool cmp(station a, station b)
{
	return a.dist < b.dist;
}

const int inf = 999999;

int main()
{
	//freopen("in.txt", "r", stdin);
	//input
	double Cmax, d, Davg;
	int n;
	scanf("%lf%lf%lf%d", &Cmax, &d, &Davg, &n);
	vector<station> stas(n + 1);
	stas[n].price = 0;
	stas[n].dist = d;
	for (int i = 0; i < n; i++)
	{
		scanf("%lf %lf", &stas[i].price, &stas[i].dist);
	}

	sort(stas.begin(), stas.end(), cmp);
	if (stas[0].dist != 0)//初试没油,如果第一个站的dist不是0,就没法到第一个站去加油,so出师未捷身先死。
	{
		printf("The maximum travel distance = 0.00");
		return 0;
	}
	double cost = 0, nowDis = 0, nowPrice = stas[0].price,  tankleft = 0, maxdis = Cmax * Davg;
	int i = 1, k;//k记录实际到达的站的下标
	while (nowDis < d)
	{
		int flag = 0;
		double minPrice = inf;
		for (; i <= n && stas[i].dist <= nowDis + maxdis; i++)//在能跑到的站中找符合条件的
		{
			if (stas[i].price < nowPrice)//能跑到的站中有个比当前油价便宜的,就直接去,因为贪心算法,这样费用少
			{
				cost += ((stas[i].dist - nowDis) / Davg - tankleft)*nowPrice;
				tankleft = 0;
				nowPrice = stas[i].price;
				nowDis = stas[i].dist;
				flag = 1;
				k = i;
				break;
			}
			if (stas[i].price < minPrice)//如果没有比当前油价便宜的,只好找能跑到的站中最便宜的那家,虽然比当前油价高
			{
				minPrice = stas[i].price;
				k = i;//记录最低那家的下标,我们就去这家
			}
		}
		if (flag == 0 && minPrice != inf)//注意:这是贪心的关键,因为后面价高,趁现在便宜,把油箱加满,这样费用才最低。
		{
			cost += (Cmax - tankleft)*nowPrice;
			tankleft = Cmax - (stas[k].dist - nowDis) / Davg;
			nowDis = stas[k].dist;
			nowPrice = minPrice;
		}
		if (flag == 0 && minPrice == inf)//flag==0说明没有找到比当前低的,minPrice==inf说明没有进入if(stas[i].price<minPrice)分支中判断,因为minPrice=inf,只要进入分支,肯定会有比inf低的,minPrice必定不会==inf。
		{//说明没有满足for循环里的条件,也就是下个油站的距离>当前位置加满油能跑到的距离,即到不了下个油站。
			printf("The maximum travel distance = %.2lf", nowDis + maxdis);
			return 0;
		}
		i = k + 1;//将i赋值为实际到达的油站的下一个油站的下标。继续进行下一轮寻找应该去哪个站加油。
	}
	printf("%.2f", cost);
	return 0;
}

另一种,容易看懂,分的很清楚:

#include <cstdio>
#include <algorithm>
using namespace std;
struct Sta{
	double price, distance;
}sta[510];
bool cmp(Sta a, Sta b){
	return a.distance<b.distance;
}
int main(){
	double cmax,d,davg;
	int n;
	scanf("%lf%lf%lf%d",&cmax, &d, &davg,&n);
	for (int i=0; i<n; i++){
		scanf("%lf %lf",&sta[i].price, &sta[i].distance);
	}
	sta[n].price=0;
	sta[n].distance=d;
	sort(sta,sta+n+1,cmp);
	if (sta[0].distance){
		printf("The maximum travel distance = 0.00");//出不了杭州 直接return 
		return 0;
	}else {
		double maxDis=davg*cmax;//加满油能跑的最大距离
		int now=0;//现在在第0号加油站 
		double distance=0, payment=0, nowTank=0;
		int flag=1;
		while(now<n){//没到终点
			distance=sta[now].distance+maxDis;//此时加满油能到的最远的地方
			if (distance<sta[now+1].distance) {
				printf("The maximum travel distance = %.2f",distance);//加满油都跑不到下一站 直接return
				return 0;
			}else {//我能跑到其他加油站
				flag=1;
				for (int i=now+1; sta[i].distance<=distance && i<=n; i++){
					if (sta[i].price<sta[now].price){//从下一站开始 直到我能跑到的最大距离 只要有加油站价格比我低 我就跑到那个加油站
						double dis=sta[i].distance-sta[now].distance;
						double needGas=dis/davg;
						if (nowTank>=needGas){
							nowTank-=needGas;//我不用加油 直接跑到那个加油站
						}else {
							payment+=(needGas-nowTank)*sta[now].price;//我需要加油才能跑到下一个比我还便宜的加油站 
							nowTank=0;//我加的油此刻 正好能让我跑到下一比现在便宜的加油站 跑到下一个加油站时 油箱就空了
						}
						now=i;//我现在跑到了 下一个便宜的加油站了
						flag=0;//有加油站比我最开始的加油站便宜
						break;
					}
				}
				if (flag){//在我能跑到的范围内 所有加油站都比现在的贵
					int min=now+1;
					for (int i=now+2; sta[i].distance<=distance && i<=n; i++){
						if (sta[min].price>sta[i].price) {
							min=i;
						}
					}//那就找出 其余加油站中 最便宜的那个加油站吧 
                    //在现在的这个加油站 一次性加满油 跑到下一个加油站
					double dis=sta[min].distance-sta[now].distance;
					double needGas=dis/davg;
					payment+=(cmax-nowTank)*sta[now].price;
					nowTank=cmax-needGas;//跑到下一加油站的时候 油箱油就要损失needGas了
					now=min;
				}
			}
		}
		printf("%.2f",payment);
	}
}

 二刷:柳

 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct node
{
	double price;
	int dis;
};

bool cmp(node a, node b)
{
	return a.dis < b.dis;
}

const int inf = 999999;
int main()
{
	//freopen("in.txt", "r", stdin);
	int n,d ;
	double cmax,  davg;
	cin >> cmax >> d >> davg >> n;
	double fullcanrun = cmax * davg;
	vector<node> v(n);
	for (int i = 0; i < n; i++)
	{
		cin >> v[i].price >> v[i].dis;
	}
	v.push_back(node{ 0.00,d });
	sort(v.begin(), v.end(), cmp);
	if (v[0].dis != 0)
	{
		cout << "The maximum travel distance = 0.00" << endl;
		return 0;
	}
	double nowdis = 0, nowgasindex = 0, cost = 0,tankleft=0;
	int i = 0,minpriceindex;
	double nowprice = v[nowgasindex].price;
	while (nowdis < d)
	{
		int flag = 0;
		double minprice = inf;
		for (i=nowgasindex+1; v[i].dis <= nowdis + fullcanrun; i++)
		{
			if (v[i].price<nowprice)
			{
				cost += ((v[i].dis - nowdis) / davg - tankleft)*nowprice;
				nowdis = v[i].dis;
				tankleft = 0;
				flag = 1;
				nowgasindex = i;
				nowprice = v[nowgasindex].price;
				break;
			}
			else
			{
				if (v[i].price<minprice)
				{
					minprice = v[i].price;
					minpriceindex = i;
				}
			}
		}
		if (flag==0&&minprice!=inf)
		{
			cost += (cmax - tankleft)*nowprice;
			tankleft = cmax - (v[minpriceindex].dis - nowdis) / davg;
			nowdis = v[minpriceindex].dis;
			nowgasindex = minpriceindex;
			nowprice = v[nowgasindex].price;
		}
		if (flag==0&&minprice==inf)
		{
			printf("The maximum travel distance = %.2f\n", nowdis + fullcanrun);
			return 0;
		}
	}
	printf("%.2f\n", cost);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值