旅行家的预算
问题描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 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个油站循环一遍,步骤如下:
- 按照各油站与起点的距离从近到远排个序,终点可以认为是油价为零的加油站。
- 从前往后刷一遍,如果某两个相邻油站的距离大于满箱油能行驶的距离,则输出 No Solution。
- 从前往后查找油站:
- 情况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;
}