一、概述
这是一道考察贪心算法的题目。
我在设计算法的时候想错了,我是这样思考的:
设置窗口为满油时能跑的距离,以加油站为左端点的窗口长度的范围内,寻找油价最低的加油站,并驱车前往。这是错误的。如下:
设置区间内有三个加油站a,b,c,油价分别为6,4,3,左端点油价为5,那么按照我的想法,则是直接从左端点加油,油量为加完之后恰好能开到c加油站的油,那么我加油的单价就是5;
但是正确的思路应该是:以加油站为左端点的窗口长度的范围内,首先寻找第一个油价低于左端点的加油站,并驱车前往,如果没有油价低于左端点的加油站,则加满油,前往油价最低的加油站。同样以上文举例,由于存在b加油站油价低于左端点,那么就加油然后开到b,再在b加油然后开到c,这样一部分油价是5,一部分是4,比上面的思路要省钱。
另外,为了使代码简洁易懂,要设置终点为距离为D油价为0的加油站,不然会很麻烦。要多判断好多步。
另外要注意,当不加满油时,只要使油箱内油的总量能够跑到下一个加油站即可,意思就是可能在这个加油站停下了,但是由于油箱内的油还够跑到下一个加油站的,那么就不加油。
二、分析
首先输入数据,并按距离排序,然后在最后一个加上目的地节点。如下:
float Cmax,Davg;
int D,N;
scanf("%f %d %f %d",&Cmax,&D,&Davg,&N);//油箱容量,总距离,每单位油能跑多远,总加油站数量
float Maxlength=Cmax*Davg;//油箱是满的的时候,最多可以走多远,这是一个窗口
int i;
for(i=0;i<N;i++)
scanf("%f %f",&gas[i].price,&gas[i].distance);
gas[N].distance=D;
gas[N].price=0;
sort(gas,gas+N+1,cmpdistance);
注意下标一定要是int型,不能是float型。
然后,设置四个变量,
目前油箱有多少油,负责计算加满要多少钱和用不用加油;
目前在哪个加油站,负责定位;
目前花了多少钱,负责最后输出;
目前走了多远,没用,历史原因。
注意变量,该用float用float,该用int用int。
如下:
float Cnow=0;//目前油箱有多少油
float Dnow=0;//目前公里数
int Nnow=0;//目前在哪个加油站
float sum=0;//目前花了多少钱
int dest=0;//不能到达目的地
if(gas[0].distance!=0)
{
printf("The maximum travel distance = 0.00");
}
else
{
while(Nnow<N)
{
int j;
float min=INF;
int Nmin=-1;
for(j=Nnow+1;j<=N&&gas[j].distance-gas[Nnow].distance<=Maxlength;j++)
{
if(gas[j].price<min)
{
min=gas[j].price;
Nmin=j;
if(min<gas[Nnow].price)
{
break;
}
}
}
if(Nmin==-1)
{
printf("The maximum travel distance = %.02f",gas[Nnow].distance+Maxlength);
break;
}
if(min>gas[Nnow].price)//加满油
{
float _D=gas[Nmin].distance-gas[Nnow].distance;
Dnow+=_D;
float _C=_D/Davg;
sum+=(Cmax-Cnow)*gas[Nnow].price;
Cnow=Cmax-_C;
Nnow=Nmin;
}
else//加到够下一站的油
{
float _D=gas[Nmin].distance-gas[Nnow].distance;
Dnow+=_D;
float _C=_D/Davg;
if(_C<Cnow)
Cnow=Cnow-_C;
else
{
sum+=(_C-Cnow)*gas[Nnow].price;
Cnow=0;
}
Nnow=Nmin;
}
}
}
分两种情况:
加满油和加够油。
当左端点是窗口的最小值时,加满油;否则加到下一个加油站的油。
不会存在到目的地还有油的情况,分析如下:
如果窗口内有目的地存在,那么不存在加满油的情况;
如果窗口内没有目的地存在,即使加满油也到不了目的地;
而不加满油的话,当第一次在窗口内看到目的地时,一定不会把油加满,这样就杜绝了多余油的可能性。
还是有点绕的。
三、总结
对于这类需要自己分析逻辑的问题,最好的方法就是把样例手算一遍。算完了也就全懂了,之后就是把自然语言翻译成代码的过程了。
PS:代码如下
#include<stdio.h>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
int INF=1000000000;
struct Gas
{
float price;
float distance;
}gas[510];
bool cmpdistance(Gas a,Gas b)
{
if(a.distance!=b.distance)
return a.distance<b.distance;
else
return a.price<b.price;
}
int main()
{
float Cmax,Davg;
int D,N;
scanf("%f %d %f %d",&Cmax,&D,&Davg,&N);//油箱容量,总距离,每单位油能跑多远,总加油站数量
float Maxlength=Cmax*Davg;//油箱是满的的时候,最多可以走多远,这是一个窗口
int i;
for(i=0;i<N;i++)
scanf("%f %f",&gas[i].price,&gas[i].distance);
gas[N].distance=D;
gas[N].price=0;
sort(gas,gas+N+1,cmpdistance);
float Cnow=0;//目前油箱有多少油
float Dnow=0;//目前公里数
int Nnow=0;//目前在哪个加油站
float sum=0;//目前花了多少钱
int dest=0;//不能到达目的地
if(gas[0].distance!=0)
{
printf("The maximum travel distance = 0.00");
}
else
{
while(Nnow<N)
{
int j;
float min=INF;
int Nmin=-1;
for(j=Nnow+1;j<=N&&gas[j].distance-gas[Nnow].distance<=Maxlength;j++)
{
if(gas[j].price<min)
{
min=gas[j].price;
Nmin=j;
if(min<gas[Nnow].price)
{
break;
}
}
}
if(Nmin==-1)
{
printf("The maximum travel distance = %.02f",gas[Nnow].distance+Maxlength);
break;
}
if(min>gas[Nnow].price)//加满油
{
float _D=gas[Nmin].distance-gas[Nnow].distance;
Dnow+=_D;
float _C=_D/Davg;
sum+=(Cmax-Cnow)*gas[Nnow].price;
Cnow=Cmax-_C;
Nnow=Nmin;
}
else//加到够下一站的油
{
float _D=gas[Nmin].distance-gas[Nnow].distance;
Dnow+=_D;
float _C=_D/Davg;
if(_C<Cnow)
Cnow=Cnow-_C;
else
{
sum+=(_C-Cnow)*gas[Nnow].price;
Cnow=0;
}
Nnow=Nmin;
}
}
}
if(Nnow==N)
printf("%.02f",sum);
/*while(Nnow<N)//
{
float cheap=gas[Nnow].price;//最便宜的价格默认是起点的价格
int j=Nnow;
int cheapstation=Nnow + 1;
while(gas[j]<=gas[Nnow]+MAxlength&&j<N)
{
if(gas[j].price<=cheap)
{
cheap=gas[j].price;
cheapstation=j;
}//找到从起点开始,能跑一整箱的距离内,最便宜的加油站
j++;
}
if(gas[cheapstation].price>gas[Nnow].price)//如果起点的油价最低
{
float _D=gas[cheapstation].distance-gas[Nnow].distance;//到最便宜加油站距离
float _C=_D/Davg;//到最便宜加油站要多少油
sum+=(Cmax-Cnow)*gas[Nnow].price;
Cnow=Cmax-_C;//在起点加满油
Nnow=cheapstation;//走到最便宜加油站
if(Dnow-_D>0)
Dnow=Dnow-_D;
else
{
dest=1;
break;
}
}
else//如果起点油价不是最低
{
float _D=gas[cheapstation].distance-gas[Nnow].distance;//到最便宜加油站距离
float _C=_D/Davg;//到最便宜加油站要多少油
float _sum=0;
if(Cnow>_C)//如果油箱的油够到
{
_sum=0;//这里不加油
Cnow=Cnow-_C;
}
else //油不够
{
_sum=(_C-Cnow)*gas[Nnow].price;//这么多油要多少钱
Cnow=0;
}
sum+=_sum;
Nnow=cheapstation;//走到最便宜加油站
if(Dnow-_D>0)
Dnow=Dnow-_D;
else
{
dest=1;
break;
}
}
}*/
}