算法题15 穿越沙漠问题,飞机加油问题

 

一、问题描述

一辆吉普车来到1000km宽的沙漠边沿。吉普车的耗油量为1L/km,总装油量为500L。显然,吉普车必须用自身油箱中的油在沙漠中设几个临时 加油点,否则是通不过沙漠的。假设在沙漠边沿有充足的汽油可供使用,那么吉普车应在哪些地方、建多大的临的加油点,才能以最少的油耗穿过这块沙漠?

二、问题分析

本题是一个极值问题,要求具有最小的油耗。因此,它的解是唯一的。吉普车在沙漠中建临时油库,是逐步向前推进的,即建好一个油库后,再建下一个油库。为使油耗最小应做到:

(1)每次吉普车出发时都应满载,放下一部分油再返回时,油恰好用完,并且把下一    个油库建好后这个油库中的油恰好用完。所以每个点的油库中的油都应是吉普车装油量的整数倍(因为出发时满载),即500Xk(k为正整数),并且每个点的 存油量为下一个点的存油量及吉普车为建立下个油库在两点之间往返的油耗之和 (下一个油库建成,前一个油库中的油恰好用完)。

(2)吉普车为建立下一个油库运油次数应最少。

用递推法解这个题,可由一个点的存油量推出相邻的另一个点的存油量及两点之    间的距离。但正推是不可能的,因为第一个点的存油量及其距A的距离尚无法确定。但是可推得最后一个点Cl的存油量应为500L,它与B相距为500km, 这样吉普车从Cl到达B恰好跑一趟B。递推必须由已知的初始条件开始。为此本题应使用倒推法。A为起始点,B为终 点, C1,…,Cn分别为倒数第1,2,…,n个临时油库点。

由于B点无需储油,吉普车只须从Cl到达B即可,所以C1点的存油量应为500L,C1到B的距离为500km。为向C1送500L油,吉普车最少 要满载出发两次(若一趟,因途中要耗油而不可能),往返共三程(应为奇数)。考虑最少油耗,C2点应存油2*500L。由此可得如下关系:

    v2=3*x2+500=2*500

    x2=500/3

    C2:距B的路程为:

    d2=d1+x2=500+500/3=(1+1/3)*500

为向C2:送1000L油,吉普车最少要满载出发3次,往返共5趟。考虑最少油耗,C3,点应存油3*500L。由此可得:

    v3=5*x3+v2=3*500

    x3=500/5

    d3=d2+x3=(1+1/3+1/5)*500

同理可知,对倒数第i个点有:  

    Vi=(2*i-1)Xi+Vi-1=i*500    —

    Xi=500/(2*i—1)    :

    Di=di-1+xi=(1+1/3+1/5+…1/(2*i-1))*500

    递推到di≥1000时结束。当di≥1000时,Ci-1就是倒数最后一个油库点。它距A的距离为1000—di-l。

 

相关代码:

 //************************************ // 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

 

 

 

相关问题1:

飞机加油问题

每个飞机只有一个油箱,
飞机之间可以相互加油(注意是相互,没有加油机)
一箱油可供一架飞机绕地球飞半圈,
问题
为使至少一架飞机绕地球一圈回到起飞时的飞机场,至少需要出动几架飞机?(所有飞机从同一机场起飞,而且必须安全返回机场,不允许中途降落,中间没有飞机场)


3 架解法(地球是圆的)

 

首先AB两架飞机同时满油起飞,油耗1/3,即飞行1/6的距离点1时,把B中1/3的油加到A中,B返回,此时A满油,如不加油可飞1/2的距离点2,总共飞1/6+1/2=2/3的距离,此时距离原点还有1/3距离,故可在飞机A距离点2还有1/3的距离时,从机场起飞满油飞机C迎向A,可在A空油时正好在点2相遇,C给A加1/3油,C返回即可。当C起飞时,A从点1飞行了1/2-1/3 = 1/6的距离,此时B尚未返回。

 

 

问题变形:

 

一个商人骑一头驴要穿越1000公里长的沙漠,去卖3000根胡萝卜。已知驴一次性可驮1000根胡萝卜,但每走1公里又要吃掉1根胡萝卜。问:商人最多可卖出多少胡萝卜?

同样的道理:为使利益最大,需要建立临时补给站。且临时补给站的存货应该是驴最大负重的整数倍。此题与第一题的不同之处在于在最小消耗下运送最大的量。

设沙漠两端AB,最后的补给站为C1,则C1 = 1000,距离B点还有x公里,d1 = x>=0.目标x最小。

C2点:

C2 = 1000*2,

d2 = d1+x2 = d1+1000/3 = x+1000/3;

 

C3点:

C3 = 1000*3

d3 = d2+x3 = x + (1/3+1/5)*1000

 

di = x+(1/3+1/5+...+1/(2*i-1))*1000

Ci = 1000*i

 

商人要卖出最多的胡萝卜就要使Cn = 初始总量W。即把起点也看作一个临时补给站。

商人做多可卖出的胡萝卜y = 1000-x = (1/3+1/5)*1000 = 533

你可能感兴趣的:(算法题)