题目

With highways available, driving a car from Hangzhou to any other city is easy. But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time. Different gas station may give different price. You are asked to carefully design the cheapest route to go.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 positive numbers: C​max​​ (≤ 100), the maximum capacity of the tank; D (≤30000), the distance between Hangzhou and the destination city; D​avg​​ (≤20), the average distance per unit gas that the car can run; and N (≤ 500), the total number of gas stations. Then N lines follow, each contains a pair of non-negative numbers: P​i​​ , the unit gas price, and D​i​​ (≤D), the distance between this station and Hangzhou, for i=1,⋯,N. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print the cheapest price in a line, accurate up to 2 decimal places. It is assumed that the tank is empty at the beginning. If it is impossible to reach the destination, print The maximum travel distance = X where X is the maximum possible distance the car can run, accurate up to 2 decimal places.

Sample Input 1:

50 1300 12 8

6.00 1250

7.00 600

7.00 150

7.10 0

7.20 200

7.50 400

7.30 1000

6.85 300

Sample Output 1:

749.17

Sample Input 2:

50 1300 12 2

7.10 0

7.00 600

Sample Output 2:

The maximum travel distance = 1200.00

题目解读

题目大意:汽车从杭州出发可以通过高速公路去任何城市,但是油箱的容量是有限的,路上有很多加油站,每个加油站的价格不同,为汽车设计一个从杭州到终点的最便宜的加油策略。

输入:第一行:Cmax表示油箱最大容量,D表示杭州到目的地的距离,Davg表示平均每单位的汽油可以让汽车行驶的距离,N表示途中加油站的数量;接下来 N 行:给出给个加油站的单位油价Pi和杭州(起点)到这个站点的距离Di

输出:求汽车从杭州到终点的最少花费(精确到两位小数)。如果不能够到达,就输出汽车能够行驶的最大距离(精确到两位小数)。

思路分析

核心思想:贪心算法(每次寻找局部最优,在最便宜的加油站加最多的油)。

前期准备:

  • 最终输出无论是距离还是价格都要求精确到两位小数,虽然从给出的输入数据来看,距离、邮箱容量等好像都是整数,但为了操作方便,避免运算过程精度丢失,我们全都用double保存。(再说了,它给出的数据说不定就是坑你的呢?)
  • 设置结构体数组保存每个加油站的单价和到杭州的距离。
  • 按照到杭州的距离对结构体数组排序,因为输入是无序的。
  • 排序完判断第1个结构体到杭州的距离是否为0,也就是说最近的加油站是不是在起点。因为题目说了假定刚开始邮箱没有油,那么如果起点处没有加油站,就比欸想开车了,直接输出并返回吧。

贪心核心:怎么实现每次都做出局部最优的选择?

对于任意一个站点:如果我们在这个站点加满油,那么最多就可以跑cmax*davg的距离,我们对这个距离段中遇到的加油站情况进行分析:

  • 按顺序遍历【当前位置,当前位置+cmax*davg】中的所有加油站,如果某个加油站的收费低于当前站点,那么我就在当前站点加油,跑到那个站点去,加多少呢?就加能恰好让我到达那个加油站的油。这样我去那个站点加油就能更便宜。
  • 如果当前站点后面有不止一个站点更便宜,怎么选择?比如我现在在A,价格是10,后面是 B 价格9, 后面是C 价格8, 我先找到的是B,那我就退出本次循环,刚好加油跑到B去,在B处重新继续分析。为啥不直接加油去C,如果从当前位置直接加油去C,那么BC之间的花费单价是当前加油站的价格也就是10,但我如果先去了B,那么从B到C的油价就是B处的价格9,显然更便宜。这样才满足局部最优。
  • 如果当前位置后面没有更便宜的加油站呢?
    • 如果我在当前位置最多能达到的最远距离超过了终点,那么我直接加油跑到终点,因为后面的站点只会更贵。
    • 如果我不能直接到终点,那么我肯定是需要加油的,那我就找尽可能地找比较便宜的那个加油站,在当前加油站加满油之后过去。既然没有比当前更低价格的了,就让油箱加到最大值,这样能保证利益最大化,保证最大的距离使用的是便宜的油。
  • 如果当前位置不能直接到达终点,并且后面没有加油站了呢?那么肯定不能到达中终点了,只能到达当前位置+cmax*davg,也就是说在当前位置加满,能跑多远是多远。

总结:

  • 当前位置能到达的范围中如果存在更便宜的加油站,就加合适的油刚好到达那个加油站。
  • 如果不存在更便宜的,但是当前位置能直接到达终点,那就加合适的油到达终点。
  • 不存在更便宜的,并且不能直接到终点,找到可达的加油站的相对而言最便宜那个,在当前位置加满油,然后去那个站点。
  • 当前位置不能到终点,并且后面没有加油站了,输出能到达的最大距离。

代码

#include <iostream>
#include <algorithm>
using namespace std; struct Station {
// 每单位汽油价格
double price;
// 从起点到这里的距离
double dis;
}stat[500]; // 对加油站 离起点 从近到远 排序
bool cmp(Station a, Station b) {
return a.dis < b.dis;
} int main() {
// cmax油箱容量 d 距离 davg 每单位油能跑多远 n个加油站
double cmax, d, davg;
int n;
cin >> cmax >> d >> davg >> n;
// 每个加油站的 价格 位置
for (int i = 0; i < n; ++i)
cin >> stat[i].price >> stat[i].dis;
// 根据离起点的距离排序
sort(stat, stat + n, cmp);
// 第一个加油站不在起点,无法起步
if(stat[0].dis != 0) {
printf("The maximum travel distance = 0.00");
return 0;
}
// nowpos当前在哪个加油站,
int nowpos = 0;
// nowgas 当前剩余多少油,total_price 总花费
double nowgas = 0.00, total_price = 0.00;
// 油箱加满一次油,可以跑多远
double each_max_run_dis = cmax * davg;
// 是否到达终点
bool arrived = false;
while (!arrived) {
// 遍历 【从当前加油站到最远能跑到的位置】 之间的 全部加油站
bool exist_stat = false; // 当前位置后面是否存在可达加油站
bool exist_cheaper_stat = false; // 是否存在比当前位置更便宜的加油站
// 不存在比当前便宜的,就找到其中价格最低的
int min_pos = -1; double min_price = 9999.99;
for (int i = nowpos + 1; i < n; ++i) {
// 当前位置到不了这个加油站,退出循环
if (stat[i].dis - stat[nowpos].dis > each_max_run_dis) {
// 最多还能走 nowgas * davg
break;
}
exist_stat = true; // 存在可达加油站
// 如果有比当前加油站价格更低的加油站
// 算一下恰好跑到那个加油站需要多少油,
// 加油跑到那个加油站
if (stat[i].price < stat[nowpos].price) {
// 设置标志
exist_cheaper_stat = true;
double needgas = (stat[i].dis - stat[nowpos].dis) / davg - nowgas;
// 加这么多油,刚好跑到那个加油站,算一下花费
total_price += stat[nowpos].price * needgas;
// 到达那个位置后剩余油量归0
nowgas = 0;
// 改变位置
nowpos = i;
// 不再遍历后面的加油站
// 比如我现在 在A,价格是10,后面是 B 价格9, 后面是C 价格8
// 我先找到的是B,那我就刚好加油跑到B去,在B处重新考虑
// 为啥不直接加油去C,如果从当前位置直接加油去C,那么BC之间的花费单价是当前加油站的价格也就是10
// 但我如果先去了B,那么从B到C的油价就是B处的价格9,显然更便宜
// 这样才满足局部最优
break;
}
// 如果说我能从当前位置跑1000米,但是在此之间的加油站的价格没有一个比我现在的价格低
// 那我就尽量找最便宜的那个,然后在当前位置加满油,跑到相对而言最便宜的那个加油站去加油
// 这样才满足局部最优(在最便宜的位置加更多的油跑最多的距离)
// 这个if不会和上面的if同时执行(上面执行完就break了),所以不用加else
if (stat[i].price < min_price) {
min_pos = i;
min_price = stat[i].price;
}
}
// 不存在比当前便宜的,但是当前位置最远能达到终点
if (!exist_cheaper_stat && (d - stat[nowpos].dis <= each_max_run_dis)) {
double needgas = (d - stat[nowpos].dis) / davg - nowgas;
// 加这么多油,刚好跑到终点,算一下花费
total_price += stat[nowpos].price * needgas;
// 到达终点
arrived = true;
break;
}
// 不存在比当前便宜的,但是找到了其他加油站中相对最便宜那个
if (!exist_cheaper_stat && exist_stat) {
// 后面有加油站,但是都比当前位置的加油站贵
// 那我就尽量找最便宜的那个,然后在当前位置加满油,跑到相对而言最便宜的那个加油站去加油
// 这样才满足局部最优(在最便宜的位置加更多的油跑最多的距离)
double needgas = cmax - nowgas;
// 在当前位置加满油,算一下花费
total_price += stat[nowpos].price * needgas;
// 到达那个位置后的剩余油量
nowgas = cmax - (stat[min_pos].dis - stat[nowpos].dis) / davg;
// 改变位置
nowpos = min_pos;
// 当前位置无法抵达下一个加油站
} else if (!exist_stat){
// 最多还能走 cmax * davg
printf("The maximum travel distance = %.2f", stat[nowpos].dis + each_max_run_dis);
return 0;
}
}
// while正常结束,说明到达终点
printf("%.2f", total_price);
return 0;
}

PAT 1033 To Fill or Not to Fill (25分) 贪心思想的更多相关文章

  1. PAT 甲级 1067 Sort with Swap(0, i) (25 分)(贪心,思维题)*

    1067 Sort with Swap(0, i) (25 分)   Given any permutation of the numbers {0, 1, 2,..., N−1}, it is ea ...

  2. PAT甲级:1066 Root of AVL Tree (25分)

    PAT甲级:1066 Root of AVL Tree (25分) 题干 An AVL tree is a self-balancing binary search tree. In an AVL t ...

  3. 1033 To Fill or Not to Fill (25分)(贪心)

    With highways available, driving a car from Hangzhou to any other city is easy. But since the tank c ...

  4. PAT 甲级 1002 A+B for Polynomials (25 分)

    1002 A+B for Polynomials (25 分) This time, you are supposed to find A+B where A and B are two polyno ...

  5. PAT A1106 Lowest Price in Supply Chain (25 分)——树的bfs遍历

    A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)-- everyone invo ...

  6. PAT A1097 Deduplication on a Linked List (25 分)——链表

    Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated ...

  7. pat 1006 Sign In and Sign Out(25 分)

    1006 Sign In and Sign Out(25 分) At the beginning of every day, the first person who signs in the com ...

  8. PAT 甲级 1079 Total Sales of Supply Chain (25 分)(简单,不建树,bfs即可)

    1079 Total Sales of Supply Chain (25 分)   A supply chain is a network of retailers(零售商), distributor ...

  9. PAT Advanced 1006 Sign In and Sign Out (25 分)

    At the beginning of every day, the first person who signs in the computer room will unlock the door, ...

随机推荐

  1. undef用法

    #undef的语法 定义:#undef 标识符,用来将前面定义的宏标识符取消定义. 整理了如下几种#undef的常见用法. 1. 防止宏定义冲突在一个程序块中用完宏定义后,为防止后面标识符冲突需要取消 ...

  2. docker学习笔记一篇就通系列(持续更新)

    docker三要素 仓库 镜像 容器 仓库 仓库用来存放docker的镜像,类似于github存放代码医养 镜像 镜像是一个模板,封装了应用程序和配置依赖的可交付的运行环境,这个打包好的运行环境就是镜 ...

  3. 如何使用简单 PHP 对象 POPO (Plain old PHP Object) 来优化你的代码

    如果您熟悉 Java,可能您已经知道 POJO (普通 Java 类). 因为 POJO 这个词最早是由 Martin Fowler.Rebecca Parsons 和 Josh MacKenzie ...

  4. P1353 Running S

    题意:https://www.luogu.com.cn/problem/P1353 奶牛们打算通过锻炼来培养自己的运动细胞,作为其中的一员,贝茜选择的运动方式是每天进行 n 分钟的晨跑.在每分钟的开始 ...

  5. STC8A8K64S4A12通过SPI接口操作基于ST7920的LCD12864液晶模块

    文章地址:https://www.cnblogs.com/jqdy/p/12665430.html 1. 硬件连接 1.1 64引脚的STC8A8K64S4A12 使用的是最小核心板,所以引脚皆引出可 ...

  6. Qt 操作sql server数据库

    添加qtsql的库 连接数据库 QSqlDatabase_db = QSqlDatabase::addDatabase("QODBC"); _db.setHostName(); _ ...

  7. 设计模式之GOF23观察者模式

    观察者模式Observer 广播机制 场景:多个观察者--被通知改变 CS的时候,人物移动坐标变化,更新每个人地图上的坐标 核心:当目标对象(Subject)的状态值改变时,需要及时告知所有观察者(O ...

  8. 【Docker】在本地打包maven程序为docker镜像报错: Connect to localhost:2375 [localhost/127.0.0.1, localhost/0:0:0:0:0:0:0:1]

    错误信息: [ERROR] Failed to execute goal com.spotify:docker-maven-plugin:1.0.0:build (default-cli) on pr ...

  9. 常用header头

    // ok 正常访问header('HTTP/1.1 404 Not Found'); //通知浏览器 页面不存在 header('HTTP/1.1 200 OK'); //设置地址被永久的重定向 3 ...

  10. Gitlab 安装、升级、备份、恢复、汉化等

    一.Gitlab安装 1. 基于yum方式安装Gitlab 安装步骤如下 (1)配置yum源 # vim /etc/yum.repos.d/gitlab-ce.repo (2)复制如下内容并保存(注意 ...