codeup 2031 PAT 1033 To Fill or Not to Fill

codeup 2031 / PAT 1033 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

分析:
本题求全程最短花费,要获得最优结果就需要中间的每步策略都是最优的,所以本题是贪心问题。
把每个收费站等效成一个具有结点:
{
double p; //单价
int s; //离起点的距离
};
为了便于处理也把终点等效为单价为0,距离为D的结点。
用sort()函数按照与终点的距离递增排序后:

  1. 若除了终点外只有一个结点
    ① 若第一个结点位置不在起始位置,输出能行驶最大距离为0.00
    ②否则,判断是否能到达终点

  2. 否则 若当前的能力范围内能探寻到下一结点,比较当前结点价格与下一个结点价格哪个小
    ① 若当前结点价格大于或等于下一个结点价格,那么下一站就行驶到这个结点,加的油也只要够行驶到选定的结点就行,更新总花费,更新选定的结点为当前结点。(注意:所加的油量要减去油箱中原本剩余的油量,由于本次加的油只能跑到下一结点,要更新油箱剩余油量为0)
    ②若当前结点价格小于下一个结点价格,遍历在当前结点能力范围(加满油最远能行驶的范围)内的结点,选定价格最低的结点。(注意:若结点价格小于或等于当前结点价格,要立刻退出比较break 选定这个结点,即下一站赞就行驶到这个结点)
    a.若选定的结点价格大于当前结点价格,要把油箱加满,并把油箱剩余量更新为行驶到选定结点的剩余量
    b.若选定的结点价格大于当前结点价格,只要把加油到能行驶到选定结点就行,并把油箱剩余量更新为0

  3. 在当前的能力范围内找不到下一结点,即不能抵达终点的情况,注意要精确到小数点后两位输出。

推荐样例输入

//sample 1:
10 200 20 5
4 0
5 50
3 100
2 120
100 140
//sample 2:
10 200 20 2
5 9
3 89

推荐样例输出

//sample 1:
31.00
//sample 2:
The maximum travel distance = 0.00

AC代码

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

struct Node
{
	double p;
	int s;
};

bool cmp(Node a,Node b)
{
	return a.s<b.s;
}


int main()
{
	int Cmax,D,Dv,n;
	Node nodes[510];
	double ans;
	double left;
	Node plow;
	int plowid;
	bool flag=false;

	while(scanf("%d%d%d%d",&Cmax,&D,&Dv,&n) != EOF )
	{

		for(int i=0;i<n;i++)
		{
			scanf("%lf %d",&nodes[i].p,&nodes[i].s);
		}

		nodes[n].p=0;
		nodes[n].s=D;
		int capacity=Cmax*Dv;
		ans=0;
		left=0;
		flag=false;
		bool sller=false;

		sort(nodes,nodes+n+1,cmp);

		if(nodes[0].s == 0  &&  n>1  )
		{
			Node pn=nodes[0]; 

			for(int i=1;i<=n;)
			{
				if(capacity>= (nodes[i].s - pn.s ))
				{
					if(pn.p >= nodes[i].p )  
					{
						ans+= pn.p * ((double)(nodes[i].s-pn.s)/Dv - left);
						pn=nodes[i];
						left=0;  //只需能跑到下一结点就行,不剩油
						i++;
					}
					else
					{
						plow=nodes[i];
						plowid=i;
						i++;
						while(capacity>= (nodes[i].s - pn.s ) &&  i<=n )
						{
							if(plow.p >= nodes[i].p ) //考虑最后3 5 2 0 的情况  4 5 3 2 若最小值已被非终点结修改过,终点就不能再修改它
							{
								plow=nodes[i];
								plowid=i;
			                   if(nodes[i].p<= pn.p ) break;
							}
								
							i++;
						}
						if(pn.p<= plow.p)
						{
							ans+=pn.p * (Cmax - left);   //加满
							left = Cmax- ((double)(nodes[plowid].s-pn.s))/Dv;
						}
						else
						{
							ans+= pn.p * ((double)(nodes[plowid].s-pn.s)/Dv - left);
							left=0;
						}

						pn=nodes[plowid];
						i=plowid+1;
					}
				}

				else 
				{
					flag=true;
					printf("The maximum travel distance = %d.00\n",pn.s + capacity);
					break;
				}
				
			}
			if(!flag)
			{
				printf("%.2f",ans);
			}
		
			
		}
		else
		{
			if(n==1)
			{
				if(nodes[0].s == 0)
				{
					if(capacity >= D )  printf("%.2f\n", (double)D/Dv*nodes[0].p);
					
					else printf("The maximum travel distance = %d.00\n",capacity);
				}
			}
			else printf("The maximum travel distance = 0.00\n");
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值