驾车旅游
题目描述
如今许多普通百姓家有了私家车,一些人喜爱自己驾车从一个城市到另一个城市旅游。自己驾车旅游时总会碰到加油和吃饭的问题,在出发之前,驾车人总要想方设法得到从一个城市到另一个城市路线上的加油站的列表,列表中包括了所有加油站的位置及其每升的油价(如 3.25 3.25 3.25 元/L)。驾车者一般都有以下的习惯:
- 除非汽车无法用油箱里的汽油达到下一个加油站或目的地,在油箱里还有不少于最大容量一半的汽油时,驾驶员从不在加油站停下来;
- 在第一个停下的加油站总是将油箱加满;
- 在加油站加油的同时,买快餐等吃的东西花去 20 20 20 元。
- 从起始城市出发时油箱总是满的。
- 加油站付钱总是精确到 0.1 0.1 0.1 元(四舍五入)。
- 驾车者都知道自己的汽车每升汽油能够行驶的里程数。
现在要你帮忙做的就是编写一个程序,计算出驾车从一个城市到另一个城市的旅游在加油和吃饭方面最少的费用。
输入格式
第一行是一个实数,是从出发地到目的地的距离(单位:km)。
第二行是三个实数和一个整数,其中第一个实数是汽车油箱的最大容量(单位:L);第二个实数是汽车每升油能行驶的公里数;第三个实数是汽车在出发地加满油箱时的费用(单位:元);一个整数是 1 1 1 到 50 50 50 间的数,表示从出发地到目的地线路上加油站的数目。
接下来 n n n 行都是两个实数,第一个数表示从出发地到某一个加油站的距离(单位:km);第二个实数表示该加油站汽油的价格(单位:元)。
数据项中的每个数据都是正确的,不需判错。一条线路上的加油站根据其到出发地的距离递增排列并且都不会大于从出发地到目的地的距离。
输出格式
输出一个实数,即精确到 0.1 0.1 0.1 元的最小的加油和吃饭费用。
样例 #1
样例输入 #1
600
40 8.5 128 3
200 3.52
350 3.45
500 365
样例输出 #1
13133.2
思路
这道题很简单,出题人都把答案写到了题目上。
- 首先,在油箱里还有不少于最大容量一半的汽油时,驾驶员从不在加油站停下来。
- 其次,每次到了加油站都是加满汽油并吃饭。
- 然后,此时的dfs就很好写了,因为数据规模也就 N ≤ 50 N\leq50 N≤50,所以我们对dfs的参数就是u表示当前加油站的编号,current表示在当前加油站的油量,sum表示在当前加油站所花的费用。
- 这边我们剪枝一下,如果我们的 a n s ≤ s u m ans \leq sum ans≤sum,那么就没必要再搜索了(为什么呢?因为你的sum都比我ans小了,那后面的搜索就不会使得sum变小,因此不能要)
- 注意,在dfs写的dfs参数是针对下一个的编号、油量、花费。别搞错了,我这里搞错调了30min。
代码
//数据范围不大,我们可以尝试用搜索来解决
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 55;
double dist[N],price[N];
double D;
double maxv,d,p;
int n;
double ans=0x3f3f3f3f;
void dfs(int u,double sum,double current){//current当前油量
if(ans<sum)return;
if(u==n+1){
ans=min(ans,sum);
return;
}
if(current*d>=(dist[u+1]-dist[u])){//如果当前油量在当前加油站的时候能撑到到下个加油点的话
if(current>=maxv/2)dfs(u+1,sum,current-(dist[u+1]-dist[u])/d);//不加
else{
dfs(u+1,sum+(maxv-current)*price[u]+20,maxv-(dist[u+1]-dist[u])/d);//加
dfs(u+1,sum,current-(dist[u+1]-dist[u])/d);//不加
}
}else{
dfs(u+1,sum+(maxv-current)*price[u]+20,maxv-(dist[u+1]-dist[u])/d);//加
}
}
int main(){
cin>>D>>maxv>>d>>p>>n;
for(int i=1;i<=n;i++){
cin>>dist[i]>>price[i];
}
dist[n+1]=D;
dfs(1,p,maxv-dist[1]/d);
printf("%.1lf",ans);
return 0;
}