Đặc biệt, trong công tác bồi dưỡng học sinh giỏi thì yêu cầu học sinh phải nắm vững các kiến thức về tư duy thuật toán, sử dụng ngôn ngữ lập trình thành thạo để có thể giải được các bài
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƯỜNG ĐẠI HỌC VINH
Trang 2TRƯỜNG ĐẠI HỌC VINH
LUẬN VĂN THẠC SĨ CÔNG NGHỆ THÔNG TIN
Người hướng dẫn khoa học: TS PHAN LÊ NA
NGHỆ AN, 8/2018
Trang 3LỜI CAM ĐOAN
Tôi xin cam đoan luận văn "Nghiên cứu giải thuật đệ quy ứng dụng trong bồi dưỡng học sinh giỏi" này là công trình nghiên cứu của riêng tôi
Các số liệu sử dụng trong luận văn là trung thực Các kết quả nghiên cứu được trình bày trong luận văn chưa từng được công bố tại bất kỳ công trình nào khác
Tác giả
Trần Nam Cường
Trang 4
LỜI CẢM ƠN
Để hoàn thành luận văn này, trước tiên em xin gửi lời cảm ơn sâu sắc tới cô giáo TS Phan Lê Na, người hướng dẫn khoa học, đã định hướng và chỉ bảo tận tình từ những bước nghiên cứu đầu tiên cho tới khi hoàn thành luận văn Em xin chân thành cảm ơn các Thầy cô giáo trong Viện kỹ thuật công nghệ Trường Đại học Vinh đã tâm huyết, nhiệt tình truyền thụ những kiến thức cho em trong quá trình học tập, hỗ trợ em trong quá trình nghiên cứu luận văn Xin cảm ơn các Thầy cô, cán bộ phòng sau đại học Trường Đại học Vinh đã tạo cho em những điều kiện thuận lợi để học tập và nghiên cứu Cuối cùng, xin gửi lời cảm ơn tới cơ quan, gia đình, bạn bè và đồng nghiệp nguồn động viên tinh thần to lớn, đã luôn cổ vũ và tin tưởng để tôi hoàn thành nhiệm
vụ học tập và cuốn luận văn này./
Nghệ An, tháng 7 năm 2018
Tác giả
Trần Nam Cường
Trang 5MỤC LỤC
LỜI CAM ĐOAN 1
LỜI CẢM ƠN 2
DANH MỤC CÁC TỪ VIẾT TẮT 5
DANH MỤC CÁC HÌNH VẼ 6
DANH MỤC CÁC BẢNG 7
MỞ ĐẦU 8
Chương 1: MỘT SỐ KHÁI NIỆM CƠ BẢN VỀ ĐỆ QUY 10
1.1 Khái niệm đệ quy 10
1.1.1 Khái niệm hình thức đệ quy 10
1.1.2 Khái niệm về đệ quy 11
1.1.3 Các bước để giải bài toán đệ quy 11
1.2 Giải thuật đệ quy 12
1.2.1 Khái niệm giải thuật đệ quy 12
1.2.2 Ví dụ 12
1.3 Chương trình con đệ quy 14
1.3.1 Khái niệm chương tình con đệ quy 14
1.3.2 Cấu trúc chương trình con đệ quy 14
1.3.3 Phân loại đệ quy 15
1.4 Nguyên tắc hoạt động của giải thuật đệ quy 17
1.4.1 Khái niệm Stack 17
1.4.2 Nguyên tắc hoạt động 17
1.4.3 Ưu điểm và hạn chế của giải thuật đệ quy 21
1.5 Một số bài toán về đệ quy 21
1.5.1 Bài toán tìm số Fibonacci thứ n 21
1.5.2 Bài toán sắp xếp mảng 23
1.5.3 Bài toán tìm nghiệm xấp xỉ của phương trình f(x)=0 24
1.5.4 Bài toán tháp Hà Nội 26
1.5.5 Bài toán giả thuyết của Collatz 28
1.6 Kết luận chương 1 30
Chương 2: ĐỆ QUY QUAY LUI 31
2.1 Tổng quan về đệ quy quay lui 31
2.2 Giải thuật đệ quy quay lui tổng quát 36
2.3 Ba dạng của đệ quy quay lui 37
2.3.1 Dạng 1 tìm một nghiệm 37
2.3.2 Dạng 2 tìm mọi nghiệm 41
2.3.3 Dạng 3 tìm nghiệm tối ưu 43
2.4 Một số bài toán về đệ quy quay lui 46
2.4.1 Bài toán Hoán vị 46
Trang 62.4.2 Bài toán liệt kê các chỉnh hợp không lặp chập k 48
2.4.3 Bài toán xếp các quân Hậu 49
Chương 3: ỨNG DỤNG GIẢI THUẬT ĐỆ QUY GIẢI MỘT SỐ NHÓM BÀI TOÁN BỒI DƯỠNG HỌC SINH GIỎI 53
3.1 Cài đặt các bài toán điển hình về đệ quy 53
3.1.1 Cài đặt Bài toán tìm số Fibonacci thứ n 53
3.1.2 Cài đặt bài toán sắp xếp mảng 53
3.1.3 Cài đặt Bài toán tìm nghiệm xấp xỉ của phương trình f(x)=0 55
3.1.4 Cài đặt Bài toán Tháp Hà Nội 55
3.2 Cài đặt các bài toán điển hình về đệ quy quay lui 56
3.2.1 Cài đặt Bài toán Hoán vị 56
3.2.2 Cài đặt Bài toán liệt kê các chỉnh hợp không lặp chập k 57
3.2.3 Cài đặt Bài toán Tám quân Hậu 58
3.3 Ứng dụng giải thuật Đệ quy giải nhóm bài toán học sinh giỏi 59
3.3.1 Ứng dụng giải nhóm bài toán tìm một nghiệm 59
3.3.1.1 Bài toán M quân hậu 59
3.3.1.2 Bài toán Mã đi tuần 61
3.3.1.3 Bài toánTìm đường đi trong mê cung 64
3.3.1.4 Bài toán máy rút tiền tự động ATM 69
3.3.2 Ứng dụng giải nhóm bài tập tìm mọi nghiệm 71
3.3.2.1 Bài toán đảo ký tự trong từ 71
3.3.2.2 Bài toán M quân Hậu 74
3.3.2.3 Bài toánTừ chuẩn loại M 76
3.3.2.4 Bài toán Biểu thức Zero 79
3.3.2.5 Bài toán Xổ số điện toán 82
3.3.2.6 Bài toán Phân tích số 85
3.3.3 Ứng dụng giải nhóm bài tập tìm nghiệm tối ưu 88
3.3.3.1 Bài toán cái Valy 88
3.3.3.2 Bài toán tháp Hà Nội xuôi 90
3.3.3.3 Bài toán chia phần thưởng 95
3.3.3.4 Bài toán Palindrome 99
3.3.3.5 Bài toán Mật khẩu 102
3.3.3.6 Bài toán Dây dẫn 105
3.3.3.7 Bài toán Xâu gần nhất 107
3.3.4.8 Bài toán Du lịch khứ hồi 109
3.3.4.9 Bài toán Tam giác số 113
3.5 Kết luận Chương 3 116
KẾT LUẬN 117
TÀI LIỆU THAM KHẢO 119
Trang 8DANH MỤC CÁC HÌNH VẼ
1 Hình 1.1 Một số hình ảnh ứng dụng của đệ quy trong tạo hình 10
2 Hình 1.2 Chiến thuật tìm kiếm từ trong Tự điển 13
7 Hình 2.1 Quá trình tìm kiếm lời giải của thuật toán quay lui 36
8 Hình 2.2 Một cách xếp quân Hậu trên bàn cờ 8x8 49
9 Hình 3.1 Một phương án đặt quân Hậu trên bàn cờ 4x4 59
10 Hình 3.2 Kết quả chạy chương trình MHAU.PAS 61
11 Hình 3.3 Hai trong số nhiều hành tình của quân Mã 62
12 Hình 3.4 Kết quả chạy chương trình HORSE.PAS 64
14 HÌnh 3.6 Kết quả chạy chương tình MECUNG.PAS 68
15 Hình 3.7 Kết quả chạy chương trình ATM.PAS 70
16 Hình 3.8 kết quả chạy chương tình DAOKT.PAS 73
17 Hình 3.9 Kết quả chạy chương trình MHAU1.PAS 75
18 Hình 3.10 Kết quả chạy chương trình TUCHUAN.PAS 79
19 Hình 3.11 Kết quả chạy chương trình ZERO.PAS 82
20 Hình 3.12 Kết quả chạy chương trình XOSO.PAS 85
21 Hình 3.13 Kết quả chạy chương trình PTS.PAS 87
22 Hình 3.14 Kết quả chạy chương trình VALY.PAS 90
23 Hình 3.15 Quy tắc chuyển Tháp Hà Nội xuôi 91
24 Hình 3.16 Kết quả chạy chương trình HNXUOI.PAS 95
25 Hình 3.17 Kết quả chạy chương trình CHIATH.PAS 99
26 Hình 3.18 Kết quả chạy chương trình PALIN.PAS 102
27 Hình 3.19 Kết quả chạy chương trình MATKHAU.PAS 105
28 Hình 3.20 Kết quả chạy chương trình WIRES.PAS 107
29 Hình 3.21 Kết quả chạy chương trình CSTR.PAS 109
31 Hình 3.23 Kết quả chạy chương trình DULICH.PAS 113
32 Hình 3.24 Kết quả chạy chương trình TGS.PAS 115
Trang 9DANH MỤC CÁC BẢNG
1 Bảng 1.1 Stack trong khi thực hiện giải thuật tính 3! 21
2 Bảng 1.2 Một số phần tử đầu tiên của dãy số Fibonacci 22
3 Bảng 2.1 Mô hình thuật toán quay lui tìm một nghiệm 34
4 Bảng 2.2 Mô hình thuật toán quay lui tìm mọi nghiệm 35
5 Bảng 3.1 Đặc tả Tháp Hà Nội xuôi khi b đứng sát a 92
6 Bảng 3.2 Hình trạng Tháp Hà Nội xuôi khi b đứng sát a 93
7 Bảng 3.3 Đặc tả Tháp Hà Nội xuôi khi cọc b không sát a 93
8 Bảng 3.4 Hình trạng Tháp Hà Nội xuôi khi b không đứng
sát a
94
9 Bảng 3.5 Tính chất hàm Chia i phần thưởng cho j học sinh 97
Trang 10MỞ ĐẦU
1 Sự cần thiết của vấn đề nghiên cứu
Ngôn ngữ lập trình là một trong những nội dung được đưa vào giảng dạy chính thức ở bộ môn Tin học trong nhà trường phổ thông Đặc biệt, trong công tác bồi dưỡng học sinh giỏi thì yêu cầu học sinh phải nắm vững các kiến thức về tư duy thuật toán, sử dụng ngôn ngữ lập trình thành thạo để có thể giải được các bài toán trong Tin học
Như chúng ta đã biết, các phép lặp là một trong những kỹ thuật được dùng để giải các bài toán trong Tin học và đã được giới thiệu ở phần tin học
cơ sở Với các phép lặp, ta giải bài toán bằng cách thực hiện liên tiếp một số các câu lệnh trong vòng lặp cho tới khi một điều kiện nào đó được thỏa mãn Một kỹ thuật lập trình được sử dụng để thay thế cho các phép lặp đó là kỹ thuật đệ quy Mặt khác, trong thực tế có rất nhiều bài toán đòi hỏi sự lặp đi lặp lại một cách phức tạp Đệ quy không những giúp người lập trình giải quyết tốt
các bài toán mà còn giúp nâng cao tư duy tính toán, rèn luyện kỹ thuật lập
trình Đệ quy cung cấp cho ta cơ chế giải quyết bài toán phức tạp một cách đơn giản Hơn nữa, đệ quy còn thích hợp để giải quyết các bài toán có bản chất đệ quy và rất nhiều bài toán cho đến nay vẫn chưa có lời giải phi đệ quy
Để có thể hiểu rõ hơn về giải thuật đệ quy, ứng dụng của đệ quy để giải
các bài toán trong Tin học tôi đã chọn đề tài “Nghiên cứu giải thuật đệ quy ứng dụng trong bồi dưỡng học sinh giỏi” để tìm hiểu, nghiên cứu sâu hơn về
giải thuật đệ quy trong bồi dưỡng học sinh giỏi THPT
Qua đề tài này, tôi hy vọng sẽ giúp bản thân và nhiều người có thể hiểu sâu hơn giải thuật đệ quy Một trong những giải thuật khó và được áp dụng nhiều trong các bài toán tin học đặc biệt trong bồi dưỡng học sinh giỏi Đồng thời sẽ tạo ra được một nguồn tài liệu ý nghĩa để giáo viên bồi dưỡng học sinh giỏi tin học tham khảo
Trang 112 Mục tiêu nghiên cứu
Nghiên cứu để hiểu rõ giải thuật đệ quy bao gồm cách thức hoạt động, phân loại đệ quy, nghiên cứu các bài toán đệ quy điển hình từ đó hình thành một tài liệu nghiên cứu trong bồi dưỡng học sinh giỏi Đồng thời ứng dụng giải thuật này giải nhóm các bài tập bồi dưỡng học sinh giỏi tại trường THPT Lê Hồng Phong tỉnh Quảng Bình
3 Đối tượng và phạm vi nghiên cứu
3.1 Đối tượng nghiên cứu:
- Giải thuật đệ quy
- Các bài toán đệ quy điển hình
- Giải thuật đệ quy quay lui
- Các bài toán đệ quy quay lui điển hình
3.2 Phạm vi nghiên cứu:
Nghiên cứu lý thuyết đệ quy để áp dụng giải một số nhóm các bài toán bồi dưỡng học sinh giỏi
4 Nội dung nghiên cứu
- Nghiên cứu lý thuyết về giải thuật đệ quy
- Nghiên cứu lý thuyết về giải thuật đệ quy quay lui
- Ứng dụng giải thuật đệ quy giải một số nhóm bài toán bồi dưỡng học sinh giỏi
5 Kết cấu của luận văn
Ngoài phần mở đầu và phần kết luận, luận văn được sắp xếp theo bố cục sau đây:
Chương 1: Một số khái niệm cơ bản về đệ quy
Chương 2: Đệ quy quay lui
Chương 3: Ứng dụng giải thuật đệ quy giải một số nhóm bài toán bồi dưỡng học sinh giỏi
Trang 12Chương 1: MỘT SỐ KHÁI NIỆM CƠ BẢN VỀ ĐỆ QUY
Chương này giới thiệu tổng quan về giải thuật đệ quy trong toán học và khoa học máy tính, các nghiên cứu trong nước và thế giới về giải thuật đệ quy, những bài toán điển hình sử dụng giải thuật đệ quy Từ đó phân tích, đánh giá và làm rõ những ưu điểm và hạn chế giải thuật này (xem [1], [7], [8])
1.1 Khái niệm đệ quy
1.1.1 Khái niệm hình thức đệ quy
Trong toán học và khoa học máy tính, các tính chất (hoặc cấu trúc) được gọi là đệ quy nếu trong đó một lớp các đối tượng hoặc phương pháp được xác định bằng việc xác định một số rất ít các trường hợp hoặc phương pháp đơn giản (thông thường chỉ một) và sau đó xác định quy tắc đưa các trường hợp phức tạp về các trường hợp đơn giản [1]
Chẳng hạn, định nghĩa sau là định nghĩa đệ quy của tổ tiên [1]
- Bố mẹ của một người là tổ tiên của người ấy (trường hợp cơ bản)
- Bố mẹ của tổ tiên một người bất kỳ là tổ tiên của người ấy (bước đệ quy)
Các định nghĩa kiểu như vậy cũng thường thấy trong toán học (chính là quy nạp toán học)
Tam giác sierpinski Kim tự tháp sierpinski Bông tuyết Koch
Hình 1.1 Một số hình ảnh ứng dụng của đệ quy trong tạo hình
Trang 131.1.2 Khái niệm về đệ quy
Từ những định nghĩa trên, khái niệm cơ bản của Đệ quy theo 2 cách:
Đệ quy (trong tiếng Anh là Recursion) là phương pháp dùng trong các chương trình máy tính trong đó có một hàm tự gọi chính nó [7]
Một khái niệm X được định nghĩa theo đệ quy nếu trong định nghĩa X có sử dụng chính khái niệm X
Sau đây là một số ví dụ điển hình về đệ quy:
Ví dụ 1.1: Định nghĩa về số tự nhiên:
0 là một số tự nhiên;
N là một số tự nhiên khi N-1 là một số tự nhiên
Ví dụ 1.2: Định nghĩa về giai thừa (N!):
0! = 1;
Nếu N>0 thì N! = N*(N-1)!
1.1.3 Các bước để giải bài toán đệ quy
Bước 1: Thông số hóa bài toán (hiểu bài toán)
Bước 2: Tìm các điều kiện biên (chặn), tìm giải thuật cho các tình huống này Bước 3: Tìm giải thuật tổng quát theo hướng đệ quy lui dần về tình huống bị chặn [8]
Ví dụ 1.3: Bài toán tính giai thừa của một số tự nhiên (tính N!):
Thông số hóa bài toán: Cách tính giai thừa (N!)
Trang 141.2 Giải thuật đệ quy
1.2.1 Khái niệm giải thuật đệ quy
Nếu lời giải của một bài toán T được thực hiện bằng lời giải của một bài toán T’ có dạng giống như T, thì đó là một lời giải đệ quy Giải thuật tương ứng với lời giải như vậy gọi là giải thuật đệ quy [5]
Nghe qua ta thấy hơi lạ, nhưng điểm quan trọng cần lưu ý là: T’ tuy có dạng giống như T, tuy nhiên theo một nghĩa nào đó, nó phải "nhỏ" hơn T
Trong khoa học máy tính có một phương pháp chung để giải các bài toán trong Tin học là chia bài toán thành các bài toán con đơn giản hơn cùng loại Phương pháp này được gọi là kỹ thuật lập trình chia để trị Chính nó là chìa khóa để thiết kế nhiều giải thuật quan trọng, là cơ sở của quy hoạch động
Ví dụ 1.5: Hãy xét bài toán tìm một từ trong một quyển từ điển
Có thể nêu giải thuật như sau:
If Từ điển là một trang Then Tìm từ trong trang này
Else Begin
Mở từ điển vào trang giữa
Xác định xem nửa nào của từ điển chứa từ cần tìm
if Từ đó nằm ở nửa trước của từ điển Then Tìm từ đó trong nửa trước
Else Tìm từ đó trong nửa sau
End;
Trang 15Chiến thuật tìm kiếm này khái quát theo sơ đồ sau:
Ta thấy có hai điểm chính cần lưu ý:
Sau mỗi lần Tự điển được tách đôi thì một nửa thích hợp sẽ lại được tìm kiếm bằng một "chiến thuật” như đã dùng trước đó
Có một trường hợp đặc biệt, khác với mọi trường hợp trước, sẽ đạt được sau nhiều lần tách đôi, đó là trường hợp tự điển chỉ còn duy nhất một trang Lúc đó việc tách đôi dừng lại và bài toán trở thành đủ nhỏ để ta có thể giải quyết trực tiếp bằng cách tìm từ mong muốn trên trang đó, chẳng hạn bằng cách tìm tuần tự Trường hợp đặc biệt này được gọi là trường hợp suy biến
Có thể coi đây là một "chiến thuật " kiểu "chia để trị" Bài toán được tách thành bài toán nhỏ hơn và bài toán nhỏ hơn lại được giải quyết với thuật chia
để trị như trước, cho tới khi xuất hiện trường hợp suy biến
Thủ tục sau thể hiện giải thuật tìm kiếm này:
Procedure TIMKIEM (TD,Tu)
{TD được coi là đầu mối để truy nhập được vào tự điển đang xét, Tu chỉ từ cần tìm}
Begin
if Tự điển chỉ còn là một trang then Tìm từ Tu trong trang này else begin
Mở tự điển vào trang giữa
Tìm từ trong Tự điển
Tìm từ trong Tự điển nữa trước
Tìm từ trong Tự điển
nữa sau
Hình 1.2 Chiến thuật tìm kiếm từ trong tự điển
Trang 16Xác định xem nửa nào của tự điển chứa từ Tu
If Tu nằm ở nửa trước của tự điển
Then TIMKIEM (TD 1,Tu)
Else TIMKIEM (TD 2,Tu);
End;
{TD 1 và TD 2 là đầu mối để truy nhập được vào nửa trước và nửa sau của từ điển}
End;
1.3 Chương trình con đệ quy
1.3.1 Khái niệm chương tình con đệ quy
Khái niệm: Chương tình con đệ quy là một chương trình con (hàm, thủ tục) mà trong thân của nó có lời gọi đến chính nó (hay còn gọi là lời gọi đệ quy) với kích thước nhỏ hơn của tham số [7]
Ví dụ 1.6: Hàm tính giai thừa của một số tự nhiên N (tính N!):
Function GT(N: Word): Longint;
Begin
If N = 0 then GT: =1
Else GT:= N*GT(N - 1);
End;
1.3.2 Cấu trúc chương trình con đệ quy
Một chương trình con đệ qui căn bản gồm hai phần [7]
Phần neo (phần suy biến, cơ sở): chứa các tác động của hàm hoặc thủ tục với
một số giá trị cụ thể ban đầu của tham số
Phần đệ quy (phần tổng quát, hạ bậc): định nghĩa tác động cần được thực hiện
cho giá trị hiện thời của các tham số bằng các tác động đã được định nghĩa trước đây với kích thước tham số nhỏ hơn
Ví dụ1.7: Hàm tính N!
Trang 17Phần neo: If N:=0 then GT:= 1;
Phần đệ quy: GT:=N*GT(N-1);
1.3.3 Phân loại đệ quy
Tùy theo lời gọi hàm đệ quy mà ta phân loại thành các dạng như sau:
- Đệ quy tuyến tính: là dạng đệ quy mà thân hàm chỉ có một lời gọi chính
- Đệ quy nhị phân: Là dạng đệ quy mà thân hàm gọi 2 lần chính nó Ta
mô tả Hàm tìm dãy số Fibonacci như sau:
Function F(N: integer): integer;
Ví dụ 1.9: Hàm tìm ước chung lớn nhất (UCLN) của hai số nguyên dương:
Function UCLN(M, N: Longint): Longint;
Begin
If(M=N) then UCLN:= N Else
If (M>N) then UCLN:=UCLN(M-N, N) else UCLN:=UCLN(M, N-M); End;
Trang 18- Đệ quy hỗ tương: nếu có 2 chương trình con B1 và B2 gọi lẫn nhau ta sẽ
có đệ quy hỗ tương
Có những trường hợp cần phải tiến hành khai báo đầu một chương trình con trước khi khai báo đầy đủ chương trình con đó đặc biệt là trong đệ quy hỗ tương, khi B1 gọi B2 và B2 lại gọi B1 ta phải dùng từ khóa Forwar
Ví dụ 1.10: Chương trình có Đệ quy hổ tương:
Program A;
Procedure B2 (X: integer): Forward ;
Procedure B1 (Y: integer) ;
Begin
If Y > 0 then
Begin
Y:= Y + 1 ; B2 (Y)
End ;
BEGIN {Chương trình chính}
B1(3);
END
Trang 191.4 Nguyên tắc hoạt động của giải thuật đệ quy
1.4.1 Khái niệm Stack
Stack là một cấu trúc lưu trữ, hoạt động theo nguyên tắc sau [8]:
Mỗi lần nộp vào hoặc lấy ra chỉ thực hiện với một phần tử
Phần tử nộp vào sau sẽ được lấy ra trước
- Stack bị tràn khi bổ sung vào mảng đã đầy
- Stack là rỗng khi số phần tử thực sự đang chứa trong mảng = 0
Hình 1.3 Mô tả Stack
Trang 20Nguyên tắc 3: Đến lúc nào đó không thể thực hiện lời gọi đệ quy nữa thì các đối tượng được lưu trong Stack sẽ lần lượt được lấy ra để xử lý
Nghĩa là khi một thủ tục đệ quy được gọi tới từ chương trình chính, ta nói: thủ tục được thực hiện ở mức 1 hay độ sâu 1 của tính đệ quy Nhưng khi thực hiện ở mức 1 lại gặp lại lời gọi chính nó, nghĩa là phải đi sâu vào mức 2
và cứ như thế cho tới một mức nào đó Mức k phải được hoàn thành xong thì mức (k-1) mới được thực hiện Vậy việc thực hiện được quay về mức (k-1) Khi từ một mức i, đi sâu vào mức (i+1) thì có thể có một số tham số, biến cục
bộ hay địa chỉ (gọi là địa chỉ quay lui) ứng với mức i cần phải được bảo lưu
để khi quay về tiếp tục sử dụng
Như vậy trong quá trình thực hiện, những tham số, biến cục bộ hay địa chỉ bảo lưu sau lại được khôi phục trước Tính chất “vào sau ra trước” phù hợp với việc sử dụng Stack trong cài đặt thủ tục đệ quy Mỗi khi có lời gọi tới chính nó thì Stack sẽ được nạp để bảo lưu các giá trị cần thiết Còn mỗi khi thoát ra khỏi một mức thì phần tử ở đỉnh Stack sẽ được lấy ra để khôi phục lại các giá trị cần thiết cho mức tiếp theo [12]
Tóm tắt các bước này như sau:
Phần đầu: Bảo lưu tham số, biến cục và địa chỉ quay lui
Phần thân: Nếu tiêu chuẩn cơ sở ứng với trường hợp suy biến đã đạt được thì thực hiện được ở phần tính kết thúc và chuyển sang bước 3
Phần cuối: Khôi phục lại tham số, biến cục bộ và địa chỉ quay lui và chuyển tới địa chỉ quay lui này
Ví dụ 1.11: Sử dụng Stack cài đặt thủ tục đệ qui cho bài toán tính N! [10]
Ta sử dụng một Stack A mà đỉnh được trỏ bởi T Mỗi phần tử của A là một bản ghi gồm có hai trường:
Trường N ghi giá trị động của N ở mức hiện hành
Trường RETADD ghi địa chỉ quay lui
Trang 21Lúc đầu Stack A rỗng: T = 0
Bản ghi TEMREC được dùng làm bản ghi trung chuyển, nó có 2 trường: PARA ứng với N
ADDRESS ứng với RETADD
Đặt giả thuyết: lúc đầu TEMREC đã chứa các giá trị cần thiết, nghĩa là PARA chứa giá trị n đã cho, ADDRESS chứa địa chỉ ứng với lời gọi trong chương trình chính mà ta gọi là địa chỉ chính (ĐCC)
Các giải thuật PUSH và POS sẽ được sử dụng Ký hiệu N(T) có nghĩa là giá trị ở trường N của phần tử đang trỏ tới bởi T (phần tử ở đỉnh Stack A)
Program Factorial
1.{Bảo lưu giá trị của N và địa chỉ quay lui}
Call PUSH(A,T, TEMREC)
2.{Tiêu chuẩn cơ sở đã đạt?}
Goto bước 1
3.{tính N!}
Factorial:= N(T)* Factorial;
4.{Khôi phục giá trị trước của N và địa chỉ quay lui}
Call POP(A, T, TEMREC);
Goto ADDRESS
5 End
Trang 22Sau đây là minh hoạ tình trạng của Stack A trong quá trình thực hiện giải thuật, ứng với N =3
Vào mức 1(lời gọi chính)
Bước 1 PUSH(A,O,(3,ĐCC)) Bước 2:
N <>0 PARA:= 2;
ADDRESS:= bước 3
Vào mức 2 (gọi đệ quy lần 1)
Bước 1:
PUSH(A,1,(2,bước 3)) Bước 2:
N<>0 PARA:=1;
ADDRESS:= bước 3
Vào mức 3 (gọi đệ quy lần 2)
Bước 1:
PUSH(A,2,(1, bước 3)) Bước 2:
N<>0;
PARA:=0;
ADDRESS:= bước 3;
Vào mức 4 (gọi đệ quy lần 3)
Bước 1:
PUSH(A,3,(0,bước 3)) Bước 2:
Trang 23Factorial:=1*1 Bước 4:
Goto bước 3
Quay lại mức 1
Bước 3:
Factorial:= 3*2 Bước 4:
1.5 Một số bài toán về đệ quy
1.5.1 Bài toán tìm số Fibonacci thứ n
Dãy số Fibonacci bắt nguồn từ bài toán cổ về việc sinh sản của các cặp thỏ Bài toán đặt ra như sau [2]:
Bảng 1.1 Mô tả Stack trong khi thực hiện giải thuật đệ quy tính 3!
Trang 24Các con thỏ không bao giờ chết
Hai tháng sau khi ra đời, mỗi cặp thỏ mới sẽ sinh ra một cặp thỏ con (một đực, một cái)
Khi đã sinh con rồi thì cứ mỗi tháng tiếp theo chúng lại sinh được một cặp thỏ mới
Giả sử từ đầu tháng 1 có một cặp mới ra đời thì đến tháng thứ n sẽ có bao nhiêu cặp?
Ví dụ 1.12 Khi N = 5 ta thấy:
Giữa tháng 1: 1 cặp ab ban đầu
Giữa tháng 2: 1 cặp ab ban đầu chưa đẻ
Giữa tháng 3: 2 cặp ab ban đầu và cặp cd
Giữa tháng 4: 3 cặp ab, cd, ef, cặp ab ban đầu tiếp tục đẻ
Giữa tháng 5: 5 cặp ab, cd, ef, gh, ik; cặp ab ban đầu đẻ thêm và cặp cd bắt đầu đẻ
Ta xét tới việc tính số cặp thỏ ở tháng thứ N: F(N)
Nếu mỗi cặp thỏ ở tháng thứ N-1 đều sinh ra một cặp thỏ con thì số cặp thỏ ở tháng thứ N sẽ là:
F(N) = 2*F(N-1) Nhưng ta cần chú ý là trong các cặp thỏ ở tháng thứ N-1, chỉ có những cặp thỏ đã ở tháng thứ N-2 mới sinh ra con ở tháng thứ N được thôi Do đó F(N)
=F(N-1) + F(N- 2) (= số cũ+ số sinh ra) Vậy có thể tính được F(N) theo công thức sau:
Trang 25Hàm đệ quy tìm số Fibonacci thứ N viết như sau:
Function F(N: integer): Longint;
Yêu cầu: Hãy sắp xếp dãy số A thành dãy số tăng dần
Ý tưởng giải thuật (QUICKSORT)
Ta dùng phương pháp phân vùng để xử lí nội dung chính là chọn phần
tử X ở giữa của dãy làm chuẩn để so sánh, từ đó phân hoạch dãy này thành 3 dãy con liên tiếp như sau:
* Dãy con thứ nhất gồm các phần tử nhỏ hơn X
* Dãy con thứ hai gồm các phần tử bằng X
* Dãy con thứ ba gồm các phần tử lớn hơn X
Sau đó lại áp dụng giải thuật phân hoạch này cho dãy con thứ nhất và dãy con thứ ba, nếu các dãy con này có nhiều hơn một phần tử (Đệ quy)
Cụ thể là xét một đoạn của dãy từ thành phần thứ L đến thành phần thứ R ta thực hiện các bước sau:
* Lấy giá trị của thành phần thứ (L + R) div 2 gán vào biến X
* Cho i ban đầu là L
* Cho j ban đầu là R
* Lặp lại
• Chừng nào còn A[i] < X thì tăng i
• Chừng nào còn A[j] > X thì giảm J
Trang 26• Sắp xếp đoạn từ A[L] đến A[j]
• Sắp xếp đoạn từ A[i] đến A[R]
Thủ tục QUICKSORT được viết như sau:
Procedure QUICKSORT (Var A: Array [l N] of integer); Procedure SORT (L, R: integer);
1.5.3 Bài toán tìm nghiệm xấp xỉ của phương trình f(x)=0
Cho Hàm f(x) là hàm liên tục trên đoạn [ao,bo]
Trang 27Yêu cầu: Tìm một nghiệm xấp xỉ với độ chính xác trên [ao,bo] của phương trình f(x) = 0
Ý tưởng và phân tích bài toán:
- Ta xét trường hợp: bo - ao < ε (Phần neo)
+ Nếu f(ao).f(bo) ≤ 0 thì hàm f có nghiệm trên [ao,bo].Vì ta đang tìm nghiệm xấp xỉ với độ chính xác nên ao là nghiệm xấp xỉ cần tìm
+ Nếu f(ao).f(bo) > 0 thì ta xem như không có nghiệm xấp xỉ trên đoạn xét
- Trương hợp bo - ao ≥ ε: Ta chia đôi đoạn [ao,bo] rồi tìm lần lượt nghiệm trên từng đoạn con: Đoạn con trái, đoạn con phải (Phần đệ quy)
Ta sẽ xây dựng một hàm đệ quy trả về giá trị là nghiệm xấp xỉ của f(x) (nếu có), hoặc là một hằng số E nếu f(x) không có nghiệm xấp xỉ trên [ao,bo]
Thông số cho bài toán:
Tạo hàm ROOT với 3 thông số là g, a, b; (ROOT(g,a,b)) trả về giá trị nghiệm xấp xỉ của phương trình g(x) =0 trên đoạn [a,b] hoặc giá trị C nếu phương trình xét không có nghiệm xấp xỉ Để giải bài toán ban đầu ta gọi hàm ROOT(f,ao,bo), được thể hiện như sau:
Phần neo: Là khi b - a < ε Khi đó:
If ( g(a).g(b)) <= 0 Then ROOT(g,a,b):= a; {a là nghiệm xấp xỉ};
Else ROOT(g,a,b) = E; { không có nghiệm xấp xỉ}
Phần tổng quát: Khi b - a ≥ 0 ta phân [a,b] làm 2 đoạn [a,c] và [c,b] với c = (a + b) / 2
- Nếu ROOT(g, a,c) < E thì ROOT(g, a, b) = ROOT(g,a,c) nghĩa là bài toán tìm nghiệm trên đoạn [a,c];
- Ngược lại thì ROOT(g, a, b) = ROOT(g,c,b) (bài toán tìm nghiệm trên đoạn [c,b])
Trang 281.5.4 Bài toán tháp Hà Nội
Có 3 cái cọc, đánh dấu A, B, C, và N cái đĩa Mỗi đĩa đều có một lỗ chính giữa để đặt xuyên qua cọc, các đĩa đều có kích thước khác nhau Ban đầu tất cả đĩa đều được đặt ở cọc thứ nhất theo thứ tự đĩa nhỏ hơn ở trên [8]
Yêu cầu: chuyển tất cả các đĩa từ cọc A qua cọc C với ba ràng buộc như sau:
Quy tắc 1: Mỗi lần chỉ chuyển được một đĩa
Quy tắc 2: Trong quá trình chuyển đĩa có thể dùng cọc còn lại (B) để làm cọc trung gian
Quy tắc 3: Chỉ cho phép đặt đĩa có bán kính nhỏ hơn lên đĩa có bán kính lớn hơn
Ý tưởng và phân tích bài toán:
Trong bài toán trên hình dung một lời giải tổng quát cho trường hợp tổng quát
N đĩa là không dễ dàng
Bài toán Tháp Hà Nội với 1 đĩa: Chỉ cần 1 lần chuyển
Bước 1: Chuyển đĩa từ cọc A sang cọc C
Bài toán Tháp Hà Nội với 2 đĩa: Cần 3 lần chuyển
Bước 1: Chuyển đĩa số 1 từ cọc A sang cọc B
Bước 2: Chuyển đĩa số 2 từ cọc A sang cọc C
Bước 3: Chuyển đĩa số 1 từ cọc B sang cọc C (lên trên đĩa số 2) Kết thúc
Hình 1.4 Bài toán Tháp Hà Nội với N=1
Hình 1.5 Bài toán Tháp Hà Nội với N=2
Trang 29Bài toán Tháp Hà Nội với 3 đĩa: Cần 7 lần chuyển
Bước 1: Chuyển một đĩa từ A qua C
Bước 2: Chuyển một đĩa từ A qua B
Bước 3: Chuyển một đĩa từ C qua B
Bước 4: Chuyển một đĩa từ A qua C
Bước 5: Chuyển một đĩa từ B qua A
Bước 6: Chuyển một đĩa từ B qua C
Bước7: Chuyểnmột đĩa từ A qua C Kết thúc
Nhận xét: Ở kết quả của bước thứ ba Đây là một kết quả quan trọng vì nó cho
ta thấy từ trường hợp N=3 bài toán đã được phân chia thành hai bài toán với kích thước nhỏ hơn: đó là bài toán chuyển 1 đĩa từ cọc A qua cọc C lấy cọc B làm trung gian và bài toán chuyển 2 đĩa (dời) từ cọc B sang cọc C lấy cọc A làm trung gian Hai bài toán con này đã biết cách giải (trường hợp N=1 và trường hợp N=2)
Nhận xét đó cho ta thấy rằng trong trường hợp tổng quát N đĩa:
Bước 1: Dời (N-1) đĩa trên cùng từ cọc A sang cọc B lấy cọc C làm trung gian
Bước 2: Chuyển 1 đĩa dưới cùng từ cọc A sang cọc C
Hình 1.6 Bài toán Tháp Hà Nội với N=3
Trang 30Bước 3: Chuyển (N-1) đĩa đang ở cọc B sang cọc C lấy cọc A làm trung gian Như vây, bài toán đối với N đĩa ở trên được “đệ quy” về hai bài toán (N-1) đĩa và bài toán 1 đĩa Quá trình đệ quy sẽ dừng lại khi N=0 nghĩa là khi không còn đĩa để chuyển
Thủ tục đệ quy cho bài toán Tháp Hà Nội như sau:
1.5.5 Bài toán giả thuyết của Collatz
Collatz đưa ra giả thuyết là với một số nguyên dương X, nếu X chẵn thì
ta gán X:= X div 2; nếu X lẻ thì ta gán X:= X*3+1 Sau một số hữu hạn bước,
Phân tích bài toán:
Ta giả sử giả thuyết Collatz là đúng đắn, vậy: Cho trước số 1 cùng với hai phép toán *2 và div 3, hãy sử dụng một cách hợp lí hai phép toán đó để biến số 1 thành giá trị nguyên dương X cho trước
Trang 31Khi X= 10 ta có 1*2*2*2*2 div 3 =10
Ta thấy rằng lời giải của bài toán này gần như thứ tự ngược của phép biến đổi Collatz: để biểu diễn số X >1 bằng một biểu thức bắt đầu bằng số 1 và hai phép toán “*2”, “div 3” Chia hai trường hợp:
- Nếu X chẵn, thì ta tìm cách biểu diễn số X div 2 và viết thêm phép toán
*2 vào cuối
- Nếu X lẻ, thì ta tìm cách biểu diễn số X*3+1 và viết thêm phép toán div
3 vào cuối
Thủ tục đệ quy cho bài toán giả thuyết Collatz mô tả như sau:
Procedure Collatz(x: Longint);
Begin
If x = 1 then write(x)
Else
If x mod 2 = 0 then Begin
Collatz (x div 2);
write(‘ *2’);
End Else
Trang 321.6 Kết luận chương 1
Như vậy, thông qua các nội dung được trình bày ở chương 1 có thể nói rằng đệ quy là quả tim trong các nghiên cứu lý thuyết, cũng như thực hành tính toán đã thể hiện rất nhiều sức mạnh và có ưu điểm trong nhiều bài toán Thuật toán đệ quy đưa ra cách giải quyết một số bài toán một cách tổng quát Hơn nữa, đệ quy còn thích hợp để giải quyết các bài toán có bản chất đệ quy Qua chương 1 đã giúp chúng ta hiểu được sâu hơn về các khái niệm, tính chất
và nguyên tắc hoạt động của giải thuật Đệ quy thông qua việc phân tích một
số bài toán Đệ quy cơ bản
Trang 33Chương 2: ĐỆ QUY QUAY LUI
Chương này tìm hiểu khái niệm và đưa ra các kiến thức về đệ quy quay lui, các dạng tổng quát của giải thuật đệ quy quay lui Nghiên cứu các bài toán điển hình sử dụng giải thuật đệ quy quay lui để từ đó phân tích, đánh giá và làm rõ những ưu điểm và hạn chế giải thuật đệ quy quay lui (xem [4], [5],
[12], [13])
2.1 Tổng quan về đệ quy quay lui
Trong lập trình có nhiều trường hợp, nghiệm của bài toán là dãy các phần tử được xác định không theo một luật tính toán nhất định, muốn tìm nghiệm phải thực hiện từng bước, tìm kiếm dần từng phần tử của nghiệm Để tìm mỗi phần tử, phải kiểm tra “đúng, sai” các khả năng có thể chấp nhận của phần tử này
+ Nếu khả năng nào đó không dẫn tới giá trị chấp nhận được của phần
tử đang xét thì phải loại bỏ khả năng đó, chuyển sang chọn khả năng khác (chưa được chọn) Mỗi khi chọn một khả năng cho một phần tử thì thông thường trạng thái bài toán sẽ thay đổi vì thế khi chuyển sang chọn khả năng khác, phải trả lại trạng thái như trước khi chọn khả năng vừa loại bỏ (nghĩa là phải quay lui lại trạng thái cũ)
+ Nếu có 1 khả năng chấp nhận được tức là gán được giá trị cho phần
tử đang xét của nghiệm và chưa là phần tử cuối cùng thì tìm tiếp phần tử tiếp theo
+ Nếu bài toán yêu cầu chỉ tìm một nghiệm thì sau khi chọn được một khả năng cho một phần tử của nghiệm, ta kiểm tra phần tử này đã là phần tử cuối cùng của một nghiệm hay chưa gọi là lệnh kiểm tra kết thúc một nghiệm Nếu đúng là phần tử cuối cùng của nghiệm thì: Hiện nghiệm và thoát hẳn khỏi thủ tục đệ quy;
Trang 34Nếu bài toán yêu cầu tìm tất cả các nghiệm thì chưa kết thúc khi mới kiểm tra kết thúc một nghiệm
+ Trong việc thử mọi khả năng của một phần tử của nghiệm, ta cần tìm những điều kiện để nhanh chóng loại bỏ những khả năng không thể chấp nhận được thì việc thử sẽ nhanh chóng hơn Việc thử mọi khả năng của một phần
tử của nghiệm cũng giống như một người đi đường, mỗi khi đến ngã đường, lần lượt chọn một đường thích hợp trong các con đường của ngã N-đường đó, nếu biết chắc chắn những đường nào đó trong các đường của ngã N-đường là đường “cụt” không thể đi tới đích thì người đi đường sẽ loại ngay những đường đó; hoặc ngược lại nếu nhìn thấy trước những điều kiện cho phép chỉ cần đi theo một số con đường nhất định trong N đường mà vẫn tới đích nhanh chóng thì người đi đường sẽ dùng những điều kiện ấy như là định hướng cho lựa chọn của mình
N-+ Nếu tìm một nghiệm tốt nhất – theo một điều kiện nào đó thì mỗi khi tìm được một nghiệm, ta so sánh với nghiệm tốt nhất đã tìm được cho đến lúc này (gọi là nghiệm tối ưu) Nếu nghiệm vừa tìm được tốt hơn nghiệm tối ưu thì gán lại nghiệm tối ưu là nghiệm mới
Quá trình tiếp diễn cho đến khi duyệt hết các nghiệm của bài toán ta sẽ được nghiệm tối ưu của bài toán
Như vậy: Thuật toán “duyệt trên cơ sở tìm kiếm và quay lui ” - Thuật toán BackTracking có các nội dung sau:
+ Vét cạn mọi nghiệm bằng tìm kiếm tiến dần về đích đồng thời biết quay lui khi không thể tiến
+ Có thể đặt các “mắt lọc” để việc tìm kiếm nhanh hơn: hoặc loại bỏ hoặc chỉ chọn một số hướng
+ Có thể so sánh các nghiệm để có nghiệm tối ưu
Trang 35+ Tuỳ theo yêu cầu, có thể chỉ tìm một nghiệm, cũng có thể tìm mọi nghiệm
Giả sử ta phải tìm trong một tập dữ liệu D cho trước một dãy dữ liệu:
v = (v[1], v[2], , v[n]) thoả mãn đồng thời hai tính chất P và Q Trước hết ta chọn một trong hai tính chất đã cho để làm nền, giả sử ta chọn tính chất P Sau đó ta thực hiện các bước sau đây:
Bước 1 (Khởi trị) Xuất phát từ một dãy ban đầu v = (v[1], , v[i]) nào đó của các phần tử trong D sao cho v thoả P
Bước 2 Nếu v thoả Q ta dừng thuật toán và thông báo kết quả là dãy v, ngược lại ta thực hiện Bước 3
Bước 3 Tìm tiếp một phần tử v[i + 1] để bổ sung cho v sao cho v = (v[1], , v[i], v[i + 1]) thoả P
Có thể xảy ra các trường hợp sau đây:
- Trường hợp 1: Tìm được phần tử v[i + 1]: quay lại bước 2
- Trường hợp 2: Không tìm được v[i + 1] như vậy, tức là với mọi v[i + 1] có thể lấy trong D, dãy v = (v[1], , v[i], v[i + 1]) không thoả P Điều này có nghĩa là đi theo đường v = (v[1], , v[i]) sẽ không dẫn tới kết quả Ta phải đổi hướng tại một vị trí nào đó Để thoát khỏi ngõ cụt này, ta tìm cách thay v[i] bằng một giá trị khác trong D Nói cách khác, ta loại v[i] khỏi dãy v, giảm i đi một đơn vị rồi quay lại Bước 3
Cách làm như trên được gọi là quay lui - Lùi lại một bước
Ta phải đánh dấu v[i] là phần tử đã loại tại vị trí i để sau đó không đặt lại phần tử đó vào vị trí i trong dãy v
Vậy khi nào thì có thể trả lời là không tồn tại dãy v thoả đồng thời hai tính chất P
và Q Hay khi nào thì ta có thể thông báo là bài toán vô nghiệm?
Bài toán vô nghiệm khi ta đã duyệt hết mọi khả năng Ta nói là đã vét cạn mọi khả năng Có thể đến một lúc nào đó ta phải lùi liên tiếp nhiều lần
Trang 36Từ đó suy ra thông thường bài toán vô nghiệm khi ta không còn có thể lùi được nữa
Có nhiều mô hình giải các bài toán quay lui, dưới đây trình bày hai mô hình khá thông dụng
Mô hình 1: Giải bài toán quay lui
tìm một nghiệm
Mô hình 2: Giải bài toán quay lui
tìm một nghiệm Khởi trị v: v thoả P;
Thông thường ta khởi trị cho v là dãy rỗng hoặc dãy có một phần tử
Ta chỉ yêu cầu dãy v được khởi trị sao cho v thoả P Cả dãy v thoả P chứ không phải từng phần tử trong v thoả P
Có bài toán yêu cầu tìm toàn bộ (mọi nghiệm) các dãy v thoả đồng thời hai tính chất P và Q Khi biết cách tìm một nghiệm ta dễ dàng suy ra cách tìm
Bảng 2.1 Mô hình thuật toán quay lui tìm một nghiệm
Trang 37mọi nghiệm như sau: Mỗi khi tìm được một nghiệm, ta thông báo nghiệm
đó rồi thực hiện thao tác lùi, tức là giả vờ như không công nhận nghiệm đó,
do đó phải loại v[i] cuối cùng trong dãy v để tiếp tục tìm hướng khác Phương pháp này có tên là phương pháp giả sai Hai mô hình trên sẽ được
mô tả lại như sau để tìm mọi nghiệm
Mô hình 3: Giải bài toán quay lui
tìm mọi nghiệm
Mô hình 4: Giải bài toán quay lui
tìm mọi nghiệm Khởi trị: v thoả P;
Begin
If d = 0 then Ghi nhận: vô nghiệm;
Else Ghi nhận: d nghiệm;
Trang 38Thuật toán quay lui xây dựng trên cơ sở tìm kiếm dần, kết quả sau hình thành từ kết quả trước, nên có thể dùng các hàm, thủ tục đệ qui để thực hiện thuật toán Cụ thể từ hai mô hình trên ta xây dựng ba dạng dàn bài thường gặp
bắt đầu từ giải thuật đệ quy quay lui tổng quát sau đây:
2.2 Giải thuật đệ quy quay lui tổng quát
Procedure Try(k); {Chọn thực hiện bước thứ k}
Begin
For Các phương án chọn do
If Được chọn then Begin
- Thủ tục trên sẽ được khởi động bởi lệnh: Try(1);
Ta có thể trình bày quá trình tìm kiếm lời giải của thuật toán quay lui bằng cây sau:
Hình 2.1 Quá trình tìm kiếm lời giải của thuật toán quay lui
Trang 392.3 Ba dạng của đệ quy quay lui
2.3.1 Dạng 1 tìm một nghiệm
Trên cơ sở tư tưởng của thuật toán quay lui, để giải quyết một số bài toán chỉ yêu cầu hiển thị một nghiệm, ta xây dựng mô hình thuật toán tìm một nhiệm như sau:
Procedure Tim(k: Integer);
* Lưu trạng thái mới của bài toán sau đề cử;
* Nếu là bước cuối cùng thì Begin
Mô hình giải thuật cho bài toán tìm một nghiệm, cách 1
Thủ tục này có thể viết lại dưới dạng sau:
Trang 40Procedure Tim(k: Integer);
+ Nếu đề cử này thoả mãn bài toán thì
Begin
* Ghi nhận giá trị đề cử;
* Lưu trạng thái mới của bài toán sau đề cử;
* Nếu chưa phải bước cuối cùng thì Tim(K+1);
* Trả lại trạng thái của bài toán trước khi đề cử; End;
End;
End;
Mô hình giải thuật cho bài toán tìm một nghiệm, cách 2
Một khó khăn khác của bài toán tìm một nghiệm là: Trường hợp bài toán vô nghiệm chúng ta cần kiểm soát như thế nào Ta phải duyệt hết mọi khả năng mới rõ kết luận vô nghiệm hay không vô nghiệm Nghĩa là đã đi theo mọi nhánh nhưng nhánh nào cũng đều không tới đích, do đó theo quy luật cứ quay lui mãi để tìm kiếm thì đến lúc nào đó dẫn đến tình trạng phải trở