Thuật Thuật toán toán:: Xét Xét tất tất cả cả các các phần phần tử tử aaii với với i= i=11....nn Bỏ Bỏ hầ hầ tử tử khỏi khỏi dã dã ốố Bỏ Bỏ phần phần tử tử aaii ra ra khỏi khỏi dãy dãy s
Trang 1ii Tìm Tìm kiếm kiếm nhị nhị phân phân pp
int
int searchBinary(int searchBinary(int left,int left,int right, right, intx){ intx){
if(left<right){ ( ( g ){ g ){
int
int mid=(left+right)/ mid=(left+right)/22;;
if(x==A[i])return
if(x==A[i])return ii;; ( ( [ ]) [ ]) ;;
if(x<A[i])return
if(x<A[i])return searchBinary(left,mid searchBinary(left,mid 11,x) ,x);;
return return searchBinary(mid+ searchBinary(mid+11,right,x) ,right,x);;
return
return searchBinary(mid searchBinary(mid 11,right,x) ,right,x);;
}}
return
return 11;;
return
return 11;;
}}
iii Phân Phân tích tích một một số số nguyên nguyên ra ra thừa thừa số số nguyên nguyên tố tố (( Bài
iii Phân Phân tích tích một một số số nguyên nguyên ra ra thừa thừa số số nguyên nguyên tố tố (( Bài
tập ))
Phạm Thế Bảo
Trang 22 Đệ Đệ quy quy nhánh nhánh
Là
Là dạng dạng đệ đệ quy quy mà mà trong trong quá quá trình trình đệ đệ quy, quy, lời lời gọi gọi được được thực thực hiện hiện
nhiều
nhiều lần lần
Ví
Ví dụ dụ::
i.i Tháp Tháp Hà Hà nội nội
ii Liệt Liệt kê kê tất tất cả cả hoán hoán vị vị của của nn phần phần tử tử khác khác nhau nhau
ii Liệt Liệt kê kê tất tất cả cả hoán hoán vị vị của của nn phần phần tử tử khác khác nhau nhau
Thuật
Thuật toán toán::
Xét
Xét tất tất cả cả các các phần phần tử tử aaii với với i= i=11 nn Bỏ
Bỏ hầ hầ tử tử khỏi khỏi dã dã ốố Bỏ
Bỏ phần phần tử tử aaii ra ra khỏi khỏi dãy dãy số số Ghi
Ghi nhận nhận đã đã lấy lấy ra ra phần phần tử tử aaii Hoán
Hoán vị vị (Dãy (Dãy số) số)
Đ hầ hầ tử tử àà l i l i dã dã ốố Đưa
Đưa phần phần tử tử aaii vào vào lại lại dãy dãy số số Nếu
Nếu (Dãy (Dãy số) số) rỗng rỗng thì thì thứ thứ tự tự các các phần phần tử tử được được lấy lấy ra ra chính chính là là một
một hoán hoán vị vị
Bài Bài toán toán tô tô mà mà (floodfill) (floodfill)
iii Bài Bài toán toán tô tô màu màu (floodfill) (floodfill)
Phạm Thế Bảo
Trang 33 Đệ Đệ quy quy hỗ hỗ tương tương
Là
Là dạng dạng đệ ạ g ạ g ệệ q y đệ quy quy mà q y mà trong trong đó gg đó việc việc gọi ệệ gọ gọi có gọ có xoay xoay vòng, yy vòng, như g, như A A
gọi
gọi B, B, B B gọi gọi C, C, và và C C gọi gọi A A Đây Đây là là trường trường hợp hợp rất rất phức phức
tạp
tạp
Ví
Ví dụ dụ::
i.i Đường Đường Hilbert Hilbert
ii Đường Đường Sierpinski Sierpinski
Phạm Thế Bảo
Trang 4Cá h há khử đệ
Các phương pháp khử đệ quy
1 Vòng Vòng lặp lặp
2 Bằng Bằng stack stack
Phạm Thế Bảo
Trang 5Đệ quy
Ví Ví dụ dụ: : Viết ụụ Viết chương chương trình gg trình nhập nhập số ập số tự tự nhiên ựự nhiên n n và và tính tính giai giai thừa gg thừa : n! : n!.
Giải Giải quyết quyết bài bài toán toán bằng bằng vòng vòng lặp lặp
1 #include < #include <stdio.h stdio.h> >
2 unsigned long unsigned long int int factorial( factorial(int int n) n)
3 { unsigned long f = 1;
4 for ( for (int int ii = 1; = 1; ii<=n; <=n; ii++) ++)
55 f *= f *= ii;;
5 f *= f *= ii;;
7 }}
8 int int main(void) main(void)
9 { { int int n; n;
10 printf printf(“ (“Nhap Nhap n:”); n:”); scanf scanf(“%d”, &n); (“%d”, &n);
10 printf printf(( Nhap Nhap n: ); n: ); scanf scanf( %d , &n); ( %d , &n);
printf
printf(“n! = %d! = %l (“n! = %d! = %l\\n”, n, factorial(n)); n”, n, factorial(n));
11 return 0;
12 }}
Trang 6Đệ quy
Một Một hàm hàm được được gọi gọi là là đệ đệ quy quy nếu nếu như như trong trong quá quá trình trình xử xử lý, lý, hàm hàm này này có có một một lời lời gọi gọi
đến
đến chính chính nó nó
Giải Giải quyết quyết bài bài toán toán bằng bằng đệ đệ quy quy
1 #include #include <stdio <stdio h> h>
1 #include #include stdio stdio hh
2 unsigned unsigned long long int int factorial(int factorial(int n) n)
3 {{ if(n== if(n==00))
44 return return 11;;
4 return return 11;;
5 return return (n* (n* factorial(n factorial(n 11)) ));;
6 }}
7 int int main(void) main(void)
8 {{ int int nn;;
9 printf(“Nhap printf(“Nhap nn::”) ”);; scanf(“ scanf(“% %d”, d”, &n) &n);;
9 printf( Nhap printf( Nhap nn:: ));; scanf( scanf( % %d , d , &n) &n);;
10 printf(“n! printf(“n! = = % %d! d! = = % %ll\\n”, n”, n, n, factorial(n)) factorial(n));;
11 return return 00;;
12 }}
Trang 7dừng
Bài
Bài t á t á iải iải bằ bằ th ật th ật iải iải đệ đệ hải hải óó điề điề kiệ kiệ
Bài Bài toán toán giải giải bằng bằng thuật thuật giải giải đệ đệ quy quy phải phải có có điều điều kiện kiện dừng
dừng
Thuật Thuật toán toán đệ đệ quy quy trên trên máy máy tính tính có có thể thể bị bị giới giới hạn hạn bởi bởi dung
dung lượng lượng bộ bộ nhớ nhớ do do lời lời gọi gọi hàm hàm liên liên tiếp tiếp
dung
dung lượng lượng bộ bộ nhớ nhớ do do lời lời gọi gọi hàm hàm liên liên tiếp tiếp
main
factorial (4) factorial (3) factorial (2) factorial (1)
Hãy
Hãy vẽ vẽ sơ sơ đồ đồ tiến tiến trình trình gọi gọi hàm hàm khi khi thực thực hiện hiện tính tính dãy dãy fibonacci fibonacci bằng bằng
Hãy
Hãy vẽ vẽ sơ sơ đồ đồ tiến tiến trình trình gọi gọi hàm hàm khi khi thực thực hiện hiện tính tính dãy dãy fibonacci fibonacci bằng bằng
đệ
đệ quy quy
Trang 8Bài t á Thá Hà Nội
Có Có 33 cái cái cột cột và và một một chồng chồng đĩa đĩa ởở cột cột thứ thứ nhất nhất Hãy Hãy chuyển chuyển
Có Có 33 cái cái cột cột và và một một chồng chồng đĩa đĩa ởở cột cột thứ thứ nhất nhất Hãy Hãy chuyển chuyển chồng
chồng đĩa đĩa sang sang cột cột thứ thứ ba ba với với điều điều kiện kiện mỗi mỗi lần lần di di chuyển chuyển chỉ
chỉ một một đĩa đĩa và và các các đĩa đĩa bé bé luôn luôn nằm nằm trên trên đĩa đĩa lớn lớn
Trang 9Th ật iải
Ch ể
Chuyển Chuyển (n (n 11)) đĩa đĩa sang sang cột cột trung trung gian gian
Chuyển Chuyển đĩa đĩa lớn lớn nhất nhất sang sang cột cột đích đích
Ch ể
Ch ể (( 11)) đĩ đĩ từ từ ột ột tt ii ột ột đí h đí h
Chuyển Chuyển (n (n 11)) đĩa đĩa từ từ cột cột trung trung gian gian sang sang cột cột đích đích
Trang 10Cài đặt bằ đệ
Cài đặt bằng đệ quy
11 MoveDisk MoveDisk((disk number disk number starting post starting post target post target post
1 MoveDisk MoveDisk((disk_number disk_number, , starting_post starting_post, , target_post target_post,,
intermediate_post
intermediate_post))
2 {{
33 if(disk)number > 1)
3 if(disk)number > 1)
5 MoveDisk MoveDisk(disk_number (disk_number 1, 1, starting_post starting_post, ,
intermediate post intermediate post target post target post); );
intermediate_post
intermediate_post, , target_post target_post); );
6 printf printf(“Move disk number %d, from post %d to post %d (“Move disk number %d, from post %d to post %d.\\n”, n”,
disk_number
disk_number, , starting_post starting_post, , target_post target_post); );
77 MoveDisk MoveDisk(disk number (disk number 1 intermediate post 1 intermediate post
7 MoveDisk MoveDisk(disk_number (disk_number 1,intermediate_post, 1,intermediate_post,
target_post
target_post, , starting_post starting_post); );
10 printf printf(“Move disk number 1 from post %d to post %d (“Move disk number 1 from post %d to post %d.\\n”, n”,
starting_post
starting_post, , target_post target_post); );
11 }}
11 }}
Trang 11Bài toán Xếp Hậu (8 Queens)
Liệt kê tất cả các cách xếp n quân hậu trên bàn cờ n x n sao cho chúng không ăn được nhau
Bàn cờ có n hàng được đánh số từ 0 đến n-1, n cột được đánh số từ 0 đến n-1; Bàn cờ có n*2
-1 đường chéo xuôi được đánh số từ 0 đến 2*n -2, 2 *n -1 đường chéo ngược được đánh số từ 2*n -2 Ví dụ: với bàn cờ 8 x 8, chúng ta có 8 hàng được đánh số từ 0 đến 7, 8 cột được đánh
số từ 0 đến 7, 15 đường chéo xuôi, 15 đường chéo ngược được đánh số từ 0 15
Vì trên mỗi hàng chỉ xếp được đúng một quân hậu, nên chúng ta chỉ cần quan tâm đến quân
hậu được xếp ở cột nào Từ đó dẫn đến việc xác định bộ n thành phần x1, x2, , xn,trong đó
xi = j được hiểu là quân hậu tại dòng i xếp vào cột thứ j Giá trị của i được nhận từ 0 đến n-1;
giá trị của j cũng được nhận từ 0 đến n-1, nhưng thoả mãn điều kiện ô (i,j) chưa bị quân hậu
khác chiếu đến theo cột, đường chéo xuôi, đường chéo ngược
Việc kiểm soát theo hàng ngang là không cần thiết vì trên mỗi hàng chỉ xếp đúng một quân
hậu Việc kiểm soát theo cột được ghi nhận nhờ dãy biến logic aj với qui ước aj=1nếu cột j còn trống, cột aj=0 nếu cột j không còn trống Để ghi nhận đường chéo xuôi và đường chéo ngược có chiếu tới ô (i,j) hay không, ta sử dụng phương trình i + j = const và i - j = const, đường chéo thứ nhất được ghi nhận bởi dãy biến bj, đường chéo thứ 2 được ghi nhận bởi dãy biến cj với qui ước nếu đường chéo nào còn trống thì giá trị tương ứng của nó là 1 ngược lại
là 0 Như vậy, cột j được chấp nhận khi cả 3 biến aj, bi+j, ci+j đều có giá trị 1 Các biến này phải được khởi đầu giá trị 1 trước đó, gán lại giá trị 0 khi xếp xong quân hậu thứ i và trả lại giá trị 1 khi đưa ra kết quả
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
void hoanghau(int);
void inloigiai(int loigiai[]);
FILE *fp;
Trang 12int A[N], B[D], C[D], loigiai[N];
int soloigiai =0;
void hoanghau(int i){
int j;
for (j=0; j<N;j++){
if (A[j] && B[i-j+SG] && C[i+j] ) {
loigiai[i]=j;
A[j]=FALSE;
B[i-j+SG]=FALSE;
C[i+j]=FALSE;
if (i==N-1){
soloigiai++;
inloigiai(loigiai); delay(500);
} else
hoanghau(i+1); A[j]=TRUE;
B[i-j+SG]=TRUE;
C[i+j]=TRUE;
} }
}
void inloigiai(int *loigiai){
int j;
printf("\n Lời giải %3d:",soloigiai);
fprintf(fp,"\n Lời giải %3d:",soloigiai); for (j=0;j<N;j++){
printf("%3d",loigiai[j]);
fprintf(fp,"%3d",loigiai[j]);
}
}
void main(void){
int i;
clrscr();
fp=fopen("loigiai.txt","w");
for (i=0;i<N;i++)
A[i]=TRUE;
for(i=0;i<D; i++){
B[i]=TRUE;
C[i]=TRUE;
}
hoanghau(0);
fclose(fp);
}
Trang 13Bài tốn Tháp Hà Nội (Tower of Hanoi)
Truyền thuyết 1: Một nhà toán học Pháp sang thăm Đông Dương đến một ngôi chùa cổ ở Hà Nội thấy các vị sư đang chuyển một chồng đĩa qúy gồm 64 đĩa với kích thước khác nhau từ cột A sang cột C theo cách:
- Mỗi lần chỉ chuyển 1 đĩa
- Khi chuyển có thể dùng cột trung gian B
- Trong suốt qúa trình chuyển các chồng đĩa ở các cột luôn được xếp đúng (đĩa có kích thước bé được đặt trên đĩa có kích thước lớn )
Khi được hỏi các vị sư cho biết khi chuyển xong chồng đĩa thì đến ngày tận thế !
Truyền thuyết 2: Lúc thế giới hình thành, trong ngơi đền thờ Brahma cĩ một chồng 64 cái đĩa Mỗi ngày, cĩ một thầy tu di chuyển một đĩa Đến khi hết đĩa thì đĩ là ngày tận thế
Như sẽ chỉ ra sau này với chồng gồm n đĩa cần 2n- 1 lần chuyển cơ bản (chuyển 1 đĩa ) 2n
Giả sử thời gian để chuyển 1 đỉa là t giây thì thời gian để chuyển xong chồng 64 đĩa sẽ là:
T = ( 264-1 ) * t giây = 11.84*1019*t giây
Với t = 1/100 giây thì T =5.8*109 năm = 5.8 tỷ năm
Ta có thể tìm thấy giải thuật (dãy các thao tác cơ bản ) cho bài toán một cách dễ dàng ứng với trường hợp chồng đĩa gồm 0, 1, 2, 3 đĩa Với chồng 4 đĩa giải thuật bài toán đã trở nên phức tạp Tuy nhiên giải thuật của bài toán lại được tìm thấy rất dễ dàng nhanh chóng khi ta khái quát số đĩa là n bất kỳ và nhìn bài toán bằng quan niệm đệ quy
a) Thông số hóa bài toán
Xét bài toán ở mức tổng quát nhất : chuyển n (n>=0) đĩa từ cột X sang cột Z lấy cột Y làm trung gian
Ta gọi giải thuật giải bài toán ở mức tổng quát là thủ tục THN(n ,X ,Y,Z) chứa 4 thông số n,X,Y,Z ; n thuộc tập số tự nhiên N (kiểu nguyên không dấu ); X ,Y,Z thuộc tập các ký tự (kiểu ký tự )
Bài toán cổ ở trên sẻ được thực hiện bằng lời gọi THN(64,A,B,C)
Dễ thấy rằng : trong 4 thông số của bài toán thì thông số n là thông số quyết định độ phức tạp của bài toán ( n càng lớn thì số thao tác chuyển đỉa càng nhiều và thứ tự thực hiện chúng càng khó hình dung ) , n là thông số điều khiển
b) Trường hợp suy biến và cách giải
Với n =1 bài toán tổng quát suy biến thành bài toán đơn giản THN (1,X,Y,Z) : tìm dãy thao tác để chuyển chồng 1 đĩa từ cột X sang cột Z lấy cột Y làm trung gian Giải thuật giải bài toán THN (1,X,Y,Z) là thực hiện chỉ 1 thao tác cơ bản : Chuyển 1 đĩa từ X sang Z ( ký hiệu là Move (X , Z) ) THN(1,X,Y,Z) ≡ { Move( X, Z ) }
Chú ý : Hoàn toàn tương tự ta cũng có thể quan niện trường hợp suy biến là trường hợp n=
0 tương ứng với bài toán THN(0,X,Y,Z) : chuyển 0 đĩa từ X sang Z lấy Y làm trung gian mà giải thuật tương ứng là không làm gì cả ( thực hiện thao tác rỗng )
THN(0,X,Y,Z) ≡ {φ }
c) Phân rã bài toán :
Ta có thể phần rã bài toán TH N (k,X,Y,Z) : chuyển k đĩa từ cột X sang cột Z lấy cột Y làm trung gian thành dãy tuần tự 3 công việc sau :
Trang 14+ Chuyển (k -1) đĩa từ cột X sang cột Y lấy cột Z làm trung gian :
THN (k -1,X,Z,Y) (bài toán THN với n = k-1,X= X , Y = Z , Z = Y )
+ Chuyển 1 đĩa từ cột X sang cột Z : Move ( X, Z ) (thao tác cơ bản )
+ Chuyển (k - 1 ) đĩa từ cột Y sang cột Z lấy cột X làm trung gian :
THN( k -1,Y,X,Z) ( bài toán THN với n = k-1 , X = Y , Y = X , Z = Z )
Vậy giải thuật trong trường hợp tổng quát (n > 1) là :
THN(n,X,Y,Z) ≡ {
THN (n -1,X,Z,Y) ; Move ( X, Z ) ; THN (n -1,Y,X,Z) ; }
Với n đĩa thì cần bao nhiêu bước chuyển 1 đĩa? Thực chất trong thủ tục THN các lệnh gọi đệ qui chỉ nhằm sắp sếp trình tự các thao tác chuyển 1 đĩa
Số lần chuyển 1 đĩa được thực hiện là đặc trưng cho độ phức tạp của giải thuật
Với n đĩa , gọi f(n) là số các thao tác chuyển _một_đĩa
f(1) =1 f(n) = 2f(n -1) + 1 với n > 0
Do đo ù : f(n) = 1+ 2 + 2 2 + + 2 n-1 = 2 n - 1
Để chuyển 64 đĩa cần 2 64 - 1 bước hay xấp xỉ 10 20 bước Cần khoảng 10 triệu năm với một máy tính nhanh nhất hiện nay để làm việc này
Hàm thực hiện:
void THN(int n, char X,Y,Z){
if(n > 0) {
THN(n -1,X,Z,Y ) ; Move ( X , Z ) ; THN(n - 1,Y,X,Z ) ; }
return ;
}
hoặc :
void THN( int n , char X,Y,Z) {
if(n = = 1) Move ( X , Z ) ;
else {
THN(n -1,X,Z,Y ) ; Move ( X, Z ) ; THN(n - 1,Y,X,Z ) ; }
return ;
}
Trang 15Bài toán tìm cặp điểm gần nhất trong mặt phẳng (Closest
Pair)
Trang 16Bài tập
Phần 1: Mảng và chuỗi ký tự
1 Nhập vào một dãy số nguyên gồm n phần tử Tìm cặp phần tử có tổng đúng bằng k (k nhập từ bàn phím)
2 Nhập dãy n số (n ≤ 1000) Xác định đường chạy dài nhất, xuất lên màn hình vị trí phần tử đầu tiên và độ dài của đường chạy đó Đường chạy là một dãy liên tiếp các phần tử không giảm của dãy ban đầu
Ví dụ : Nhập dãy 1 4 2 3 1 2 6 8 3 5 7
Đường chạy dài nhất là : 4 4
3 Nhập dãy n số (n ≤ 1000) Xét dãy số có đối xứng không?
4 Viết chương trình nhập/ xuất một ma trận số thực n x m (n, m ≤ 100) Sắp xếp các giá trị các phần tử của ma trận không giảm theo đường zigzag
Ví dụ:
5 Viết chương trình nhập/ xuất một ma trận vuông số nguyên dương n x n (n≤ 100 và n lẻ) Xét ma trận có đối xứng qua:
a Đường chéo chính
b Theo dòng, cột
c Tâm
6 Viết chương trình nhập chuỗi ký S:
a Đếm và cho biết số lượng khoảng trắng, số lượng ký số, số lượng chữ cái latin, số lượng các ký tự khác
b Đếm và cho biết số lượng từ của chuỗi – các từ cách nhau bởi khoảng trắng
c Biến đổi chuỗi sao cho các ký tự đầu mỗi từ là ký tự in hoa, các ký tự khác in thường
2 Viết chương trình nhập chuỗi ký S, đếm và in cho biết số lượng của mỗi chữ cái latin trong chuỗi (không phân biệt chữ in hoa và chữ in thường)
7 Viết chương trình nhập 3 chuỗi ký tự S, S1, S2 Hãy tìm trên chuỗi S tất cả những lần xuất hiện của S1 và thay bằng S2
8 Một số tự nhiên là Palindrom nếu các chữ số của nó viết theo thứ tự ngược lại thì số tạo thành là chính số đó ( Ví dụ: 4884, 393) Hãy tìm: Tất cả các số tự nhiên nhỏ hơn 100 mà khi bình phương lên thì cho một Palindrom
9 Viết chương trình đảo ngược vị trí các từ trong câu Ví dụ: “KIEN AN CA” đổi thành
“CA AN KIEN”
10 Nhập một câu không quá 20 từ, mỗi từ không quá 10 ký tự Viết chương trình tách các từ trong câu và in các từ theo thứ tự Alphabet Ví dụ: “PHAN VIEN CONG NGHE THONG TIN” tách thành [PHAN], [VIEN], [CONG], [NGHE], [THONG], [TIN] và in ra: CONG NGHE PHAN THONG TIN VIEN
Phần 2: Cấu trúc
Xây dựng cấu trúc điểm, đường thẳng, hình chữ nhật, đường tròn
1 Xét vị trí tương đối của 03 điểm trên mặt phẳng
2 Xét vị trí tương đối giữa hai đoạn thẳng
3 Xét 1 điểm có nằm trong 1 : hình chữ nhật, tròn hay không
4 Xét vị trí tương đối của 1 đường thẳng và hình chữ nhật, tròn