2031: To Fill or Not to Fill

时间限制: 1 Sec  内存限制: 32 MB
提交: 599  解决: 132
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

题意就是从起点到终点有很多的加油站 每个加油站有距离起点的距离和单价 我们从起点开车到终点 开始油量为0 要尽可能走到终点 问所求的最小花费是多少?如果走不到终点 就输出最远距离。

一开始给出油箱大小,到终点的距离,还有每单价油可以走的里程数,以及加油站的信息

分析:

由于这个问题逻辑比较复杂 可以先研究样例

假设汽车从起点S到终点E必须通过加一次油到达 可达范围内有多个价格不一的加油站

如果可达范围内有更便宜的G 我们要选择那个加油站续命 先加够到这个加油站G的油 在到G处加新的油 这样就相当于从起点到G再到终点的松弛 可以通过这个加油站把后面的路程的花费给减小“松弛”掉

如果选择某个并不是选择可达范围内最靠前的更便宜的加油站去加油站

如果选择了一个较远的,花费更大的站A 那么就必然导致起点加油变多花费变多,从A站新加的油到终点的这段距离花费变多 虽然路程变小 从全局来看 两种不同的选择花费不同的路段里 第二段从G到A花费变多 从A到终点E花费也变多 从而导致全局花费更大

如果选择了一个较近的花费更大的站B 那么从起点S到B花费不变 那么从B到G花费变多 从G到终点花费也变多  从而导致全局更大的花费

所以在当前站 选择可达范围内最近的且更便宜的能够带来更小的局部最优 从而获得更小的全局花费

如果没有更便宜的

那么就要在初始S加满 这样才能尽可能少加更贵的油 从而减小花费

那么选择所有比初始S贵的里面最便宜G的  那么从S到G花费起点S的油钱 从G到终点E 再化一部分新加的G站油钱 如果不是这样选 得到的花费只会更大 怎么呢?

我们来看 这种情况下 续命油的油量是确定的 因为我前面加满了

如果选择一个更近的站A但并不是可选加油站中最便宜的 那么从起点S到A花费不变,从A到G花费不变 但到终点需要加一次油 这时需要加的油会更贵一点(A站油钱) 从而全局花费更大

如果选择一个更远的站B但并不是可选加油站中最便宜的 那么起点到G花费不变 G到B花费不变 B到终点E 需要续一次油 花费变大(B站油钱)

所以在这种 分支下 我们也要选择贵中最便宜的那个去加油 从而获得全局最优

我们要找的续命的加油站 必须是可达范围里最便宜的 只有这样 才能通过这个最便宜的加油站 获取尽可能便宜的局部最优花费 这样再去选

你有可能会有疑问

如果我们想G走着走着发现一个可达范围内更便宜站P的怎么办 即便如此 我们也要先到G站 看看能不能不加油直接走到P站 不过不可能! 因为P是G站决策之前的可达范围之外的站 必然不可能不加油走到P站 所以我们有必要中间续油 那么续油的话 只能在G续油 因为G是最相对便宜的 我们只有先到了G再看看需要续多少油到更便宜的加油站去 如果没有更便宜的加油站 则继续选择可达范围内所有更贵的里面最便宜的  所以整个过程就是

局部最优+局部最优+...+局部最优 = 全局最优

于是这个问题的逻辑大致就是如此 对每个加油站执行相同的逻辑 我们发现这样的话就是贪心策略 每到一个加油站 在能到达的范围内选择局部最优策略 这样走下来就能得到全局最优策略 如果在加油站不进行局部最优的策略 那么就必然导致花费变大

如果起始点没有加油站 那么就输出0 因为加不到油必然走不出去

否则:

看看加满油的话 能到达的范围内 有没有加油站

如果没有 那么就加满油尽可能跑 能跑多远就输出多远

如果有加油站 看看有没有一个加油站是他能到达的范围内且离当前点比较近的?我们设此站位G站

如果有 我们就买刚好到G站的油量:因为到了G站买油可以得到更便宜的价格 从而尽可能的得到更小的花费                                 如果没有 全都是比当前站更贵的加油站 那么就要从贵中选一个最便宜的设为H站 我们要走到那里继续买油才能尽可能的减小花费 注意 这时要从当前站加满油 因为H站的油是更贵的 但是又不能因为油贵而不走 还是要尽可能往前走的 这时如果不从H站买 从其他站买 只会导致更多的花费  所以我们要尽可能少的从H站买油 我们到了H站要站在H站的位置考虑更优的花费时 再从H站买油 故从当前站要加满油 然后去向H站 

由于本题需要维护的参数比较多 逻辑比较复杂 还是要想清楚逻辑后 把变量写的可读性高点 才能少出bug

时间复杂度:O(n^(所能到达的范围中的加油站个数))<O(n^2)<1000ms

#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<cmath>
#include<algorithm>
#include<set>
#include<vector>
#include<climits>
#define Equal(a,b) (fabs((a)-(b))<=eps)
#define LessEqu(a,b) (((a)-(b))<=eps)
#define Lessthan(a,b) (((a)-(b))<-eps)
#define Morethan(a,b) (((a)-(b))>=eps)
#define MoreEqu(a,b) (((a)-(b))>=-eps)
const double eps = 1e-5;
using namespace std;
typedef long long ll;
struct station{double cost;double dis;
}S[510];
bool cmp(station a,station b){return Lessthan(a.dis,b.dis);
}
int main(){double c,dis,avg;int sta;ios::sync_with_stdio(0);cin>>c>>dis>>avg>>sta;for(int i=1;i<=sta;i++){cin>>S[i].cost>>S[i].dis;}double Lowest = S[1].cost;for(int i=2;i<=sta;i++){if(Lessthan(S[i].cost,Lowest)){Lowest = S[i].cost;}}sort(S+1,S+1+sta,cmp);if(!Equal(S[1].dis,0.0)){cout<<"The maximum travel distance = 0.00"<<endl;return 0;}bool f=0;S[sta+1].cost = 0,S[sta+1].dis = dis;double exp=0,canadd=c,distans=0,cut=0,unit=c;double costoil,oil = 0;bool fal = 0;for(int i=1;i<sta+1;i++){oil = (distans-S[i].dis)/avg;double Maxlim = S[i].dis + c*avg;double CMP = S[i].cost;int j,u=i;for(j=i+1;j<=sta+1&&LessEqu(S[j].dis,Maxlim);j++){if(Lessthan(S[j].cost,CMP)){CMP = S[j].cost;u = j;break;}}if(u==i&&j==i+1){//后面没加油站distans = Maxlim;fal = 1;break;}if(u!=i){//有个更便宜的unit = (S[u].dis-distans)/avg;//减去的是什么很关键exp+=S[i].cost*unit;// canadd = unit;distans = S[u].dis;i = u-1;oil += unit;costoil = unit;continue;}//如果后面的都是比自己贵的CMP = S[i+1].cost;u = i+1;for(int j=i+2;j<=sta+1&&LessEqu(S[j].dis,Maxlim);j++){if(LessEqu(S[j].cost,CMP)){//尽可能少买 也就是尽可能远CMP = S[j].cost;u = j;}}canadd = c-oil;distans += (canadd)*avg;exp+=canadd*S[i].cost;costoil = (S[u].dis-S[i].dis)/avg;oil=c;i = u-1;}if(fal)printf("The maximum travel distance = %.2f\n",distans);else printf("%.2f\n",round(exp*100)/100);return 0;
}

codeUp 2031 To fill or not to fill 复杂贪心相关推荐

  1. 数组的fill方法_数组fill()方法以及JavaScript中的示例

    数组的fill方法 JavaScript fill()方法 (JavaScript fill() method) fill() method is used fill the array with a ...

  2. A1033 To Fill or Not to Fill

    Powered by:NEFU AB-IN Link 文章目录 A1033 To Fill or Not to Fill 题意 思路 代码 A1033 To Fill or Not to Fill 题 ...

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

    题解: 贪心??个人感觉贪心的思维不难,总觉得像个模拟题. 我们可知目的地也是一个点,我们将目的地的距离也加入到数组里面去,并且油价设置为0. 然后按照距离进行排序. 1.首先我们去暴力处理一下达不到 ...

  4. 1033 To Fill or Not to Fill (25 分)【难度: 难 / 知识点: 模拟 贪心】

    https://pintia.cn/problem-sets/994805342720868352/problems/994805458722734080 #include<cstdio> ...

  5. 【详细解析】1033 To Fill or Not to Fill (25 分)

    立志用最少的代码做最高效的表达 PAT甲级最优题解-->传送门 With highways available, driving a car from Hangzhou to any other ...

  6. 九度OJ 1437 To Fill or Not to Fill -- 贪心算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1437 题目描述: With highways available, driving a car from Hang ...

  7. c# mysql fill_C#里sqlDataAdapter.fill(DataSet,String)的用法

    第二个参数 String是指定DataSet 里表的名字,例如 sqlDataAdapter.fill(DataSet,"学生表") 指定后,以后就可以这样调用这张表 DataSe ...

  8. 对matlab中colormap的解释及fill、imshow的用法说明

    这篇文章的主要目的在于对colormap的解释,会涉及到fill和imshow的使用,因此首先解释fill和imshow的用法. fill的用法说明 fill就是填充一个多边形区域.函数用法fill( ...

  9. matlab中fill函数的使用方法

    填充的二维多边形 fill 函数创建彩色多边形. 语法 ①fill(X,Y,C) fill(X,Y,C) 根据 X 和 Y 中的数据创建填充的多边形(顶点颜色由 C 指定).C 是一个用作颜色图索引的 ...

最新文章

  1. 【7.2】__getattr__、__getattribute__魔法函数
  2. 用命令行连接到远程计算机
  3. [小改进]在个人Blog页面显示文章阅读数
  4. SAP Spartacus Unit List树形数据的加载
  5. ES5-2 语法、规范、错误、运算符、判断分支、注释
  6. JDBC学习笔记之JDBC简介
  7. 亲自实践Blazor构建桌面应用程序
  8. OSS.Social微信项目标准库介绍
  9. quartz mysql 初始化_quartz scheduler 从数据库初始化
  10. mysql添加临时索引_mysql 中添加索引的三种方法
  11. Spring框架----Spring的bean的作用范围
  12. sql server management studio快捷键
  13. [剑指Offer] 36.两个链表的第一个公共结点
  14. mysql中修改表字段的类型长度_mysql中修改表字段名/字段长度/字段类型详解
  15. Android学习笔记--菜单
  16. 高斯模糊处理头像作为背景图的两种高效便捷方法
  17. 遭遇七年禁令,中兴通讯会破产吗?
  18. TeeChart 商业版 [2022.4.8] TeeChart.NET 专业版
  19. 防伪防窜货追溯系统解决方案 定制开发
  20. [转]复旦投毒案的一些思考

热门文章

  1. 前端测试框架 jasmine 的使用
  2. python写http post请求的四种请求体
  3. 同事更新几个表_最近计划学习的几个网站资源
  4. 入门指南_激光切管快速入门指南
  5. linux u盘 uid pid,linux下的pid文件的作用
  6. oracle仲裁磁盘是一块磁盘吗,基于ASM冗余设计的架构,仲裁磁盘组应该如何去规划?...
  7. idea创建springboot项目出现的问题
  8. 6、Flutter Error waiting for a debug connection: ProcessException: adb did not report f(转)
  9. android 清理缓存 简书,分享:Android清除本地数据缓存代码
  10. mysql5.1win7_免安装版mysql5.1.57在win7下成功配置