1. Trang chủ
  2. » Luận Văn - Báo Cáo

Tìm xâu con chung dài nhất của hai xâu

15 1,5K 2

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 15
Dung lượng 170,18 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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.

Trang 1

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 con chung dài nhất và 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

Trang 2

MỤC LỤC

I GIỚI THIỆU CHUNG VỀ PHƯƠNG PHÁP QUY HOẠCH ĐỘNG 3

1 Ý tưởng 3

2 Mô hình 3

II THUẬT TOÁN LCS ( Longest Common Subsequence) 4

1 Bài toán 4

2 Mô tả chi tiết thuật toán 4

3 Đánh giá độ phức tạp thuật toán 6

4 Tự xác định 2 bộ dữ liệu (với số phần tử N>=5), với mỗi bộ dữ liệu thực hiện từng thuật toán đã mô tả ở mục 2 và ghi ra kết quả mỗi bước 7 5 Viết chương trình sử dụng C, C++ 9

Trang 3

I GIỚI THIỆU CHUNG VỀ PHƯƠNG PHÁP QUY HOẠCH ĐỘNG

1 Ý tưởng

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ị (devide-and-conquer)

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

2 Mô hình

Quá trình phát triển của một thuật toán qui hoạch động có thể chia làm 4 bước như sau:

- Bước 1: Xác định đặc điểm cấu trúc của giải pháp tối ưu của bài toán

- Bước 2: Tìm công thức truy hồi (đệ qui) xác định giá trị của một giải pháp tối ưu

- Bước 3: Tính giá trị tối ưu của bài toán dựa vào các giá trị tối ưu của các bài toán con của nó (bottom-up)

- Bước 4: Xây dựng nghiệm đạt giá trị tối ưu từ các thông tin đã tính

Trang 4

Các bước 1-3 là các bước cơ bản trong việc giải quyết bất cứ bài toán tối

ưu nào bằng phương pháp qui hoạch động Bước 4 có thể bỏ qua nếu như bài toán chỉ yêu cầu tìm ra giá trị tối ưu chứ không cần chỉ ra nghiệm cụ thể Thông thường 2 bước đầu là quan trọng và cũng là khó khăn hơn cả, việc xác định cấu trúc nghiệm cũng như công thức truy hồi cần dựa vào kinh nghiệm và sự quan sát các trường hợp cụ thể của bài toán Do vậy trong quá trình xây dựng thuật toán qui hoạch động cho các bài toán tối

ưu chúng ta cần khảo sát các bộ giá trị thực tế của bài toán, giá trị tối ưu

và nghiệm của bài toán ứng với các bộ giá trị đó

II. THUẬT TOÁN LCS ( Longest Common Subsequence)

1. Bài toán

Cho hai xâu A và xâu B Tìm xâu con chung dài nhất của hai xâu A và xâu B

Ứng dụng: Nó giải quyết rất nhiều bài toán trong thực tế nhằm đưa ra mức độ tương đương giữa hai xâu

2 Mô tả chi tiết thuật toán

Cho hai xâu ký tự: A = (a1, a2… am), B = (b1, b2, …, bn) và

P = (p1, p2… pn) là xâu co chung dài nhất của A và B

Áp dụng nguyên lý quy hoạch động ta có thể giải quyết bài toán LCS Gọi

T [i, j] là độ dài xâu con chung dài nhất của hai xâu A [1… i]i m và

B[1,…,j] j n , điều này có nghĩa là T[i,j] là độ dài xâu con chung dài nhất của i ký tự đầu của xâu A và j ký tự đầu của xâu B Do đó T [m, n] chính

là độ dài xâu con chung dài nhất của A và B

a) Định lý:

Cho hai xâu ký tự: A = (a1, a2…, am), B = ( b1, b2, …, bn) và

P = (p1, p2… pn) là xâu con chung dài nhất của A và B

- Nếu am = bn thì pk = am = bn và Pk-1 là LCS của Am-1 và Bn-1

- Nếu am bn và pk am thì P là LCS của Am-1 và B

- Nếu am bn và pk bn thì P là LCS của A và Bn-1

Chứng minh:

- Nếu pk am thì chúng ta có thể thêm am = bn vào P chứa xâu con chung của A và B sẽ có độ dài là k+1, mâu thuẫn với giả thiết rằng P là LCS

Trang 5

của A và B, như vậy chúng ta phải có pk = am = bn Bây giờ tiền tố Pk-1

có độ dài k-1 là xâu chung của Am-1 và Bn-1 Chúng ta chứng minh nó

là một LCS, giả sử có một xâu chung W kết quả là W có độ dài lớn hơn k, đó là mâu thuẫn

- Nếu pk am, thì P là xâu chung của Am-1 và B Nếu tồn tại một xâu chung W của Am-1 và B với chiều dài lớn hơn k, khi đó W có thể là xâu chung của Am-1 và B, trái với giả thiết rằng P là LCS của A và B

- Chứng minh tương tự như trên với pk bn

b) Công thức truy hồi cho LCS:

Qua định lý trên ta có thể rút ra một số vấn đề:

- Trường hợp i=0 hoặc j = 0 thì độ dài xâu con chung dài nhất của A và

B là 0, nghĩa là T [0, j] = T [i, 0] = 0

- Trường hợp xét ai = bj thì ta thêm pk = am = bn vào P và độ dài xâu con chung dài nhất T[i, j] sẽ bằng độ dài xâu con chung dài nhất của Ai-1

và Bj-1 là T[i-1, j-1] cộng thêm 1

- Ngược lại nếu ai bj ta phải tìm LCS của Ai-1 và B, tìm LCS của A và

Bj-1 là T [i-1, j] và T [i, j-1] Xâu nào lớn hơn sẽ là LCS của A và B

Ta có : T[i, j] =

Giải thuật 1 :

1) Input (A[1,…, m], B[1,…, n])

2) For i = 0 to m T [i, 0] =0;

For j = 0 to n T [0, j] = 0;

Trang 6

3) For i = 1 to m

For j = 1 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 con chung dài nhất

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ử đang đứng tại ô C[i,j]

ta sẽ xét 2 ô trước đó là ô C[i-1,j], C[i,j-1], nếu một trong hai ô có giá trị bằng ô T[i,j] thì ta sẽ lùi về ô đó cho tới khi hai ô trước có giá trị nhỏ hơn ô đang đứng C[i’,j’], Khi đó X[i’] = Y[j’] Kết nạp A[i’] vào chuỗi P Lùi về ô T[i’-1,j’-1] và tiếp tục lặp lại cho tới T[0,0]

Giải thuật 2

1) P := ‘’;

m := length(A); n := length(B);A;B; T[m,n]

2) While (n>0) and (m>0) do

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

3 Đánh giá độ phức tạp thuật toán

a) Quy hoạch động cho 2 xâu : Khảo sát độ phức tạp trên số phép gán

Input (A [1… m], B [1… n])

Trang 7

For i = 0 to m T [i, 0] =0; Phép gán (m)

For j = 0 to n T [0, j] = 0; Phép gán (n)

For i = 1 to m Phép gán (m)

For j = 1 to n Phép gán (m.n)

If A[i] = B[j] then T [i, j] = T [i-1, j-1] +1 Số phép gán

Else T [i, j] = max {T [i-1, j], T [i, j-1] } (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 con 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) do

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 của vòng lặp while là min(m,n)

Số phép gán trong vòng lặp m+n

Thuật toán có độ phức tạp là

O((m+n)*min(m,n))=O(m+n)

Trang 8

4 Tự xác định 2 bộ dữ liệu (với số phần tử N>=5), với mỗi bộ dữ liệu

thực hiện từng thuật toán đã mô tả ở mục 2 và ghi ra kết quả mỗi

bước

a) Bộ dữ liệu 1

Hai chuỗi: A= “AABEF”

B = “ EABCEGF”

Công thức truy hồi cho LCS:

B[j]

A[i]

Bảng phương án tìm độ dài xâu con chung dài nhất

Truy vết tìm xâu con chung dài nhất

Trang 9

B[j]

A[i]

Bảng truy vết tìm xâu chung dài nhất

Xâu con chung dài nhất cần tìm là “ ABEF”

b)

Bộ dữ liệu 2:

Hai chuỗi : A= ”123457”

B =”13545”

Công thức truy hồi cho LCS:

Trang 10

B[j]

A[i]

Bảng phương án tìm độ dài xâu con chung dài nhất

Truy vết xâu con chung dài nhất

Trang 11

0 1 2 2 3 3

Bảng truy vết tìm xâu chung dài nhất

Xâu con chung lớn nhất là :”1345”

5 Viết chương trình sử dụng C, C++

#include<iostream>

#include<cstdlib>

#include<algorithm>

#include<string.h>

#include<cstring>

#include<stdio.h>

#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<n;i++)

{

L[i][0]=0;

}

for (i=0;i<m;i++)

{

Trang 12

}

}

int LCS(string X ,string Y , int L[MAX][MAX], int n , int m ) {

int i,j;

for ( i=1;i<n;i++)

{

for(j=1;j<m;j++) {

if(X[i-1]==Y[j-1]) {

L[i][j]=L[i-1][j-1]+1;

} else {

if(L[i-1][j]>=L[i][j-1]) {

L[i][j]=L[i-1][j];

} else {

L[i][j]=L[i][j-1];

} /*L[i][j]=Math.max(L[i-1][j],L[i][j-1]);*/ }

} }

return L[n-1][m-1];

}

string findPath(string X ,string Y ,int L[][MAX],int n ,int m)

{

Trang 13

string word;

while(n>0 && m>0)

{

if(X[n-1]==Y[m-1]) {

word += X[n-1];

n ;

m ;

} else {

if(L[n-1][m]>= 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];

Trang 14

int sol = LCS(X,Y,L,n,m);

for (int i=0; i<n; i++)

{

for (int j =0; j<m; j++) {

cout<<L[i][j]<<"\t"; }

cout << endl;

}

cout <<"LCS is " << sol << endl;

string path = findPath(X,Y,L,n-1,m-1); reverse(path.begin(),path.end());

cout<< "Word is : " << path << endl; }

Kết quả với 2 bộ dữ liệu:

Trang 15

KẾT LUẬN

Trong bài báo cáo này đã phân tích bài toán, sử dụng các giải pháp để giải quyết bài toán trong trường hợp của k xâu ký tự

Ngày đăng: 16/03/2018, 11:46

TỪ KHÓA LIÊN QUAN

w