1. Trang chủ
  2. » Giáo án - Bài giảng

Thuật toán sinh và quay lui

42 728 0

Đ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 42
Dung lượng 282,5 KB

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

Nội dung

Bài giảng hay về thuật toán sinh và quay lui.

Trang 1

ÔN TẬP KTLT 2

Thuật toán sinh và quay lui

Trang 2

Dàn bài

1. Thuật toán sinh và bài tập

2. Thuật toán quay lui và bài tập

Trang 3

Bài toán sinh

1. Định nghĩa: Tạo ra dữ liệu.

2. Phương pháp sinh: Từ dữ liệu ban đầu, sinh ra dữ

liệu kế tiếp cho đến khi kết thúc.

3. Điều kiện của thuật toán sinh:

(1) Có thể xác định 1 thứ tự tập các cấu hình của tổ hợp

(thứ tự của các phép gán trị, thường dùng thứ tự từ điển)

Ví dụ: S1=“123 4 589”, S2=“123 5 789”

S1 < S2 nếu có 1 vị trí i tại đó S1[ i ] < S2[ i ]

(2) Có một cấu hình cuối (điều kiện kết thúc của thuật

toán).

(3) Có một cách để suy ra được cấu hình kế tiếp.

4 Áp dụng: giải bài toán liệt kê

Trang 4

Ví dụ

Bài toán:Tìm số chuỗi có

độ dài 3 ký tự xyz với

Cấu hình cuối: trị cuối cùng

của mỗi miền trị

Cách sinh:Lấy trị kết tiếp của

mỗi miền trị theo cơ chế

vòng tròn

Dùng thứ

tự từ điển

để so sánh các phép gán trị

Ví dụ:

adm < adn

Trang 5

Thuật toán sinh tổng quát.

Generate()

{

c = InitialConfigure(); //cấu hình ban đầu

Process (c); // xử lý cấu hình đang có

if (c=LastConfigure()) Stop=true

else stop = false;

while (not stop)

{

//Sinh cấu hình kế tiếp từ cấu hình đang có

c=getNextConfigure(c);

Process (c); // xử lý cấu hình này

if c= LastConfigure then stop = true;

}

End;

Trang 6

Bài toán liệt kê các tập con của 1 tập

Với tập cha là 4 phần tử X={ a, b, c, d }, có thể dùng mảng “0111” mô tả cho tập con { b,c,d }

Mỗi tập con được biểu diễn là một chuỗi (xâu) nhị phân.

Trạng thái khởi tạo: “0000” mang ý nghĩa tập trống.

Trạng thái kết thúc: “1111” mang ý nghĩa là tập cha.

Trang 7

Ví dụ : liệt kê các tập con

Với tập cha gồm 4 phần tử, có 24 tập con b

với các biểu diễn:

Trang 8

Đặt tả thuật toán sinh

Cách cộng thêm 1 vào chuỗi nhị phân:

Trang 9

Viết chương trình liệt kê

void InitConfigure(char bits[], int n) { for (int i=0; i<n; i++) bits[i]=0;

}

bits p(b)0123 _

{ for (int i=0; i<n; i++) if (bits[i]==0) return 0;

return 1;

}

bits p(b)0123 _

0000 0

bits p(b)0123 _

1111 15

Trang 10

Viết chương trình liệt kê

void Generate(char bits[], int n)

{ int stop= FALSE;

InitialConfigure(bits, n); //cấu hình ban đầu

void Output(char bits[], int n, int count)

{ printf( ‘’\nTap con thu %d\t’’,count);

for (int i=0; i<n; i++) printf(‘’%d’’,bits[i]);

}

Trang 11

Cải tiến thuật toán liệt kê các tập con

Nhận xét: Có thể tối ưu lại chương trình.

void NextConfigure(char bits[], int n,

if (!stop) { count++;

Output(bits,n,count); //xuat cấu hình này }

}}

Trang 12

Bài toán tập con k-phần tử : Tìm hiều

Liệt kê các tập con k phần tử của tập n phần tử.

Ví dụ: Các tập con 3 phần tử của tập 5 phần tử { 1,2,3,4,5 } là:

Tổ hợp n chập k

Trang 13

Bài toán tập con k-phần tử: Đặc tả

Trang 14

Thuật toán sinh tập con kế tiếp từ tập con đã có

a1 a2 a3 a4 ak , chỉ số ở đây đi từ 1

(1) Tìm vị trí đầu tiên từ bên

phải 1 vị trí i sao cho a[i]

≠ n-k+i

i=k;

while (a[i]==n-k+i) i ;

(2) Thay a[i] bằng a[i] +1

Trang 15

Viết chương trình bài toán tập con k- phần tử (1)

void Init (int result[], int k)

{ for (int i=1; i<=k; i++) result[i]=i;

{ 3,4,5 }

Trang 16

void Generate(int result[], int n, int k)

{ int stop= FALSE;

Init(result, k); //cấu hình ban đầu

Process(result,k) // xuat cấu hình khoi dau

Trang 17

Bài tập

Tạo tập tin văn bản có tên Tapcon.in chứa nội dung : 10 4

Ý nghĩa: số đầu: số phần tử của tập, số kế tiếp là số phần tử của tập con.

Dùng kỹ thuật sinh, viết chương trình ghi các tập con của tập này lên file Tapcon.out

Trang 18

Bài toán hoán vị tập n phần tử

Cho tập X = { 1,2,3, , n} Hãy liệt kê tất cả các hoán vị của tập này.

Một hoán vị của X là một bộ A = (a1, a2, , an ) với ai

aj nếu i ≠ j

Định nghĩa 1 thứ tự:

A = (a1, a2, ,ak-1, ak, an ) là hoán vị trước của

A’= (a’1, a’2, ,a’k-1, a’k, a’n ) nếu tìm được vị trí k sao cho ak < a’k

Ví dụ : 1234 5 67 là hoán vị trước của

1234 6 57

Đây chính là thứ tự từ điển.

Độ phức tạp n!

Trang 19

Thuật toán sinh hoán vị kế tiếp

Trạng thái đầu {1,2,3,4} trạng thái cuối: {4,3,2,1}

Trạng thái trước {1,3,4,2} trạng thái sau: {1,4,2,3}

Trang 20

hoán vị a[j], a[k]

Đảo mảng con từ a[j+1] đến a[n]

Trang 21

Viết chương trình hoán vị (1)

void Init (int result[], int k)

{ for (int i=1; i<=k; i++) result[i]=i;

}

int LastConfigure(char result[], int n)

{ for (int i=1; i<n; i++) if (result[i] < result[i+1])

return 0;

return 1;

}

void Output(char result[], int n, int count)

{ printf( ‘’\n Hoan vi thu %d\t’’,count);

for (int i=0; i<n; i++) printf(‘’%d’’,result[i]);

}

Trang 22

Viết chương trình hoán vị (2)

void NextConfigure (int result[],int n)

{ int j=n-1;

// Tìm chỉ số lớn nhất j mà aj<aj+1 từ phía phải, đây là phần tử sẽ bị hoán vị.

while(j>0 && result[j] > result[j+1]) j ;

int k=n;

//Tìm vị trí đầu tiên k đi ngược từ cuối tập trị với a[k] > a[j]

while(k>0 && result[j] > result[k]) k ;

// Hoán vị a[j], a[k]

int t= result[j];

result[j]= result[k];

result[k]= t;

//Đảo ngược nhóm trị a[j+1], a[n]

int left=j+1, right=n;

while (left < right)

{ t = result[left];

result[left]= result[right];

result[right]=t;

Trang 23

Viết chương trình hoán vị (3)

void Generate(char result[], int n)

{ Init(result, n); //cấu hình ban đầu

Trang 25

Thuật toán quay lui

Backtracking

Trang 26

Vì sao cần thuật toán backtracking?

Không phải cấu hình nào cũng được sinh ra từ cấu hình trước đó một cách dễ dàng.

Phương pháp sinh kế tiếp chỉ giải quyết được

các bài toán đơn giản.

Không phải cấu hình ban đầu và cấu hình kế tiếp được nhận diện một cách dễ dàng, nhiều khi

phải chứng minh là tồn tại chúng.

Với bài toán liệt kê phức tạp, thuật toán

backtracking được áp dụng

Trang 27

Backtracking: Ý tưởng

Tập biến x1 x2 x3 xn có thứ tự.

Mỗi biến có thể có 1 miền trị riêng.

Tại mỗi thời điểm, biến xi được tìm trị phù hợp.

Nếu tìm được trị phù hợp thì tiếp tục sang biến xi+1

Ngược lại, tìm trị khác cho biến xi-1

Trang 29

Backtracking: thuật toán tổng quát

if (i==n) Process (CấuHìnhCủa X)

else Try (i+1, X, n)

}

}

}

Trang 30

Thuật toán tổng quát

Trang 31

Bài toán chuỗi bit

Tập biến: char result[], int n bit

Nhận xét: Miền trị chung D={‘0’, ‘1’}

Bit nào cũng được chấp nhận  Không cần kiểm tra acceptable(xi ,j)

Trang 32

Bài toán chuỗi 4 bit

Process (result, n, count);

} else Try (i+1, result, n, count);

}

}

Trang 33

Viết chương trình chuỗi bit bằng backtracking

void Try ( int i, int result[], int n, int &count)

void Process (int result[], int n, int count)

{ printf(‘’\n Chuoi thu %d: \t ’’,count);

for (int i=1; i<=n; i++) printf(‘’%d,’’, result[i]);

}

Lời gọi hàm : Try(1, result, n, count); với count= 0;

Trang 34

Bài toán liệt kê tập con 3 phần tử

if (i==k) Process (result, k);

else Try (i+1, result, n, k);

}

}

Trang 35

Viết chương trình liệt kê tập con k-phần

void Try ( int i, int result[], int n, int k)

{ for (int j=result[i-1]+1; j <= n-k+i; j++ )

{ result[i]=j;

if (i==k) Process (result, k);

else Try (i+1, result, n, k);

}

}

Lời gọi hàm : Try(1, result, n, k) và result[0]=0

Trang 36

Bài toán hoán vị

Liệt kê các hoán vị của một tập n phần tử

Một hoán vị được biểu diễn dạng p1p2p3 pnvới pi ≠ pj với i ≠ j, mỗi pi sẽ nhận trị từ 1 n.

Một trị j được gán cho pi nếu trị j này chưa được dùng  Cần quản lý trị j này đã dùng hay chưa  mảng B, n phần tử B[j] mang trị

TRUE mô tả rằng trị j chưa được dùng 

Ban đầu mọi B[j]= TRUE.

Trang 37

Bài toán hoán vị

hết tập biến) phải trả lại B[j]= TRUE để dùng

cho lần sau.

Trang 38

Ví dụ về bài toán hoán vị với n= 3

101 001

101 100 111

B[j]=FALSE;

if (i==n) { count++;

Process (result, n, count); }

else Try (i+1, count);

B[j]=TRUE;

}

}

Trang 39

Viết chương trình hoán vị bằng thuật toán backtracking

void Init (int *B, int n)

{ for (int i=1; i<=n; i++) B[i]=TRUE;

}

void Process (int result[], int n, int count)

{ printf(‘’\n Hoan vi thu %d: \t ’’,count);

for (int i=1; i<=n; i++) printf(‘’%d,’’, result[i]);

B[j]=FALSE;

if (i==n) { count++;

Process (result, n, count); }

else Try (i+1, count);

B[j]=TRUE;

}

}

Trang 40

Bài tập

1. Cho dãy gồm n số tự nhiên phân biệt a1, a2, , an (n 1000);

và hai số tự nhiên k (k<n) và B Hãy liệt kê tất cả các dãy con k phần tử của dãy số {an} sao cho tổng các phần tử của dãy con

đó đúng bằng B.

2. Cho dãy gồm n số tự nhiên phân biệt a1, a2, , an (n 1000)

và số tự nhiên B Hãy liệt kê tất cả các dãy con của dãy số

{an} sao cho tổng các phần tử của dãy con đó đúng bằng B

Trang 41

1. Cho dãy gồm n số tự nhiên phân biệt a1, a2, , an (n 1000);

và hai số tự nhiên k (k<n) và B Hãy liệt kê tất cả các dãy con k phần tử của dãy số {an} sao cho tổng các phần tử của dãy con

void Try ( int i, int result[], int n, int k)

{ for (int j=result[i-1]+1; j <= n-k+i; j++ )

Trang 42

Cho dãy gồm n số tự nhiên phân biệt a1, a2, , an (n ≤ 1000) và số tự

nhiên B Hãy liệt kê tất cả các dãy con của dãy số {an} sao cho tổng các phần tử của dãy con đó đúng bằng B

void Try ( int i, int result[], int n, int &count)

else Try (i+1, result, n, count);

void Process (int result[], int n, int count)

{ printf(‘’\n Chuoi thu %d: \t ’’,count);

for (int i=1; i<=n; i++) printf(‘’%d,’’, result[i]);

}

Lời gọi hàm : Try(1, result,

n, count); với count= 0;

Ngày đăng: 11/04/2017, 09:22

TỪ KHÓA LIÊN QUAN

w