You are on page 1of 42

Chương 3

Giải thuật đệ quy

LOGO
Nội dung

 Khái niệm đệ qui


 Giải thuật đệ qui và thủ tục đệ qui
 Thiết kế một số giải thuật đệ qui
• Hàm n!
• Dãy số Fibonacci
• Bài toán tháp Hà Nội
• Giải thuật quay lui và bài toán tám quân hậu
 Hiệu lực của đệ qui
 Đệ qui và qui nạp toán học
Khái niệm về đệ qui
 Đệ qui: Đưa ra 1 định nghĩa có sử dụng
chính khái niệm đang cần định
nghĩa( quay về).

 Ví dụ
 Người = con của hai người khác.
 Trong toán học:
• Số tự nhiên: 0 là số tự nhiên, n là số tự nhiên nếu
n- 1 là số tự nhiên
• Hàm n!
Giải thuật đệ qui

 Giải thuật đệ qui


 Nếu bài toán T được thực hiện bằng lời giải
của bài toán T’ có dạng giống T là 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 đệ qui.
Giải thuật đệ qui

 Quá trình đệ qui gồm 2 phần:


 Trường hợp cơ sở (base case)
 Trường hợp đệ qui: cố gắng tiến về trường
hợp cơ sở
 Ví dụ:
 Giai thừa của n là 1 nếu n = 0
 Giai thừa của n là n * (giai thừa của n-1) nếu
n>0
Giải thuật đệ qui
 Ví dụ: Xét bài toán tìm một từ trong
quyển từ điển:

If (từ điển là một trang)


tìm từ trong trang này
else {
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)
tìm từ đó ở nửa trước
else tìm từ đó ở nửa sau.
}
Cài đặt hàm đệ qui

 Cấu trúc hàm đệ qui như sau


If (suy biến)
<Giải quyết trường hợp suy biến>;
Else
{ <tiền xử lý đệ qui>;
<Gọi đệ qui> ;
<Xử lý hậu đệ qui>;
}
Thiết kế giải thuật đệ qui
 Để xây dựng giải thuật đệ quy, ta cần thực
hiện tuần tự 3 nội dung sau:
 Thông số hóa bài toán.
 Tìm các trường hợp neo cùng giải thuật giải
tương ứng.
 Tìm giải thuật giải trong trường hợp tổng quát
bằng phân rã bài toán theo kiểu đệ quy.
Một số giải thuật đệ qui

 Hàm n!

 Dãy số Fibonacci

 Bài toán tháp Hà Nội

 Giải thuật quay lui và bài toán tám quân


hậu
Hàm n!

 Định nghĩa không đệ qui:

n! = n * (n-1) * … * 1
 Định nghĩa đệ qui
 n! = 1 nếu n=0
 n! = n * (n-1)! nếu n>0
Hàm n!

 Function FACTORIAL(n)

if (n==0) return 1;

else return n*FACTORIAL(n-1);

}
Hàm n!
Dãy số Fibonacci

 Định nghĩa:
 Fn = 1 nếu n ≤ 2
 Fn = Fn-1 + Fn-2 nếu n>2
 Ví dụ: 1, 1, 2, 3, 5, 8, 13, 21, 34, …
 Hàm đệ qui:

F(n) {
if (n<=2) return 1;
else return (F(n-1) + F(n-2));
}
Bài toán tháp Hà Nội

A B C
Bài toán tháp Hà Nội
 Bài toán tháp Hà nội : n đĩa
 Mỗi lần chỉ di chuyển một đĩa
 Đĩa lớn luôn nằm dưới đĩa nhỏ A
 Được phép sử dụng một cọc trung gian
 Ký hiệu
• A: cọc nguồn B
• B: cọc trung gian
• C: cọc đích

C
Bài toán tháp Hà Nội
 Trường hợp n = 1
• Chuyển từ A sang C
 Trường hợp n > 1
• Chuyển (n-1) đĩa từ A sang B, C trung gian
• Chuyển đĩa n từ A sang C
• Chuyển (n-1) đĩa từ B sang C, A làm trung gian
Bài toán tháp Hà Nội

A B C
Bài toán tháp Hà Nội
 A  C, B trung gian

A (n) B (n-1) C (1)


Bài toán tháp Hà Nội
 B  C (A trung gian)

A (n-2) B (n-1) C (2)


Bài toán tháp Hà Nội
 A  C (B trung gian)

A (n-2) B (n-3) C (3)


Bài toán tháp Hà Nội
 B  C (A trung gian)

A (n-4) B (n-3) C (4)


Bài toán tháp Hà Nội
A  C

A (0) B (0) C (n)


Phương pháp quay lui
(back tracking)
 Đặc trưng: các bước hướng tới lời giải cuối
cùng của bài toán hoàn toàn được làm thử.
 Tại mỗi bước
 Nếu có một lựa chọn được chấp nhận thì ghi
nhận lại lựa chọn này và tiến hành các bước thử
tiếp theo.
 Ngược lại, không có lựa chọn nào thích hợp thì
làm lại bước trước, xóa bỏ sự ghi nhận và quay
về chu trình thử các lựa chọn còn lại
Phương pháp quay lui
(back tracking)
 Mô hình bài toán:
 Tìm X=(x1, x2, ..,xn) thỏa B.
 Để chỉ ra lời giải X, ta phải dựng dần các
thành phần lời giải xi
Phương pháp quay lui
(back tracking)
Phương pháp: xây dựng x1, x2, ..,xn
theo cách sau
 Tập T1 các ứng cử viên có thể là thành phần
đầu tiên của vectơ nghiệm chính là x1
 Chọn x1  T1,
 Giả sử, đã xác định được k-1 phần tử đầu
tiên của dãy đó là x1, x2, ..,xk-1. Cần xác định
phần tử kế tiếp xk
 Xác định Tk là tập tất cả các ứng viên mà xk có
thể nhận được, có hai khả năng:
Phương pháp quay lui
(back tracking)
 Nếu Tk không rỗng, chọn xi  Tk và có được
nghiệm bộ (x1,x2,…,xk-1,xk), đồng thời loại xk đã
chọn khỏi Tk. Sau đó lại tiếp tục mở rộng bộ (x 1,x2,
…,xk) bằng cách áp dụng đệ quy thủ tục mở rộng
nghiệm.
 Nếu Tk rỗng, tức là không thể mở rộng bộ (x 1,x2,
…,xk-2,xk-1), thì quay lại chọn phần tử mới x’ k-1 trong
Tk-1 làm thành phần thứ k-1 của vectơ nghiệm
 Chú ý: phải có thêm thao tác "Trả lại trạng
thái cũ” cho bài toán để hỗ trợ cho bước quay
lui
Phương pháp quay lui
(back tracking)
Thu(k)
{
if (k==n) <ghi nhận bộ giá trị mới>
else
for ( j = 1 → nk) // Mỗi j thuộc tập Tk
if ( j chấp nhận được)
{
<Xác định xk theo khả năng j>
<Ghi nhận trạng thái mới>
Thu(k+1);
<Trả lại trạng thái cũ cho bài toán>;
}
}
Phương pháp quay lui
(back tracking)
 Quan tâm:
 Làm thế nào để xác định được tập Tk, tức là
tập tất cả các khả năng mà phàn tử thứ k của
dãy x1, x2, ..,xn có thể nhận
 Khi đã có tập Tk, để xác định xk, thấy rằng xk
phụ thuộc vào chỉ số j mà còn phụ thuộc vào
x1, x2, .., xk-1
Bài toán 8 quân hậu

 Sắp xếp 8 quân hậu trên


bàn cờ 8x8 sao cho
chúng không ‘ăn’ lẫn
nhau
(mỗi hàng, mỗi cột, mỗi
đường chéo có đúng một
quân)
Bài toán 8 quân hậu

 Đặt quân hậu thứ j vào cột


thứ j sao cho nó không bị 1 2 3 4 5 6 7 8
‘ăn’ bởi j-1 quân hậu hiện
1
có trên bàn cờ 2
3
 Mỗi cột chỉ có 1 quân hậu, 4
nên việc chọn vị trí quân hậu 5
thứ j, ứng với cột j là đặt nó
6
vào hàng nào để “an toàn”
7
8
Bài toán 8 quân hậu
Try(j)
{
Khởi phát việc chọn vị trí cho quân hậu thứ j;
do
{
Thực hiện phép chọn tiếp theo;
if (an toàn)
{
Đặt quân hậu; // Ghi nhớ các thông tin cần thiết
if (j<8)
{
Try(j+1);
if (không thành công)
cất quân hậu; // Xoá bớt các ghi nhớ
}
}
}
while (chưa thành công và còn chỗ);
}
Bài toán 8 quân hậu
 Để lựa chọn i được chấp nhận thì :
 hàng i và hai đường chéo qua ô (i, j) phải còn tự do
(không có quân hậu nào khác ở trên đó). Chú ý: trong
hai đường chéo thì đường chéo theo chiều ↑ có các ô
(i,j) mà tổng i+j không đổi, còn đường chéo theo chiều ↓
có các ô (i,j) mà i-j không đổi. 1 ≤ i, j ≤ 8 => 1 ≤ i ≤ 8 ;
=> chọn các mảng nguyên một 2 ≤ i+j ≤ 16; -7 ≤ i –j ≤ 7
chiều để biểu diễn các tình
trạng:
a[i] = 1 (đúng): chưa có quân
hậu nào chiếm hàng i.
b[i+j] = 1 - chưa có quân hậu
nào chiếm đường chéo i+j
c[i-j] = 1 - chưa có quân hậu
nào chiếm đường chéo i-j
Bài toán 8 quân hậu
Try (j) }
{ else // j=8, đã tìm được một
i = 0; cách đặt cho 8 quân hậu
do q = 1; // ghi nhận thành công
{ }
i = i+1; }
q = 0; // Biến q để kiểm tra có while (q || i!=8);
thành công hay không }
if (a[i] && b[i+j] && c[i-j])
{
x [j] = i;
a[i] =b[i+j] = c[i-j] = 0;
if (j<8)
{
Try(j+1);
if (not q)
{
a[i] = b[i+j] = c[i-j] = 1;
}
Bài toán 8 quân hậu
main()
{ // khởi tạo tình trạng ban đầu khi chưa quân hậu
nào được đặt
for (i = 1; i<=8; i++) a[i] = 1;
for (i = 2; i<=16; i++) b[i] = 1;
for (i = -7; i<=7; i++) c[i] = 1;
Try(1) ; // tìm một lời giải
if (q)
for (i = 1; i<=8; i++) printf(x[i]);
}
Bài toán 8 quân hậu
Try(j) main()
{ {
for (i = 1; i<=8; i++) for (i = 1; i<=8; i++) a[i] = 1;
if (a[i] && b[i+j] && c[i-j]) for (i = 2; i<=16; i++) b[i] =
{ 1;
x[j] = i; for (i = -7; i<=7; i++) c[i] = 1;
a[i] = b[i+j] = c[i-j] = 0; Try(1);
if (j<8) }
Try(j+1);
else
In_kqua(x);
a[i] = b[i+j] = c[i-j] = 1;
}
}
Đệ quy và quy nạp toán học
 Dùng đệ quy để giải các bài toán truy hồi
 Dùng quy nạp toán học để chứng minh
tính đúng đắn, xác định độ phức tạp của
giải thuật đệ quy
Đệ quy và quy nạp toán học
Bài tập áp dụng
1. Xét định nghĩa đệ qui:

Hàm này được gọi là hàm Ackermann. Nó có


đặc điểm là giá trị của nó tăng rất nhanh,
ứng với giá trị nguyên của m và n.
- Hãy xác định Acker (1,2)
- Viết một hàm đệ qui thực hiện tính giá
trị hàm này.
Bài tập áp dụng
Bài tập áp dụng
3. Hãy nêu rõ các bước thực hiện khi có lời gọi
HANOI(3, A, B, C)
4. Viết một hàm đệ qui thực hiện in ngược một
dòng ký tự cho trước. Ví dụ, cho dòng
“TURBO C” thì in ra “C OBRUT”.
5. Viết một hàm đệ qui nhằm in ra tất cả các
hoán vị của n phần tử của một dãy số a =
{a1, a2,…an}.
Ví dụ, với n = 3, a1 = 1, a2 = 2, a3 = 3 thì in ra:
1 2 3; 1 3 2; 2 1 3; 2 3 1; 3 1 2; 3 2 1;
Bài tập áp dụng
6. Có n người và n công việc. Biết rằng nếu
người i làm việc j thì đạt hiệu suất a[i][j].
Hãy viết hàm đệ qui để lập phương án
phân công mỗi người một việc khác nhau,
sao cho tổng hiệu suất là lớn nhất.
Q&A

You might also like