2. Đánh giá độ phức tạp của các thuật toán đệ quy 3. Một số bài toán sử dụng thuật toán quay lui 2. Đánh giá độ phức tạp của các thuật toán đệ quy Xây dựng công thức truy hồi theo g(n). Giải công thức truy hồi để xác định g(n). Ví dụ: float Power(float a, int n) { if (n==0) return 1; else return a* Power(a,n-1); } Suy ra: g(0)=1 và g(n)=g(n-1)+1 g(n) = n+1 T(n) = O(n+1) = O(n) 3. Một số bài toán sử dụng thuật toán quay lui Có dạng: Hãy xác định các bộ gồm n thành phần: (x1, x2, ..., xn) thoả mãn điều kiện B nào đó. Với xi được chọn từ tập Si cho trước gồm ni phần tử (i=1..n).
Ví dụ: Xác định tất cả các bộ gồm n thành
phần (x[1], x[2], ..., x[n]), trong đó: x[i] là các số nguyên nhận giá trị từ 1 đến m (i=1..n). Một phương pháp giải quyết Khi cần xác định xi, ta giả sử đã xác định được i-1 thành phần: x1, x2,..., xi-1. Để xác định thành phần xi, ta duyệt tất cả các khả năng có thể có của nó. Với mỗi khả năng j ta luôn kiểm tra xem j có được chấp nhận không? Nếu chấp nhận j, thì xác định x i theo khả năng j. Tiếp đến kiểm tra, nếu i < n thì ta tiến hành xác định x i+1, ngược lại (i=n) thì ta được một lời giải. Rồi kiểm tra khả năng j tiếp theo của xi. Nếu tất cả các khả năng của j không có khả năng nào được chấp nhận thì quay lại bước trước để xác định lại xi-1. (Cơ chế đệ quy giúp có thể thực hiện được điều này) Minh hoạ void Try(int i) //Thử xem xi sẽ nhận giá trị nào { for <mỗi khả năng j của xi> { if (<chấp nhận j>) { xi = j; if (i==n) <Ghi nhận một lời giải>; else Try (i+1); } } } main() //Nội dung chương trình chính { <Khai báo và khởi tạo các biến của chương trình>; Try(1); } Ví dụ: Liệt kê các số nhị phân gồm n chữ số void Try(int i) { int j; for (j=0; j<=1; j++) { x[i]=j; if (i==n) print(x); else Try(i+1); } } Trong đó: 1. Chương trình chính: main() { int x[10]; int n; cin>>n; Try(1); } 2. void print(int x[]) { int k; for (k=1; k<=n; k++) cout<<x[k]; cout<<endl; } Ví dụ: Liệt kê các hoán vị của n void Try(int i) { int j; for (j=1; j<=n; j++) { if (b[j]==1) { x[i]=j; b[j]=0; if (i==n) print(x); else Try(i+1); b[j]=1; } } } Trong đó: main() //Chương trình chính { int x[10]; int b[10]; int n, i; cin>>n; for (i=1; i<=n; i++) b[i]=1; Try(1); } Ví dụ: Liệt kê các tổ hợp chập k của n phần tử (1..n) void Try(int i) { int j; for (j=1; j<=n; j++) { if ((b[j]==1) && (j>x[i-1])) { x[i]=j; b[j]=0; if (i==k) print(x); else Try(i+1); b[j]=1; } } } Chương trình chính: main() { int x[10]; int b[10]; int n, k, i; cin>>n; cin>>k; x[0]=0; for (i=1; i<=n; i++) b[i]=1; Try(1); }