[NOIP1999 提高组] 旅行家的预算

旅行家的预算

问题描述

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 D1​、汽车油箱的容量 C(以升为单位)、每升汽油能行驶的距离 D2​、出发点每升汽油价格P和沿途油站数 N(N 可以为零),油站 i 离出发点的距离 Di​、每升汽油价格 Pi​(i=1,2,…,N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution。
输入格式
第一行,D1​,C,D2​,P,N。
接下来有 N 行。
第i+1 行,两个数字,油站i 离出发点的距离Di​ 和每升汽油价格 Pi​。
输出格式
所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution。
输入输出样例
输入
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
输出
26.95
说明/提示
N≤6,其余数字≤500。

解题分析

算法: 贪心算法,贪心策略是每次找到下一个应到达并停下加油的加油站,并求得局部最优解。
代码实现: 递归或循环。

算法描述:包含终点共N + 2个加油站,按照这N + 2个油站循环一遍,步骤如下:
  1. 按照各油站与起点的距离从近到远排个序,终点可以认为是油价为零的加油站
  2. 从前往后刷一遍,如果某两个相邻油站的距离大于满箱油能行驶的距离,则输出 No Solution。
  3. 从前往后查找油站:
  4. 情况a: 如果在满箱油能行驶的范围内,能找到油价不大于当前油站价格的油站,那么就补加上若干升油,使得油箱里的油刚好能够行驶到那个油站。这时油箱清零,并且如果刚好是终点,则结束程序,否则,循环执行 3。
    情况b: 如果在满箱油能行驶的范围内,各油站的价格均大于当前油站,则在当前油站把油箱加满,奔着最便宜的油站开过去(如有多个价格一样的便宜油站,奔着最远的开过去)。 更新油箱剩余油料,循环执行 3。
代码实现
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
//greedy algorithm
double JL, C,d, P;
int n;
struct ost{//油站类型
	double s;
	double p;
	bool operator<(const ost & c) const
		return s < c.s;
};
ost gas[9];
double zp;

int main()
{
	cin >> JL >> C >> d >> P >> n;
	double ls = d * C;//满箱距离 
	gas[0].p = P, gas[0].s = 0;
	
	for(int i =1; i < n + 1; i ++)
	{
		float s,p;
		cin >> s >> p;
		gas[i] = {s,p};	
	}
	gas[n + 1] = {JL, 0};
	sort(gas + 1,gas+n + 2);
	
	for(int i = 1; i <= n + 1; i ++)
	  if(gas[i].s - gas[i-1].s > ls)
	  {
	  	cout << "No Solution" << endl;
	  	return 0;
	  } 
	    
	double yy = 0;//余油料 
	for(int i = 0; i <= n + 1; )//enum
	{
		//能找到小于等于当前点价格的油站
		int ns = -1, k = i + 1;
		while( k <= n +1  && gas[k].p > gas[i].p) k ++;
		if(!(gas[k].s - gas[i].s > ls))  ns =k;//下一个低价油站可达 
		if(ns != -1)//情况a
		{
			zp += ((gas[ns].s - gas[i].s) /d - yy) * gas[i].p;//补充刚好到那的油料 
			if(ns == n + 1)
			{
				printf("%.2lf\n",zp);
				return 0;
			}
			yy = 0; //油箱清零
			i = ns; //更新循环变量
		 } 
		//情况b:不能找到,求其次 
		if(ns == -1) //加满当前便宜油, 朝着后面可达范围里的相对最便宜的站开过去
		{
			zp += (C -yy ) * gas[i].p;//FULL BOX
			int k = i + 1;
			double yj = gas[i + 1].p;
			int rps ;
			
			while(!(gas[k].s - gas[i].s > ls)  ) 
			{
				if(!(gas[k].p > yj))
				    yj = gas[k].p, rps = k;//rps 为最远的最便宜油站 
				    
				k ++;
			 }
			 yy =  C - (gas[rps].s - gas[i].s) / d;//更新剩余油料
			 i = rps;//更新循环变量,即出发点
			 
		}
	}
  return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值