Tài liệu Kỹ thuật lập trình - Bài 3: Giải thuật đệ quy - Ngô Hữu Dũng: Kỹ thuật lập trình
Bài 3 – Giải thuật đệ quy
Ngô Hữu Dũng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201761
Quy nạp toán học
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201762
 Chứng minh hàm F(n) đúng với mọi số tự nhiên n ≥ N0.
 Phương pháp quy nạp:
 Bước cơ sở: Chỉ ra trường hợp ban đầu F(N0) đúng
 Bước quy nạp: Chứng minh rằng giả sử F(k) đúng thì F(k+1) đúng.
 Ví dụ: Chứng minh S(n): 1 + 3 + 5 + 7 + + (2n-1) = n2 (*), với n ≥ 1
 Bước cơ sở: Trường hợp n = 1, ta có (2n-1) = n2 = 1 là đúng hiển nhiên.
 Bước quy nạp: Giả sử S(k) đúng, ta có 1 + 3 + 5 + ... + (2k – 1) = k2
 Khi đó: S(k+1): 1 + 3 + 5 + ... + (2k – 1) + [2(k+1) – 1] = k2 + (2k + 1)
= (k + 1)2
 Vậy S(k + 1) = (k + 1)2 là đúng. Suy ra S(n) đúng với mọi n ≥ 1.
Ngô Hữu Dũng
Lập trình đệ quy
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201763
 Lập trình tính S(n) = 1 + 3 + 5 +  + (2n – 1) = n2 với n ≥ 1.
 Từ bài toán quy nạp ta có:
 Bước cơ sở: S(1) = 1
 Bước quy nạp: S(k+1) = S(k) + ...
                
              
                                            
                                
            
 
            
                 30 trang
30 trang | 
Chia sẻ: putihuynh11 | Lượt xem: 823 | Lượt tải: 0 
              
            Bạn đang xem trước 20 trang mẫu tài liệu Kỹ thuật lập trình - Bài 3: Giải thuật đệ quy - Ngô Hữu Dũng, để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Kỹ thuật lập trình
Bài 3 – Giải thuật đệ quy
Ngô Hữu Dũng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201761
Quy nạp toán học
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201762
 Chứng minh hàm F(n) đúng với mọi số tự nhiên n ≥ N0.
 Phương pháp quy nạp:
 Bước cơ sở: Chỉ ra trường hợp ban đầu F(N0) đúng
 Bước quy nạp: Chứng minh rằng giả sử F(k) đúng thì F(k+1) đúng.
 Ví dụ: Chứng minh S(n): 1 + 3 + 5 + 7 + + (2n-1) = n2 (*), với n ≥ 1
 Bước cơ sở: Trường hợp n = 1, ta có (2n-1) = n2 = 1 là đúng hiển nhiên.
 Bước quy nạp: Giả sử S(k) đúng, ta có 1 + 3 + 5 + ... + (2k – 1) = k2
 Khi đó: S(k+1): 1 + 3 + 5 + ... + (2k – 1) + [2(k+1) – 1] = k2 + (2k + 1)
= (k + 1)2
 Vậy S(k + 1) = (k + 1)2 là đúng. Suy ra S(n) đúng với mọi n ≥ 1.
Ngô Hữu Dũng
Lập trình đệ quy
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201763
 Lập trình tính S(n) = 1 + 3 + 5 +  + (2n – 1) = n2 với n ≥ 1.
 Từ bài toán quy nạp ta có:
 Bước cơ sở: S(1) = 1
 Bước quy nạp: S(k+1) = S(k) + [2(k + 1) – 1] hay S(k) = S(k – 1) + (2k – 1)
 Phương pháp lập trình đệ quy:
 Phần cơ sở: S(1) = 1
 Phần đệ quy: S(n) = S(n – 1) + (2n – 1)
 Áp dụng vào lập trình:
1. int S(int n)
2. {
3. if (n==1) return 1;
4. else return S(n-1) + (2*n – 1);
5. }
Ngô Hữu Dũng
Cách hoạt động
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201764
 Giả sử n = 5, 
hàm đệ quy chạy như sau:
S(5) = S(4) + 9 // Gọi hàm S(4)
S(4) = S(3) + 7 // Gọi hàm S(3)
S(3) = S(2) + 5 // Gọi hàm S(2)
S(2) = S(1) + 3 // Gọi hàm S(1)
S(1) = 1 // Return S(1)
S(2) = 1 + 3 // Return S(2)
S(3) = 1 + 3 + 5 // Return S(3)
S(4) = 1 + 3 + 5 + 7 // Return S(4)
S(5) = 1 + 3 + 5 + 7 + 9 = 25 = 52 // Return S(5)
1. int S(int n)
2. {
3. if (n==1) return 1;
4. else return S(n-1) + (2*n–1);
5. }
Ngô Hữu Dũng
Khái niệm đệ quy
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201765
 Khái niệm
 Một hàm gọi là đệ quy khi có phép gọi lại chính nó trong thân hàm
 Thành phần
 Phần cơ sở: Điều kiện thoát
 Phần đệ quy: Có phép gọi lại chính nó
 Ưu điểm
 Thuận lợi trong việc giải những bài toán có tính chất quy nạp
 Làm gọn chương trình
 Nhược điểm
 Không tối ưu, tốn bộ nhớ
Ngô Hữu Dũng
Một số loại đệ quy
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201766
 Đệ quy tuyến tính (Linear Recursion)
 Hàm đệ quy chỉ gọi lại chính nó một lần
 Đệ quy nhị phân, đa đệ quy (Binary Recursion, Multiple Recursion)
 Hàm đệ quy gọi lại chính nó hai lần hoặc nhiều hơn hai lần
 Đệ quy đuôi (Tail Recursion)
 Lời gọi đệ quy được thực hiện ở cuối hàm đệ quy
 Đệ quy lồng (Nested Recursion)
 Tham số của một lời gọi đệ quy là một lời gọi đệ quy
 Đệ quy hỗ tương (Mutual Recursion)
 Hai hàm đệ quy gọi lẫn nhau
 Đệ quy quay lui (Backtracking)
 Là hàm đệ quy có phép thử và sai
Ngô Hữu Dũng
Đệ quy tuyến tính
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201767
 Chỉ có một lời gọi đệ quy
 Được dùng thông dụng
 Ví dụ
 Tính giai thừa Fact(n) với n > 0
 Fact(n) = 1 * 2 * 3 * * n
 Phần cơ sở: Fact(1) = 1
 Phần đệ quy: Fact(n)=n*Fact(n-1)
 Tính T(n) = 1 + 2 + 3 +  + n
 Phần cơ sở: T(1) = 1
 Phần đệ quy: T(n) = T(n-1) + n
1. int Fact(int n)
2. {
3. if (n==1) 
4. return 1;
5. else
6. return n * Fact(n-1);
7. }
Ngô Hữu Dũng
1. int T(int n)
2. {
3. if (n==1) 
4. return 1;
5. else
6. return T(n-1) + n;
7. }
Đệ quy nhị phân
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201768
 Hàm đệ quy có hai lời gọi đệ quy tại một thời điểm
 Thường dùng trong các bài toán kiểu cấu trúc cây
 Ví dụ: Tính số Fibonacci thứ n, với n > 0
 Fib(1) = 1, Fib(2) = 1
 Fib(n) = Fib(n-1) + Fib(n-2)
 Tính Fib(5) = ?
 = Fib(4)+Fib(3)
 = Fib(3)+Fib(2) + Fib(2)+Fib(1)
 = Fib(2)+Fib(1)+1+1+1
 = 5
1. int Fib(int n)
2. {
3. if (n==1 || n==2)
4. return 1;
5. else
6. return Fib(n-1)+Fib(n-2);
7. }
Ngô Hữu Dũng
Fib(1) Fib(2) Fib(3) Fib(4) Fib(5)
1 1 2 3 5
Đệ quy nhiều lần
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201769
 Lời gọi đệ quy được thực hiện
nhiều lần trong hàm
 Ví dụ: Tính hàm mystery
 Hàm có hai lời gọi đệ quy
 Hàm trả về kết quả ?
 Tính mystery(2,4) = ?
 = mystery(4, 2)
 = mystery(8, 1)
 = mystery(16, 0) + 8 = 8
 Vậy mystery(2,4) = ?
1. int mystery(int a, int b)
2. {
3. if (b == 0) 
4. return 0;
5. if (b % 2 == 0) 
6. return mystery(a+a, b/2);
7. else
8. return mystery(a+a, b/2)+a; 
9. }
Ngô Hữu Dũng
Đệ quy nhiều lần (tt)
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201770
 Thay dòng số 4 thành return 1;
và thay dấu + bằng dấu *
 Hàm trả về kết quả?
 Tính mystery(2,4) = ?
 = mystery(4,2)
 = mystery(16,1)
 = mystery(256,0)*16
 = 16
 Vậy mystery(2,4) = ?
1. int mystery(int a, int b)
2. {
3. if (b == 0) 
4. return 1;
5. if (b % 2 == 0) 
6. return mystery(a*a, b/2);
7. else
8. return mystery(a*a, b/2)*a; 
9. }
Ngô Hữu Dũng
Đệ quy đuôi
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201771
 Hàm đệ quy có lời gọi đệ quy ở cuối hàm
 Ví dụ
 Tính số Fibonacci thứ n, với n > 0
 Tính Fib(5,1,1) = ?
 = Fib(5,1,1)
 = Fib(4,1,2)
 = Fib(3,2,3)
 = Fib(2,3,5)
 = Fib(1,5,8)
 = 5
1. int Fib(int n, int x, int y)
2. {
3. if (n==1)
4. return x;
5. else
6. return Fib(n-1, y, x+y);
7. }
Ngô Hữu Dũng
Fib(1) Fib(2) Fib(3) Fib(4) Fib(5)
1 1 2 3 5
Đệ quy lồng
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201772
 Lời gọi đệ quy là tham số của một lời gọi đệ quy
 Ví dụ
 Tính hàm Ackermann
 Trường hợp m>0 và n>0,
lời gọi đệ quy chính là tham
số của một lời gọi đệ quy.
1. int A(int m, int n)
2. {
3. if (m==0)
4. return n + 1;
5. if (m>0 && n==0)
6. return A(m-1, 1);
7. if (m>0 && n>0)
8. return A(m-1, A(m, n - 1));
9. }
   ,   =  
  + 1
 (  1,1)
 (  1,    ,   1 )
  = 0
  > 0  à   = 0
  > 0  à   > 0
Đệ quy hỗ tương
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201773
 Các hàm gọi lẫn nhau
 Hàm A gọi B và hàm B gọi lại A.
 Ví dụ
 Tìm số n là chẵn hay lẻ
 Ví dụ SoLe(5) = ?
 = SoChan(4)
 = SoLe(3)
 = SoChan(2)
 = SoLe(1)
 = SoChan(0) = 1
1. bool SoLe(int n)
2. {
3. if (n==0)
4. return 0;
5. else
6. return SoChan(n-1);
7. }
8.
9. bool SoChan(int n)
10. {
11. if (n==0)
12. return 1;
13. else
14. return SoLe(n-1);
15. }
Ngô Hữu Dũng
Đệ quy quay lui – thử và sai
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201774
 Liệt kê các kết quả thỏa mãn những điều
kiện ràng buộc nào đó
 Mỗi kết quả được xây dựng từ các phần tử
 Mỗi phần tử của kết quả được chọn bằng
cách thử tất cả các khả năng
 Ví dụ: Liệt kê tất cả các số có n chữ số, 
được hình thành từ các chữ số từ 1 đến n
 Gọi lietke(1,2)
 Kết quả: 11 12 21 22
Ngô Hữu Dũng
1. int so[10];
2. void in(int n) // In số
3. {
4. for (int i=1;i<=n;i++)
5. printf("%d",so[i]);
6. printf(" ");
7. }
8. void lietke(int i, int n)
9. {
10. for (int j=1;j<=n;j++)
11. {
12. so[i] = j; // Chọn số j
13. if (i==n) // Đủ n số
14. in(n);
15. else
16. lietke(i+1,n);//next
17. }
18. }
Cách hoạt động
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201775
 Lần lượt xét các trường hợp cho số thứ nhất
 Ứng với mỗi trường hợp của số thứ nhất, tìm
số thứ hai
 Cứ như vậy cho đến khi tìm được n số thì
xuất kết quả ra màn hình
Ngô Hữu Dũng
lietke(1,2)
lietke(2,2) lietke(2,2)
so[1]=1 so[1]=2
11
so[2]=1 so[2]=2 so[2]=1 so[2]=2
12 21 22
1. int so[10];
2. void in(int n) // In số
3. {
4. for (int i=1;i<=n;i++)
5. printf("%d",so[i]);
6. printf(" ");
7. }
8. void lietke(int i, int n)
9. {
10. for (int j=1;j<=n;j++)
11. {
12. so[i] = j; // Chọn số j
13. if (i==n) // Đủ n số
14. in(n);
15. else
16. lietke(i+1,n);//next
17. }
18. }
Liệt kê các dãy nhị phân có độ dài n
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201776
 Dãy nhị phân gồm các phần tử là số nhị
phân
 Có giá trị 0 hoặc 1
 Ở dòng 10, biến j chạy từ 0 đến 1
 Bài trước, slide 74-75, biến j chạy từ 1 đến n 
 Tương tự, nếu liệt kê dãy bát phân
 Biến j chạy từ 0 đến 7
 Tương tự, nếu liệt kê dãy thập lục phân
 Biến j chạy từ 0 đến 15, tức từ 0 đến F (!?)
 nhiphan(1,4)
 0000 0001 0010 0011 0100 0101 0110 0111 
1000 1001 1010 1011 1100 1101 1110 1111
1. int so[10];
2. void in(int n) // In số
3. {
4. for (int i=1;i<=n;i++)
5. printf("%d",so[i]);
6. printf(" ");
7. }
8. void nhiphan(int i, int n)
9. {
10. for (int j=0;j<=1;j++)
11. {
12. so[i] = j; // Chọn số j
13. if (i==n) // Đủ n số
14. in(n);
15. else
16. nhiphan(i+1,n);
17. }
18. }
Liệt kê các dãy thập lục phân có độ dài n
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201777
 Dãy thập lục phân gồm các
phần tử là số thập lục phân
 Giá trị từ 0 đến F
 Mảng so_hexa khai báo các
chữ số thập lục phân (dòng 2-3)
 Thay số thành ký tự
 hexa(1,2)
 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 
28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 
3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 
4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 
62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 
76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 
8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 
9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD 
AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE 
BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF 
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 
E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 
F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
1. char so[10];
2. char so_hexa[16]={'0','1','2','3','4','5',
3. '6','7','8','9','A','B','C','D','E','F'};
4. void in_hexa(int n) // In số hexa
5. {
6. for (int i=1;i<=n;i++)
7. printf("%c",so[i]);// In kiểu ký tự
8. printf(" ");
9. }
10. void hexa(int i, int n)
11. {
12. for (int j=0;j<=15;j++)
13. {
14. so[i] = so_hexa[j];// Chọn chữ số j
15. if (i==n) // Đủ n số
16. in_hexa(n);
17. else
18. hexa(i+1,n);
19. }
20. }
Liệt kê các tập con k phần tử của dãy số từ 1 đến n (1≤k≤n)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201778
 Còn gọi là tổ hợp chập k của n phần tử
 Các tập con không trùng nhau, không phân
biệt thứ tự, vị trí
 {1,2,3} = {2,1,3} = {2,3,1}
 Các phần tử được chọn từ so[i-1]+1 đến
n-k+i
 i có giá trị từ 1 đến k
 Phần tử cuối cùng, tức i = k, biến j chạy đến n
 Ví dụ
 tapcon(1,2,3)   
  =
 !
 !     !
= 3
 12 13 23
 tapcon(1,5,5)   
  = 1
 12345
 tapcon(1,3,6)   
  = 20
 123 124 125 126 134 135 136 145 146 156 234 
235 236 245 246 256 345 346 356 456
1. char so[10];
2. void in(int k) 
3. {
4. for (int i=1;i<=k;i++)
5. printf("%d",so[i]);
6. printf(" ");
7. }
8. void tapcon(int i, int k, int n)
9. {
10. so[0] = 0;
11. for (int j=so[i-1]+1;j<=n-k+i;j++)
12. {
13. so[i] = j;
14. if (i==k) 
15. in(k);
16. else
17. tapcon(i+1,k,n);
18. }
19. }
Liệt kê các hoán vị
Kỹ thuật lập trình | DHTH11C | HK1 | 2016-201779
 Liệt kê các hoán vị của các số
từ 1 đến n
 Các chữ số không được trùng
nhau
 Phải kiểm tra xem một số đã
được chọn hay chưa?
 Dùng mảng kiểu bool để đánh
dấu và bỏ đánh dấu một số
được chọn hoặc bỏ chọn
 hoanvi(1,3): 
 123 132 213 231 312 321
Ngô Hữu Dũng
1. int so[10];
2. bool kt[10]={1,1,1,1,1,1,1,1,1,1}
3. void hoanvi(int i, int n)
4. {
5. for (int j=1;j<=n;j++)
6. if (kt[j]) // Số j chưa được dùng
7. {
8. so[i] = j; // Chọn j
9. if (i==n) // Đủ n số
10. in(n);
11. else
12. {
13. kt[j]=false; // Đánh dấu
14. hoanvi(i+1,n); // Tìm số tiếp
15. kt[j]=true; // Bỏ đánh dấu
16. }
17. }
18. }
Chỉnh hợp chập k của n phần tử (1≤k≤n)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201780
 Lấy k phần tử trong số n phần tử, 
mỗi cách sắp xếp là một chỉnh hợp
 Tổ hợp không phân biệt cách sắp
xếp.
 Chỉnh hợp phân biệt vị trí, thứ tự, 
cách sắp xếp
 Tương tự bài liệt kê hoán vị ở slide 
trước nhưng chỉ lấy k số trong n 
phần tử
 Bài trước hoán vị n phần tử
 chinhhop(1,2,3)   
  =
 !
    !
= 6
 12 13 21 23 31 32
 chinhhop(1,3,3)   
  = 6
 123 132 213 231 312 321
 Chính là hoanvi(1,3)
1. int so[10];
2. bool kt[10]={1,1,1,1,1,1,1,1,1,1}
3. void chinhhop(int i, int k, int n)
4. {
5. for (int j=1;j<=n;j++)
6. if (kt[j]) // Số j chưa được dùng
7. {
8. so[i] = j; // Chọn j
9. if (i==k) // Đủ k số
10. in(k);
11. else
12. {
13. kt[j]=false; // Đánh dấu
14. chinhhop(i+1,k,n);
15. kt[j]=true; // Bỏ đánh dấu
16. }
17. }
18. }
Bài toán xếp quân hậu
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201781
 Tìm các cách xếp n quân hậu trên bàn cờ n x n sao
cho các quân cờ không ăn được nhau
 Quân hậu có thể ăn ngang, dọc, chéo
 Lưu vị trí các quân hậu trên bàn cờ (x,y)
 Mảng h (hậu) gồm n phần tử tương ứng với n hàng, 
mỗi phần tử lưu vị trí cột có giá trị từ 1 đến n
 Dùng giải thuật đệ quy quay lui lần lượt thử chọn
vị trí các cột trên từng hàng
 Khi một quân hậu được được đặt lên bàn cờ, các
vị trí liên quan theo chiều ngang, dọc, chéo cần
được đánh dấu để tránh đặt quân cờ khác
h[x]=y
h[1]=1
h[2]=5
h[3]=8
h[4]=6
h[5]=3
h[6]=7
h[7]=2
h[8]=4
Bài toán xếp quân hậu (2)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201782
 Đánh dấu
 Chiều ngang: Mỗi quân cờ được đặt trên một hàng khác nhau tương ứng với mỗi phần
tử ở mảng h
 Chiều dọc: Dùng một mảng kiểu bool d[1→n] để đánh dấu
 Chéo lên: Có tính chất (x + y) là một số cố định
 Dùng một mảng kiểu bool cl[2→2n] để đánh dấu
 Chéo xuống: Có tính chất x – y là một số cố định
 (x – y) cố định nên (x – y + n) cũng cố định
 Dùng một mảng kiểu bool cx[1→2n-1] để đánh dấu
 Ví dụ quân hậu được đặt ở vị trí: h[x]=y (h[5]=3)
 d[y] = d[3] = false
 cl[x+y] = cl[5+3] = cl[8] = false
 cx[x-y+n] = cx[5-3+8] = cx[10] = false;
Bài toán xếp quân hậu (3)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201783
1. void quan_hau(int x, int n)
2. {
3. for(int y=1; y<=n; y++)
4. if(d[y]&&cl[x+y]&&cx[x-y+n])
5. {
6. hau[x] = y;
7. if(x==n)in_banco(n);
8. else
9. {
10. d[y] = false;
11. cl[x+y] = false;
12. cx[x-y+n] = false;
13. quan_hau(x+1,n);
14. d[y] = true;
15. cl[x+y] = true;
16. cx[x-y+n] = true;
17. }
18. }
19. }
1. #include 
2. void quan_hau(int, int);
3. void in_banco(int);
4. #define max 10
5. int h[max];
6. bool d[max];
7. bool cl[2*max];
8. bool cx[2*max];
9.
10. int main()
11. {
12. int i;
13. for(i=0;i<max;i++) d[i]=true;
14. for(i=0;i<2*max;i++)
15. {
16. cl[i]=true;cx[i]=true;
17. }
18. quan_hau(1,8);
19. }
Bài toán xếp quân hậu (4)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201784
1. #include void in_banco(int n)
2. {
3. int i,j,k;
4. for(k=1;k<=n;k++) printf("+----");
5. printf("+\n");
6. for(i=1; i<=n; i++)
7. {
8. printf("| ");
9. for(j=1;j<=n;j++)
10. if(j==h[i])
11. printf("%c%c | ",219,219);
12. else
13. printf(" | ");
14. printf("\n");
15. for(k=1;k<=n;k++) printf("+----");
16. printf("+\n");
17. }
18. getchar();
19. }
Trò chơi Sudoku
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201785
 Điền các số từ 1 đến 9 vào bàn cờ 9 x 9, sao cho
 Các số trên cùng hàng khác nhau
 Các số trên cùng cột khác nhau
 Các số trong mỗi vùng 3 x 3 khác nhau
 Dùng mảng hai chiều để lưu bàn cờ
 Dùng thuật toán đệ quy quay lui để chọn giá trị cho
từng ô
 Kiểm tra chiều ngang, dọc và ô 3 x 3 tránh trùng số
 Xuất mảng hai chiều để in kết quả
 Nhận xét
 Kích cỡ bàn cờ có dạng: 3 x 3 = 9
 Ta có thể làm bài toán tương tự với các kích cỡ khác
 2 x 2 = 4
 4 x 4 =16
3 x 3
Trò chơi Sudoku (2)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201786
1. void sudoku(int banco[size][size],int x,int y)
2. {
3. int i;
4. for(i=1; i<=size; i++)
5. if(kt(i,x,y))
6. {
7. banco[x][y]=i;
8. if(y<size-1)
9. sudoku(banco,x,y+1);
10. else
11. if(x<size-1)
12. sudoku(banco,x+1,0);
13. else
14. in();
15. banco[x][y]=0;
16. }
17. }
2 x 2
4 x 4
Trò chơi Sudoku (3)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201787
1. #include 
2. #define s 3
3. #define size s*s
4. int banco[size][size];
5. bool kt(int k, int x, int y)
6. {
7. int i,j;
8. for(i=0; i<size; i++)
9. if(banco[x][i]==k 
10. || banco[i][y]==k) 
11. return 0;
12. x=x/s,y=y/s;
13. for(i=x*s; i<x*s+s; i++)
14. for(j=y*s; j<y*s+s; j++)
15. if(banco[i][j]==k) 
16. return 0;
17. return 1;
18. }
1. void in()
2. {
3. int i,j;
4. printf("\n");
5. for(i=0; i<size; i++)
6. {
7. for(j=0;j<size;j++)
8. printf(" %d",banco[i][j]);
9. printf("\n");
10. }
11. getchar();
12. }
13. int main()
14. {
15. sudoku(banco,0,0);
16. }
Tháp Hà Nội
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201788
 Chuyển chồng đĩa từ cột 1 sang cột 3 theo quy tắc:
 Mỗi lần chỉ được di chuyển 1 đĩa từ cột này sang cột 
khác
 Chỉ được di chuyển đĩa trên cùng của cột
 Đĩa có kích thước lớn hơn luôn nằm dưới.
 Tính đệ quy của bài toán, để chuyển n đĩa từ cột một
sang cột 3
 Bước cơ sở, n =1: Ta chuyển một đĩa từ cột 1 sang cột 3
 Bước đệ quy: n > 1
 Chuyển n-1 đĩa sang cột trung gian (đệ quy)
 Chuyển 1 đĩa dưới cùng từ cột 1 sang cột 3
 Chuyển n-1 đĩa từ cột trung gian sang cột 3 (đệ quy)
Tháp Hà Nội (2)
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201789
1. void chuyendia(int sodia, int toaMot, int toaHai, int toaBa)
2. {
3. if (sodia==1)chuyen(toaMot, toaBa);
4. else
5. {
6. chuyendia(sodia-1,toaMot,toaBa,toaHai);
7. chuyen(toaMot, toaBa);
8. chuyendia(sodia-1,toaHai,toaMot,toaBa);
9. }
10. }
Hết bài 3
Ngô Hữu DũngKỹ thuật lập trình | DHTH11C | HK1 | 2016-201790
 Quy nạp toán học
 Giải thuật đệ quy
 Các loại đệ quy
 Tuyến tính
 Nhị phân
 Đệ quy đuôi
 Hỗ tương
 Quay lui
 Một số bài toán
            Các file đính kèm theo tài liệu này:
 bai_giang_ky_thuat_lap_trinh_ts_ngo_huu_dung_ky_thuat_lap_trinh_ngo_huu_dung_bai_03_6624_1985328.pdf bai_giang_ky_thuat_lap_trinh_ts_ngo_huu_dung_ky_thuat_lap_trinh_ngo_huu_dung_bai_03_6624_1985328.pdf