You are on page 1of 23

Bài Tập Độ Phức Tạp Thuật Toán

Haidt3@fpt.com.vn
Bài 1: Viết một thuật toán (thủ tục) để tính giá trị của f n trong hệ thức hồi fn = fn-1 + fn-2, n ≥ 2, f0 =
1, f1 = 1 . Đánh giá độ phức tạp về thời gian của thuật toán vừa viết. Có thuật toán khác hiệu quả
hơn không?.
Giải:
TONG_TRUYHOI(F, n)
1. for i ← 0 to n
2. do if i < 2
3. then F[0] ← 1
4. F[1] ← 1
5. else F[n] ← F[n-1] + F[n-2]
6. return F

Gọi α, β và γ lần lượt là thời gian thực hiện của phép gán, phép so sánh và phép trả về của thuật
toán. Khi đó, có n+1 phép so sánh ở dòng 2, do đó tương ứng có n+1 phép gán ở các dòng lệnh 3, 4,
5; cuối cùng là một phép trả về ở dòng 6. Suy ra, thời gian để thực thi của thuật giải này là: T(n) =
(n+1)α + (n+1)β + γ = O(n)

Bài 2: Viết thuật toán tính tích của hai ma trận vuông cấp n và đánh giá độ phức tạp về thời gian
của thuật toán này.
Giải:
Tích của hai ma trận vuông A và B cấp n với
A có chiều là n × n (“ma trận n hàng n cột”)
B có chiều là n × n
là một ma trận C có chiều là n × n

MATRIX-MULTIPLY(A, B, n)
1. for i ← 1 to n
2. do for j ← 1 to n
3. do C[i, j] ← 0
4. for k ← 1 to n
5. do C[i, j] ← C[i, j] + A[i, k]⋅ B[k, j]
6. return C

Gọi α và γ theo thứ tự là thời gian thực hiện của phép gán và phép trả về của thuật toán. Ta có: n2
phép gán ở dòng 3; n3 phép gán ở dòng lệnh 5 và một lệnh trả về ở dòng lệnh 6. Do đó tổng thời
gian thực thi của thuật giải là: T(n) = n2α + n3α + γ = O(n3)

Bài 3: Viết thuật toán tính tích của hai ma trận và đánh giá độ phức tạp về thời gian chạy của của
thuật toán này.
Giải:
Tích của hai ma trận A và B với
A có chiều là p × q (“ma trận p hàng q cột”)
B có chiều là q × r
là một ma trận C có chiều là p × r

MATRIX-MULTIPLY(A, B)
1. if columns[A] ≠ rows[B]
2. then error “các chiều không tương thích”
3. else for i ← 1 to rows[A]
4. do for j ← 1 to columns[B]
5. do C[i, j] ← 0
6. for k ← 1 to columns[A]
7. do C[i, j] ← C[i, j] + A[i, k]⋅ B[k, j]
8. return C

Ta có thể giải như bài 2 và cụ thể là thời gian để tính C tỉ lệ với số phép nhân vô hướng thực
thi trong dòng 7, tức là: p⋅ q⋅ r

Bài 4: Viết và đánh giá độ phức tạp của thuật toán tìm kiếm nhị phân trên một dãy số thực đã được
sắp xếp.
Giải:
BINARY_SEARCH(A, n, x)
1. left ← 1
2. right ← n
3. while left ≤ right
4. do mid ← (left + right)/2
5. if x = A[mid]
6. then return mid
7. else if x < A[mid]
8. then right ← mid – 1
9. else left ← mid + 1
10. return NIL

Thuật giải có độ phức tạp là O(lgn) và cũng là trường hợp xấu nhất khi không có phần tử x trong
dãy. Trường hợp tốt nhất O(1) khi tìm được x ngay giữa dãy, còn trường hợp trung bình O(lgn/2)
khi tồn tại phần tử x trong dãy.

Bài 5: Viết thuật toán tính n! và đánh giá độ phức tạp về thời gian của nó.
Giải:
FACTORIAL(n)
1. if n = 0 or n = 1
2. then return 1
3. else if n > 1
4. then return n*FACTORIAL(n-1)

Gọi T(n) là thời gian chạy của thuật giải. Ta có:


 O(1) n = 0,1
T ( n) = 
 T (n − 1) + O(1) n > 1
Đặt c = O(1). Ta có:
T(n) = T(n-1) + c
= (T(n-2) + c) + c = T(n-2) + 2c
= (T(n-3) + c) + 2c = T(n-3) + 3c
……………………………………
= T(n-(n-1)) + (n-1)c = T(1) + (n-1)c = c + (n-1)c = nc
Suy ra thời gian chạy của thuật giải là: O(n)

Bài 6: Viết và đánh giá độ phức tạp về thời gian của thuật toán Tháp Hà Nội.
Giải:
Giả sử muốn chuyển n cái đĩa từ cọc A sang cọc B lấy cọc C làm trung gian.

HANOI_TOWER(A, B, C, n)
1. if n = 1
2. then MOVE(A, B, 1)
3. else HANOI_TOWER(A, C, B, n-1)
4. MOVE(A, B, 1)
5. HANOI_TOWER(C, B, A, n-1)

Gọi T(n) là thời gian chạy của thuật giải. Ta có:

 O(1) n = 1
T ( n) = 
 2T (n − 1) + O(1) n > 1
Giả sử cho: O(1) = 1 (Việc giả sử này không làm thay đổi tính tổng đúng đắn)
Ta có: T(n) = 2T(n-1) + 1 = 2(2T(n-2) + 1) + 1 = 22T(n-2) + 2 + 1
= 22(2T(n-3) + 1) = 23T(n-3) + 22 + 2 + 1
………………………..
= 2n-1T(n-(n-1)) + 2n-2 +2n-3 + … + 23 + 22 + 2 + 1
= 2n-1 + 2n-2 +2n-3 + … + 23 + 22 + 2 + 1 = 2n – 1
Vậy độ phức tạp của thuật giải là: O(2n)

Bài Tập Heapsort


Bài 1 Số phần tử nhiều, ít nhất trong một heap chiều cao h là bao nhiêu?
Hướng dẫn: Heap chiều cao h có số node lớn nhất M khi các con ở mức h-1 đều có 2 con là lá
M=2h+1-1. Số node ít nhất m = [2(h-1)+1-1]+1 =2h
Giải:
Với h = 2 ta có hai hình sau biểu diễn cho số node nhiều nhất và số node ít nhất của cây.

h=2
Khi đó: Số node nhiều nhất của cây khi h = 2 chính là tổng số node được lấp đầy ở tất cả cách mức
từ 0 đến 2 là: 7 = 1 + 2 + 4 = 20 + 21 + 22
Tổng quát: Ta có số node nhiều nhất của một heap chiều cao h là:
Mh = 20 + 21 + 22 + … + 2h = 2h+1 – 1
Tương tự, ta thấy số node ít nhất của heap chiều cao h chính là số node nhiều nhất của heap chiều
cao h-1 rồi thêm 1. Do đó:
mh = Mh-1 + 1 = [2(h-1)+1 – 1] + 1 = 2h

Bài 2 Chứng minh 1 heap n phần tử thì có chiều cao là  lgn


Hướng dẫn: Theo bài 1: 2h ≤ n ≤ 2h+1-1 suy ra lg(n+1) -1≤ h ≤ lgn, vì lgn < lg(n+1)
Nên lg(n) -1≤ h ≤ lgn. Nghĩa là h =  lgn
Giải:
Gọi m, M theo thứ tự là số node ít nhất và số node nhiều nhất của heap có chiều cao h.
Khi đó: m ≤ n ≤ M ⇔ 2h ≤ n ≤ 2h+1-1

 2 ≤ n  h ≤ l n g  h ≤ l n g
h

⇔  h+ 1 ⇔  ⇔ 
 n+ 1≤ 2  l n+g1) ≤ h + (1  l n+g1) 1≤− (h
 h≤ l n g
⇔  ⇔ l n g1<− h ≤ l n ⇔g h =  l n g
 l n g1<− h
Bài 3 Dãy sau đây có là một max-heap hay không 〈23, 17, 14, 6, 13, 10, 1, 5, 7, 12〉
Giải:
Biểu diễn heap trên cây nhị phân ta thấy, vi phạm tính chất max-heap tại node thứ tư vì A[4] < A[9]
Do vậy dãy số cho trên không phải là một max-heap

Bài 4 Sử dụng hình trên như một mô hình, biểu diễn thao tác MAX-HEAPIFY(A, 4) trên mảng A =
〈23, 17, 14, 6, 13, 10, 1, 5, 7, 12〉
Giải:
Gọi hàm MAX_HEAPIFY(A, 4) ⇒ exchange A[4] ↔ A[9]

Bài 5 Dựa trên thủ tục MAX-HEAPIFY(A, i) hãy viết mã giả cho thủ tục MIN-HEAPIFY(A, i) thực
hiện thao tác duy trì tính chất heap trên một min-heap.
Giải:
MIN_HEAPIFY(A, i)
1. l ← left(i)
2. r ← right(i)
3. if l ≤ HEAP_SIZE[A] and A[l] < A[i]
4. then smallest ← l
5. else smallest ← i
6. if r ≤ HEAP_SIZE[A] and A[r] < smallest
7. then smallest ← r
8. if smallest ≠ i
9. then exchange A[i] ↔ A[smallest]
10. MIN_HEAPIFY(A, smallest)

Bài 6 Sử dụng hình 6.3 như một mô hình, biểu diễn thao tác BUILD-MAX-HEAP(A) trên mảng A
= 〈5, 3, 17, 10, 84, 19, 6, 22, 9〉
Giải:
Bài 7 Sử dụng mô hình biểu diễn thao tác HEAPSORT(A) trên mảng A = 〈5, 13, 2, 25, 7, 17, 20, 8,
4〉
Giải:
HEAPSORT(A)
1. BUILD_MAX_HEAP(A)
2. for i ← length[A] downto 2
3. do exchange A[1] ↔ A[i]
4. HEAP_SIZE[A] ← HEAP_SIZE[A] – 1
5. MAX_HEAPIFY(A, 1)
Bài 8 Phân tích thời gian chạy của MAX-HEAPIFY(A, i) trên cây con kích thước n định gốc tại
node i
Giải:
Từ giải thuật MAX_HEAPIFY(A, i) ta có số bước thực hiện lời gọi đệ quy nhỏ hơn hoặc bằng
chiều cao h của cây. Mà mỗi lần thực hiện MAX_HEAPIFY có chi phí là: O(1).
Suy ra: T(n) = h.O(1) = O(1). lgn = O( lgn )

Bài 9 Sử dụng max-heap biểu diễn dãy các số thực 〈a1, a2, …, an 〉 để viết một thuật toán
tìm max {a1, a2, …, an}
Giải:
MAX_ELEMENT(A)
1. BUILD_MAX_HEAP(A)
2. return A[1]

Thời gian chạy của MAX_ELEMENT là: T(n) = O(n) + O(1) = O(n)

Bài 10 Đánh giá thời gian thực hiện các thao tác trên hàng được ưu tiên dựa trên mô hình dữ liệu
max-heap.
Giải:
Thủ tục HEAP-MAXIMUM thực thi trả về giá trị MAXIMUM với chi phí Θ(1).

HEAP-MAXIMUM(A)
1. return A[1]

Thủ tục HEAP-EXTRACT-MAX thi hành thao tác EXTRACT-MAX. Nó giống với phần
thân của vòng lặp for từ dòng 3 đến dòng 5 trong giải thuật HEAPSORT.

HEAP-EXTRACT-MAX(A)
1. if heap-size[A] < 1
2. then error "heap underflow"
3. max ← A[1]
4. A[1] ← A[heap-size[A]]
5. heap-size[A] ← heap-size[A] - 1
6. MAX-HEAPIFY(A, 1)
7. return max

Thời gian chạy của HEAP-EXTRACT-MAX là O(lg n), vì nó thực thi chỉ một số lượng thao
tác không đổi ở phần trên của O(lg n) thời gian chạy cho MAX-HEAPIFY.
HEAP-INCREASE-KEY(A, i, key)
1. if key < A[i]
2. then error "new key is smaller than current key"
3. A[i] ← key
4. while i > 1 and A[PARENT(i)] < A[i]
5. do exchange A[i] ↔ A[PARENT(i)]
6. i ← PARENT(i)

Thời gian chạy của HEAP-INCREASE-KEY trên một heap n phần tử là O(lg n).

MAX-HEAP-INSERT(A, key)
1. heap-size[A] ← heap-size[A] + 1
2. A[heap-size[A]] ← -∞
3. HEAP-INCREASE-KEY(A, heap-size[A], key)

Thời gian chạy của MAX-HEAP-INSERT trên một heap n phần tử là O(lg n).
Tóm lại, một heap có thể hỗ trợ bất cứ thao tác nào của hàng đợi ưu tiên trên một tập kích
thước n trong O(lg n) thời gian.

Bài 11 Giả sử heap được bởi một mảng 〈a1, a2, …, an 〉 . Chứng tỏ các phần tử có chỉ số  n/2 +1,
 n/2 +2,…, n là các lá của heap này.
Giải:
Xét node có chỉ số: i =  n/2 +1
Giả sử: node i có con trái là l
Khi đó: l = 2i = 2( n/2 +1)
Mà: n/2-1 <  n/2 ≤ n/2
Suy ra: l > 2((n/2 – 1) + 1)
Hay: l > n; điều đó chứng tỏ l vượt quá HEAP_SIZE.
Do vậy, node i không có con trái, suy ra node i cũng không có con phải.
Suy ra: node có chỉ số  n/2 +1 là một node lá.
Chứng minh tương tự ta có các node  n/2 +2,  n/2 +3,…, n cũng là các lá của heap kích
thước n.

Bài Tập Quicksort


Bài 1 Sử dụng mô hình, biểu diễn thao tác PARTITION trên mảng A = 〈13, 19, 9, 5, 12, 8, 7, 4, 11,
2, 6〉
Giải:
PARTITION(A, p, r)
1. x ← A[r]
2. i ← p - 1
3. for j ← p to r - 1
4. do if A[j] ≤ x
5. then i ← i + 1
6. exchange A[i] ↔ A[j]
7. exchange A[i + 1] ↔ A[r]
8. return i + 1
Bài 2 Sử dụng mô hình, biểu diễn thao tác PARTITION trên mảng A = 〈13, 19, 9, 5, 12, 8, 7, 4, 11,
2, 6, 21〉
Giải:

Thực hiện tương tự cho 10 bước tiếp theo và nhận xét đây là trường hợp đặc biệt, với mọi j ≤ r ta
có: A[j] ≤ x (x = A[r]), do vậy sau khi thực thi xong giải thuật PARTITION thì thứ tự các phần tử
không có sự thay đổi. Kết quả PARTITON chia ra 2 mảng con gồm n-1 phần tử nhỏ hơn hoặc bằng
x và 0 phần tử lớn hơn x. Kết quả trả về của PARTITION là: r

Bài 3 Biểu diễn quá trình thực hiện giải thuật QUICKSORT trên A = 〈13, 19, 9, 5, 12, 8, 7, 4, 11,
2, 6, 21〉
Giải:
QUICKSORT(A, p, r)
1. if p < r
2. then q ← PARTITION(A, p, r)
3. QUICKSORT(A, p, q - 1)
4. QUICKSORT(A, q + 1, r)

Dựa vào kết quả Bài 2 ta thấy dòng 2 kết quả phép gán q = r . Vậy có nghĩa là ta chỉ thực hiện tiếp
lời gọi đệ quy QUICKSORT(A, p, q - 1) ở dòng 3 thôi, còn lời gọi đệ quy QUICKSORT(A,
q + 1, r) ở dòng 4 không thực thi tiếp vì không thoả điều kiện ở dòng 1.
Vậy ta thực hiện QUICKSORT(A, p, q - 1) như sau:

Lúc này bài toán thực hiện PARTITION trên đoạn (p, q-1). Kết hợp kết quả Bài 1 và tiếp tục thực
hiện QUICKSORT trên các mảng con mới. Kết quả cuối cùng ta được dãy sắp xếp tăng dần.

Bài 4 PARTITION trả về giá trị q gì khi tất cả các phần tử của mảng A[p..r] có cùng giá trị, sửa
PARTITION sao cho q = (p+r)/2 khi tất cả các phần tử của A[p..r] có cùng giá trị
Hướng dẫn: kết thúc vòng lặp for cần thêm lệnh (đúng cho cả trường hợp các phần tử có giá trị tăng
dần):
if i= j+1 (i=r)
then return q=(p+r)/2
else exchange (A[i+1], A[r])
return i+1
Giải:
Khi tất cả các phần tử của mảng A[p..r] có cùng giá trị thì PARTITION trả về giá trị q = r . Vì với
mọi j ≤ r ta có: A[j] ≤ x (x = A[r]).
Để giá trị trả về q = (p+r)/2 của PARTITION trong trường hợp này, ta phải sửa lại giải thuật
PARTITION như sau:

PARTITION(A, p, r)
1. x ← A[r]
2. i ← p - 1
3. for j ← p to r - 1
4. do if A[j] ≤ x
5. then i ← i + 1
6. exchange A[i] ↔ A[j]
7. if i = j + 1 or i = r
8. then return (p+r)/2
9. else exchange A[i + 1] ↔ A[r]
10. return i + 1

Vậy lúc này thời gian chạy QUICKSORT trên mảng các phần tử cùng giá trị là tốt nhất.

Bài 5 Chứng tỏ thời gian chạy của PARTITION là Θ (n)


Giải:
Gọi α, β và γ lần lượt là thời gian thực hiện của phép gán, phép so sánh và phép trả về của thuật
toán PARTITION trên mảng có n phần tử.
Ta có: thời gian chạy tốt nhất khi các phần tử trong mảng A[p..(r-1)] đều không lớn hơn A[r] là:
2α + (n-1)β + α + γ
Còn thời gian chạy xấu nhất khi tất cả các phần tử trong mảng A[p..(r-1)] đều lớn hơn A[r] là:
2α + (n-1)β + 2(n-1)α + α + γ
Gọi T(n) là tổng thời gian chạy của PARTITION trên mảng có n phần tử.
Suy ra: 2α + (n-1)β + α + γ ≤ T(n) ≤ 2α + (n-1)β + 2(n-1)α + α + γ
Hay: C1.n ≤ T(n) ≤ C2.n (Với C1; C2 là các hằng số)
Vậy: T(n) = Θ (n)

Bài 6 Sửa quicksort để sắp xếp mảng A[p..r] theo trật tự không tăng.
Giải:
PARTITION(A, p, r)
1. x ← A[r]
2. i ← p - 1
3. for j ← p to r - 1
4. do if A[j] ≥ x
5. then i ← i + 1
6. exchange A[i] ↔ A[j]
7. exchange A[i + 1] ↔ A[r]
8. return i + 1

Bài 7 Đánh giá thời gian thực hiện quicksort trong trường hợp tất cả các phần tử của mảng có cùng
giá trị.
Giải:
Đặt n = r – p + 1
Do A[i] = A[j] = A[r] với mọi i, j ∈ [p, r-1], nên PARTITION(A, p, r) trả về giá trị r và chia ra 2
mảng con với mảng con thứ nhất có n-1 phần tử nhỏ hơn hoặc bằng A[r], còn mảng con thứ hai có 0
phần tử lớn hơn A[r].
Suy ra thời gian chạy của QUICKSORT(A, p, r) là:
1 n = 0,1
T ( n) = 
 Θ (n) + T (n − 1) + T (0)
1 n = 0,1
=
 n + T (n − 1) + 1
= T (n − 1) + n + 1
= T (n − 2) + (n − 1) + 1 + n + 1 = T (n − 2) + n + (n + 1)
= T (n − 3) + (n − 2) + 1 + n + (n + 1) = T (n − 3) + (n − 1) + n + (n + 1)
..........
..........
..........
..........
.......
= T (1) + 3 + 4 + 5 + ......+ (n − 1) + n + (n + 1)
= 1 + 3 + 4 + 5 + ......+ (n − 1) + n + (n + 1)
= [1 + 3 + 4 + 5 + ......+ (n − 1) + n + (n + 1) ]− 2
(n + 1) (n + 2)
= −2
2
Suy ra thời gian chạy QUICKSORT trong trường hợp này là: O(n2)

Bài 8 Đánh giá thời gian thực hiện quicksort trong trường hợp tất cả các phần tử của mảng có có giá
trị theo trật tự tăng dần.
Giải:
Trường hợp này cũng là trường hợp xấu nhất vì các phần tử trong mảng A[p, r-1] luôn nhỏ hơn A[r]
nên PARTITION chia thành 2 mảng trong đó mảng con trái có n-1 phần tử nhỏ hơn A[r] và mảng
con phải có 0 phần tử lớn hơn A[r].
Do đó: thời gian chạy QUICKSORT trong trường hợp này là: O(n2)

Bài 9 Đánh giá thời gian thực hiện quicksort trong trường hợp tất cả các phần tử của mảng có có giá
trị theo trật tự giảm dần.
Giải:
Đây cũng là trường hợp xấu nhất vì các phần tử trong mảng A[p, r-1] luôn lớn hơn A[r] nên
PARTITION chia thành 2 mảng trong đó một mảng con phải có n-1 phần tử lớn hơn A[r] và mảng
con trái có 0 phần tử nhỏ hơn A[r]
Do đó: thời gian chạy QUICKSORT trong trường hợp này là: O(n2)

Bài 10 Chứng minh rằng thời gian chạy của quicksort trong trường hợp xấu nhất là Ω (nlgn)
Giải:
Trường hợp phân hoạch tốt nhất (best-case partitioning)
1 •Trường hợp này xảy ra khi kết quả phân hoạch là hai bài toán con kích thước không lớn
hơn n/2
2 •Chi phí cho thủ tục PARTITION là Θ(n)
3 •Hệ thức truy hồi cho thời gian chạy của Quicksort là
0 �T’( n) ≤ 2T’(n/2) + Θ(n) = O(nlgn)
1 �Quicksort chạy nhanh nhất trong trường hợp này
Suy ra: thời gian chạy chậm nhất của QUICKSORT là:
2 T(n) ≥ 2T(n/2) + Θ(n) = O(nlgn)
Vậy: T(n) = Ω (nlgn)

Bài Tập Chương 4


Bài 1. Hãy vẽ đồ thị được biểu diễn bởi ma trận trọng số sau:
1 2 3
C =
3 0 4


2 4 0

Giải:

Bài 2. Cho đồ thị vô hướng, viết chương trình xác định bậc của mỗi đỉnh.
Giải:
Xét ma trận kề A biểu diễn đồ thị vô hướng có n đỉnh. Chú ý ma trận này có tính chất đối
xứng qua đường chéo chính.

Ta có: Bậc của đỉnh u nào đó chính là tổng các số của dòng thứ u. Do vậy ta lập thuật toán
để tính bậc của đỉnh như sau:
VERTEX_DEGREE(G, u)
1. S ← 0
2. for k ← 1 to G.n
3. do S ← S + G.A[u][k]
4. return S

Bài 3. Cho đồ thị có hướng, viết chương trình xác định bán bậc ra (vào) của mỗi đỉnh.
Giải:
Xét ma trận kề A biểu diễn đồ thị có hướng có n đỉnh.
Ta có: Bán bậc ra của đỉnh u nào đó trong đồ thị có hướng chính là tổng các số của dòng thứ
u. Do vậy ta lập thuật toán để tính bán bậc ra của đỉnh như sau:
OUTER_DEGREE(G, u)
5. S ← 0
6. for k ← 1 to G.n
7. do S ← S + G.A[u][k]
8. return S

Còn bán bậc vào của đỉnh u nào đó trong đồ thị có hướng chính là tổng các số của cột thứ u.
Do vậy ta lập thuật toán để tính bán bậc vào của đỉnh như sau:
INNER_DEGREE(G, u)
9. S ← 0
10. for k ← 1 to G.n
11. do S ← S + G.A[k][u]
12. return S

Bài 4. Sử dụng đỉnh 3 như là đỉnh nguồn, chỉ ra các giá trị của d và π khi thực thi thuật
toán tìm kiếm theo chiều rộng trên đồ thị sau.

Giải:
BFS(G, s)
1. for each vertex u ∈ V[G] – {s}
2. do color[u] ← WHITE
3. d[u] ← ∞
4. π [u] ← NIL
5. color[s] ← GRAY
6. d[s] ← 0
7. π [s] ← NIL
8. Q ← ∅
9. ENQUEUE(Q, s)
10. while Q ≠ ∅
11. do u ← DEQUEUE(Q)
12. for each v ∈ Adj[u]
13. do if color[v] = WHITE
14. then color[v] ← GRAY
15. d[v] ← d[u] + 1
16. π [v] ← u
17. ENQUEUE(Q, v)
18. color[u] ← BLACK

Bài 5. Biểu diễn quá trình thực thi của thuật toán tìm kiếm theo chiều sâu trên đồ thị sau:

giả sử vòng lặp for 5-7 của DFS coi các đỉnh trong trật tự alphabe và danh sách kề của mỗi đỉnh
cũng có thứ tự alphabe. Chỉ ra thời gian phát hiện và hoàn thành của mỗi đỉnh và sự phân loại của
mỗi cạnh.
Giải:
DFS(G)
1. for each vertex u ∈ V[G]
2. do color[u] ← WHITE
3. π [u] ← NIL
4. time ← 0
5. for each vertex u ∈ V[G]
6. do if color[u] = WHITE
7. then DFS_VISIT(u)
1. color[u] ← GRAY
2. time ← time + 1
3. d[u] ← time
4. for each each v ∈ Adj[u]
5. do if color[v] = WHITE
6. then π [v] ← u
7. DFS_VISIT(v)
8. color[u] ← BLACK
9. f[u] ← time ← time + 1

Theo đề bài ta bắt đầu duyệt từ node 1.


Bài Tập Chương 5

Bài 1. Cho đồ thị vô hướng liên thông G=(V,E). Gọi e=(u,v)∈E là cạnh có trọng số bé nhất
trong G. C/m có một cây bao trùm bé nhất chứa e.
Giải:
Xét đồ thị trên ta có e = 2 = (u, v) = (x, y)
Giả sử không tồn tại cây bao trùm bé nhất chứa cạnh e.
Xét T’ = T ∪ {(u, v)} – {(m, n)}
với (m, n) là cạnh thuộc chu trình đã tạo ra khi thêm (u, v) vào T.
Khi đó: W(T’) = W(T) + W(u, v) – W(m, n)
Mà: W(u, v) < W(m, n) vì (u, v) là cạnh có trọng số bé nhất.
Suy ra: W(T’) < W(T) (mâu thuẫn)
Vậy cây bao trùm bé nhất luôn chứa cạnh e

Bài 2. G là một rừng gồm k cây, n đỉnh. Tìm số cạnh của G?.
Giải:
Gọi Ti (i ∈[1, k]) là cây thứ cây thứ k trong rừng G.
Và n(Ti), e(Ti) là số đỉnh và số cạnh của Ti
Số cạnh của G là:
k k k
E = ∑e(Ti ) =∑[ n(Ti ) − 1] =∑ n(Ti ) − k = n − k
i =1 i =1 i =1
Ví dụ: với rừng có 3 cây, 11 đỉnh thì số cạnh là: 11 – 3 = 8.

Bài 3. Cho G là đồ thị vô hướng có số cạnh bằng số đỉnh. Chứng minh G có ít nhất một chu
trình.
Giải:
Giả sử G không có chu trình. Theo giả thiết đề bài G là đồ thị vô hướng có số cạnh bằng số
đỉnh ( E =n ) nên G là một rừng có k cây (k>1)
Theo kết quả chứng minh Bài 2 ta có: E =n −k (mâu thuẫn)
Vậy G có ít nhất một chu trình.

Bài 4. Cho đồ thị có trọng số G=(E,V) ( Hình vẽ). Hãy dùng thuật toán Kruskal để tìm cây
bao trùm bé nhất của G
Giải:
MST_KRUSKAL(G, w)
1. A ← ∅
2. for each vertex v ∈ V[G]
3. do MAKE_SET(v)
4. sort the edges of E into nondecreasing order by weigh w
5. for each edge (u, v) ∈ E, taken in nondecreasing order by weigh
6. do if FIND_SET(u) ≠ FIND_SET(v)
7. then A ← A ∪ (u, v)
8. UNION(u, v)
9. return A
Bài 5. Hãy dùng thuật toán Prim để tìm cây bao trùm bé nhất của đồ thị G trong bài tập 6.
Giải:
MST_PRIM(G, w, r)
1. for each vertex u ∈ V[G]
2. do key[u] ← ∞
3. π [u] ← NIL
4. key[u] ← 0
5. Q ← V[G]
6. while Q ≠ ∅
7. do u ← EXTRACT_MIN(Q)
8. for each v ∈ Adj[u]
9. do if v ∈ Q and w(u, v) < key[v]
10. then π [v] ← u
11. key[v] ← w(u, v)

Giả sử duyệt node gốc r tại s.

You might also like