题目如下:

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: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=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: Pi, the unit gas price, and Di (<=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

这是一道考察贪心算法的题目,为了达到花最少的钱到达终点或是跑最远距离的目的,我们很难整体的去把握这个问题,通过贪心算法,可以把整体问题化为局部问题,只站在当前的角度分析最贪婪(最优)的抉择,从而得到问题的最优解,贪心问题的困难之处在于对问题的分析和情况分类,一旦情况考虑的不够周全,就可能满盘皆输。

对于这道题目,我们分如下的情况进行讨论。

对于当前站点S,所能到达的最大范围即满油量所能到达的距离,设满油量能前进的距离为maxToGo,则在S到S+maxToGo范围内,分如下情况进行考虑:

Ⅰ此范围内有加油站

①有比当前站点便宜的加油站,因为只从最小的局部考虑问题,如果有多个比当前便宜的,到达那个最近的而不是最便宜的(只需要在找到第一个比S便宜的站点时break即可)。

②全部比S更贵(易错点)

2.1 如果从S无法到达终点,则选择最便宜的那个,从S加满油到达那个站点。

2.2 如果从S可以直接到达终点,则从S加油至能到达终点,直接开到终点。

Ⅱ此范围内无加油站

①如果从S可以直接到达终点,则加到能到达终点,直接到达。

②如果从S无法到达终点,加满油,能跑多远跑多远。

具体实现为用结构体存储站点信息,压入vector按照升序排序,从前到后处理各个站点,用cur表示当前所在的站点,当cur为最后一个站点之后的范围时,结束循环,具体代码如下:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <iomanip>
#include <algorithm> using namespace std; #define INF 99999999 struct GasStation{ double price;
double dis; GasStation(double _p, double _d) : price(_p), dis(_d) {} }; int compare(GasStation a, GasStation b){ return a.dis < b.dis; } int main()
{
int cons,gasCnt;
double cap;
double dis;
double price;
double dist;
vector<GasStation> stations;
cin >> cap >> dis >> cons >> gasCnt;
double maxToGo = cap * cons;
for(int i = 0; i < gasCnt; i++){
scanf("%lf %lf",&price,&dist);
stations.push_back(GasStation(price,dist));
}
sort(stations.begin(),stations.end(),compare); if(stations[0].dis > 0){
printf("The maximum travel distance = 0.00\n");
return 0;
} int cur = 0;
double now_cap = 0;
double sumPrice = 0;
int curEnd = stations.size();
double stationPrice = 0;
double stationDis = 0;
int hasStation = 0;
int dest = 0; // 如果有多个起点加油站,选择那个最便宜的加油。
// 事实证明题目中并没有此类不符合实际的陷阱。
int minPrice = stations[0].price;
for(int i = 0; i < stations.size(); i++){
if(stations[i].dis == 0){
if(minPrice > stations[i].price){
cur = i;
}
}else break;
} while(cur < curEnd){
stationPrice = stations[cur].price;
stationDis = stations[cur].dis;
dest = -1;
hasStation = 0; for(int i = cur + 1; i < stations.size(); i++){ // 首先判断当前站点之后有没有可以到达的
if((stations[i].dis - stationDis) <= maxToGo){ // 发现有可到达的站点,再找出最近且最便宜的。
hasStation = 1;
// 找出最便宜的有两种情况,第一是有比当前站点便宜的,到达最近的满足条件的这样的站点。
// 或者都比当前站点贵,则加油到能到达最便宜的那个。
// 这两个判断是冲突的,因为有比当期便宜的时候选择的不是那个最便宜的而是最近的,都贵的时候找的是最便宜的
// 因此先判断有没有比当前便宜的,没有再进一步找那个贵中最便宜的。
if(stationPrice > stations[i].price){ // 找到了更便宜的,在这里中断查找,保证找到的是最近的。
dest = i;
break;
}
}else{ // 都没有可到达的站点了。
break;
}
}
if(hasStation != 1){ // 没有可到达站点
if((dis - stationDis) <= maxToGo){ // 能跑到终点,则加油到可以跑到终点
double need = dis - stationDis;
if(now_cap * cons >= need){ // 油足够到达
break;
}else{ // 油不够,加到能跑到终点
double last = (need - now_cap * cons);
sumPrice += (last / cons) * stationPrice;
break;
}
}else{ // 跑不到终点,能跑多远跑多远
double sumDis = stationDis + cap * cons;
printf("The maximum travel distance = %.2lf\n",sumDis);
return 0;
}
}else{ // 有可以到达的站点
if(dest != -1){ // 找到了比当前便宜且距离当前最近的加油站,加油到跑到那里,然后继续在那个站点考虑
double need = stations[dest].dis - stationDis;
if(need <= now_cap * cons){ // 油足够到达
now_cap -= need / cons;
}else{ // 油不够,补齐
sumPrice += (need - now_cap * cons) / cons * stationPrice;
now_cap = 0; // 跑过去就没有油了
}
cur = dest;
}else{ // 没有便宜的,选择那个最便宜的加油跑过去。 // !!!先看能否到终点,能到就直接到终点,一定注意这种情况!!!
if((dis - stationDis) <= maxToGo){
double need = dis - stationDis;
if(now_cap * cons < need){
sumPrice += (need - now_cap * cons) / cons * stationPrice;
}
break;
} int minPrice = INF;
int minCur = -1;
for(int i = cur + 1; i < stations.size(); i++){
if((stations[i].dis - stationDis) < maxToGo){
if(stations[i].price < minPrice){
minPrice = stations[i].price;
minCur = i;
}
}else{
break;
}
}
cur = minCur;
sumPrice += (cap - now_cap) * stationPrice;
now_cap = cap - (stations[cur].dis - stationDis) / cons;
}
} }
printf("%.2lf\n",sumPrice); return 0;
}

1033. To Fill or Not to Fill (25) -贪心算法的更多相关文章

  1. PAT甲题题解-1067. Sort with Swap(0,*) (25)-贪心算法

    贪心算法 次数最少的方法,即:1.每次都将0与应该放置在0位置的数字交换即可.2.如果0处在自己位置上,那么随便与一个不处在自己位置上的数交换,重复上一步即可.拿样例举例:   0 1 2 3 4 5 ...

  2. 1033. To Fill or Not to Fill (25)

     题目链接:http://www.patest.cn/contests/pat-a-practise/1033 题目: 1033. To Fill or Not to Fill (25) 时间限制 1 ...

  3. 【贪心】PAT 1033. To Fill or Not to Fill (25)

    1033. To Fill or Not to Fill (25) 时间限制 10 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 ZHANG, Gu ...

  4. 1033 To Fill or Not to Fill (25 分)

    1033 To Fill or Not to Fill (25 分) With highways available, driving a car from Hangzhou to any other ...

  5. PAT 甲级 1033 To Fill or Not to Fill (25 分)(贪心,误以为动态规划,忽视了油量问题)*

    1033 To Fill or Not to Fill (25 分)   With highways available, driving a car from Hangzhou to any oth ...

  6. PAT 1033. To Fill or Not to Fill (25)

    题目地址:http://pat.zju.edu.cn/contests/pat-a-practise/1033 此题是一道贪心算法题,难度较大,关键在于贪心策略的选择: #include <cs ...

  7. PAT 1033 To Fill or Not to Fill[dp]

    1033 To Fill or Not to Fill(25 分) With highways available, driving a car from Hangzhou to any other ...

  8. pat1033. To Fill or Not to Fill (25)

    1033. To Fill or Not to Fill (25) 时间限制 10 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 ZHANG, Gu ...

  9. 1033 To Fill or Not to Fill

    PAT A 1033 To Fill or Not to Fill With highways available, driving a car from Hangzhou to any other ...

随机推荐

  1. break 与 continue

    1.break ①只有一层循环时,作用是跳出循环语句,执行后面的代码. ②break存在于循环嵌套的内层循环时,只能跳出内层循环,如果想要跳出外层循环,需要对外层循环添加标记. 2.continue ...

  2. 解决 Popup 位置不随窗口移动更新的问题

    Popup弹出后,因业务需求设置了StaysOpen=true后,移动窗口位置或者改变窗口大小,Popup的位置不会更新. 如何更新位置? 获取当前Popup的Target绑定UserControl所 ...

  3. Windows无法安装到这个磁盘

    今天手动装系统的时候出现以下这样的错误, 请看图: 进入BIOS F9 Setup Defaults   ,初始化恢复 1.在进行windows安装分区时, 磁盘分区界面无法继续进行,出现" ...

  4. CentOS Linux上安装Oracle11g笔记

    CentOS Linux上安装Oracle11g 到 otn.oracle.com 网站上下载 Linux版的oracle 11g 编辑 /etc/sysctl.conf : kernel.shmal ...

  5. Tomcat安装及问题排查方法

    简介: Apache Jakarta的开源项目 JSP/Servlet容器 安装: 1.1进入 Tomcat 官方下载地址 选择合适版本下载,并解压到本地. (备注)Tomcat 8.5 要求 JDK ...

  6. Android源码解析——Toast

    简介 Toast是一种向用户快速展示少量信息的视图.当它显示时,它会浮在整个应用层的上面,并且不会获取到焦点.它的设计思想是能够向用户展示些信息,但又能尽量不显得唐突.本篇我们来研读一下Toast的源 ...

  7. 安卓热修复之AndFIX

    我致力于最新的前沿安卓技术分析和使用教学,不打算将很多很深的东西,因为有多少人愿意沉下你的心境去学习难点?我一般只会简单提及.文字错漏在所难免还希望同学们喜欢 热修复介绍 热修复是什么? 如果你一个项 ...

  8. 安卓高级 Android图片缓存之初识Glide

    前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架.技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自己的实 ...

  9. Lucene 6.0下使用IK分词器

    Lucene 6.0使用IK分词器需要修改修改IKAnalyzer和IKTokenizer. 使用时先新建一个MyIKTokenizer类,一个MyIkAnalyzer类: MyIKTokenizer ...

  10. ANTLR和StringTemplate实例:自动生成单元测试类

    ANTLR和StringTemplate实例:自动生成单元测试类 1. ANTLR语法 要想自动生成单元测试,首先第一步就是分析被测试类.这里以Java代码为例,用ANTLR对Java代码进行分析.要 ...