You are on page 1of 52

Chia để trị và Đệ quy

1
Bài toán cần giải

Bài toán cơ sở
2
Bài toán nào có thể giải bằng D&C
• Có thể định nghĩa được bài toán dưới dạng phối hợp của
những bài toán cùng loại nhưng nhỏ hơn hay không ? Khái
niệm “nhỏ hơn” là thế nào ? (Xác định quy tắc phân rã bài
toán)
• Trường hợp đặc biệt nào của bài toán có thể coi là đủ nhỏ để
có thể giải trực tiếp được? (Xác định các bài toán cơ sở)

3
Giải thuật đệ quy
• Cách cài đặt phổ biến nhất của thuật toán chia để trị
• Được cài đặt bằng các hàm đệ quy.
• Một lời giải bài toán với dữ kiện được cho = Một lời gọi hàm
với tham số biểu diễn dữ kiện đó.
• Hàm đệ quy chứa lời gọi tới chính nó nhưng với các tham số
khác ứng với bài toán con

4
Thành phần của hàm đệ quy
• Phần neo (anchor): Được thực hiện khi gặp bài toán cơ
sở, giải trực tiếp
• Phần đệ quy (recursion): Trong trường hợp dữ kiện
được cho chưa phải bài toán cơ sở
• Xác định bài toán con và gọi đệ quy giải các bài toán con
• Phối hợp lời giải của các bài toán con để được lời giải của bài
toán lớn.

5
Tính giai thừa

6
#include <iostream>
using namespace std; F(4)
long long F(int n)

=
{ F(3)
if (n == 0) return 1; //Neo

=
else return n * F(n - 1); //Đệ quy F(2)
}

=
int main() F(1)
{

=
int n;
F(0)
cin >> n;

=
cout << F(n);
}

7
Đổi nhị phân

13 % 2

13 = 1 1 0 1

13 / 2

8
#include <iostream> int main()
using namespace std; {
long long n;
void convert(long long x)
{ cin >> n;
if (x > 1) convert(x / 2); convert(n);
cout << x % 2; }
}

9
Số Fibonacci

10
#include <iostream>
using namespace std;

long long F(int n)


{
if (n < 2) return n;
else return F(n - 1) + F(n - 2);
}

int main()
{
cout << F(5);
}

11
F(5)

F(4) F(3)

F(3) F(2) F(2) F(1)

F(2) F(1) F(1) F(0) F(1) F(0)

F(1) F(0)

12
Tính lũy thừa

13
Tính lũy thừa (1)
long long Power(int x, int n)
{
long long p = 1;
for (; n > 0; n--)
p *= x;
return p;
}
14
Tính lũy thừa (2)
long long Power(int x, int n)
{
if (n == 0) return 1;
else return x * Power(x, n - 1);
}

15
Tính lũy thừa

16
Tính lũy thừa (3)
long long Power(int x, int n)
{
if (n == 0) return 1;
long long t = Power(x, n / 2);
if (n % 2 == 0) return t * t;
else return t * t * x;
}
17
Tháp Hà Nội

18
1 2 3

19
1 2 3

20
1 2 3

21
1 2 3

22
1 2 3

23
1 2 3

24
1 2 3

25
Thuật toán chuyển đĩa

26
x y z

27
x y z

28
x y z

29
#include <iostream> int main()
using namespace std; {
//Chuyển n đĩa từ cọc x sang cọc y int n;
void movedisks(int n, int x, int y)
cin >> n;
{
movedisks(n, 1, 2);
if (n == 1) cout << x << " -> " << y << endl;
}
else
{
movedisks(n - 1, x, 6 - x - y);
movedisks(1, x, y);
movedisks(n - 1, 6 - x - y, y);
}
}

30
Số lần chuyển

31
Giả thuyết của Collatz

32
Giả thuyết của Collatz

33
Collatz Conjecture

/2 *3+1 /2 /2 /2 /2

10 5 16 8 4 2 1

*2 /3 *2 *2 *2 *2

Reverse problem

34
Giả thuyết của Collatz

35
void express(int x)
#include <iostream> {
using namespace if (x == 1) cout << 1;
else
std; if (x % 2 == 0)
{
express(x / 2);
int main() cout << " * 2";
{ }
else
int x; {
cin >> x; express(x * 3 + 1);
cout << " / 3";
cout << x << " = "; }
express(x); }

}
36
Đệ quy tương hỗ
• Nguyên lý
• Hàm P gọi hàm Q
• Hàm Q lại gọi hàm P
• Vấn đề khai báo
• Khai báo phần tiêu đề của Q trước P để báo cho trình
dịch biết hàm Q có tồn tại nhưng sẽ đặc tả sau…

37
Giả thuyết của Collatz

38
#include <iostream> void Q(int x)
using namespace std; { P(1) 1
if (x % 2 == 1) P(x);
Q(1)
void Q(int x); else
{ Q(2) *2
Q(x / 2); cout << " * 2";
void P(int x) Q(4) *2
}
{
} Q(8) *2
if (x == 1) cout << 1;
else Q(16) *2
int main()
{
{ P(5) /3
Q(x * 3 + 1);
int x;
cout << " / 3"; Q(5)
cin >> x; cout << x << " = ";
} Q(x); Q(10) *2
} }

39
Hàm inline ★
• Lời gọi hàm cũng tốn chi phí về thời gian
• Với những hàm ngắn, không đệ quy, được gọi nhiều
lần, chỉ dẫn inline trước khai báo hàm “đề nghị”
trình dịch chèn mã của hàm vào thay cho việc gọi
hàm
• Tốc độ sẽ cải thiện hơn một chút!
40
Tìm giá trị lớn nhất

41
#include <iostream> int main()
using namespace std; {
int n, a, m = 0;
cin >> n;
inline void for (; n > 0; n--)
Maximize(int &t, int v) {
{ cin >> a;
if (v > t) t = v; //if (a > m) m = a;
} Maximize(m, a);
}
cout << m;
}
42
25 2
1 12 2
0
6 2
0
3 2
1
1 2
1 0
25 = 11001

43
6 5 4 3 2 1 0

1 1 0 0 1 0 0

44

45

22 7

10 3 . 1 4 2 8 5 7
30
20
a %= b; 60
for (k – 1 lần) 40
50
a = a * 10 % b;
1
cout << a * 10 / b;
46
• •

47
• S[0] = 1
S[1] = 10
S[2] = 1001
S[3] = 10010110
S[4] = 1001011001101001
f = 0;
for (i = 1; i <= n; ++i)
if (i lẻ) f = f * 2;
else f = f * 2 + 1;

48
• •

49

50

51
•https://tinyurl.com/bt2236/

52

You might also like