【問題描述】:算法
設有由n個不相同的整數組成的數列,記爲:b(1)、b(2)、……、b(n)且b(i)<>b(j) (i<>j),若存在i1<i2<i3< … < ie 且有b(i1)<b(i2)< … <b(ie)則稱爲長度爲e的不降低序列。程序要求,當原數列給出以後,求出最長的不降低序列。數組
例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一個長度爲7的不降低序列,同時也有7 ,9,16,18,19,21,22,63長度爲8的不降低序列。數據結構
【算法分析】:根據動態規劃的原理,由後往前進行搜索。ide
1)、對b(n)來講,因爲它是最後一個數,因此當從b(n)開始查找時,只存在長度爲1的不降低序列;spa
2)、若從b(n-1)開始查找,則存在下面的兩種可能性:code
①若b(n-1)<b(n)則存在長度爲2的不降低序列b(n-1),b(n)。blog
②若b(n-1)>b(n)則存在長度爲1的不降低序列b(n-1)或b(n)。ci
3)、通常若從b(i)開始,此時最長不降低序列應該按下列方法求出:it
在b(i+1),b(i+2),…,b(n)中,找出一個比b(i)大的且最長的不降低序列,做爲它的後繼。event
【數據結構】:
爲算法上的須要,定義一個數組整數類型二維數組b(N,3)
1)、b(i,1)表示第i個數的數值自己;
2)、b(i,2)表示從i位置到達N的最長不降低序列長度
3)、b(i,3)表示從i位置開始最長不降低序列的下一個位置,若b[i,3]=0則表示後面沒有鏈接項。
【求解過程】:
① 從倒數第二項開始計算,後面僅有1項,比較一次,因63>15,不符合要求,長度仍爲1
② 從倒數第三項開始其後有2項,需作兩次比較,獲得目前最長的不降低序列爲2,以下表:
|
11 |
12 |
13 |
14 |
…… |
|
11 |
12 |
13 |
14 |
|
|
22 |
63 |
15 |
…… |
|
21 |
22 |
63 |
15 |
|
|
2 |
1 |
1 |
…… |
|
3 |
2 |
1 |
1 |
|
|
13 |
0 |
0 |
…… |
|
12 |
13 |
0 |
0 |
【通常處理過程】:
①在i+1,i+2,…,n項中,找出比b[I,1]大的最長長度L以及位置K;
②若L>0,則b[I,2]:=L+1;b[I,3]:=k;
最後本題通過計算,其數據存儲表以下:
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
13 |
7 |
9 |
16 |
38 |
24 |
37 |
18 |
44 |
19 |
21 |
22 |
63 |
15 |
7 |
8 |
7 |
6 |
3 |
4 |
3 |
5 |
2 |
4 |
3 |
2 |
1 |
1 |
4 |
3 |
4 |
8 |
9 |
7 |
9 |
10 |
13 |
11 |
12 |
13 |
0 |
0 |
1 初始化: 2 for i:=1 to n do
3 begin
4 read(b[i,1]); 5 b[i,2]:=1;b[i,3]:=0; 6 end; 7 下面給出求最長不降低序列的算法: 8 for i:=n-1 downto 1 do
9 begin
10 L:=0;k:=0; 11 for j:=i+1 to n do
12 if(b[j,1]>b[i,1])and(b[j,2]>L) then begin
13 L:=b[j,2]; 14 k:=j; 15 end; 16 if L>0 then begin
17 b[i,2]:=L+1; 18 b[i,3]:=k; 19 end; 20 end; 21 下面找出最長不降低序列: 22 k:=1; 23 for j:=1 to n do
24 if b[j,2]>b[k,2] then k:=j; 25 最長不降低序列長度爲B(k, 2)序列 26 while k<>0 do
27 begin
28 write(b[k,1]:4); 29 k:=b[k,3]; 30 end;
1 var 2 n,i,L,k,j:integer; 3 b:array[1..100,1..3]of integer; 4 begin 5 readln(n); 6 for i:=1 to n do 7 begin 8 read(b[i,1]); 9 b[i,2]:=1;b[i,3]:=0; 10 end; 11 for i:=n-1 downto 1 do 12 begin 13 L:=0;k:=0; 14 for j:=i+1 to n do 15 if(b[j,1]>b[i,1])and(b[j,2]>L) then begin 16 L:=b[j,2]; k:=j; 17 end; 18 if L>0 then begin 19 b[i,2]:=L+1;b[i,3]:=k; 20 end; 21 end; 22 k:=1; 23 for j:=1 to n do 24 if b[j,2]>b[k,2] then k:=j; 25 writeln('max=',b[k,2]); 26 while k<>0 do 27 begin 28 write(b[k,1]:4); 29 k:=b[k,3]; 30 end; 31 writeln; 32 end.
程序運行結果:
輸入:14
13 7 9 16 38 24 37 18 44 19 21 22 63 15
輸出:max=8
7 9 16 18 19 21 22 63
1 var 2 i,n,max,st,en:longint; 3 b:array[1..100000,1..3] of longint; 4 procedure Init; 5 var i:longint; 6 begin 7 readln(n); 8 for i:=1 to n do 9 begin 10 read(b[i,1]); 11 b[i,2]:=1; b[i,3]:=0; 12 end; 13 end; 14 procedure Lis; 15 var i,j,maxl,loca:longint; 16 begin 17 for i:=n-1 downto 1 do 18 begin 19 maxl:=0; loca:=0; 20 for j:=i+1 to n do 21 if b[i,1]<b[j,1] then 22 //begin 23 if b[j,2]>maxl then 24 begin 25 maxl:=b[j,2]; 26 loca:=j; 27 end; 28 //end; 29 if maxl>0 then 30 begin 31 b[i,2]:=maxl+1; 32 b[i,3]:=loca; 33 end; 34 end; 35 end; 36 procedure Findmax; 37 var i:longint; 38 begin 39 max:=0; 40 for i:=1 to n do 41 if b[i,2]>max then 42 begin 43 max:=b[i,2]; 44 st:=i; 45 end; 46 end; 47 procedure Outit; 48 var i:longint; 49 begin 50 writeln(max); 51 i:=st; 52 while i<>0 do 53 begin 54 write(b[i,1],' '); 55 i:=b[i,3]; 56 end; 57 end; 58 begin 59 Init; 60 Lis; 61 Findmax; 62 Outit; 63 end.
某國爲了防護敵國的導彈襲擊,發展出一種導彈攔截系統。可是這種攔截系統有一個缺陷:雖然它的第一發炮彈可以到達任意的高度,可是之後每一發炮彈都不能高於前一發的高度。某天,雷達捕捉到敵國的導彈來襲,因爲該系統還在試用階段。因此只有一套系統,所以有可能不能攔截全部的導彈。輸入導彈依次飛來的高度(雷達給出的高度不大於30000的正整數)。計算這套系統最多能攔截多少導彈。
輸入:N顆依次飛來的導彈高度,(導彈個數<=1000)。
輸出:一套系統最多攔截的導彈數,並依次打印輸出被攔截導彈的高度。
在本題中不只要求輸出最優解,並且還要求輸出最優解的造成過程。爲此,咱們設置了一張記憶表C[i],在按從後往前方式求解的過程當中,將每個子問題的最佳決策保存起來,避免在輸出方案時重複計算。
階段i: 由右而左計算導彈n‥導彈1中可攔截的最多導彈數(1≤i≤n);
狀態B[i]: 因爲每一個階段中僅一個狀態,所以可經過一重循環
for i := n-1 downto 1 do 枚舉每一個階段的狀態B[i];
決策k:在攔截導彈i以後應攔截哪一枚導彈可以使得B[i]最大(i+1≤k≤n),
1 2 3 4 5 6 7 8 9 10 11 12 13 14 I
13 7 9 16 38 24 37 18 44 19 21 22 63 15 A[I] {高度}
2 1 1 2 4 3 3 2 3 2 2 2 2 1 B[I] {可攔截數}
2 0 0 14 6 8 8 14 10 14 14 14 14 0 C[I] {再攔截}
1 var 2 a,b,c:array[1..1000] of longint; 3 n,i,j,k,max:longint; 4 begin 5 n:=0; {初始化,讀入數據} 6 while not eoln do 7 begin {eoln :行結束} 8 inc(n);read(a[n]); 9 b[n]:=1; c[n]:=0; 10 end; 11 readln; 12 for i:=n-1 downto 1 do {枚舉每個階段的狀態,設導彈i被攔截} 13 begin 14 max:=0; j:=0; 15 for k:=i+1 to n do {枚舉決策,計算最佳方案中攔截的下一枚導彈} 16 if (a[k]<=a[i]) and (b[k]>max) then begin max:=b[k];j:=k; end; 17 b[i]:=max+1; c[i]:=j; {若導彈i以後攔截導彈j爲最佳方案,則記下} 18 end; 19 max := 0; 20 for i := 1 to n do {枚舉求出一套系統能攔截的最多導數} 21 if b[i]>max then begin max:=b[i]; j:=i; end; 22 writeln('Max = ',b[j]); {打印輸出結果} 23 while j>0 do 24 begin 25 write(a[j]:5); j:=c[j]; 26 end; 27 end.