Tải bản đầy đủ (.docx) (28 trang)

đề cương ôn tập môn phân tích, thiết kế và đánh giá thuật toán

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.25 MB, 28 trang )

Lý thuyết:
1. Thuật toán là gì? Tính chất, cách biểu diễn, độ phức tạp?
a. Thuật toán là cách thức, quy trình để hoàn thành 1 công việc cụ thể xác định nào đó
b. Tính chất:
- Tính đúng đắn: Thuật toán cần phải đảm bảo cho một kết quả đúng sau khi thực hiện đối
với các bộ dữ liệu đầu vào.
- Tính dừng: Thuật toán cần phải đảm bảo sẽ dừng sau 1 số bước hữu hạn bước.
- Tính xác định: Các bước của thuật toán phải được hiểu rõ ràng, cụ thể, tránh gây nhập
nhằng hoặc nhầm lẫn đối với người đọc và hiểu, cài đặt thuật toán.
- Tính hiệu quả: thuật toán được xem là hiệu quả nếu như nó có khả năng giải quyets hiệu
quả bài toán đặt ra trong thời gian hoặc các điều kiện cho phép trên thực tế đáp ứng được
yêu cầu của người dùng
- Tính phổ quát: thuật toán có thể giải quyết được 1 lớp các bài toán tương tự
c. Cách biểu diễn: có 2 cách biểu diễn thuật toán:
- Mô tả các bước thực hiện của thuật toán.
- Sử dụng sơ đồ giải thuật
d. Độ phức tạp:
Các tiêu chí đánh giá thuật toán:
+ Thuật toán đơn giản, dễ hiểu, dễ cài đặt.
+ Dựa vào thời gian thực hiện và tài nguyên mà thuật toán sử dụng để thực hiện trên
các bộ dữ liệu.
2. Thế nào là bài toán tìm kiếm? (định nghĩa, đầu vào, đầu ra, mục đích, …)
Tìm kiếm là 1 trong những vấn đề thuộc lĩnh vực nghiên cứu của ngành khoa học máy tính và được
ứng dụng rộng rãi trên thực tế.
Chúng ta quan tâm đến bài toán tìm kiếm trên 1 mảng, hoặc 1 danh sách các phần tử cùng kiểu
Kết quả tìm kiếm là vị trí của phần tử thỏa mãn điều kiện tìm kiếm: có trường khóa bằng với 1 giá trị
khóa cho trước. Từ vị trí này chúng ta có thể truy cập tới các thông tin khác được chứa trong trường
dữ liệu của phần tử tìm thấy. Nếu kết quả là không tìm thấy thì giá trị trả về sẽ được gán cho một giá
trị đặc biệt nào đó tương đương với việc không tồn tại phần tử nào có vị trí đó: chẳng hạn – 1 với
mảng và NULL với danh sách liên kết.
Có nhiều thuật toán tìm kiếm như: tìm kiếm vét cạn, tìm kiếm tuần tự, tìm kiếm nhị phân, v.v.v v.


3. Trình bày thuật toán tìm kiếm tuyến tính (các bước, sơ đồ thuật toán, độ phức tạp, …)
Các bước:
- Duyệt qua các phần tử của mảng
- Nếu tìm thấy phần tử có khóa bằng khóa tìm kiếm thì trả về vị trí của phần tử đó. Ngược lại không
tìm thấy thì trả về -1
Sơ đồ thuật toán:
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán1
Độ phức tạp thuật toán trong trường hợp trung bình và tồi nhất: O(n).
Trong trường hợp tốt nhất thuật toán có độ phức tạp O(1).
4. Bài toán sắp xếp là gì? (định nghĩa, đầu vào, đầu ra, mục đích, …)
Sắp xếp là 1 quá trình xếp đặt các bản ghi của 1 file theo một thứ tự nào đó. Việc xếp đặt đựợc thực
hiện dựa trên một hay nhiều trường nào đó, và các thông tin này được gọi là khóa sắp xếp (key). Hầu hết
các thuật toán sắp xếp được gòi là các thuật toán sắp xếp so sánh: chúng sử dụng 2 thao tác cơ bản là
so sánh và đổi chỗ (swap) các phần tử cần sắp xếp.
Các bài toán sắp xếp đơn giản được chia thành: sắp xếp trong (dữ liệu cần sắp xếp được lưu đầy đủ
trong bộ nhớ trong để thực hiện thuật toán sắp xếp), sắp xếp ngoài (Dữ liệu sắp xếp có kích thước
quá lớn và không thể lưu vào bộ nhớ trong để sắp xếp, các thao tác truy cập dữ liệu cũng mất nhiều
thời gian hơn), sắp xếp gián tiếp (khi kích thước các bản ghi lớn và việc hoán đổi các bản ghi là rất
tốn kém)
5. Trình bày thuật toán sắp xếp chọn trực tiếp (mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Mô tả thuật toán: Tìm phần tử lớn nhất (nhỏ nhất), đặt nó vào đúng vị trí và sau đó sắp xếp phần
còn lại của mảng.
Sơ đồ thuật toán:
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán2
Cài đặt bằng C:
Độ phức tạp thuật toán:O(n
2
)

Ví dụ:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void selection_sort(int a[],int n)
{
int i,j,vtmin;
for(i=0;i<n-1;i++)
{
vtrimin=i;
for(j=i+1;j<n;j++)
if(a[j]<a[vtmin]) vtmin=j;
swap(&a[vtmin],&a[i];
}
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán3
6. Trình bày thuật toán sắp xếp chèn (mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Thuật toán dựa vào thao tác chính là chèn mỗi khóa vào một dãy con đã được sắp xếp của dãy cần
sắp xếp. Phương pháp này thường được sử dụng trong việc sắp xếp các cây bài trong quá trình chơi
bài.
Sơ đồ thuật toán:
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán4
Cài đặt thuật toán bằng C:
Ví dụ:
Độ phức tạp: O(n
2
)
7. Trình bày thuật toán sắp xếp nổi bọt (mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Thuật toán dựa trên việc so sánh và đổi chỗ 2 phần tử ở kề nhau:
- Duyệt qua danh sách các bản ghi cần sắp xếp theo thứ tự, đổi chỗ 2 phần tử kề nhau nếu chúng không có
thứ tự.

- Lặp lại điều này cho tới khi không có 2 bản ghi nào sai thứ tự.
Sơ đồ thuật toán:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void insertion_sort(int a[],int n)
{
int i,j,temp;
for(i=1;i<n;i++)
{
j=i;
temp=a[i];
while(j>0&&temp<a[j-1])
{
a[j]=a[j-1];
j=j-1;
}
a[j]=temp;
}
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán5
Độ phức tạp:O(n
2
)
Ví dụ:
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán6
Cài đặt bằng C:
8. Trình bày thuật toán sắp xếp đổi chỗ (mô tả thuật toán, cài đặt, độ
9. ttphức tạp, ví dụ)
Mô tả thuật toán: Bắt đầu xét phần tử đầu tiên a[i] với i=0, ta xét tất cả các phần tử đứng sau a[i] gọi
là a[j] với j nằm trong đoạn [i+1; n-1]. Với mỗi cặp a[i], a[j] đó, nếu có sự sai khác giữa a[i] và a[j]

thì đổi chỗ a[i] và a[j]
Cài đặt thuật toán:
Sơ đồ thuật toán:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void bubble_sort(int a[],int n)
{
int i,j;
for(i=n-1;i>=0;i )
for(j=1;j<=i;j++)
if(a[j-1]>a[j])
swap(&a[j-1],a[j]);
}
void bubble_sort2(int a[],int n)
{
int i,j;
for(i=0;i<n;i++)
for(j=n-1;j>i;j )
if(a[j-1]>a[j])
swap(&a[j-1],a[j]);
}
void exchange_sort(int a[],int n)
{
int i,j,tam;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[j]<a[i])
{
tam=a[j];
a[j]=a[i];
a[i]=tam;

}
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán7
Ví dụ: Giả sử mảng ban đầu là int a[]={2, 6, 1, 19, 3, 12} thì thuật toán sẽ thực hiện như sau:
i=0, j=2: 1, 6, 2, 19, 3, 12
i=1, j=2: 1, 2, 6, 19, 3, 12
i=2, j=4: 1, 2, 3, 19, 6, 12
i=3, j=5: 1, 2, 3, 6, 12, 19
Kết quả cuối cùng: 1, 2, 3, 6, 12, 19.
10. Trình bày thuật toán sắp xếp vun đống (heap-sort) (mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Mô tả thuật toán:
- Thực hiện thủ tục buildheap để biến mảng A thành 1 heap
- Vì A là 1 heap nên phần tử lớn nhất sẽ là A[1].
- Đổi chỗ A[0] và A[n-1], A[n-1] đã nằm đúng vị trí của nó và vì thế chúng ta có thể bỏ qua nó và coi như
mảng bây giờ có kích thước là n-1 và quay trở lại xem xét phần đầu của mảng đã không là 1 heap nữa.
- Vì A[0] có thể lỗi vị trí nên ta sẽ gọi thủ tục heaprify đối với nó để chỉnh lại mảng trở thành 1 heap.
- Lặp lại các thao tác trên cho tới khi chỉ còn 1 phần tử trong heap khi đó mảng đã được sắp xếp.
Độ phức tạp: O(n*log(n))
Cài đặt bằng C:
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán8
11. Thế nào là giải thuật đệ quy? Ưu, nhược điểm của đệ quy? Cách khử đệ quy. Ví dụ.
- Đệ quy là cách định nghĩa một đối tượng dựa trên chính nó, hay cụ thể hơn là trên các thể hiện cụ thể,
đơn giản của nó. 1 hàm đệ quy là 1 hàm mà trong thân hàm có lời gọi tới chính nó (số lượng và vị trí
không hạn chế).
Ưu điểm của đệ quy: Chương trình ngắn gọn và đẹp hơn.
Nhược điểm của đệ quy: Tốn vùng nhớ, thời gian truyền đối mục, thiết lập vùng nhớ trung gian và trả
về kết quả.
Cách khử đệ quy:
- Khử đệ quy bằng vòng lặp

- Khử đệ quy bằng đệ quy arsac
Ví dụ: Hàm tính số fibonaci thứ n
12. Thế nào là chiến lược vét cạn? Ưu, nhược điểm của vét cạn? Ví dụ.
Chiến lược vét cạn là thử tất cả các khả năng xem khả năng nào là nghiệm đúng của bài toán cần giải
quyết.
Ví dụ giải bài toán in ra tất cả các số nguyên tố 4 chữ số abcd sao cho ab=cd được thực hiện bằng
thuật toán vét cạn như sau:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void heapsort(int *A, int n)
{
int i;
buildheap(A, n);
for(i=n-1;i>0;i )
{
swap(A[0],A[i]);
heaprify(A,0,i-1);
}
}
int fb(int n)
{
if(n==1||n=2) return 1;
else return fb(n-1)+fb(n-2);
}
for(a=1;a<=9;a++)
for(b=0;b<=9;b++)
for(c=0;c<=9;c++)
for(d=0;d<=9;d++)
if(ngto(a*1000+b*100+c*10+d) && (10*a+b==10*c+d)
printf("%d%d%d%d",a,b,c,d);
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán9

Ưu điểm: Tìm ra nghiệm 1 cách chắc chắn đầy đủ, có thể áp dụng cho mọi loại bài toán.
Nhược điểm: Số bước tính toán lớn và do vậy sẽ tốn thời gian để tìm nghiệm bài toán.
13. Thế nào là chiến lược quay lui? Ưu, nhược điểm của quay lui? Ví dụ.
Chiến thuật quay lui tương tự như chiến lược vét cạn song có 1 điểm khác: nó lưu lại các trạng thái
trên con đường đi tìm nghiệm của bài toán, nếu tới 1 bước nào đó không thể tiến hành tiếp, thuật toán
sẽ quay lui về trạng thái trước đó và lựa chọn các khả năng khác.
Ưu điểm: Thuật toán tìm ra được tất cả các nghiệm của bài toán 1 cách dễ dàng, có thể áp dụng cho
các bài toán với kích thước input nhỏ.
Nhược điểm: Tốn nhiều thời gian cho phép thử nghiệm.
Ví dụ: Sinh các dãy nhị phân độ dài N (N<=20)
14. Thế nào là chiến lược chia để trị? Ưu, nhược điểm của chia để trị? Ví dụ.
Thuật toán chia để trị thực hiện chia bài toán thành các bài toán nhỏ hơn, giải các bài toán nhỏ hơn
đó, sau đó kết hợp nghiệm của các bài toán nhỏ hơn đó lại thành nghiệm của bài toán ban đầu.
Ưu điểm: Số lượng công việc để tìm nghiệm bài toán sẽ giảm đi nên tốc độ thực hiện thuật toán
nhanh.
Nhược điểm: Khó tách hợp lý bài toán thành các bài toán con và việc kết hợp lời giải của các bài
toán con sẽ khó thực hiện.
Ví dụ: Thuật toán tính a
n
:
15. Trình bày thuật toán sắp xếp nhanh (Quick-Sort)?(mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Mô tả thuật toán: thuật toán được thực hiện qua 3 bước:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void try(int k)
{
int j;
if(k==n) in_nghiem();
else
for(j=0;j<=1;j++)
{

x[k]=j;
try(k+1);
}
}
int power(int a,int n)
{
if(n==0) return 1;
else
{
int t=power(a,n/2);
if(n%2==0) return t*t;
else return a*t*t;
}
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán10
- Selection: Chọn 1 phần tử gọi là phần tử quay (pivot)
- Partition (phân hoạch): đặt tất cả các phần tử của mảng < phần tử quay sang bên trái và
ngược lại là sang bên phải phần tử quay. Phần tử quay trở thành phần tử có vị trí đúng
trong mảng.
- Đệ quy: gọi tới chính thủ tục sắp xếp nhanh đối với 2 nửa mảng nằm 2 bên phần tử quay
Ví dụ:
Trong ví dụ sau đây ta luôn chọn phần tử chốt là phần tử đứng giữa danh sách với chỉ số của phần tử
chốt được chọn là k = int((k
1
+ k
2
) / 2) + 1
a = (2,6,3,7,4,5,1)
7 4
Do ngẫu nhiên, phần tử chốt a[4] = 7 là phần tử lớn nhất trong dãy, ta tìm từ trái sang phải không có

phần tử nào lớn hơn phần tử chốt, do đó ta đổi phần tử chốt với phần tử cuối cùng, danh sách được
chia thành hai danh sách con a[1 6] và a[7 7]
4
Việc phân chia tiếp tục với danh sách cona[1 6]. Phần tử chốt được chọn là a[4]=1. Từ trái sang phải
tìm được phần tử đầu tiên lớn hơna[4] = 1 là a[1] = 2, từ phải sang phần tử đầu tiên <=1 là chính
a[4]. Đổi chố hai phần tử này
4
Đi tiếp sang trái ta được a[2] > 1, ở phía ngược lại đi tiếp sang trái tìm được phần tử nhỏ hơn hoặc
bằng chốt là chính a[1] = 1 nhưng lúc này hai đường đã chạm nhau nên ta không đổi nữa. Do
vậy a[1 6] được phân chia thầnh hai danh sách con a[1 1] và a[2 6]
2 4
Tiếp tục phân chia a[2 6] với phần tử chốt a[4] = 2 ta được
3 6
Tiếp tục phân chia a[3 6] với phần tử chốt a[5] = 4 ta được
4
Tiếp tục phân chia a[3 4] với phần tử chốt a[4] = 4 và a[5 6] với phần tử chốt a[6] = 5 ta được
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán11
4
Độ phức tạp: O(n*log(n))
Cài đặt:
16. Trình bày thuật toán tìm kiếm nhị phân?(mô tả thuật toán, cài đặt, độ phức tạp, ví dụ)
Mô tả thuật toán:
- Input: mảng a[] đã được sắp xếp, có khóa tìm kiếm k.
- Output: vị trí của phần tử có khóa bằng k.
Cài đặt:
Tác giả: Đỗ Đức Hùng. Website: Mail:
void quicksort(int *A, int l, int r)
{
if(r>l)

{
int p=partition(A,l,r);
quicksort(A,l,p-1);
quicksort(A,p+1,r);
}
}
int partition(int *A, int l, int r)
{
int p=A[l];
int i=l+1;
int j=r;
while(l)
{
while(A[i]<=p && i<r) i++;
while(A[j]>=p && j>l) j ;
if(i>=j)
{
swap(A{[i],A[j]);
return j;
}
else swap(A[i],A[j]);
}
}
int binary_search(int a[], int left, int right, int key)
{
int mid;
while(left<=right)
{
mid=(left+right)/2;
if(a[mid]==key) return mid;

if(a[mid]<key) left=mid+1;
else right=mid-1;
}
return -1;
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán12
Độ phức tạp:O(log(n))
17. Trình bày chiến lược quy hoạch động?Ưu, nhược điểm? Ví dụ.
Quy hoạch động là 1 phương pháp giải bài toán bằng cách kết hợp các lời giải cho các bài toán con
của nó giống như phương pháp chia để trị. Quy hoạc động được áp dụng khi các bài toán con của bài
toán ban đầu không độc lập với nhau, chúng có chung các bài toán con nhỏ hơn. Trong trường hợp
như vậy 1 thuật toán chia để trị sẽ thực hiện nhiều việc hơn những gì thực sự cần thiết, nó sẽ lặp lại
việc giải quyết các bài toán con nhỏ hơn đó. 1 thuật toán quy hoạch động sẽ chỉ giải quyết tất cả các
bài toán con nhỏ 1 lần duy nhất sau đó lưu kết quả vào 1 bản ghi và điều này giúp nó tránh không
phải tính toán lại các kết quả mỗi khi gặp 1 bài toán con nhỏ nào đó.
Quy hoạch động thường được áp dụng cho các bài toán tối ưu, trong các bài toán đó thường có nhiều
nghiệm, mỗi nghiệm có 1 giá trị được lượng giá bằng cách sử dụng 1 hàm đánh giá tùy thuộc vào các
bài toán cụ thể và yêu cầu của bài toán là tìm ra 1 nghiệm có giá trị của hàm đánh giá là tối ưu.
Ưu điểm: Dễ cài đặt, tốc độ thực hiện bài toán nhanh.
Nhược điểm: Tốn bộ nhớ do cần lưu lại kết quả của bài toán con.
18. Trình bày bài toán tìm dãy con chung dài nhất.
Dãy con là dãy được định nghĩa là 1 tập con các ký tự của dãy (giữ nguyên thứ tự)
Giả sử ta có 2 dãy ký tự X[n] và Y[m]
Bước 1: Xác định đặc điểm của dãy con chung dài nhất:
- Giả sử chúng ta đã có lời giải Z[1 k]
- Nếu 2 ký tự cuối cùng của X và Y trùng nhau thì đó cũng là ký tự cuối cùng của Z.
- Phần còn lại của Z khi đó sẽ là xâu con chung dài nhất của X[1 n-1] và Y[1 m-1]
- Nếu 2 ký tự cuối cùng của X và Y không trùng nhau thì một trong số chúng sẽ không nằm trong
Z (có thể cả 2)
- Giả sử ký tự không nằm trong Z trong trường hợp đó là ký tự của X, thì Z sẽ là dãy con dài nhất

của X[1 n-1] và Y[1 m].
- Ngược lại nếu ký tự không nằm trong Z là ký tự của Y thì Z sẽ là dãy con dài nhất của X[1 n] và
Y[1 m-1].
Bước 2: Xây dựng công thức truy hồi tính độ dài lớn nhất của dãy con của 2 dãy
- Gọi C[i][j] là độ dài dãy con lớn nhất của 2 dãy X[1 i] và Y[1 j]
- C[i][0] = C[0][j] với mọi i, j.
- Lời giải của bài toán chính là C[n][m].
- Công thức truy hồi
[ 1][ 1] 1(1)
[ ][ ]
max( [ 1][ ], [ ][ 1])(2)
C i j
C i j
C i j C i j
− − +

=

− −

- Trường hợp 1 là khi X[i] = Y[j], ngược lại là trường hợp 2.
Bước 3: Xây dựng thuật toán tìm dãy con chung dài nhất của 2 dãy X[1 n] và Y[1 m]
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán13
Bước 4: Tìm dãy con dài nhất của X[1 n] và Y[1 m]
Ta dùng 1 mảng D[i][j] trỏ ngược tới (i, j-1) hoặc (i-1, j) hoặc (i-1, j-1) và lần ngược từ D[m][n]. D[i]
[j] = 1 (Trên trái) nếu C[i][j] = 1 + C[i-1][j-1].
D[i][j] = 2 (Trên) nếu C[i][j] = C[i-1][j]
D[i][j] = 3 (Trái) nếu C[i][j] = C[i][j-1]
19. Trình bày bài toán nhân ma trận.

Để giảm số phép nhân cần dùng chúng ta sẽ tránh tạo ra các ma trận trung gian có kích thước lớn và
do phép nhân ma trận có tính kết hợp nên có thể đạt được điều này bằng cách sử dụng các dấu đóng
mở ngoặc để chỉ ra thứ tự phép nhân giữa các ma trận. Bên cạnh đó phép nhân ma trận không đối
xứng nên không thể hoán vị thứ tự của chúng mà không làm thay đổi kết quả.
Tác giả: Đỗ Đức Hùng. Website: Mail:
int longest_common_sequence(X,Y)
{
for(i=0;i<=m;i++) C[i][0]=0;
for(j=0;j<n;j++) C[0][j]=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
if(X[i]==Y[j]) C[i][j]+=1;
else C[i][j]=max(C[i-1][j],C[i][j-1]);
return C[m][n];
}
char* findSolution()
{
row=m, col=n, lcs="";
while((row>0)&&(col>0)
{
if(D[row][col]==1)
{
lcs=lcs+X[row];
row=row-1;
col=col-1;
}
else
{
if(D[row][col]==2) row=row-1;
else if(D[row][col]==3) col=col-1;

}
}
reverse lcs; //Dao nguoc xau lcs;
return lcs;
}
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán14
Nếu có n ma trận thì sẽ có n+1 số nguyên là kích thước của chúng và sẽ có tổ hợp chập 2 của n phần
tử các xâu con (mỗi xâu tương ứng với mỗi thứ tự của các dấu ngoặc) giữa 1 và n nên chỉ cần dùng
O(n
2
) không gian nhớ để lưu kết quả các bài toán con.
20. Trình bày chiến lược tham lam.Ưu, nhược điểm? Ví dụ.
Chiến lược tham lam cũng giống như các thuật toán quy hoạch động thường được sử dụng để giải
các bài toán tối ưu (tìm nghiệm của bài toán tốt nhất theo 1 tiêu chí nào đó). Các thuật toán quy
hoạch động luôn cho 1 nghiệm tối ưu. Các thuật toán tham lam thực hiện các lựa chọn tối ưu cục bộ
với hy vọng các lựa chọn đó sẽ dẫn đến 1 nghiệm tối ưu toàn cục cho bài toán cần giải quyết.
Ưu điểm: dễ cài đặt (độ phức tạp thời gian thường là hàm tuyến tính hoặc cùng lắm là bậc 2). Dễ gỡ
lỗi và sử dụng ít bộ nhớ.
Nhược điểm: Không phải lúc nào chúng cũng cho các lời giải tối ưu.
Ví dụ: Dãy số (3, 4, 5, 17, 7, 8, 9) cần chọn ra dãy con của nó sao cho dãy con đó là một dãy đơn
điệu tăng. Dễ dàng thấy kết quả đúng là (3, 4, 5, 7, 8, 9). Tuy nhiên theo cách chọn tham ăn sau khi
chọn xong 3 phần tử đầu là 3, 4, 5 sẽ chọn tiếp phần tử 17, phần tử hợp thành 1 dãy tăng dài hơn đối
với các phần tử được chọn trước đó và kết quả là 3, 4, 5, 17. Nhưng kết quả này không phải là đúng.
21. Trình bày bài toán sắp lịch các sự kiện.
Một phòng học chỉ có thể sử dụng cho 1 lớp học tại 1 thời điểm. Có n lớp học muốn sử dụng phòng
học, mỗi lớp học có 1 lịch học được cho bởi 1 khoảng thời gian I
j
=[s
j
, f

j
]. Mục đích của bài toán là
tìm một lịch học sao cho số lượng lớp học có thể sử dụng phòng học là lớn nhất có thể được và
không có 2 lớp nào cùng sử dụng phòng học tại 1 thời điểm.
Gọi S
i, j
là tập các lớp học bắt đầu sau thời điểm f
i
và kết thúc trước thời điểm S
j
, có nghĩa là các lớp
này có thể được sắp xếp giữa các lớp C
i
và C
j
.
Chúng ta có thể thêm vào 2 lớp giả định C
0
và C
n+1
với f
0
= và S
n+1
=. Khi đó giá trị S
0, n+1
sẽ là tập
chứa tất cả các lớp.
Giả sử lớp C
k

là 1 phần của lịch học tối ưu của các lớp nằm trong S
i, j
khi đó i < k < j và lịch học tối
ưu bao gồm tập con lớn nhất của S
i, k
, {C
k
}, và 1 tập con lớn nhất của S
k, j
.
Thực hiện 1 lựa chọn tham lam:
Bổ đề 1: Tồn tại 1 lịch học (thời khóa biểu) tối ưu cho tập S
i, j
chứa lớp C
k
trong S
i, j
kết thúc đầu tiên,
có nghĩa là lớp C
k
trong S
i, j
với giá trị chỉ số k nhỏ nhất.
Bổ đề 2: Nếu chọn lớp C
k
như bổ đề 1 thì tập S
i, k
sẽ là tập rỗng.
Bài tập:
1. Cho cấu trúc sinh viên gồm các trường: tên, tuổi, địa chỉ, … Khai báo cấu trúc trên để có thể lưu

được danh sách sinh viên theo mảng. Cài đặt hàm sắp xếp mảng sinh viên tăng dần (hoặc giảm dần)
theo tuổi, cùng tuổi theo tên. Áp dụng giải thuật sắp xếp chọn (hoặc chèn, hoặc nổi bọt, hoặc đổi chỗ,
…)
#include <stdio.h>
#include <conio.h>
typedef struct{
char ten[40],diachi[50];
int tuoi;
}svien;
void nhap(svien a[],int n)
{
int i;
for(i=0;i<n;i++)
{
printf("\nNhap thong tin sinh vien thu %d: \n",i+1);
printf("Ho ten: ");
fflush(stdin);
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán15
gets(a[i].ten);
printf("Dia chi: ");
fflush(stdin);
gets(a[i].diachi);
printf("Tuoi: ");
scanf("%d",&a[i].tuoi);
}
}
void hoandoi(svien *a, svien *b)
{
svien tg;

tg=*a;
*a=*b;
*b=tg;
}
//sap xep theo chieu tang dan
void xep(svien sv[], int n)
{
int i,j;
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(sv[j].tuoi<sv[i].tuoi) hoandoi(&sv[j],&sv[i]);
else if(sv[j].tuoi==sv[i].tuoi && strcmp(sv[j].ten,sv[i].ten)<0)
hoandoi(&sv[j],&sv[i]);
}
void xuat(svien a[], int n)
{
int i;
printf("\nHo ten Dia chi Tuoi\n");
for(i=0;i<n;i++)
printf("%-20s%-20s%10d\n",a[i].ten,a[i].diachi,a[i].tuoi);
}
void main()
{
svien sv[100];
int n;
printf("So sinh vien: ");
scanf("%d",&n);
nhap(sv,n);
xep(sv,n);
xuat(sv,n);

getch();
}
2. Cho cấu trúc nhân viên gồm các trường: tên, năm sinh, hệ số lương, … Khai báo cấu trúc nhân viên
trên ở dạng danh sách liên kết. Cài đặt hàm sắp xếp danh sách nhân viên tăng dần (hoặc giảm dần)
theo năm sinh, cùng năm sinh theo tên. Áp dụng giải thuật sắp xếp chọn (hoặc chèn, hoặc nổi bọt,
hoặc đổi chỗ, …)
#include <stdio.h>
#include <conio.h>
typedef struct {
char ten[40];
int ns,hsl;
}nhanvien;
struct node{
nhanvien nvien;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán16
struct node *next;
};
typedef struct node *listnode;
//Cap phat bo nho
listnode getnode()
{
listnode p;
p=(listnode)malloc(sizeof(struct node));
p->next=NULL;
return p;
}
//Chen 1 phan tu vao dau ds
void them(nhanvien nv,listnode *list)
{

listnode p;
p=getnode();
p->nvien=nv;
if(*list==NULL) *list=p;
else
{
p->next=*list;
*list=p;
}
}
void nhap(listnode *list)
{
nhanvien a;
int n,i;
printf("So nhan vien: ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("\nNhap nhan vien thu %d:\n",i+1);
printf("Ten nhan vien: ");
fflush(stdin);
gets(a.ten);
printf("Nam sinh: ");
scanf("%d",&a.ns);
printf("He so luong: ");
scanf("%d",&a.hsl);
them(a,list);
}
}
void xep(listnode *list)

{
listnode p,q;
nhanvien tg;
p=*list;
while(p!=NULL)
{
q=p->next;
while(q!=NULL)
{
if(q->nvien.ns < p->nvien.ns || (q->nvien.ns==p->nvien.ns &&
strcmp(q->nvien.ten,p->nvien.ten)<0))
{
tg=q->nvien;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán17
q->nvien=p->nvien;
p->nvien=tg;
}
q=q->next;
}
p=p->next;
}
}
void xuat(listnode *list)
{
listnode p;
p=*list;
printf("\nTen Nam sinh HSL\n");
while(p!=NULL)
{

printf("%-20s%12d%12d\n",p->nvien.ten,p->nvien.ns,p->nvien.hsl);
p=p->next;
}
}
void main()
{
listnode nv=NULL;
nhap(&nv);
xep(&nv);
xuat(&nv);
getch();
}
3. Cho cấu trúc mặt hàng gồm: mã số, loại, tên, Khai báo cấu trúc mặt hàng ở trên (để lưu ở dạng
mảng, hoặc dạng danh sách liên kết đơn). Cài đặt hàm tìm kiếm mặt hàng nào đó theo mã (hoặc tên,
…). Nêu rõ giải thuật áp dụng.
Áp dụng thuật toán vét cạn:
#include <stdio.h>
#include <conio.h>
typedef struct {
int ms;
char loai[10],ten[20];
}hang;
void nhap(hang h[],int n)
{
int i;
for(i=0;i<n;i++)
{
printf("Nhap mat hang thu %d: \n",i+1);
printf("Ma mat hang: ");
scanf("%d",&h[i].ms);

printf("Loai hang: ");
fflush(stdin);
gets(h[i].loai);
printf("Ten hang: ");
fflush(stdin);
gets(h[i].ten);
}
}
void xuat(hang h[],int n)
{
int i;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán18
printf("\nMa hang Loai hang Ten hang\n");
for(i=0;i<n;i++)
printf("%-20d%-12s%-20s\n",h[i].ms,h[i].loai,h[i].ten);
}
int tim(hang h[],int n,int x)
{
int i=0;
while(h[i].ms!=x && i<n) i++;
if(i<n && (h[i].ms==x)) return i;
else return 0;
}
void main()
{
hang h[100];
int n,x;
printf("So mat hang: ");
scanf("%d",&n);

nhap(h,n);
xuat(h,n);
printf("Ma so can tim: ");
scanf("%d",&x);
if(tim(h,n,x)==0) printf("Khong tim thay key");
else printf("Vi tri: %d",tim(h,n,x)+1);
getch();
}
4. Cài đặt và đánh giá độ phức tạp thuật toán in ra hoán vị của n số nguyên từ 1 đến n. Các hoán vị
được in ra phải thỏa mãn một tiêu chuẩn nào đó, ví dụ: tổng 2 phần tử liên tiếp của hoán vị là số
nguyên tố, hoặc tổng 2 phần tử liên tiếp của hoán vị là số hoàn hảo, …
#include <stdio.h>
#include <conio.h>
int sngto(int a[], int n)
{
int i,tong;
for(i=0;i<n-1;i++)
{
tong=a[i]+a[i+1];
if(tong!=2 && tong!=3 && tong!=5 && tong!=7)
if((tong==1||tong%2==0||tong%3==0||tong%5==0||tong%7==0)) return 0;
}
return 1;
}
void hoandoi(int *a,int *b)
{
int tg;
tg=*a;
*a=*b;
*b=tg;

}
void autonhap(int a[],int n)
{
int i;
for(i=0;i<n;i++) a[i]=i;
}
void xuat(int a[],int n)
{
int i;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán19
if(sngto(a,n))
{
for(i=0;i<n;i++) printf("%3d",a[i]);
printf("\n");
}
}
void sinhhoanvi(int a[],int n)
{
int i,k,dau,cuoi;
do
{
xuat(a,n);
i=n-2;
while(i>=0&&a[i]>a[i+1]) i ; //Tim phan tu i dau tien < day con
giam
if(i>=0)
{
k=n-1;
while(a[k]<a[i]) k ; //Tim phan tu k dau tien de a[k]>a[i]

hoandoi(&a[k],&a[i]);
dau=i+1;
cuoi=n-1; //Lat nguoc doan cuoi giam dan, a:
while(dau<cuoi)
{
hoandoi(&a[dau],&a[cuoi]);
dau++;
cuoi ;
}
}
}while(i>=0);
}
void main()
{
int a[100],n;
printf("So phan tu can hoan vi: ");
scanf("%d",&n);
autonhap(a,n);
sinhhoanvi(a,n);
getch();
}
5. Cài đặt và đánh giá độ phức tạp thuật toán in ra tất cả các xâu nhị phân có độ dài k. Xâu được in ra
phải thỏa mãn một điều kiện nào đó, ví dụ: biểu diễn thập phân của xâu đó là số hoàn hảo, hoặc số
nguyên tố, hoặc xâu đó không có 3 phần tử liên tiếp giống nhau, hoặc xâu đó phải có 2 ký tự liền kề
không giống nhau, …
#include <stdio.h>
#include <conio.h>
/*int ktra(int a[],int n)
{
int i;

for(i=0;i<n;i++) if(a[i]==a[i+1]) return 0;
return 1;
}*/
void xuat(int a[],int n)
{
int i;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán20
// if(ktra(a,n)) //Neu muon xuat ra cac xau nhi phan 2 phan tu ke nhau
khac nhau
{
for(i=0;i<n;i++) printf("%3d",a[i]);
printf("\n");
}
}
void xuly(int i,int a[],int n)
{
int j;
for(j=0;j<=1;j++)
{
a[i]=j;
if(i==n-1) xuat(a,n);
else xuly(i+1,a,n);
}
}
void main()
{
int k,a[100];
printf("Do dai xau nhi phan: ");
scanf("%d",&k);

xuly(0,a,k);
getch();
}
6. Cài đặt và đánh giá độ phức tạp thuật toán in ra số nguyên có k chữ số. Số được in ra phải thỏa mãn
một điều kiện nào đó, ví dụ: số đó có tổng các chữ số là số nguyên tố, hoặc số hoàn hảo, hoặc các
chữ số phải khác nhau, …
#include <stdio.h>
#include <conio.h>
void xuat(int a[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d",a[i]);
printf("\t");
}
void test(int i, int a[],int n)
{
int j;
for(j=0;j<=9;j++)
if(i==0 && j!=0 || i!=0)
{
a[i]=j;
if(i==n-1) xuat(a,n);
else
test(i+1,a,n);
}
}
void main()
{
int a[100],n;

printf("So chu so: ");
scanf("%d",&n);
test(0,a,n);
getch();
}
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán21
7. Trình bày thuật toán nhân dãy ma trận A. Tìm số phép nhân ít nhất để nhân các ma trận có kích thước
nào đó, ví dụ: 6x5, 5x7, 7x8, 8x3, 3x5
Với ma trận A có kích thước p x q và B có kích thước q x r. Người ta có phép nhân 2 ma trận đó để
được ma trận C có kích thước p x r. Mỗi phần tử của ma trận C được tính theo công thức:
1
q
ij ik kj
k
C A B
=
=

( )
, :1 ;i j i p q j r∀ ≤ ≤ ≤ ≤
Số bước thực hiện nhân 2 ma trận trên là p.q.r
Công thức truy hồi:
Gọi F[i,j] là số phép nhân tối thiểu cần thực hiện để nhân đoạn ma trận liên tiếp M
i
*M
i+1
* *M
j
Thì

khi đó F[i,i]=0 với mọi i.
Để tính M
i
*M
i+1
* *M
j
ta có thể có nhiều cách kết hợp:
M
i
*M
i+1
* *M
j
=(M
i
*M
i+1
* *M
k
) * (M
k+1
* M
k+2
* * M
j
) (Với
i k j
≤ <
)

Với 1 cách kết hợp (phụ thuộc vào cách chọn vị trí k), chi phí tối thiểu phải thực hiện bằng:
• Chi phí thực hiện phép nhân M
i
* M
i+1
* * M
k
= F[i,k]
• Cộng với chi phí thực hiện phép nhân M
k+1
* M
k+2
* * M
j
= F[k+1, j]
• Cộng với chi phí thực hiện phép nhân 2 ma trận cuối cùng: ma trận tạo thành từ phép nhân (M
i
*
M
i+1
* * M
k
) có kích thước a
i
x a
k+1
và ma trận tạo thành từ phép nhân (M
k+1
* M
k+2

* * M
j
) có
kích thước a
k+1
x a
j+1
. Vậy chi phí này là a
i
*a
k+1
*a
j+1
Từ đó suy ra: do có nhiều cách kết hợp, mà ta cần chọn cách kết hợp để có chi phí ít nhất nên ta sẽ
cực tiểu hóa F[i,j] theo công thức:
[ ] [ ] [ ]
1 1
, min( , 1, * * )
i k j
F i j F i k F k j a a a
+ +
= + + +
Tại mỗi bước tính F[i,j] ta ghi nhận lại điểm k, chẳng hạn ta đặt T[i,j]=k
Sau là code chương trình:
#include <conio.h>
#include <stdio.h>
void nhap(int a[],int n)
{
int i;
for(i=0;i<n+1;i++)

{
printf("Nhap phan tu thu %d: ",i+1);
scanf("%d",&a[i]);
}
}
void xuat(int a[][100],int n)
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán22
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%6d",a[i][j]);
printf("\n");
}
}
void xuly(int a[],int n,int f[][100],int t[][100])
{
int i,j,k,len,x,p,q,r;
for(i=0;i<n;i++)
for(j=i;j<n;j++)
if(i==j) f[i][j]=0;
else f[i][j]=1000000;
for(len=1;len<=n;len++)
for(i=0;i<n-len+1;i++)
{
j=i+len-1;
for(k=i;k<j;k++)
{

p=a[i];
q=a[k+1];
r=a[j+1];
x=f[i][k]+f[k+1][j]+p*q*r;
if(x<f[i][j])
{
f[i][j]=x;
t[i][j]=k;
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán23
}
}
}
}
void trace(int i,int j,int t[][100])
{
int k;
if(i==j) printf("M[%d]",i+1);
else
{
printf("(");
k=t[i][j];
trace(i,k,t);
printf(" * ");
trace(k+1,j,t);
printf(")");
}
}
void main()
{

int a[100],f[100][100],t[100][100],n;
printf("So ma tran: ");
scanf("%d",&n);
nhap(a,n);
xuly(a,n,f,t);
printf("Ma tran F:\n");
xuat(f,n);
printf("\n\n");
printf("Ma tran T: \n");
xuat(t,n);
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán24
printf("\n");
printf("So phep nhan can thuc hien it nhat: %d\n",f[0][n-1]);
printf("Cac buoc thuc hien: ");
trace(0,n-1,t);
getch();
}
Với ma trận như đề bài, ta được kết quả:
8. Trình bày thuật toán tìm xâu con chung dài nhất của hai xâu. Áp dụng tìm xâu con chung dài nhất
của hai xâu con sau: “CDADDADC”, “ACDDCCA”.
#include <stdio.h>
#include <conio.h>
#include <string.h>
int max(int a,int b)
{
if(a>b) return a;
else return b;
}
void xuatmang(int c[][100],char a[], char b[])

{
int i,j;
a[0]=' ';
b[0]=' ';
printf(" ");
for(i=0;i<strlen(a);i++) printf("%3c",a[i]);
printf("\n");
for(i=0;i<strlen(b);i++)
{
printf("%c",b[i]);
for(j=0;j<strlen(a);j++)
printf("%3d",c[i][j]);
printf("\n");
}
Tác giả: Đỗ Đức Hùng. Website: Mail:
Đề cương ôn tập môn Phân tích, thiết kế và đánh giá thuật toán25

×