题目传送门:https://www.luogu.com.cn/problem/P1016
题目描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市( 假设出发时油箱是空的)。给定两个城市之间的距离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”。
输入输出样例
输入 #1
275.6 11.9 27.4 2.8 2 102.0 2.9 220.0 2.2输出 #1
26.95说明/提示
N ≤ 6,其余数字 ≤ 500
题目分析 (含部分代码)
和上次的驾车旅游差不多的类型(传送门:https://blog.csdn.net/zjsru_Beginner/articl/details/119850936),按照题目要求可以将汽车在它停下加油的每个加油站进行简单情况分析:汽车在当前加油站时要寻找下一个油费便宜的加油站,不断寻找直至到达目的地。
无法到达目的地的情况只有一种,汽车就算加满油也到不了任何一个加油站,或者加满油也到达不了目的地。
for (int i = 1; i <= N; i++)//输入N个加油站距离出发地的距离和相应油价 { cin >> a[i].d >> a[i].p; if (a[i].d - a[i - 1].d > max_x)//判断是否能到达目的地(max_x为汽车满油所能行驶的最大距离) { cout << "No Solution"; return 0; } }
能到达目的地时在加油站有这两种情况:1.在汽车所能行驶的最大距离中如果有油费比当前更便宜的加油站就在当前加油站加油加到刚好能到达此加油站的油量,然后再继续寻找下一个加油站;2.在汽车所能行驶的最大距离中如果没有油费比当前更便宜的加油站,就在当前加油站加满油,然后再到下一个加油站,这样能够用较为便宜的油去多行驶一段距离来节省总开销。
在汽车能行驶的最大距离寻找后面油费最便宜的加油站
for (int i = now + 1; i <= N; i++)//now为当前加油站,pay为假定在当前加油站的花费 { if (a[i].p < pay && a[i].d-a[now].d <= max_x)//在能走到的距离后面有油费最便宜的加油站 { pay = a[i].p; n = i; } }
在加油站的两种情况:加满油还是加到刚好能到达下一个油费比较便宜的加油站
if (a[now].p < pay)//当前加油站的油费和后面能走到的加油站相比最便宜 { cost += (L - last) * a[now].p;//加油加满 last = L - (a[n].d - a[now].d) / km; } else//如果在后面有油费更便宜的加油站 { cost += ((a[n].d - a[now].d) / km - last) * a[now].p; last = 0;//刚好到达该加油站 }
到达目的地
if (a[now].d + max_x >= D && a[now].p <= pay)//以最省钱的方式到达目的地 { cost += ((D - a[now].d) / km - last) * a[now].p; printf("%.2f", cost); return; }
整体代码(已ac)
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
#define S 999999
float D, L, km, P;//分别为两城市距离,油箱容量,每升油能行驶的距离,出发点每升汽油价格
int N,n;//分别为沿途油站数和假定最小花费所处的加油站
//假定在加油站加油的花费
float max_x;//汽车满油能行驶的最大距离
float cost = 0;//旅行总开销
struct jiayouzhan
{
float d;
float p;
}a[10];//每个加油站距初始地的距离d和每升汽油的价格p
bool cmp(jiayouzhan a, jiayouzhan b)
{
return a.d < b.d;
}
void travel(int now, float last)//开始旅行
{
float pay = S;
for (int i = now + 1; i <= N; i++)
{
if (a[i].p < pay && a[i].d - a[now].d <= max_x)//寻找后面油费最便宜的加油站
{
pay = a[i].p;
n = i;
}
}
if (a[now].d + max_x >= D)//到达目的地
{
cost += ((D - a[now].d) / km - last) * a[now].p;
printf("%.2f", cost);
return;
}
if (a[now].p < pay)//当前加油站的油费和后面能走到的加油站相比最便宜
{
cost += (L - last) * a[now].p;
last = L - (a[n].d - a[now].d) / km;
}
else//如果在后面有油费更便宜的加油站
{
cost += ((a[n].d - a[now].d) / km - last) * a[now].p;
last = 0;
}
travel(n, last);//继续旅行
}
int main()
{
cin >> D >> L >> km >> P >> N;//第一行的数据输入
a[0].d = 0;
a[0].p = P;//初始地为第1个加油站,油价为P
max_x = L * km;
for (int i = 1; i <= N; i++)
{
cin >> a[i].d >> a[i].p;
if (a[i].d - a[i - 1].d > max_x)//判断是否能到达目的地
{
cout << "No Solution";
return 0;
}
}
sort(a + 1, a + N + 1, cmp);//将得到的加油站的距离按照距出发地从近到远排序
travel(0, 0);//当前位于出发地且油箱油量为0
return 0;
}
其中数据中的加油站距离起始地点的距离不是按从小到大的顺序排列的,因此要先对其进行排序,题目所给的数据范围较小,数据范围扩大后可能需要进一步更改
计算机204 zjr