【1999NOIP普及组】(洛谷P1016)旅行家的预算解题报告(附代码+注释)
一、题目解读
题目要求解决旅行家从起点到终点(D1公里)的预算问题,需在沿途N个加油站中规划加油策略,使总费用最小化。每个加油站有不同油价和距离,汽车每升油可行驶D2公里,初始油量为C升,终点无加油站。需在满足油量限制的条件下,找到最经济的加油方案。
二、解题思路
1. 虚拟终点:将终点视为价格为零的虚拟加油站,确保算法完整性。
2. 距离排序:按距离对加油站排序,便于按顺序遍历。
3. 贪心选择:每次优先选择当前可达范围内最便宜的加油站,避免回溯。
4. 油量管理:实时计算当前油量能否到达下一站,按需加油至恰好可到达最远点。
三、解题步骤
1. 数据输入:读取起点距离D1、初始油量C、终点距离D2、初始油价P及N个加油站信息。
2. 构造虚拟终点:添加距离为D1、油价为0的虚拟终点站。
3. 排序加油站:按距离升序排序,确保遍历顺序正确。
4. 初始化变量:记录当前油量、总费用、当前位置。
5. 核心循环:
寻找当前可达范围内最便宜的加油站(贪心)。
计算到达该站所需油量,若当前油量不足则补充。
更新总费用与位置,直至到达终点。
6. 边界判断:若无法到达第一个加油站,直接输出无解。
四、代码与注释
#include <iostream> #include <vector> #include <algorithm> #include <iomanip> using namespace std; struct Station { // 定义加油站结构体 double distance; // 距离起点距离 double price; // 油价 }; int main() { double D1, C, D2, P; // 输入参数 int N; cin >> D1 >> C >> D2 >> P >> N; vector<Station> stations(N+2); // 包含虚拟起点和终点 stations[0] = {0, P}; // 起点加油站 for (int i = 1; i <= N; ++i) { cin >> stations[i].distance >> stations[i].price; } stations[N+1] = {D1, 0}; // 虚拟终点站 // 按距离排序 sort(stations.begin(), stations.end(), [](const Station& a, const Station& b) { return a.distance < b.distance; }); double max_distance = C * D2; // 满油可行驶距离 double current_gas = 0; // 当前油量 double total_cost = 0; // 总费用 int current_station = 0; // 当前位置 // 检查能否到达第一个加油站 if (stations[1].distance > max_distance) { cout << "No Solution" << endl; return 0; } while (current_station <= N) { int next_station = current_station + 1; double min_price = stations[current_station].price; int cheapest_station = -1; // 寻找可达范围内最便宜的加油站 while (next_station <= N+1 && stations[next_station].distance - stations[current_station].distance <= max_distance) { if (stations[next_station].price < min_price) { min_price = stations[next_station].price; cheapest_station = next_station; break; // 找到第一个更便宜的站即退出 } next_station++; } if (cheapest_station!= -1) { // 计算到达下一站所需油量 double distance = stations[cheapest_station].distance - stations[current_station].distance; double needed_gas = distance / D2 - current_gas; if (needed_gas > 0) { // 若需要加油 total_cost += needed_gas * stations[current_station].price; // 按当前站油价计费 current_gas = max_distance; // 补满油 } else { current_gas -= needed_gas; // 否则消耗油量 } current_station = cheapest_station; // 更新位置 } else { // 若找不到更便宜的站,直接前往终点 total_cost += (D1 - stations[current_station].distance) / D2 * stations[current_station].price; break; } } cout << fixed << setprecision(2) << total_cost << endl; // 输出结果 return 0; }
五、总结
本解法通过动态规划思想,将问题转化为“在固定顺序下选择最优加油站”的贪心问题,避免了复杂的回溯。关键点在于:
1. 利用虚拟终点简化边界处理;
2. 排序后顺序遍历降低时间复杂度;
3. 实时计算油量差,避免冗余加油。
该算法时间复杂度为O(NlogN)(排序),空间复杂度O(N),适用于中小规模数据。
原创内容 转载请注明出处