贪心算法解旅行家的预算问题
题目描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离D1汽车油箱的容量C(以升为单位)、每升汽油能行驶的距离D2、出发点每升汽油价格P和沿途油站数N(N可以为零),油站i离出发点的距离Di、每升汽油价格Pi(i=1,2,…,N)。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
输入格式
第一行,D1,C,D2,P,N。
接下来有N行。
第i+1行,两个数字,油站i离出发点的距离Di和每升汽油价格Pi。
输出格式
所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出“No Solution”。
输入输出样例
输入 #1
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
输出 #1
26.95
说明/提示
N≤6,其余数字≤500
解题思路
这题求解最小费用,比较适合用贪心法(贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅是在某种意义上的局部最优解。)
把起点看做第一个加油站,然后将加油站按照到起点的距离从小到大排序,方便后面求解。
遍历加油站,每到一个加油站结算一次。
如果下一个加油站的油价比当前加油站的便宜,就在当前加油站加恰好能到下一站的油。
如果在当前加油站加满油都不能到达下一个比当前油价还低的加油站,那么就在当前加油站加满油(因为之后买的油会比当前加油站贵),然后前往能到达的加油站中最便宜的那个。
如果在当前加油站加满油还是到不了任何一个加油站,也到不了终点,则无解。
完整代码
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
struct jyz//加油站结构体
{
float dis;
float cos;
}jy[500];
int compare(jyz a,jyz b)//用于下面对加油站排序
{
return a.dis<b.dis;
}
int main()
{
float d1,c,d2,p;
int n;
cin>>d1>>c>>d2>>p>>n;
jy[0].dis=0;//把起点看做第一个加油站
jy[0].cos=p;
for(int i=1;i<=n;i++)
cin>>jy[i].dis>>jy[i].cos;
sort(jy,jy+n,compare);//将加油站按照离起点的距离从小到大排列
float money=0,restdis=0;//到达当前加油站所剩余的油还能走多远
float maxdis=c*d2;//油箱加满最多能走的距离
//每到一个加油站清算一次
int now=0;//当前加油站
while(1){
int flag=-1;//标记位,代表能到达哪个加油站
for(int i=now+1;(i<=n)&&(jy[i].dis-jy[now].dis<=maxdis);i++)
{
//若下一个加油站油价比当前便宜,则在当前加油站加恰好能到下一站的油
if(jy[i].cos<jy[now].cos)
{
money=money+jy[now].cos*((jy[i].dis-jy[now].dis-restdis)/d2);
restdis=0;
now=i;
goto a;
}
if((flag==-1)||(jy[i].cos<jy[flag].cos)) flag=i;//更新能到达的加油站
}
//如果在当前加油站可以直接到达终点
if(d1-jy[now].dis<=maxdis)
{
money=money+jy[now].cos*((d1-jy[now].dis-restdis)/d2);
cout<<fixed<<setprecision(2)<<money;
break;
}
//如果flag仍然为-1代表加满油也到不了任何地方,即无解
if(flag==-1)
{
cout<<"No Solution";
break;
}
//如果在当前加油站加满油也无法到达下一个比当前油价低的加油站或终点,就加满油前往能到达的油价最低的加油站
else
{
money=money+c*jy[now].cos;
restdis=maxdis-(jy[flag].dis-jy[now].dis);
now=flag;
}
a:continue;
}
return 0;
}