题目描述
知识点:贪心
解题思路:一个很自然的想法就是,在当前加油站的可行使范围内,如何选加油站进行下一步加油。共有两种策略(1)在可行驶范围内找到第一个价格比它低的加油站,刚刚好把油加过去。(2)没有比它低的,但是在行驶范围内选择一个价格最低的,把油加满开过去。
现证明这样的选择策略是最优的
首先对于第一种可能性:这很自然这么想,因为当前加油站油费比下一个贵,我只要刚刚好加够开过去就可以了。
对于第二种证明:需要画图理解
另外对于取等号问题:第一个发现比当前加油站小的,不能取等号,一定是<号。另外一个方案则取不取=一样。同样可以画图来说明。
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 510;
struct Tank{
double price;
double dis;
bool const operator < (const Tank t)const{
return dis < t.dis;
}
}tanks[N];
int main(){
int c_max,dis,d_avg,n;
cin>>c_max>>dis>>d_avg>>n;
for(int i = 0;i < n;i++) cin>>tanks[i].price>>tanks[i].dis;
tanks[n] = {0,dis};
sort(tanks,tanks+n+1);
if(tanks[0].dis){
cout<<"The maximum travel distance = 0.00";
return 0;
}
double oil = 0,res = 0;
for(int i = 0;i < n;){
//i表示当前行驶到的加油站
//从当前加油站向后的能行驶到的距离
//首先寻找比自己便宜的加油站 其次寻找范围内最便宜的
int t = -1;
for(int j = i+1;j <= n && tanks[j].dis - tanks[i].dis <= c_max*d_avg;j++){
if(tanks[j].price < tanks[i].price){
t = j;
break;
}
else if(t == -1 || tanks[j].price < tanks[t].price)
t = j;
}
if(t == -1){
printf("The maximum travel distance = %.2lf",c_max*d_avg + tanks[i].dis);
return 0;
}
if(tanks[t].price < tanks[i].price)//只需要到达
{
res += ((tanks[t].dis - tanks[i].dis) / d_avg - oil) * tanks[i].price;
oil = 0;
}else{
res += (c_max - oil) * tanks[i].price;
oil = c_max - (tanks[t].dis - tanks[i].dis) / d_avg;
}
i = t;
}
printf("%.2lf",res);
return 0;
}