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
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;