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

Đồ Án Cấu Trúc Dữ Liệu Và Giải Thuật: ỨNG DỤNG CHIẾN LƯỢC QUY HOẠCH ĐỘNG ĐỂ TÌM DÃY CON CHUNG LỚN NHẤT

19 311 4

Đ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 19
Dung lượng 116,66 KB

Nội dung

Cấu trúc dữ liệu và giải thuật là một trong những nền tảng quan trọng của Khoa học máy tính nói chung và Kỹ thuật lập trình nói riêng. Nó giúp cho người lập trình hiểu được cấu trúc dữ liệu, các giải thuật và những chiến lược thiết kế các thuật toán để giải quyết những bài toán của lập trình. Một trong những phần chính của cấu trúc dữ liệu và giải thuật là phần Chiến lược thiết kế thuật toán. Trong phần Chiến lược thiết kế thuật toán này có phần chiến lược vô cùng quan trọng mà người lập trình viên nào cũng phải biết đó là: Chiến lược thiết kế thuật toán quy hoạch động (Dynamic Programing). Trong bài viết dưới đây sẽ nói về phần chiến lược quy hoạch động này và ứng dụng quy hoạch động để tìm chuỗi con chung lớn nhất .

Trang 1

TRƯỜNG ĐẠI HỌC ĐIỆN LỰC

KHOA CÔNG NGHỆ THÔNG TIN

BÁO CÁO CHUYÊN ĐỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT NÂNG CAO

ĐỀ TÀI ỨNG DỤNG CHIẾN LƯỢC QUY HOẠCH ĐỘNG ĐỂ TÌM DÃY

CON CHUNG LỚN NHẤT

Giảng viên hướng dẫn : VŨ VĂN ĐỊNH

Hà Nội, tháng 10 năm 2019

Trang 2

Sinh viên thực hiện

Nguyễn Hồng Kỳ

Giảng viên chấm

Giảng viên chấm 1:

Giảng viên chấm 2:

Trang 3

LỜI NÓI ĐẦU……….1

I TỔNG QUAN CHIẾN LƯỢC QUY HOẠCH ĐỘNG TRONG XÂY DỰNG THUẬT TOÁN……… 2

1 Giới thiệu quy hoạch động……….2

2 Tính chất của quy hoạch động……… 2

a Tính chất bài toán con gối nhau……….2

b Tính chất cấu trúc con tối ưu……….2

c Những khó khăn gặp phải khi sử dụng quy hoạch động………….3

3 Cách xây dựng bài toán quy hoạch động……… 3

4 So sánh quy hoạch động với chia để trị……….3

5 Ưu điểm, nhược điểm của quy hoạch động……… 4

6 Ứng dụng của quy hoạch động……… 4

II ỨNG DỤNG CHIẾN LƯỢC QUY HOẠCH ĐỘNG ĐỂ TÌM DÃY CON CHUNG LỚN NHẤT……… 5

1 Bài toán dãy con chung lớn nhất……… 5

2 Bài toán Longest common subsequence……… 5

a Đặt vấn đề……… 5

b Giải quyết bài toán……… 5

c Mã giả……… 6

3 Bài toán Longest common substring……… 7

a Đặt vấn đề……… 7

b Giải quyết bài toán……… 7

c Mã giả……… … 8

III CÀI ĐẶT……… 9

1 Code hàm DynamicProgramingLCSubsequence……….9

2 Code hàm DynamicProgramingLCSubstring………10

3 Code toàn bài……….10

4 Hình ảnh code chạy……… 14

KẾT LUẬN……… 15

Trang 4

LỜI NÓI ĐẦU

Cấu trúc dữ liệu và giải thuật là một trong những nền tảng quan trọng của Khoa học máy tính nói chung và Kỹ thuật lập trình nói riêng Nó giúp cho người lập trình hiểu được cấu trúc dữ liệu, các giải thuật và những chiến lược thiết kế các thuật toán để giải quyết những bài toán của lập trình Một trong những phần chính của cấu trúc dữ liệu và giải thuật là phần Chiến lược thiết kế thuật toán Trong phần Chiến lược thiết kế thuật toán này có phần chiến lược vô cùng quan trọng mà người lập trình viên nào cũng phải biết đó là: Chiến lược thiết kế thuật toán quy hoạch động (Dynamic Programing) Trong bài viết dưới đây sẽ nói về phần chiến lược quy hoạch động này và ứng dụng quy hoạch động để tìm chuỗi con chung lớn nhất

Qua đây em cũng xin cảm ơn thầy Vũ Văn Định đã giúp em thực hiện hoàn thành đề tài của mình

Trang 5

I TỔNG QUAN CHIẾN LƯỢC QUY HOẠCH ĐỘNG TRONG

XÂY DỰNG THUẬT TOÁN

1 Giới thiệu quy hoạch động

- Quy hoạch động(Dynamic Progarming) là chia bài toán lớn thành các bài toán nhỏ hơn có tính chất gối nhau sau đó tổng hợp lời giải của các bài toán con đó thành lời giải của bài toán lớn ban đầu

- Quy hoạch động được nhà toán học Richard Bellman phát minh năm 1953 Trong ngành Khoa học máy tính (Computer Science), quy hoạch động là một trong những chiến lược thiết kế thuật toán vô cùng quan trọng Quy hoạch động là một trong những phương pháp làm giảm thời gian chạy của các thuật toán thể hiện tính chất của các bài toán con gối nhau (Overlapping subproblem) và cấu trúc con tối ưu (Optimal substructure)

2 Tính chất của quy hoạch động

Như đề cập ở phần giới thiệu quy hoạch động thể hiện ở hai tính chất đó là: Các bài toán con gối nhau (Overlapping subproblem) và cấu trúc con tối ưu (Optimal substructure)

a Tính chất bài toán con gối nhau

Tương tự như thuật toán chia để trị, quy hoạch động cũng chia bài toán lớn thành các bài toán con nhỏ hơn Quy hoạch động được sử dụng khi các bài toán con này được gọi đi gọi lại Phương pháp quy hoạch động sẽ lưu kết quả của bài toán con này, và khi được gọi, nó sẽ không cần phải tính lại, do đó làm giảm thời gian tính toán

Quy hoạch động sẽ không thể áp dụng được (hoặc nói đúng hơn là

áp dụng cũng không có tác dụng gì) khi các bài toán con không gối nhau Ví dụ với thuật toán tìm kiếm nhị phân, quy hoạch động cũng không thể tối ưu được gì cả, bởi vì mỗi khi chia nhỏ bài toán lớn thành các bài toán con, mỗi bài toán cũng chỉ cần giải một lần mà không bao giờ được gọi lại

b Tính chất cấu trúc con tối ưu

Cấu trúc con tối ưu là một tính chất là lời giải của bài toán lớn sẽ là tập hợp lời giải từ các bài toán nhỏ hơn

Trang 6

Tính chất cấu trúc con tối ưu rất quan trọng Nó cho phép chúng ta giải bài toán lớn dựa vào các bài toán con đã giải được Nếu không có tính chất này, chúng ta không thể áp dụng quy hoạch động được

c Những khó khăn gặp phải khi sử dụng quy hoạch động

Không phải lúc nào sự kết hợp lời giải của bài toán con cũng cho

ra lời giải bài toán lớn hơn

Số lượng các bài toán con cần giải quyết và lưu trữ đáp án có thể rất lớn, không thể chấp nhận được Cho đến nay, chưa ai xác định được một cách chính xác những bài nào có thể được giải quyết hiệu quả bằng phương pháp quy hoạch động Có những vấn đề quá phức tạp và khó khăn mà xem ra không thể ứng dụng quy hoạch động để giải quyết được, trong khi cũng có những bài toán quá đơn giản khiến cho việc sử dụng quy hoạch động để giải quyết lại kém hiệu quả hơn so với dùng các thuật toán kinh điển

3 Cách xây dựng bài toán quy hoạch động

Xây dựng bài toán quy hoạch động gồm 3 giai đoạn:

- GD 1: Chia bài toán lớn thành các bài toán con nhỏ hơn cùng dạng với bài toán ban đầu, chia bài toán đến khi có thể giải bài toán con

đó một cách trực tiếp

- GD 2: Giải các bài toán con cơ sở sau đó lưu trữ các bài toán con đó để sử dụng nhiều lần trong quá trình lặp của bài toán

- GD 3: Gộp các lời giải của bài toán con thành bài toán lớn hơn, tiếp tục cho đến khi gặp bài toán yêu cầu

Bài toán cơ sở là bài toán hiển nhiên đúng hoặc dễ dàng giải được Xây dựng công thức truy hồi để giải bài toán lớn hơn Từ lời giải của bài toán cơ sở với công thức truy hồi ta có thể sử dụng mảng một chiều hoặc mảng nhiều chiều để lưu trữ kết quả của bài toán cơ sở Dựa vào phương

án và công thức truy hồi để giải bài toán ban đầu

4 So sánh quy hoạch động (Dynamic progarming) với chia để trị (Devide and conquer)

Trang 7

Giống nhau: Đều chia các bài toán lớn thành các bài toán con nhỏ hơn và tổng hợp lời giải để giải bài toán lớn

Khác nhau:

- Quy hoạch động: Từ bài toán cơ sở giải các bài toán lớn hơn tiếp tục như thế cho đến khi gặp bài toán đề ra (Bottom up)

- Chia để trị: Từ bài toán lớn chia thành các bài toán nhỏ hơn sau

đó tổng hợp lại được kết quả của bài toán ban đầu (Top down)

5 Ưu điểm, nhược điểm của quy hoạch động

Ưu điểm: Các lời giải của bài toán con lưu trữ theo phương án , khi cần chỉ tổng hợp và gọi lời giải, giảm thời gian chạy của thuật toán

Nhược điểm: Tốn vùng nhớ để lưu trữ lời giải các bài toán con

6 Ứng dụng của quy hoạch động

Quy hoạch động có ứng dụng rất lớn trong việc giảm thời gian chạy của một số thuật toán và khử đệ quy

II ỨNG DỤNG CHIẾN LƯỢC QUY HOẠCH ĐỘNG ĐỂ TÌM DÃY CON CHUNG LỚN NHẤT

Trang 8

1 Giới thiệu chung về bài toán dãy con chung lớn nhất.

Dãy con chung lớn nhất là một trong nhưng bài toán cơ bản của quy hoạch động

Với bài toán dãy con chung lớn nhất có 2 dạng bài toán đó là:

Longest common subsequence và Longest common substring

Có thể hiểu hai bài toán này này qua ví dụ sau:

Ta có 2 chuỗi s1 = abcxyz và s2 = abcjkx thì Longest common

subsequence cho ra kết quả là: abcx với độ dài chuỗi con là 4 còn

Longest common substring cho ra kết quả là: abc với độ dài chuỗi con

là 3.

2 Bài toán Longest common subsequence

a Đặt vấn đề

Vấn đề của bài toán là: Cho hai chuỗi S1 gồm n phần tử và S2 gồm

m phần tử và tìm chuỗi con chung dài nhất của 2 chuỗi S1 và S2 (Với chuỗi con của một chuỗi thu được khi xóa một số ký tự kế tiếp thuộc chuỗi đó hoặc không xóa ký tự nào.)

Ví dụ nhập vào chuỗi S1 = abcxyz và chuỗi S2 = abcjkx thì hàm trả về độ dài chuỗi con (abcx) lớn nhất là 4

b Giải quyết bài toán

Ta gọi L[i, j] là độ dài của dãy con chung lớn nhất của chuỗi S1 gồm i ký tự phần đầu của S1(chạy từ 0 đến i) và chuỗi S2 gồm j ký tự phần đầu của S2(chạy từ 0 đến j)

Ta có công thức truy hồi quy hoạch động như sau:

L[0, j] = L[i, 0] = 0

L[i, j] = { L[i−1, j−1]+1 nếu S 1[i−1]=S 2[ j−1]

max ⁡( L[i−1, j], L[i, j−1]nếu S 1[i−1]≠ S 2[ j−1])

Giả sử với đề bài trên ta có ma trận của L[I, j] như sau:

Trang 9

chuỗi có

chuỗi con

chung lớn

nhất là

abcx.

j] cuối

cùng (Đánh dấu X) chính là độ dài dãy con chung lớn nhất.

Và cũng từ bảng trên ta thấy được thuật toán chạy so sánh từng phần tử trong chuỗi s1 với từng phần tử trong chuỗi s2

c Mã giả(Pseudo code)

Hàm DynamicProgramingLCSubsequence sẽ trả về độ dài của chuỗi con lớn nhất

int DynamicProgramingLCSubsequence(string s1, string s2)

{

int m = độ dài chuỗi S1;

int n = dộ dài chuỗi S2;

int L[m + 1, n + 1];

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

Nếu i = 0 hoặc j = 0 thì L[i, j] = 0;

Nếu không thì nếu S1[i - 1] = S2[j - 1]

thì L[i, j] = L[i - 1, j - 1] + 1;

Nếu không thì L[i, j] = max(L[i - 1, j], L[i, j - 1]);

} return L[m, n];

Trang 10

}

3 Bài toán Longest common substring

a Đặt vấn đề

Vấn đề của bài toán là: Cho hai chuỗi S1 gồm n phần tử và S2 gồm

m phần tử và tìm chuỗi con chung dài nhất của 2 chuỗi S1 và S2 (Với chuỗi con của một chuỗi thu được là các phần tử trong chuỗi con liền kề nhau.)

Ví dụ nhập vào chuỗi S1 = abcxyz và chuỗi S2 = abcjkx thì hàm trả về độ dài chuỗi con (abc) lớn nhất là 3

b Giải quyết bài toán

Cũng tương tự Longest common subsequence,ta gọi L[i, j] là độ dài của dãy con chung lớn nhất của chuỗi S1 gồm i ký tự phần đầu của S1(chạy từ 0 đến i) và chuỗi S2 gồm j ký tự phần đầu của S2(chạy từ 0 đến j)

Tuy nhiên đến công thức truy hồi quy hoạch động của

LCSubstring có phần khác với so LCSubsequence:

L[0, j] = L[i, 0] = 0

L[i, j] = {L[i−1, j−1]+1 nếu S 1[i−1]=S 2[ j−1]

0

Ta có thể viết gọn lại như sau:

L[i, j] = {L[i−1, j−1]+1 nếu S 1[i−1]=S 2[ j−1]

0

Giả sử với đề bài trên ta có ma trận của L[I, j] như sau:

Trang 11

Từ bảng trên ta có thể thấy 2 chuỗi có chuỗi con chung lớn nhất là

abc Phần tử L[i, j] (Đánh dấu X) chính là độ dài dãy con chung lớn nhất.

Và cũng từ bảng trên ta thấy được thuật toán chạy so sánh từng phần tử trong chuỗi s1 với từng phần tử trong chuỗi s2

III CÀI ĐẶT

Trang 12

1 Code hàm DynamicProgramingLCSubsequence

Ta sẽ sử dụng toán tử 3 ngôi thay cho việc phải viết thêm hàm max

so sánh L[i – 1, j] và L[i, j - 1]

Đoạn code sử dụng ngôn ngữ C# nền tảng Console với IDE Visual Studio 2015 Professional

public int DynamicProgarmingLCS()

{

int m = s1.Length;

int n = s2.Length;

int[,] L = new int[m + 1, n + 1];

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

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

if (i == 0 || j == 0) // L[0, j] =

L[i, 0] = 0

L[i, j] = 0;

else if (s1[i - 1] == s2[j - 1]) // L[i, j] = L[i - 1, j - 1] + 1 if s1[i] = s2[j] L[i, j] = L[i - 1, j - 1] + 1;

else

L[i, j] = (L[i - 1, j] > L[i,

j - 1] ? L[i - 1, j] : L[i, j - 1]); // L[i, j] = max(L[i - 1, j], L[i, j - 1]) if s1[i] <> s2[j]

}

return L[m, n];

}

Trang 13

2 Code hàm DynamicProgramingLCSubstring

public int DynamicProgramingLCSubstring()

{

int n = s1.Length;

int m = s2.Length;

int result = 0; // Bien lay tra tri lon nhat trong L[i, j]

int[,] L = new int[n + 1, m + 1]; //

do i va j chay tu 0 den n va m nen phai co (n + 1) x (m + 1) phan tu

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

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

{

if (i == 0 || j == 0) // L[0, j] = L[i, 0] = 0 neu i = 0 va j = 0

L[i, j] = 0;

else if (s1[i - 1] == s2[j -

1] = s2[j - 1]

{

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

result = (result > L[i, j] ? result : L[i, j]); // Lay gia tri lon nhat trong L[i, j]

}

}

return result;

}

3 Code toàn bài

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace Longest_Common_Subsequence

{

class DynamicPrograming

{

private string s1;

private string s2;

public void Input()

{

Trang 14

Console.WriteLine("\nNhap chuoi s1:

");

s1 = Console.ReadLine();

Console.WriteLine("\nNhap chuoi s2:

");

s2 = Console.ReadLine();

}

//Ham Longest common subsequence

public int

DynamicProgarmingLCSubsequence()

{

int n = s1.Length;

int m = s2.Length;

int[,] L = new int[n + 1, m + 1]; //

do i va j chay tu 0 den n va m nen phai co (n + 1) x (m + 1) phan tu

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

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

{

if (i == 0 || j == 0) // L[0, j] = L[i, 0] = 0 neu i = 0 va j = 0

L[i, j] = 0;

else if (s1[i - 1] == s2[j -

1] = s2[j - 1]

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

else

L[i, j] = (L[i - 1, j] > L[i, j - 1] ? L[i - 1, j] : L[i, j - 1]); // L[i, j] = max(L[i - 1, j], L[i, j - 1]) neu s1[i] <> s2[j]

}

// Hien thi bang phuong an L[i, j]

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

{

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

Console.Write("{0} ", L[i, j]);

Console.WriteLine();

}

return L[n, m];

}

Trang 15

{

int n = s1.Length;

int m = s2.Length;

int result = 0; // Bien lay tra tri lon nhat trong L[i, j]

int[,] L = new int[n + 1, m + 1]; //

do i va j chay tu 0 den n va m nen phai co (n + 1) x (m + 1) phan tu

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

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

{

if (i == 0 || j == 0) // L[0, j] = L[i, 0] = 0 neu i = 0 va j = 0

L[i, j] = 0;

else if (s1[i - 1] == s2[j -

1] = s2[j - 1]

{

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

result = (result > L[i, j] ? result : L[i, j]); // Lay gia tri lon nhat trong L[i, j]

}

}

// Hien thi bang phuong an L[i, j]

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

{

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

Console.Write("{0} ", L[i, j]);

Console.WriteLine();

}

return result;

}

}

class Program

{

static void Main(string[] args)

{

DynamicPrograming DPLCS = new

int key;

do

{

Console.WriteLine("VUI LONG CHON MOT TRONG HAI BAI TOAN \n");

Trang 16

Console.WriteLine("1 Bai toan chuoi con trong hai chuoi lon nhat (Longest

common substring)");

Console.WriteLine("2 Bai toan day con chung lon nhat (Longest common

subsequence)");

Console.Write("Chon bai toan: "); key =

int.Parse(Console.ReadLine());

Console.WriteLine();

if(key == 1)

{

DPLCS.Input();

int LCSMax =

DPLCS.DynamicProgramingLCSubstring();

Console.WriteLine("Do dai cua

Console.ReadKey();

}

else if (key == 2)

{

DPLCS.Input();

int LCSMax =

DPLCS.DynamicProgarmingLCSubsequence();

Console.WriteLine("Do dai cua

Console.ReadKey();

}

}

while (key < 1 || key > 2);

}

}

}

Trang 17

4 Hình ảnh code chạy

Hình ảnh dưới đây code của bài toán Longest common subsequence với chuỗi S1 = abcxyz và chuỗi S2 = abcjkx thì hàm trả về

độ dài chuỗi con (abc) lớn nhất là 4 và bảng phương án L[i, j] của bài toán

Hình ảnh dưới đây code của bài toán Longest common substring với chuỗi S1 = abcxyz và chuỗi S2 = abcjkx thì hàm trả về độ dài chuỗi con (abc) lớn nhất là 4 và bảng phương án L[i, j] của bài toán

Ngày đăng: 13/01/2020, 22:53

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w