题意:油箱量为Cmax,每单位油能跑Davg的车,要从杭州跑到距离为D的城市,途中有N个加油站。每个加油站有单位价格Pi和与杭州的距离Di这两个信息。问车最多能跑多远,且在该前提下,最少花费多少钱。
思路:用贪心算法。把自己想成车,要为”眼前的利益”做出下一步的选择。具体决策见图:
体会:做贪心算法的题,可根据题目给的示例,自己演算一遍,从中总结规律,然后再思考和补充上特例即可。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
//加油站结构体
struct Station{
double Pi; //价格
double Di; //距离
};
//相关变量
double Cmax,D,Davg;
double fullD,sumP,nowC; //fullD:加满油后跑的最大距离,sumP:总油费,nowC:现有油量
int N,i;
Station station[502];
//比较函数
bool Cmp(Station a,Station b){
if(a.Di<=b.Di)
return true;
return false;
}
//求更低价或较低价站函数
//在范围内,有更低价的站,则用z引用带回,返回true,;没有,返回false,用z引用带回
bool FindLowStation(int a,double Dis,int &z);
int main(){
while(~scanf("%lf %lf %lf %d",&Cmax,&D,&Davg,&N)){ //输入信息
memset(station,0,502*sizeof(Station)); //加油站信息清0
fullD=Cmax*Davg; //计算加满油后跑的最大距离
for(i=0;i<N;i++) //输入加油站信息
scanf("%lf %lf",&station[i].Pi,&station[i].Di);
sort(station,station+N,Cmp); //对加油站的距离由小到大排序
//计算最远距离
if(station[0].Di!=0){ //起始点没加油站
printf("The maximum travel distance = 0.00\n");
continue;
}
for(sumP=0.0,nowC=0.0,i=0;i<N;){ //起始点有加油站
if(station[i].Di+fullD>=D){ //fullD内有终点
if((D-station[i].Di)/Davg<=nowC){ //油够到终点:直接跑到终点
printf("%.2lf\n",sumP);
break;
}
else{ //油不够到终点
int z;
if(!FindLowStation(i,(D-station[i].Di),z)){ //剩下的站没有更低价的:加足够油,直达终点
if((D-station[i].Di)/Davg<=nowC){ //油够,直达终点
printf("%.2lf\n",sumP);
break;
}
else{ //油不够,本站加刚好的油,直达终点
printf("%.2lf\n",sumP+((D-station[i].Di)/Davg-nowC)*station[i].Pi);
break;
}
}
else{ //剩下的站有更低价的:加足够油,直达z站
if((station[z].Di-station[i].Di)/Davg<=nowC){ //油够,直达更低价站
nowC=nowC-(station[z].Di-station[i].Di)/Davg;
i=z;
}
else{ //油不够,本站加刚好的油,直达更低价站
sumP+=((station[z].Di-station[i].Di)/Davg-nowC)*station[i].Pi;
nowC=0.0;
i=z;
}
}
}
}
else{ //fullD内无终点
if(((i<=N-2)&&(station[i+1].Di-station[i].Di>fullD))||((i==N-1)&&(D-station[i].Di>fullD))){ //fullD内无下一站:不能到终点,能跑多远就多远
printf("The maximum travel distance = %.2lf\n",(station[i].Di+fullD));
break;
}
else{ //fullD内有下一站
int z;
if(!FindLowStation(i,fullD,z)){ //fullD内无更低价:加满油,跑到z
sumP+=(Cmax-nowC)*station[i].Pi;
nowC=Cmax-(station[z].Di-station[i].Di)/Davg;
i=z;
}
else{ //fullD内有更低价:用足够的油,跑到z
if((station[z].Di-station[i].Di)/Davg<=nowC){ //油够
nowC=nowC-(station[z].Di-station[i].Di)/Davg;
i=z;
}
else{ //油不够
sumP+=((station[z].Di-station[i].Di)/Davg-nowC)*station[i].Pi;
nowC=0.0;
i=z;
}
}
}
}
}
}
return 0;
}
//求更低价或较低价站函数
//在范围内,有更低价的站,则用z引用带回最近的,返回true,;没有,返回false,用z引用带回相对最低价的
//a:当前站;Dis:在该距离范围内搜索;z:见上行
bool FindLowStation(int a,double Dis,int &z){
int j=1;
double lowerP=station[a+1].Pi;
while(station[a+j].Di<=(station[a].Di+Dis) && (a+j)<N){
if(station[a+j].Pi<station[a].Pi){
z=a+j;
return true;
}
else{
if(station[a+j].Pi<=lowerP){
lowerP=station[a+j].Pi;
z=a+j;
}
}
j++;
}
return false;
}