查看: 29|回复: 0

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

[复制链接]
  • TA的每日心情
    郁闷
    前天 10:01
  • 签到天数: 32 天

    [LV.5]常住居民I

    31

    主题

    0

    回帖

    62

    积分

    注册会员

    Rank: 2

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

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

    四、完整代码解析
    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类型并控制输出精度
    • 边界条件:特别注意终点处理和无解情况

    来源:竞赛学习

    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

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