Qui hoạch động (DP – Dynamic Programming), một thuật ngữ được nhà toán học Rechard Bellman đưa ra vào năm 1957, là một phương pháp giải bài toán bằng cách kết hợp các lời giải cho các bài toán con của nó giống như phương pháp chia để trị (devideandconquer). Các bài thuật toán chia để trị để phân hoạch bài toán cần giải quyết thành các bài toán con độc lập với nhau, sau đó giải quyết bằng phương pháp đệ qui (recursive) và kết hợp các lời giải lại để được lời giải của bài toán ban đầu. Ngược lại qui hoạch động là phương pháp được áp dụng khi mà các bài toán con của bài toán ban đầu (bài toán gốc) là không độc lập với nhau, chúng có chung các bài toán nhỏ hơn. Trong các trường hợp như vậy một thuật toán chia để trị sẽ thực hiện nhiều việc hơn những gì thực sự cần thiết, nó sẽ lặp lại việc giải quyết các bài toán con nhỏ hơn đó. Một thuật toán qui hoạch động sẽ chỉ giải quyết các bài toán con nhỏ một lần duy nhất sau đó lưu kết quả vào một bảng và điều này giúp nó tránh không phải tính toán lại các kết quả mỗi khi gặp một bài toán nhỏ nào đó. Các bài toán qui hoạch động thường được áp dụng trong các bài toán tối ưu. Trong các bài toán tối ưu đó thường có nhiều nghiệm (lời giải). Mỗi lời giải của một giá trị được lượng giá bằng cách sử dụng một hàm đánh giá tùy thuộc vào các bài toán cụ thể và yêu cầu của bài toán là tìm ra một nghiệm có giá trị của hàm đánh giá tối ưu (lớn nhất hoặc nhỏ nhất). Qui hoạch động là một phương pháp chung rất hiệu quả để giải quyết các vấn đề tối ưu chẳng hạn như trên các đối tượng sắp thứ tự từ trái qua phải, vấn đề tìm đường đi ngắn nhất, vấn đề điều khiển tối ưu… Khi đã hiểu rõ về qui hoạch động thì việc ứng dụng vào giải các bài toán tối ưu không phải là quá khó khăn nhưng rất nhiều lập trình viên ban đầu phải mất rất nhiều thời gian mới có thể hiểu được.
HỌC VIỆN KỸ THUẬT QUÂN SỰ KHOA CÔNG NGHỆ THÔNG TIN BÁO CÁO MƠN HỌC PHÂN TÍCH VÀ THIẾT KẾ GIẢI THUẬT Đề 21: Bài toán xâu chung dài thuật toán LCS (Longest Common Subsequence Giáo viên hướng dẫn: Hà Đại Dương Sinh viên thực hiện: Nguyễn Thị Ngọc Hà Lớp: HTTT14 Hà Nội, 1/2018 MỤC LỤC I GIỚI THIỆU CHUNG VỀ PHƯƠNG PHÁP QUY HOẠCH ĐỘNG Ý tưởng Mô hình II THUẬT TOÁN LCS ( Longest Common Subsequence) .4 Bài toán Mơ tả chi tiết thuật tốn Đánh giá độ phức tạp thuật toán Tự xác định liệu (với số phần tử N>=5), với liệu thực thuật tốn mơ tả mục ghi kết bước Viết chương trình sử dụng C, C++ .9 I GIỚI THIỆU CHUNG VỀ PHƯƠNG PHÁP QUY HOẠCH ĐỘNG Ý tưởng Qui hoạch động (DP – Dynamic Programming), thuật ngữ nhà toán học Rechard Bellman đưa vào năm 1957, phương pháp giải toán cách kết hợp lời giải cho toán giống phương pháp chia để trị (devide-and-conquer) Các thuật toán chia để trị để phân hoạch toán cần giải thành toán độc lập với nhau, sau giải phương pháp đệ qui (recursive) kết hợp lời giải lại để lời giải toán ban đầu Ngược lại qui hoạch động phương pháp áp dụng mà toán toán ban đầu (bài tốn gốc) khơng độc lập với nhau, chúng có chung tốn nhỏ Trong trường hợp thuật toán chia để trị thực nhiều việc thực cần thiết, lặp lại việc giải tốn nhỏ Một thuật tốn qui hoạch động giải toán nhỏ lần sau lưu kết vào bảng điều giúp tránh khơng phải tính tốn lại kết gặp tốn nhỏ Các tốn qui hoạch động thường áp dụng toán tối ưu Trong tốn tối ưu thường có nhiều nghiệm (lời giải) Mỗi lời giải giá trị lượng giá cách sử dụng hàm đánh giá tùy thuộc vào toán cụ thể u cầu tốn tìm nghiệm có giá trị hàm đánh giá tối ưu (lớn nhỏ nhất) Qui hoạch động phương pháp chung hiệu để giải vấn đề tối ưu chẳng hạn đối tượng thứ tự từ trái qua phải, vấn đề tìm đường ngắn nhất, vấn đề điều khiển tối ưu… Khi hiểu rõ qui hoạch động việc ứng dụng vào giải tốn tối ưu khơng phải q khó khăn nhiều lập trình viên ban đầu phải nhiều thời gian hiểu Mơ hình Q trình phát triển thuật tốn qui hoạch động chia làm bước sau: - Bước 1: Xác định đặc điểm cấu trúc giải pháp tối ưu tốn - Bước 2: Tìm cơng thức truy hồi (đệ qui) xác định giá trị giải pháp tối ưu - Bước 3: Tính giá trị tối ưu toán dựa vào giá trị tối ưu tốn (bottom-up) - Bước 4: Xây dựng nghiệm đạt giá trị tối ưu từ thơng tin tính Các bước 1-3 bước việc giải toán tối ưu phương pháp qui hoạch động Bước bỏ qua tốn u cầu tìm giá trị tối ưu không cần nghiệm cụ thể Thông thường bước đầu quan trọng khó khăn cả, việc xác định cấu trúc nghiệm công thức truy hồi cần dựa vào kinh nghiệm quan sát trường hợp cụ thể tốn Do q trình xây dựng thuật toán qui hoạch động cho toán tối ưu cần khảo sát giá trị thực tế toán, giá trị tối ưu nghiệm toán ứng với giá trị II THUẬT TỐN LCS ( Longest Common Subsequence) Bài toán Cho hai xâu A xâu B Tìm xâu chung dài hai xâu A xâu B Ứng dụng: Nó giải nhiều toán thực tế nhằm đưa mức độ tương đương hai xâu Mô tả chi tiết thuật toán Cho hai xâu ký tự: A = (a1, a2… am), B = (b1, b2, …, bn) P = (p1, p2… pn) xâu co chung dài A B Áp dụng nguyên lý quy hoạch động ta giải tốn LCS Gọi T [i, j] độ dài xâu chung dài hai xâu A [1… i]i m B[1,…,j] j n , điều có nghĩa T[i,j] độ dài xâu chung dài i ký tự đầu xâu A j ký tự đầu xâu B Do T [m, n] độ dài xâu chung dài A B a) Định lý: Cho hai xâu ký tự: A = (a1, a2…, am), B = ( b1, b2, …, bn) P = (p1, p2… pn) xâu chung dài A B - Nếu am = bn pk = am = bn Pk-1 LCS Am-1 Bn-1 - Nếu am bn pk am P LCS Am-1 B - Nếu am bn pk bn P LCS A Bn-1 Chứng minh: - Nếu pk am thêm am = bn vào P chứa xâu chung A B có độ dài k+1, mâu thuẫn với giả thiết P LCS A B, phải có p k = am = bn Bây tiền tố P k-1 có độ dài k-1 xâu chung A m-1 Bn-1 Chúng ta chứng minh LCS, giả sử có xâu chung W kết W có độ dài lớn k, mâu thuẫn - Nếu pk am, P xâu chung Am-1 B Nếu tồn xâu chung W Am-1 B với chiều dài lớn k, W xâu chung Am-1 B, trái với giả thiết P LCS A B - Chứng minh tương tự với pk bn b) Công thức truy hồi cho LCS: Qua định lý ta rút số vấn đề: - Trường hợp i=0 j = độ dài xâu chung dài A B 0, nghĩa T [0, j] = T [i, 0] = - Trường hợp xét = bj ta thêm pk = am = bn vào P độ dài xâu chung dài T[i, j] độ dài xâu chung dài A i-1 Bj-1 T[i-1, j-1] cộng thêm - Ngược lại bj ta phải tìm LCS Ai-1 B, tìm LCS A Bj-1 T [i-1, j] T [i, j-1] Xâu lớn LCS A B Ta có : T[i, j] = Giải thuật : 1) Input (A[1,…, m], B[1,…, n]) 2) For i = to m T [i, 0] =0; For j = to n T [0, j] = 0; 3) For i = to m For j = to n If A[i] = B[j] then T [i, j] = T [i-1, j-1] +1 Else T [i, j] = max {T [i-1, j], T [i, j-1] } 4) Output ( T[m,n]) c) Truy vết tìm xâu chung dài Ta dựa vào bảng phương án để truy vết tìm xâu chung Xuất phát từ T[m,n], giả sử đứng ô C[i,j] ta xét ô trước ô C[i-1,j], C[i,j-1], hai có giá trị T[i,j] ta lùi hai trước có giá trị nhỏ đứng C[i’,j’], Khi X[i’] = Y[j’] Kết nạp A[i’] vào chuỗi P Lùi ô T[i’-1,j’-1] tiếp tục lặp lại T[0,0] Giải thuật 1) P := ‘’; m := length(A); n := length(B);A;B; T[m,n] 2) While (n>0) and (m>0) begin a) if (A[m-1]=B[n-1]) begin P := A[m] +P; m := m -1 ; n := n-1 ; b) else if (T[m-1,n] >= T[m,n-1]) then m:=m-1; else then n:=n-1; end ; 3) Output(P); Đánh giá độ phức tạp thuật toán a) Quy hoạch động cho xâu : Khảo sát độ phức tạp số phép gán Input (A [1… m], B [1… n]) For i = to m T [i, 0] =0; For j = to n T [0, j] = 0; For i = to m For j = to n Phép gán (m) Phép gán (n) Phép gán (m) Phép gán (m.n) If A[i] = B[j] then T [i, j] = T [i-1, j-1] +1 Else T [i, j] = max {T [i-1, j], T [i, j-1] } Số phép gán (m.n) Output (T [m, n]) Tổng số phép gán = m+ n+ m+ m.n+ m.n = 2m.n + 2m + n = O(mn) b) Truy vết tìm xâu chung dài nhất: 1) P := ‘’; m := length(A); n := length(B);A;B; T[m,n] 2) While (n>0) and (m>0) begin a) if (A[m-1]=B[n-1]) begin P := A[m] +P; m := m -1 ; n := n-1 ; b) else if (T[m-1,n] >= T[m,n-1]) then m:=m-1; else then n:=n-1; end ; 3) Output(P); Số phép so sánh vòng lặp while min(m,n) Số phép gán vòng lặp m+n Thuật tốn có độ phức tạp O((m+n)*min(m,n))=O(m+n) 4 Tự xác định liệu (với số phần tử N>=5), với liệu thực thuật tốn mơ tả mục ghi kết bước a) Bộ liệu Hai chuỗi: A= “AABEF” B = “ EABCEGF” Công thức truy hồi cho LCS: B[j] E A B C E G F 0 +1 0 0 0 A 0+1 1 1 1 A 0 1+1 1 1 B 0+1 2+1 2 E 1 2 3+1 F 1 2 3 A[i] Bảng phương án tìm độ dài xâu chung dài Truy vết tìm xâu chung dài B[j] E A B C E G F 0 0 0 0 A 0 1 1 1 A 0 1 1 1 B 0 2 2 E 1 2 3 F 1 2 3 A[i] Bảng truy vết tìm xâu chung dài Xâu chung dài cần tìm “ ABEF” b) Bộ liệu 2: Hai chuỗi : A= ”123457” B =”13545” Công thức truy hồi cho LCS: B[j] 5 0+1 0 0 1 1 1 1+1 1 1 2+1 2 2+1 3+1 3 3 A[i] Bảng phương án tìm độ dài xâu chung dài Truy vết xâu chung dài 5 0 0 0 1 1 1 1 1 2 2 2 3 3 3 Bảng truy vết tìm xâu chung dài Xâu chung lớn :”1345” Viết chương trình sử dụng C, C++ #include #include #include #include #include #include #define MAX 101 using namespace std; void ini(string X ,string Y , int L[MAX][MAX], int n , int m) { int i,j; for (i=0;i= L[n][m-1]) { n ; } else { m ; } } } return word; } int main() { string X,Y; int L[MAX][MAX]; cin >> X>>Y; int n = X.length() + 1; int m = Y.length() + 1; L[n][m]; ini(X,Y,L,n,m); int sol = LCS(X,Y,L,n,m); for (int i=0; i