Professional Documents
Culture Documents
Divide and Conquer
Divide and Conquer
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;
int main()
{
cout << F(5);
}
11
F(5)
F(4) F(3)
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