1. BÀI TOÁN XÂU TRONG CỰC ĐẠI
Xâu con:
S là xâu con của T nếu S nhận được bằng cách xoá đi một số ký tự nào đó trong T.
Ví dụ: ‘EAC’ là xâu con của ‘CEAEEC’
Xâu con chung:
Nếu xóa một số ký tự của hai xâu thì hai xâu con còn lại của chúng bằng nhau
Ví dụ: S1=‘ABCDAE’ và S2=‘XYACADK’ có xâu ‘ACD’ là xâu con chung có độ
dài cực đại.
Bài toán đặt ra:
Cho 2 xâu A, B. Tìm một xâu S là xâu con chung của A và B có độ dài cực đại.
- Input: File Input.doc có cấu trúc:
+ Dòng thứ nhất chứa xâu A
+ Dòng thứ hai chứa xâu B
- Output: File output.doc có cấu trúc:
Nếu bài toán vô nghiệm thì ghi số 0, ngược lại ghi như sau:
+ Dòng thứ nhất ghi số K là số kí tự của xâu chung S
+ Dòng thứ hai là xâu S gồm K kí tự.
BÀI GIẢI:
B1: Phân tích bài toán
Gọi M= length(A); N= length(B);
* Cần xây dựng mảng L[0 M, 0 N] với ý nghĩa: L[I,j] là độ dài của xâu chung dài
nhất của 2 xâu: A[0 i] và B[0 j].
* Bài toán ban đầu là: L[M,N].
Đương nhiên nếu một xâu là rỗng (số kí tự là 0) thì xâu con chung cũng là rỗng, vì
vậy:
L[0,j]=0 ∀ j, j=1 N.
L[i,0]=0 ∀ i, i=1 M.
B2: Giải pháp đệ quy
Với M ≥ I > 0 và N ≥ j > 0 thì:
+ Nếu A[i]=B[j] thì L[I,j] = L[i-1,j-1] +1
+ Nếu A[i] < > B[j] thì:
* Nếu A[i] trong B[1 j] thì nó chỉ thuộc B[1 j-1] nên L[I,j]=L[I,j-1]
* Nếu B[j] trong A[1 i] thì nó chỉ thuộc A[1 i-1] nên L[I,j]=L[I-1,j]
Vì vậy: L[I,j] được tính theo công thức truy hồi sau:
L[I,j] = Max{L[I,j-1], L[i-1,j], L[i-1,j-1] + X} (với X=0 nếu A[i] < > B[j]; X=1 nếu
A[i] = B[j]).
B3: Lập bảng
PROCEDURE LAPBANG;
VAR I,J: BYTE;
BEGIN
FOR I:=1 TO M DO L[I,0]:=0;
FOR J:=1 TO N DO L[0,J]:=0;
FOR I:=1 TO M DO
FOR J:=1 TO N DO
BEGIN
IF A[I] = B[J] THEN L[I,J]:= L[I-1,J-1] +1
ELSE
L[I,J]:=MAX(L[I,J-1],L[I-1,J]);
END;
END;
B4: Tổng hợp kết quả
Procedure TongHop;
Begin
S:=’’;
While (i>0) and (j>0) Do
If L[i,j]=L[i,j-1] then j:=j-1
Else
If L[i,j]=L[i-1,j] then i:=i-1
Else
Begin
S:=A[i]+S;
i:=i-1;
j:=j-1;
End;
End;
* CÀI ĐẶT:
USES CRT;
CONST FI='INPUT.DOC'; FO='OUTPUT.DOC';
VAR F: TEXT; M,N: BYTE; A,B,S: STRING; CH:CHAR;
L: ARRAY[0 100,0 100] OF BYTE;
PROCEDURE DOC_INPUT;
VAR F: TEXT;
BEGIN
M:=0; N:=0;A:=''; B:='';
ASSIGN(F,FI); RESET(F);
WHILE NOT EOLN(F) DO
BEGIN
INC(M); READ(F,CH); A:=A+CH;
END;
READLN(F);
WHILE NOT EOLN(F) DO
BEGIN
INC(N); READ(F,CH); B:=B+CH;
END;
CLOSE(F);
END;
FUNCTION MAX(I,J: INTEGER) : INTEGER;
VAR P: INTEGER;
BEGIN
IF I>J THEN MAX:=I ELSE MAX:=J;
END;
PROCEDURE LAPBANG;
VAR I,J: BYTE;
BEGIN
FOR I:=1 TO M DO L[I,0]:=0;
FOR J:=1 TO N DO L[0,J]:=0;
FOR I:=1 TO M DO
FOR J:=1 TO N DO
BEGIN
IF A[I] = B[J] THEN L[I,J]:= L[I-1,J-1] +1
ELSE
L[I,J]:=MAX(L[I,J-1],L[I-1,J]);
END;
END;
PROCEDURE TONGHOP;
VAR F: TEXT; I,J: INTEGER;
BEGIN
ASSIGN(F,FO); REWRITE(F);
IF L[M,N]= 0 THEN
BEGIN
WRITE(F,0); CLOSE(F);HALT;
END
ELSE
BEGIN
WRITELN(F,L[M,N]);
I:=M; J:=N;
S:='';
WHILE (I>0) AND (J>0) DO
IF L[I,J] = L[I,J-1] THEN DEC(J)
ELSE
IF L[I,J]=L[I-1,J] THEN DEC(I)
ELSE
BEGIN
S:=A[I]+S;
DEC(I); DEC(J);
END;
END;
WRITE(F,S);
CLOSE(F);
END;
BEGIN
CLRSCR;
DOC_INPUT; LAPBANG; TONGHOP;
END.
2. BÀI TOÁN DU LỊCH
* Phát biểu bài toán:
Một người đi từ thành phố 0 đến thành phố n và có thể đi qua n-1 thành phố
khác 1, 2, . . ., n-1, theo lộ trình: 0 -> i
1
-> i
2
. . . -> i
k
-> n, trong đó: 0 < i
1
< i
2
<
i
k
< n. Giá vé xe đi từ thành phố i đến thành phố j là c[i,j].
Tìm một lộ trình từ thành phố 0 đến thành phố n sao cho tổng chi phí về giá vé
đạt cực tiểu.
*Bước 1: Phân tích bài toán
- Gọi ρ(s) là bài toán du lịch, với:
(thành phố xuất phát là 0)
s Î N: là thành phố cần đến.
( Bài toán ban đầu là ρ(n))
- Các giá trị cần tìm:
l[s]: chi phí nhỏ nhất để đi từ 0
→
s của bài toán ρ(s)
u[s]: đỉnh kế cuối trên đường đi từ 0
→
s của bài toán ρ(s)
* Bước 2: Giải pháp đệ quy
- Nếu s=0 thì:
• l[0] = 0
• u[0] = -1
- Nếu s≠0 (0<s) thì:
• l[s] = min (l[k] + c[k,s])
(0
≤
k<s)
= l[k’] + c[k’,s]
• u[s] = k’
* Bước 3: Lập bảng
Procedure Lapbang;
Begin
for s:= 0 to n do
if (s= 0) then Tính l[0] và u[0]
else Tính l[s] và u[s]
End;
Cụ thể:
Procedure lapbang;
var s,k,ke: byte;
min,tam: integer;
begin
for s:=0 to n do
if (s=0) then
begin
l[0]:=0;
u[0]:=-1;
end
else
begin
ke:=0;
min:=max;
for k:=r to s-1 do
if (c[k,s]>0) then
begin
tam:=l[k]+c[k,s];
if (tam<min) then
begin
ke:=k;
min:=tam;
end;
end;
l[s]:=min;
u[s]:=ke;
end;
end;
Độ phức tạp tính toán: O(n
2
)
* Bước 4: Tổng hợp kết quả
Procedure Tonghop;
Begin
i :=1; s := n; x[1] := s;
while s ≠ 0 do
begin
i := i + 1;
s := u[s];
x[i]:= s;
end;
End;
* Chương trình:
const max=32767;
var c:array[0 100,0 100] of integer;
u,l, x:array[1 100] of integer;
n:byte;
procedure docfile;
var f:text;
i,j:byte;
begin
assign(f,'input.txt');reset(f);
readln(f,n);
for i:=0 to n do
for j:=0 to n do read(f,c[i,j]);
close(f);
end;
procedure lapbang;
var s,k,ke:byte;
min,tam:integer;
begin
for s:=0 to n do
if (s=0) then
begin
l[0]:=0;
u[0]:=-1;
end
else
begin
ke:=0;
min:=max;
for k:=0 to s-1 do
if (c[k,s]>0) then
begin
tam:=l[k]+c[k,s];
if (tam<min) then
begin
ke:=k;
min:=tam;
end;
end;
l[s]:=min;
u[s]:=ke;
end;
end;
procedure tonghop;
var i,s,dem:byte;
begin
s:=n;
x[1]:=s;
i:=2;
while (s<>0) do
begin
x[i]:=u[s];
s:=x[i];
i:=i+1;
end;
if (s<>0) then write('Khong co duong di')
else
begin
write('Duong di voi chi phi nho nhat: ');
for dem:=i-1 downto 1 do write(' ',x[dem]:2);
writeln;
writeln('Chi phi nho nhat: ',l[n]);
end;
end;
BEGIN
docfile;
lapbang;
tonghop;
readln;
END.
3. BÀI TOÁN SINH VIÊN ÔN THI
a. Phát biểu bài toán
Một sinh viên còn m ngày để ôn thi n môn. Theo kinh nghiệm của anh ta,
nếu ôn môn j trong i ngày thì được điểm là a[i,j]. Giả sử cho biết các a[i,j] (với
a[i,j] ≤ a[i+1,j]).
Tìm bộ x[j] (số ngày ôn môn j, j = 1 n) sao cho Σx[j] = m và sinh viên đạt
tổng điểm lớn nhất. (Σa[x[j], j] → max).
Input:
- m ∈ N: số ngày ôn thi
- n ∈ N* : số môn ôn thi
- a[i,j] ∈ R: điểm đạt được khi ôn thi môn j trong i ngày. (i=0 m, j=1 n)
Output:
x[j]: số ngày ôn thi môn j (j=1 n) sao cho Σx[j]=n và Σa[x[j],j] đạt max
b. Phân tích bài toán
Gọi P(r,s) là bài toán ôn thi, với:
• r ∈N là số ngày ôn thi.
• s ∈ N* là số môn ôn thi.
(Bài toán ban đầu là P(m,n))
Các giá trị cần tìm:
• diem[r,s]: tổng điểm lớn nhất Σa[x[j],j] của bài toán P(r,s).
• ngay[r,s]: số ngày ôn thi môn s (tức là x[s]) của bài toán P(r,s).
c. Giải pháp đệ quy
• Trường hợp suy biến: s=1 (chỉ có 1 môn)
- ngay[r,s]=ngay[r,1]=r (vì chỉ có 1 môn nên tận dụng hết tất cả r ngày để
ôn thi)
- diem[r,s]=diem[r,1]=a[r,1]
• Trường hợp đệ quy (s>1):
- diem[r,s] = max (a[k,s]+diem[r-k,s-1]) (k: số ngày ôn, 0≤k≤ r thi môn
s)
= a[k’,s]+diem[r-k’,s-1]
Trong đó:
a[k,s] là điểm thi môn thứ s với k ngày ôn
diem[r-k,s-1] là tổng điểm tối ưu của s-1 môn thi với r-k ngày ôn
k' là số ngày ôn thi môn s mà tại đó diem[r,s] có giá trị tối ưu
- ngay[r,s] = k’
d. Lập bảng
Thủ tục LapBang như sau:
Procedure LapBang;
Begin
For r:=0 to m do
For s:=1 to n do
If s=1 then
begin
diem[r,s]:=a[r,s];
ngay[r,s]:=r;
end
Else Tinhdiem_ngay; {Tinh diem[r,s] và ngay[r,s]}
End;
Độ phức tạp tính toán: O(n.m
2
)
Trong đó:
Procedure Tinhdiem_ngay;
Var tam, k,k1:integer;
Begin
k1:=0;
tam:=a[0,s]+diem[r,s-1];
For k:=1 to r do
if tam<a[k,s]+diem[r-k,s-1] then
begin
tam:=a[k,s]+diem[r-k,s-1];
k1:=k;
end;
diem[r,s]:=tam;
ngay[r,s]:=k1;
End;
e. Tổng hợp kết quả
Procedure TongHop;
Begin
r:=m;
For s:=n downto 1 do
begin
x[s]:=ngay[r,s];
r:=r-x[s];
end;
End;
• Độ phức tạp tính toán: O(n)
f. Cài đặt chương trình (bằng Turbo Pascal)
Program Sinh_vien_on_thi;
Uses crt;
Type Mang=array[1 50,1 50] of integer;
Var i,j,r,s,k,n,m,tam,k1:Integer;
A,ngay,diem:Mang;
X:Array[1 2500] of integer;
f:Text;
ch:Char;
{Tao file Input.txt de luu du lieu}
Procedure NhapDL;
Begin
Assign(f,'Input.txt');
Rewrite(f);
Write('Nhap so ngay on thi: ');
Readln(m);
Writeln(f,m);
Write('Nhap so mon on thi: ');
Readln(n);
Writeln(f,n);
For i:=0 to m do
begin
For j:=1 to n do
begin
Write('Nhap diem a[',i,',',j,']= ');
Readln(a[i,j]);
Write(f,a[i,j]:5,' ');
end;
Writeln(f);
end;
Close(f);
End;
{Doc du lieu tu file Input.txt luu vao bien m,n va mang A}
Procedure DocDL;
Begin
Assign(f,'Input.txt');
Reset(f);
Readln(f,m);
Readln(f,n);
For i:=0 to m do
begin
For j:=1 to n do
Read(f,a[i,j]);
Readln(f);
end;
Close(f);
End;
{Buoc lap bang}
Procedure Lap_bang;
Begin
DocDL;
For r:=0 to m do
begin
For s:=1 to n do
begin
If s=1 then
begin
ngay[r,1]:=r;
diem[r,1]:=A[r,1];
end
Else
begin
tam:=a[0,s]+diem[r,s-1];
k1:=0; {k1 la k'}
For k:=1 to r do
If tam<a[k,s]+diem[r-k,s-1] then
begin
tam:=a[k,s]+diem[r-k,s-1];
k1:=k;
end;
diem[r,s]:=tam;
ngay[r,s]:=k1;
end;
Write(diem[r,s]:5,'/',ngay[r,s],' ');
end;
Writeln;
end;
End;
{Buoc tong hop ket qua}
Procedure Tong_hop;
Begin
r:=m;
For s:=n downto 1 do
Begin
X[s]:=ngay[r,s];
Writeln('So ngay on thi mon ',s,' tot nhat la: ',X[s]);
r:=r-X[s];
End;
End;
{In du lieu vua doc ra tu file Input.txt}
Procedure HienthiDL;
Begin
DocDL;
Writeln('So ngay on thi: ',m);
Writeln('So mon on thi: ',n);
Writeln('So diem: ');
For i:=0 to m do
begin
For j:=1 to n do
Write(a[i,j]:5);
Writeln;
end;
End;
BEGIN
Clrscr;
Write('Ban co muon tao moi du lieu khong? (c/k) ');
Readln(ch);
If upcase(ch)<>'K' then
NhapDL;
Writeln;
Writeln('* DU LIEU VAO: ');
HienthiDL;
Readln;
Writeln('* LAP BANG');
Lap_bang;
Writeln;
Writeln('* KET QUA: ');
Tong_hop;
Write('Tong diem: ',diem[m,n]);
Readln;
END.