Đề bài:
Thuật toán:
- Gọi L[i] là độ dài dãy con tăng dài nhất bắt đầu bằng phần tử thứ i trong dãy
- L[i] = L[j] + 1 với j=i+1..n và a[j] > a[i]
- Sử dụng tìm kiếm nhị phân để tính nhanh mảng L[]
Bạn hãy tham khảo cụ thể thuật toán bài này ở trang 143 quyển “Giải thuật và lập trình” – thầy Lê Minh Hoàng. Theo mình đánh giá thì đây là thuật + code chi tiết nhất, rất phù hợp cho các bạn newbie. Nếu đã hiểu rồi thì code sẽ ngắn hơn thầy nhiều 🙂
Code:
program LongestSubSequence;
const
InputFile = 'INCSEQ.INP';
OutputFile = 'INCSEQ.OUT';
const
max = 5000;
var
a, L, T, StartOf: array[0..max + 1] of Integer;
n, m: Integer;
procedure Enter;
var
i: Word;
f: Text;
begin
Assign(f, InputFile); Reset(f);
ReadLn(f, n);
for i := 1 to n do Read(f, a[i]);
Close(f);
end;
procedure Init;
begin
a[0] := -32768;
a[n + 1] := 32767;
m := 1;
L[n + 1] := 1;
StartOf[1] := n + 1;
end;
function Find(i: Integer): Integer;
var
inf, sup, median, j: Integer;
begin
inf := 1; sup := m + 1;
repeat
median := (inf + sup) div 2;
j := StartOf[median];
if a[j] > a[i] then inf := median
else sup := median;
until inf + 1 = sup;
Find := StartOf[inf];
end;
procedure Optimize;
var
i, j, k: Integer;
begin
for i := n downto 0 do
begin
j := Find(i);
k := L[j] + 1;
if k > m then
begin
m := k;
StartOf[k] := i;
end
else
if a[StartOf[k]] < a[i] then
StartOf[k] := i;
L[i] := k;
T[i] := j;
end;
end;
procedure Result;
var
f: Text;
i: Integer;
begin
Assign(f, OutputFile); Rewrite(f);
Writeln(f, m - 2);
i := T[0];
while i <> n + 1 do
begin
Writeln(f, 'a[', i, '] = ', a[i]);
i := T[i];
end;
Close(f);
end;
begin
Enter;
Init;
Optimize;
Result;
end.
Speak Your Mind