洛谷 P1016旅行家的预算题解--zhengjun
题目描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离\(D1\)、汽车油箱的容量\(C\)(以升为单位)、每升汽油能行驶的距离\(D2\)、出发点每升汽油价格\(P\)和沿途油站数\(N\)(\(N\)可以为零),油站\(i\)离出发点的距离\(D_i\)、每升汽油价格\(P_i\)(\(i=1,2,…,N\))。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出No Solution
。
输入格式
第一行,\(D1\),\(C\),\(D2\),\(P\),\(N\)。
接下来有\(N\)行。
第 \(i+1\) 行,两个数字,油站\(i\)离出发点的距离\(D_i\)和每升汽油价格\(P_i\)。
输出格式
所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出No Solution
。
输入输出样例
输入 #1
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
输出 #1
26.95
说明/提示
\(N \le 6\) \(,\) 其余数字 \(\le 500\) 。
思路
我一开始做的时候,这么水的模拟+贪心题怎么是绿题。
就开始了。
首先,如果在这个点能够到达的点中没有比这个点的\(P\)更小的了,就找一个最小的开过去。
可是还有一个误区,就是这样:
\(D_{i+1}=D_i+1,P_{i+1}\lt P_{i}\)
\(D_{i+2}=D_i+2,P_{i+2}\lt P_{i+1}\)
\(D_{i+3}=D_i+3,P_{i+3}\lt P_{i+2}\)
这些都是点 \(i\) 能够到达的点。
比较一下以下两种方案:
- 直接从 \(i\) 到 \(i+3\)
- 从 \(i\) 到 \(i+1\) ,从 \(i+1\) 到 \(i+2\) ,从 \(i+2\) 到 \(i+3\)
应该是方案 \(2\) 更好。
所以,只要在这个点所能到达的点中直接跳到离这个点最近的并且 \(P_x\lt P_i\) 的点上就可以了。
代码
#include<bits/stdc++.h>
#define maxn 10000
using namespace std;
double l,c,d,p[maxn],w[maxn];
int n;
int main(){
scanf("%lf%lf%lf%lf%d",&l,&c,&d,&p[0],&n);
w[0]=0;
double x=c*d;
for(int i=1;i<=n;i++){
scanf("%lf%lf",&w[i],&p[i]);
if(w[i]-w[i-1]>x){
cout<<"No Solution";
return 0;
}
}
w[++n]=l;
p[n]=0x3fffffff;
double ans=0;
int now=0;
while(now!=n){
int k=now;
for(int j=now+1;j<=n&&w[j]-w[now]<=x;j++)
if(p[j]<=p[k]||j==n){
k=j;
break;//第一个!!!
}
if(k==now){//没有比P{now}更小的Px了
k=now+1;
for(int j=now+2;j<=n&&w[j]-w[now]<=x;j++)
if(p[j]<=p[k]){
k=j;
}
}
ans+=(w[k]-w[now])/d*p[now];
now=k;
}
printf("%0.2lf",ans);
return 0;
}
别急着抄代码,这还不是正解。
因为,还有一种情况,如果你要去的下一个点的 \(P\) 比当前点的 \(P\) 小,那就应该加满油,到下一个点的时候稍加一点油,就会更划算。
代码
#include<bits/stdc++.h>
#define maxn 8
using namespace std;
double l,c,d,p[maxn],w[maxn];
double y[maxn];
int n;
int main(){
scanf("%lf%lf%lf%lf%d",&l,&c,&d,&p[0],&n);
w[0]=0;
double x=c*d;
for(int i=1;i<=n;i++){
scanf("%lf%lf",&w[i],&p[i]);
if(w[i]-w[i-1]>x){
cout<<"No Solution";
return 0;
}
}
w[++n]=l;
p[n]=0x3fffffff;
double ans=0,youliang=0;
int now=0;
while(now!=n){
int k=now;
for(int j=now+1;j<=n&&w[j]-w[now]<=x;j++){
if(p[j]<=p[k]||j==n){
k=j;
ans+=((w[k]-w[now])/d-youliang)*p[now];
youliang=0;
break;
}
}
if(k==now){
k=now+1;
for(int j=now+2;j<=n&&w[j]-w[now]<=x;j++)
if(p[j]<=p[k]){
k=j;
}
ans+=(c-youliang)*p[now];
youliang=c-youliang-(w[k]-w[now])/d;
}
now=k;
}
printf("%0.2lf",ans);
return 0;
}