遞推算法之一:倒推法
1、一般分析思路:
if 求解初始條件F1
then begin
{ 倒推 }
由題意(或遞推關系)確定最終結果Fn;
求出倒推關系式Fi-1 =G(Fi );
i=n;
{ 從最終結果Fn出發進行倒推 }
while 當前結果Fi非初始值F1
do 由Fi-1=G(Fi)倒推前項;
輸出倒推結果F1和倒推過程;
end { of then } else
begin
{ 順推 }
由題意(或遞推關系)確定初始值F1(邊界條件);
求出順推關系式Fi=G(Fi-1); i=1;
{ 由邊界條件F1出發進行順推 }
while 當前結果Fi非最終結果Fn
do
由Fi=G(Fi-1)順推后項;
輸出順推結果Fn和順推過程;
end;
{ of else }
所謂倒推法,就是在不知初始值的情況下,經某種遞推關系而獲知問題的解或目標,再倒過來,推知它的初始條件。因為這類問題的運算過程是一一映射的,故可分析得其遞推公式。然后再從這個解或目標出發,采用倒推手段,一步步地倒推到這個問題的初始陳述。
2,【例一】貯油點
一輛重型卡車欲穿過1000公里的沙漠,卡車耗油為1升/公里,卡車總載油能力為500公升。顯然卡車裝一次油是過不了沙漠的。因此司機必須設法在沿途建立幾個貯油點,使卡車能順利穿越沙漠,試問司機如何建立這些貯油點?每一貯油點應存多少汽油,才能使卡車以消耗最少汽油的代價通過沙漠?
算法分析:
編程計算及打印建立的貯油點序號,各貯油點距沙漠邊沿出發的距離以及存油量。
No. distance(km) oil(litre)
1 ×× ××
2 ×× ××
3 ×× ××
… …… ……
設dis[i]─第i個貯油點至終點(i=0)的距離; oil[i]─第i個貯油點的存貯油量; 我們可以用倒推法來解決這個問題。從終點向始點倒推,逐一求出每個貯油點的位置及存油量。
從貯油點i向貯油點i+1倒推的策略是,卡車在點i和點i+1間往返若干次。卡車每次返回i+1處時正好耗盡500公升汽油,而每次從i+1處出發時又必須裝足500 公升汽油。兩點之間的距離必須滿足在耗油最少的條件下使i點貯足i*500公升汽油的要求(0≤i≤n-1)。具體地講,嵉諞桓鮒 偷鉯=1應距終點i=0處500 km 且在該處貯藏500公升汽油, 這樣才能保證卡車能由i=1處到達終點i=0處,這就是說 dis[1]=500 ol[1]=500;
為了在i=1處貯藏500公升汽油,卡車至少從i=2處開兩趟滿載油的車至i=1處。所以 i=2處至少貯有2*500公升汽油,即oil[2]=500*2=1000。另外,再加上從i=1返回至i=2處的一趟空載,合計往返3次。三次往返路程的耗油量按最省要求只能為500公升,即d12 =500/3km, dis[2]=dis[1]+d12 = dis[1]+500/3
為了在i=2處貯存1000公升汽油,卡車至少從i=3處開三趟滿載油的車至i=2 處。所以i=3處至少貯有3*500公升汽油,即oil[3]=500*3=1500。加上i=2至i=3 處的二趟返程空車, 合計5次。路途耗油量亦應500公升,即d23 =500/5, dis[3]=dis[2]+d23 = dis[2]+500/5;
依次類推,為了在i=k處貯藏k*500公升汽油,卡車至少從i=k+1處開k趟滿載車至i=k處,即oil[k+1]=(k+1)*500=oil[k]+500,加上從i=k返回i=k+1的k-1 趟返程空車,合計2k-1次。這2k-1次總耗油量按最省要求為500公升,即dk,k+1 = 500/(2k-1), dis[k+1] = dis[k]+dk,k+1 = dis[k]+500/(2k-1);
最后, i=n至始點的距離為1000-dis[n],oil[n]=500*n。為了在i=n處取得n*500公升汽油, 卡車至少從始點開n+1次滿載車至i=n,加上從i=n返回始點的n 趟返程空車,合計2n+1次,2n+1 趟的總耗油量應正好為(1000-dis[n])*(2n+1), 即始點藏油為oil[n]+(1000-dis[n])*(2n+1)。
下面為程序題解:
program oil_lib;
var k: integer; {貯油點位置序號}
d, {累計終點至當前貯油點的距離} d1: real; {i=n至始點的距離}
oil, dis: array[1..10] of real;
i: integer; {輔助變量}
begin
writeln ('NO.',' distance(k.m)':30,'oil(l.)':80);
k:=1; d:=500;
{從i=1處開始向始點倒推}
dis[1]:=500;
oil[1]:=500;
repeat k:=k+1;
d:=d+500/(2*k-1);
dis[k]:=d;
oil[k]:=oil[k-1]+500;
until d>=1000;
dis[k]:=1000; {置始點至終點的距離值}
d1:=1000-dis[k-1]; {求i=n處至始點的距離}
oil[k]:=d1*(2*k+1)+oil[k-1]; {求始點藏油量}
for i:=0 to k do {由始點開始,逐一打印始點至當前貯油點的距離和藏油量}
writeln (i,1000-dis[k-i]:30,oil[k-i]:80);
end. {main}
代碼實現:
/******************貯油點問題********************/ #include<stdio.h> int main() { int k=1;//貯油點的編號 int dis[10],oil[10];//貯油點距離終點的距離以及存油量 int d1;//d1記錄離起點最近的貯油點距離,d:累計終點至當前貯油點的距離 int i=0; printf("no.distance(km).oil(L)\n"); dis[1]=500;//從k=1處開始向始點倒推 oil[1]=500; do { k=k+1; dis[k]=dis[k-1]+500/(2*k-1); oil[k]=oil[k-1]+500; }while(!(dis[k]>=1000)); dis[k]=1000;//置始點至終點的距離值 d1=1000-dis[k-1];//求k=n處至始點的距離 oil[k]=d1*(2*k+1)+oil[k-1];//求始點藏油量 for(i=0;i<k;i++)//由始點開始逐一打印始點至當前貯油點的距離和藏油量 { printf("%d\t%d\t%d\n",i,1000-dis[k-i],oil[k-i]); } return 0; }