一、问题描述
一辆吉普车来到1000km宽的沙漠边沿。吉普车的耗油量为1L/km,总装油量为500L。显然,吉普车必须用自身油箱中的油在沙漠中设几个临时 加油点,否则是通不过沙漠的。假设在沙漠边沿有充足的汽油可供使用,那么吉普车应在哪些地方、建多大的临的加油点,才能以最少的油耗穿过这块沙漠?
二、分析解答
A-----------Cn---C3---------C2------------------C1--------------------B
起点 临时加油站 终点
从这个题目来看,这是一个极限问题,求得是最少耗油的量,所以只有唯一答案。
1、从题目来看,为了穿越这个沙漠,同时耗油量最少,那么吉普车就应该每次出发的时候都要满油量出发。
2、为了保证每一次都是满油量的从每个临时加油站出发,那么每一个临时加油站的油量储备都应该是500L的倍数。
3、为了保证耗油量最少,每一次建立一个临时加油站的时候,运输的次数也是越少越好,减少重复的路段。
4、如果这道题通过递推法正推的话很难确定第一个临时加油站的地点。
5、所以这里我们用倒推法来做。
6、假设我们已经到达了B点,这个时候B点的储油量应该0,这是可以倒推C1点的储油量应该为500L,这时候可以刚好到达终点B。好了现在我们知道C1点的储油量了,也就知道了C1到B点的距离为500米。
7、这时候我们应该想,如果向C1点运输500L的油量,C2点应该存储多少油呢?根据上面的步骤2(临时加油站的油量储备都应该是500L的倍数)和步骤3(运输的次数也是越少越好,这里肯定是两次或者两次以上才能向C1点运输500L油,这里取2次),那么我们就知道了C2点的储油量应该是500L*2,也就是1000L油。这时,C2到C1的距离为500/3。
8、如果想C2点运输1000L的油,重复步骤7可知,C3点存储油量为500×3L,C3到C2的距离为500/5。
9、所以到达临时加油站Cn的时候,储油量应该是500×n,Cn到Cn-1的距离为500/2n-1。
所以这里通过下面这个式子算出n:
500+500/3+500/5+500/(2n-1) = 1000;
然后就可以得出最少耗油量。
//************************************
// Method: 穿越沙漠问题,最小油耗解法.临时补给站不留油
// Parameter: double dDis,沙漠宽度,两端距离
// Parameter: double speed,单位距离的油耗速度
// Parameter: double oilPer,单次的最大负载
// Returns: void
//************************************
void Travel_Answer(double dDis, double speed, double oilPer)
{
// 满负载可行距离
double disPer = oilPer/speed;
if(dDis <= disPer)
{
printf("总距离小于单次满负载可行距离,直接通过即可/n");
return;
}
// 否则需要设置临时补给站,每个临时补给站的储油量应该是单次最大负载的整数倍
double d = disPer;
int i = 1;
while(d < dDis)
{
// 计算下一个补给站
++i;
d += 1.0/(2*i-1)*disPer;
}
printf("起点需设储油量:%g/n", oilPer*i);
double totalOil = -1;
while(i>1)
{
d -= disPer/(2*i-1);
--i;
if(totalOil < 0)
{
totalOil = oilPer*i + (dDis-d)*(2*i+1)/speed;
}
printf("下一个补给点为距起点%g处,储油量:%g/n", dDis - d, oilPer*i);
}
printf("总耗油量:%g", totalOil);
}
输出的结果:
起点需设储油量:4000
下一个补给点为距起点22.4331处,储油量:3500
下一个补给点为距起点60.8947处,储油量:3000
下一个补给点为距起点106.349处,储油量:2500
下一个补给点为距起点161.905处,储油量:2000
下一个补给点为距起点233.333处,储油量:1500
下一个补给点为距起点333.333处,储油量:1000
下一个补给点为距起点500处,储油量:500
总耗油量:3836.5