1033 To Fill or Not to Fill
是决策,不太确定能不能用贪心。一开始自己没想清楚,参考了别人的思路,发现还是贪心。
实际上就是两个规则
- 在可到达的最大范围内,存在相邻的加油站比你现在所处的加油站便宜,那么加油量恰好能让车到达这个新加油站,是一个局部最优决策。
- 如果可达最大范围内没有更便宜的新加油站,就加满油。这样做使你到了新的加油站也能用剩余的便宜油多走一会,降低成本。
注意特判起点没有加油站,输出
The maximum travel distance = 0.00
感觉别人的代码看着不是很清爽,自己写了一下,或许看着更直观点
#include<bits/stdc++.h>
using namespace std;
struct Station{
double p;
int d;
}s[505];
int c,d,dv,n;
double sum = 0;
const double INF = DBL_MAX;
bool cmp(Station a,Station b){//同距离,费用小在前
if(a.d==b.d)
return a.p<b.p;
return a.d<b.d;
}
int main(){
cin>>c>>d>>dv>>n;
for(int i=0;i<n;i++){
cin>>s[i].p>>s[i].d;
}
sort(s,s+n,cmp);
if(s[0].d!=0){//特判起点没有加油站
cout<<"The maximum travel distance = 0.00"<<endl;//注意输出不是0而是0.00 (一般认为是0)
return 0;
}
int posNow=0;//当前位置
int dRes=0;//可走距离
int dMax = c*dv;//最大行程
double pNow = s[0].p;//当前油价
while(posNow<d){
// printf("posNow %d pNow %f dRes %d\n",posNow,pNow,dRes);
int posNext=-1;
double pMin=INF;
bool flag=false;//没找到低价点
for(int i=0;i<n&&s[i].d<=posNow+dMax;i++){//假设终点后没有加油站
if(s[i].d<posNow)continue;
if(s[i].p<pNow){//找到低价点,不用多加更新
if(dRes>=s[i].d-posNow){//剩够
dRes-=s[i].d-posNow;
}
else if(dRes){//有剩
sum+=pNow*(s[i].d-posNow-dRes);
dRes=0;
}
else
sum+=pNow*(s[i].d-posNow);
posNow = s[i].d;
pNow = s[i].p;
flag = true;
break;
}
if(s[i].p<pMin&&posNow<s[i].d){//下一个最便宜点,不含posNow
pMin=s[i].p;
posNext = i;
}
}
if(!flag){//加满油箱,去下一站
if(posNow+dMax>=d){//能到终点
sum+=pNow*(d-posNow);
printf("%.2f\n",sum/dv);
break;
}
else if(posNext==-1){//没有站
printf("The maximum travel distance = %.2f\n",(double)(posNow+dMax));
break;
}
else{
sum+=pNow*(dMax-dRes);//加满油箱
dRes = dMax-(s[posNext].d-posNow);//到下一站后的剩余距离
posNow = s[posNext].d;
pNow = s[posNext].p;
// printf("ADD posNow %d pNow %f dRes %d\n",posNow,pNow,dRes);
}
}
}
return 0;
}
启示
1、写贪心题的关键在于确定贪心策略,策略定好后才好实现。不然硬模拟很容易写不出来。