<基础训练>旅行家的预算(贪心算法)

问题描述
  一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1、汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,……N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
输入格式
  第一行为4个实数D1、C、D2、P与一个非负整数N;
  接下来N行,每行两个实数Di、Pi。
输出格式
  如果可以到达目的地,输出一个实数(四舍五入至小数点后两位),表示最小费用;否则输出“No Solution”(不含引号)。
样例输入
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
样例输出

26.95


思路:是找在最大行驶距离内寻找比当前便宜的加油站,然后判断是否能一次到达,不能的话先加满,然后一个一个判断直到剩下的油量不足到下一个加油站就加油,加适量。

于是有以下2 situations:

1.这个站点j 就是pos 
  再细分两种情况:
    1.从pos就可以走到终点
      于是我们把油加到刚好到达终点即可
         cost += ((d[i] - d[pos]) / d2 - remain)*p[pos];就得到了最后答案。
          remain是当前剩余的油
    2.从pos不能一把走到终点
      于是,从当前位置走,走到哪里加油都不够在pos这里加油划算。
      所以加满。
2.这个站点j 是在pos后面的某个站点
  也有两种情况
    1.当前剩余的油remain不够走到j
      于是我们,把油加来刚好能够走到j就行了。(因为j这里好好便宜!)
    2.剩余的油remain足够,直接开过去就行了。
########具体操作见如下代码

#include<iostream>  
#include<algorithm>  
#include<iomanip>  
using namespace std;
double d[10000], p[10000];   //出发点每升汽油的价格p
int main()
{
	ios::sync_with_stdio(false);  //取消cin在stdin上的同步,增加cin的读取效率
	double d1, c, d2;  
	int n;   //沿途油站数目
	cin >> d1 >> c >> d2 >> p[0] >> n;
	d[n + 1] = d1;   //第n个油站后即为最后的站点
	for (int i = 1; i <= n; i++)  //输入每一个油站离出发点的距离以及每个站点汽油的价格
	{
		cin >> d[i] >> p[i];
	}
	int pos = 0;
	double remain = 0, cost = 0;
	do
	{
		bool found = false;   //判定能不能到达
		for (int i = pos + 1; i <= n + 1 && d[i] <= d[pos] + c*d2; i++) //循环判断加满油能不能到达下一个加油站
		{
			if (p[i] < p[pos])   //判断下个站点汽油的价格是不是比这个pos站点汽油的价格小
			{
				if (d[pos] + remain*d2 >= d[i])  //若是剩余的油足够,刚好开过去
				{
					remain -= (d[i] - d[pos]) / d2;    //剩余的油减少,减少量就是从一个站点到下一个站点用到的油
				}
				else  //剩余的油不够
				{
					cost += ((d[i] - d[pos]) / d2 - remain)*p[pos];  //还需要加的油花费的价钱,不用加满
					remain = 0;   //到达下一个站点恰好没油了,所以剩余汽油量清0
				}
				pos = i;
				found = true;
				break;
			}
		}
		if (!found)
		{
			cost += (c - remain)*p[pos];  //不能到达前花费了多少钱
			remain = c - (d[pos + 1] - d[pos]) / d2;     //还剩多少油
			if (remain >= 0) pos++;  //小于0,油根本不够到达下一个站点,大于0,代表可以去下一个加油站
			else
			{
				cout << "No Solution";
				return 0;
			}
		}
	} while (pos <= n);  //循环条件:没到达终点
	cout.setf(ios::fixed);  //以定点形式显示浮点数
	cout << setprecision(2) << cost;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值