找回密码
 立即注册
查看: 16|回复: 0

1999年NOIP普及组旅行家的预算(洛谷P1016):贪心算法实战指南

[复制链接]
  • 打卡等级:即来则安
  • 打卡总天数:15
  • 打卡月天数:1
  • 打卡总奖励:117
  • 最近打卡:2025-08-02 15:29:27

21

主题

5

回帖

2388

积分

VIP

积分
2388
发表于 2025-7-26 17:18:35 | 显示全部楼层 |阅读模式
一、问题背景
旅行家的预算是NOIP1999普及组的经典题目,考察贪心算法在实际问题中的应用。题目描述一位旅行家需要从起点到终点,途中有若干个加油站,每个加油站油价不同,要求在有限油箱容量下规划**加油策略,使总花费最少。
二、数据结构设计struct Station {    double distance;  // 加油站距离起点的位置    double price;     // 该加油站的油价};
使用结构体存储每个加油站的信息,便于后续处理。
三、核心算法思路
  • 加油站预处理:将起点和终点也视为特殊加油站,并按距离排序
  • 可达性检查:计算满油能行驶的**距离(C*D2)

    • 优先寻找当前可达范围内比当前站更便宜的加油站
    • 若无更便宜加油站,则在当前站加满油
    • 每次只加到达下一站所需的油量

四、完整代码解析C++

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <iomanip>
  5. using namespace std;

  6. struct Station {
  7.     double distance;
  8.     double price;
  9. };

  10. int main() {
  11.     double D1, C, D2, P;
  12.     int N;
  13.     cin >> D1 >> C >> D2 >> P >> N;
  14.    
  15.     vector<Station> stations(N+2);
  16.     stations[0] = {0, P}; // 起点加油站
  17.     for (int i = 1; i <= N; ++i) {
  18.         cin >> stations[i].distance >> stations[i].price;
  19.     }
  20.     stations[N+1] = {D1, 0}; // 终点设为虚拟加油站
  21.    
  22.     // 按距离排序加油站
  23.     sort(stations.begin(), stations.end(), [](const Station& a, const Station& b) {
  24.         return a.distance < b.distance;
  25.     });
  26.    
  27.     double max_distance = C * D2; // 满油能行驶的**距离
  28.     double current_gas = 0; // 当前油量
  29.     double total_cost = 0; // 总花费
  30.     int current_station = 0; // 当前所在加油站
  31.    
  32.     // 检查是否能到达**个加油站
  33.     if (stations[1].distance > max_distance) {
  34.         cout << "No Solution" << endl;
  35.         return 0;
  36.     }
  37.    
  38.     while (current_station <= N) {
  39.         // 寻找下一个比当前便宜的加油站
  40.         int next_station = current_station + 1;
  41.         double min_price = stations[current_station].price;
  42.         int cheapest_station = -1;
  43.         
  44.         // 在可达范围内寻找**的加油站
  45.         while (next_station <= N+1 &&
  46.                stations[next_station].distance - stations[current_station].distance <= max_distance) {
  47.             if (stations[next_station].price < min_price) {
  48.                 min_price = stations[next_station].price;
  49.                 cheapest_station = next_station;
  50.                 break; // 找到**个更便宜的加油站就停止
  51.             }
  52.             next_station++;
  53.         }
  54.         
  55.         if (cheapest_station != -1) {
  56.             // 计算需要加的油量
  57.             double distance = stations[cheapest_station].distance - stations[current_station].distance;
  58.             double needed_gas = distance / D2 - current_gas;
  59.             if (needed_gas > 0) {
  60.                 total_cost += needed_gas * stations[current_station].price;
  61.                 current_gas = 0;
  62.             } else {
  63.                 current_gas -= distance / D2;
  64.             }
  65.             current_station = cheapest_station;
  66.         } else {
  67.             // 没有更便宜的加油站,加满油到最远的加油站
  68.             if (stations[current_station].distance + max_distance >= D1) {
  69.                 // 可以直接到达终点
  70.                 double distance = D1 - stations[current_station].distance;
  71.                 double needed_gas = distance / D2 - current_gas;
  72.                 if (needed_gas > 0) {
  73.                     total_cost += needed_gas * stations[current_station].price;
  74.                 }
  75.                 cout << fixed << setprecision(2) << total_cost << endl;
  76.                 return 0;
  77.             }
  78.             
  79.             // 检查是否能到达下一个加油站
  80.             next_station = current_station + 1;
  81.             if (next_station > N ||
  82.                 stations[next_station].distance - stations[current_station].distance > max_distance) {
  83.                 cout << "No Solution" << endl;
  84.                 return 0;
  85.             }
  86.             
  87.             // 加满油到下一个加油站
  88.             total_cost += (C - current_gas) * stations[current_station].price;
  89.             current_gas = C - (stations[next_station].distance - stations[current_station].distance) / D2;
  90.             current_station = next_station;
  91.         }
  92.     }
  93.    
  94.     cout << fixed << setprecision(2) << total_cost << endl;
  95.     return 0;
  96. }
复制代码

五、常见错误与优化
  • 可达性检查:必须首先检查能否到达**个加油站
  • 浮点数精度:使用double类型并控制输出精度
  • 边界条件:特别注意终点处理和无解情况

来源:竞赛学习
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

SEO网站 ( 冀ICP备2025113422号-2 )|网站地图

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表