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 (685.32 KB, 19 trang )
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
Hình 23.4: Thực hiện thuật toán Kruskal đối với đồ thị được mô tả ở hình 23.1. Những cạnh
được tô đậm thuộc rừng A đang được trồng. Thuật toán Kruskal quan tâm đến những cạnh được
sắp xếp theo thứ tự của trọng số. Một mũi tên chỉ đến một cạnh là một bước của thuật toán. Nếu
một cạnh nối hai cây phân biệt trong rừng thì cạnh đó được bổ sung vào rừng, sau đó hợp hai
cây đó thành một cây.
Thuật toán Kruskal
Thuật toán Kruskal dựa trên thuật toán cây khung nhỏ nhất tổng quát được đưa ra ở
phần 23.1. Thuật toán này tìm một cạnh an toàn để phát triển rừng bằng cách tìm trong
tất cả các cạnh (u,v) cạnh nào có trọng số nhỏ nhất nối hai cây bất kỳ trong rừng. Ví dụ
C1 và C2 là hai cây được nối với nhau bởi cạnh (u,v). Bởi vì cạnh (u,v) phải là cạnh nhỏ
nhất nối C1 với cây nào đó, thì theo hệ quả 23.2 thì (u,v) là một cạnh an toàn cho C1.
Thuật toán Kruskal là một thuật toán tham lam với vì ở mỗi bước của thuật toán bổ sung
vào rừng một cạnh có trọng số nhỏ nhất.
Cách thực hiện thuật toán Kruskal được xem như là thuật toán dùng để tính toán các
thành phần liên thông ở phần 21.1. Thuật toán này sử dụng cấu trúc dữ liệu rời nhau để
Trang 9
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
duy trì các tập phần tử rời nhau. Mỗi tập bao gồm các đỉnh của một cây của rừng hiện
thời. Hàm FIND-SET(u) trả về một phần tử đại diện từ tập chứa đỉnh u. Vì vậy, ta xác
định hai đỉnh bất kỳ u và v thuộc về cùng một cây hay không bằng cách kiểm tra hai hàm
FIND-SET(u) va FIND-SET(v) có bằng nhau hay không. Việc hợp cây được hoàn thành
bởi thủ tục UNION.
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 weight w
5. for each edge(u,v) ∈ E, taken in nondecreasing order by weight
6.
7.
do if FIND-SET(u) ≠ FIND-SET(v)
then A A ∪{(u,v)}
8.
UNION(u,v)
9. return A
Thuật toán Kruskal thực hiện như mô tả ở hình 23.4. Ban đầu từ dòng 1- 3 tập A là
tập rỗng và khởi tạo |V| cây và mỗi cây chứa một đỉnh. Các cạnh trong tập E được sắp
xếp theo thứ tự không giảm của trọng số ở dòng 4. Vòng lặp For từ dòng 5-8 làm nhiệm
vụ kiểm tra đối với mỗi cạnh (u,v) cho dù các đỉnh cuối u và v có thuộc cùng một cây
hay không. Nếu u và v thuộc cùng một cây thì cạnh (u,v) không thể bổ sung vào rừng , vì
cạnh (u,v) sẽ tạo thành chu trình do đó ta loại bỏ cạnh (u,v). Thay vào đó, hai đỉnh thuộc
về hai cây khác nhau trong trường hợp này cạnh (u,v) được bổ sung vào tập A ở dòng 7
và hai cây đó được hợp thành một cây ở dòng 8.
Thời gian thực hiện thuật toán Kruskal cho đồ thị G=(V,E) phụ thuộc vào việc thực
hiện của cấu trúc dữ liệu của tập rời nhau. Ta giả sử rằng việc thực hiện rừng tập tách rời
(disjoin-set-forest) trong phần 21.3 với việc hợp theo thứ hạng (union-by-rank) và nén
đường dẫn (path-compression) mang tính kinh nghiệm bởi vì nó gần như biết được cách
thực hiện nhanh nhất. Ban đầu tập A ở dòng 1 thời gian thực hiện mất 0(1) và thời gian
để thực hiện sắp xếp các cạnh ở dòng 4 là 0(E lg E) (Ta sẽ tính toán chi phí |V| lần thao
tác MAKE-SET trong vòng lặp For ở dòng 2 và 3 cùng một lúc). Vòng lặp For ở dòng 58 thực hiện 0(E) thao tác FIND-SET và UNION trên rừng tập tách rời. Đối với |V| thao
tác MAKE-SET thì tổng thời gian thực hiện là 0((V+E)α(V)) trong đó α là hàm phát triển
chậm được định nghĩa ở phần 21.4. Bởi vì đồ thị G đã cho là đồ thị liên thông do đó ta
có|E| ≥|V| -1 do đó thao tác thực hiện trên các tập rời nhau sẽ mất 0(Eα(V)). Mặt khác,
bởi vì α(|V|)=0(lgV)=0(lgE) do đó tổng thời gian thực hiện thuật toán Kruskal là 0(E lg
Trang 10
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
E). Ta nhận thấy |E| <|V| 2 nên ta có lg|E| =0(lg V) hay nói cách khác thời gian thực hiện
thuật toán Kruskal là O(ElgV).
Thuật toán Prim
Tương tự thuật toán Kruskal, thuật toán Prim là trường hợp đặc biệt của thuật toán
cây khung nhỏ nhất tổng quát ở phần 23.1. Thuật toán Prim thực hiện giống thuật toán
Dijsktra trong việc tìm ra đường đi ngắn nhất trong đồ thị, ta sẽ tìm hiểu trong phần 24.3.
Tuy nhiên thuật toán Prim có đặc tính khác thuật toán Kruskal ở điểm một cạnh trong tập
A tạo một cây duy nhất. Như mô tả ở hình 23.5 cây bắt đầu từ một đỉnh gốc bất kỳ r và
xây dựng cây khung cho dến khi cây khung bao gồm tất cả các đỉnh ở trong V. Ở mỗi
bước của thuật toán, một cạnh nhẹ (light edge) được bổ sung vào cây A nối cây A với
một đỉnh duy nhất của GA=(V,A). Theo hệ quả 23.2, đây là quy tắc chỉ bổ sung các cạnh
an toàn cho A. Vì thế, khi thuật toán kết thúc, những cạnh trong A hình thành một cây
khung nhỏ nhất. Đây là phương pháp tham lam bởi vì ở mỗi bước của thuật toán ứng với
một cạnh có thể làm tăng trọng số nhỏ nhất vào trọng số của cây.
Vấn đề then chốt để thực hiện thuật toán Prim một cách hiệu quả là làm cho thuật
toán trở nên dễ dàng hơn bằng cách lựa chọn một cạnh mới để bổ sung vào cây và cây
được hình thành từ các cạnh trong tập A. Trong phần dưới đây, đồ thị liên thông G và
đỉnh gốc r của cây khung nhỏ nhất là đầu vào của thuật toán. Trong suốt quá trình thực
hiện thuật toán, tất cả các đỉnh không ở trên cây nằm thường trú trong hằng đợi Q theo
thứ tự ưu tiên nhỏ nhất dựa trên trường key. Ứng với mỗi đỉnh v, key[v] là trọng số nhỏ
nhất của một cạnh bất kỳ nối v với một đỉnh trong cây, và ta quy ước key[v]=∞ nếu
không có cạnh nào nối v với một đỉnh trong cây. Trường π[v] gọi là nút cha của đỉnh v
trong cây. Trong suốt quá trình thực hiện thuật toán, tập A trong GENERIC-MST được
xác định như sau:
A={(v,π[v]):v ∈ V - {r} - Q}
Khi thuật toán kết thúc hằng đợi Q theo thứ tự ưu tiên nhỏ nhất là rỗng. Cây khung nhỏ
nhất A của đồ thị G là:
A={(v,π[v]):v ∈ V - {r}}
MST-PRIM (G, w,r)
1. For each u ϵ V[G]
2.
Do key[u] ∞
3.
π[u] NIL
4. key[r] 0
5. QV[G]
6. while Q ≠ ∅
7.
do u EXTRACT-MIN(Q)
Trang 11
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
8.
for each v∈ Adj[u]
9.
do if v∈ Q and w(u,v) > key [v]
10.
11.
then π [v] u
key[v] w(u,v)
Trang 12
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
Hình 23.5 Thực hiện thuật toán Prim đối với đồ thị hình 23.1. Đỉnh gốc là đỉnh a.
Các cạnh được tô bóng thuộc vào cây đang phát triến và các đỉnh của cây được tô màu
đen. Ở mỗi bước của thuật toán, các đỉnh của cây xác định một phép cắt của đồ thị và
một cạnh nhẹ xuyên qua phép cắt được bổ sung vào cây. Ví dụ, ở bước thứ hai, thuật
toán lựa chọn bổ sung vào cây cạnh (b,c) hoặc cạnh (a,h) bởi vì hai cạnh này đều là các
cạnh nhẹ xuyên qua phép cắt.
Thuật toán Prim thực hiện như mô tả ở hình 23.5. Dòng 1-5 thiết lập key cho mỗi
đỉnh là ∞( ngoại trừ đỉnh gốc r thì giá trị ban đầu của nó là 0 vì vậy đỉnh r được xem như
là đỉnh xuất phát được xử lý),ban đầu gán đỉnh cha của mối đỉnh là Nil và hằng đợi Q
theo thứ tự ưu tiên nhỏ nhất chứa tất cả các đỉnh. Thuật toán phải duy trì tính bất biến
của ba phần như sau:
Trước khi đi vào vòng lặp While từ dòng 6-11:
1. A={(v,π[v]):v ∈ V - {r} - Q}
2. Các đỉnh sau khi xác định là các đỉnh của cây khung nhỏ nhất là những đỉnh nằm trong
tập V-Q
3. Mọi đỉnh v ∈ Q nếu π[v] ≠ NIL, key[v]<∞ và key[v] là trọng số của một cạnh (v,π[v])
nối v với một đỉnh của cây khung nhỏ nhất.
Dòng 7 xác định một đỉnh u thuộc Q gắn liền với một cạnh nhẹ xuyên qua phép cắt (VQ,Q)(ngoại trừ vòng lặp đầu tiên khi u=r ở dòng 4). Loại bỏ u khỏi tập Q và bổ sung u
vảo tập V-Q của các đỉnh trong câu vì vậy bổ sung (u,π(u)) vào A. Vòng lặp For ở dòng
8-11 cập nhật trường key và π của mỗi đỉnh v kề với đỉnh u nhưng không ở trong cây.
Việc cập nhật duy trì tính bất biến phần thứ 3 của vòng lặp.
Thuật toán Prim hoạt động dựa vào cách thức thực hiện hằng đợi Q theo thứ tự ưu
tiên nhỏ nhất. Nếu Q hoạt động như một binary min-heap (xem ở chương 6) thì ta có thể
sử dụng thủ tục BUILD-MIN-HEAP để thay thế cho các dòng lệnh từ dòng 1-5 thực hiện
mất O(V) thời gian. Vòng lặp while thực hiện|V| lần và mỗi thao tác EXTRACT-MIN
thì thời gian thực hiệnlà O(lgV), vì vậy tổng thời gian thực hiện cho các lần gọi đến
EXTRACT-MIN là O(VlgV). Vòng lặp For ở dòng 8-11 thực hiện O(E) lần vì vậy tổng
chiều dài của tất cả các danh sách liền kề là 2|E|. Trong vòng lặp For, việc kiểm tra mỗi
đỉnh v thuộc Q ở dòng 9 có thể được thực hiện đồng thời bằng cách xem mỗi đỉnh là một
bit và giá trị của mỗi bit cho ta biết đỉnh v có thuộc Q hay không. Lệnh gán ở dòng 11
liên quan đến thao tác DECREASE-KEY trong min-heap và thao tác này có thể được
thực hiện trong một binary min-heap mất O(lgV). Vì vậy tổng thời gian thực hiện thuật
toán Prim là O(VlgV+ElgV)=O(ElgV) xem như gần bằng thời gian thực hiện thuật toán
Kruskal.
Trang 13
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
Thời gian thực hiện thuật toán Prim có thể được cải tiến bằng cách sử dụng Fibonacci
heaps. Ở chương 20 ta nhận thấy rằng nếu có |V| phần tử trong một Fibonacci heap, thì ta
có thể thực thiện thao tác EXTRACT-MIN mất O(lgV) và thao tác DECREASE-KEY chỉ
mất thời gian thực hiện là O(1). Vì vậy, ta có thể sử dụng Fibonacci heap để thực hiện độ
ưu tiên của hằng đợi Q, do đó thời gian thực hiện thuật toán Prim sẽ được cải tiến thành
O(E+VlgV).
23-2-1 Bài tập
Giải thuật Kruskal có thể trả về nhiều cây khung khác nhau cho cùng đồ thị đầu vào G
phụ thuộc vào việc mối liên kết giữa các cạnh bị phá vỡ như thế nào khi các cạnh được
sắp xếp theo thứ tự. Chứng minh rằng mỗi cây khung nhỏ nhất T của G, trong đó có một
cách để sắp thứ tự các cạnh của G trong giải thuật Kruskal sao cho giải thuật trả về T.
23-2-2
Giả sử rằng đồ thị G = (V,E) được biểu diễn bằng một ma trận liền kề (adjacency).
Cho một cách thực hiện đơn giản của giải thuật Prim trong trường hợp mà nó chỉ thực
hiện mất O(V2)
23-2-3
Việc thực hiện theo Fibonaci heap của giải thuật Prim có tiệm cận nhanh hơn việc
thực hiện theo nhị phân vun đống cho đồ thị không đầy đủ G = (V, E) trong đó |E| = Θ
(V2)? Và với trường hợp đồ thị đầy đủ mà trong đó |E| = Θ (V2)? |E| và |V| phải có mối
lien hệ như thế nào để thực hiện Fibonaci heap có thể tiệm cận nhanh hơn với cách thực
hiện theo binary-heap.
23-2-4
Giả sử rằng mọi trọng số cạnh trong một đồ thị là số nguyên trong phạm vi từ 1 tới |
V|. Làm thế nào để thực hiện nhanh thuật toán Kruskal? Điều gì sẽ xảy ra nếu trọng số
cạnh là các số nguyên trong phạm vi từ tới W với W là một hằng số nào đó.
23-2-5
Giả sử mọi trọng số cạnh trong một đồ thị là số nguyên trong phạm vi từ 1 tới |V|.
Làm thế nào để thực hiện nhanh thuật toán Prim? Điều gì sẽ xảy ra nếu trọng số cạnh là
các số nguyên trong phạm vi từ tới W với W là một hằng số nào đó.
23-2-6
Giả sử các trọng số cạnh trong đồ thị là được phân bố không trùng lặp trên một
khoảng mở [0,1). Giải thuật Prim hay Kruskal mà bạn có thể làm nó chạy nhanh hơn.
23-2-7
Trang 14
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
Giả sử một đồ thị G có một cây khung nhỏ nhất đã được tính toán. Làm thế nào để
cây khung nhỏ nhất có thể cập nhật một cách nhanh chóng khi một đỉnh và một cạnh
được bổ sung vào đồ thị G?
23-2-8
Giả sử giáo sư Toole đề xuất một giải thuật chia để trị mới để tính toán cho các cây
khung nhỏ nhất, như sau: Cho một đồ thị G = (V,E), chia tập đỉnh V thành 2 tập con V 1
và V2 sao cho |V1| và |V2| khác 1. Đặt E1 là tập các cạnh mà nó liền kề chỉ với các đỉnh
trong V1, và E2 là tập các cạnh liền kề với các đỉnh của V 2. Giải đệ qui cho bài toán cây
khung nhỏ nhất cho 2 đồ thị con G1= (V1, E1) và G2= (V2, E2). Cuối cùng, chọn một cạnh
trọng số nhỏ nhất trong E mà nó đi qua phần cắt (V 1, V2), và sử dụng cạnh này để hợp
nên kết quả của 2 cây khung nhỏ nhất thành một cây khung nhỏ nhất.
Bạn có đồng ý rằng giải thuật này là đúng đắn theo nghĩa nó tính được một cây khung
nhỏ nhất, nếu không, hãy cho một ví dụ để chứng minh rằng giải thuật này sai.
23-2 Cây khung trong đồ thị không đầy đủ
Trong đồ thị không đầy đủ liên thông G= (V,E), ta có thể cải tiến thời gian thực hiện
thuật toán Prim O(E + V lgV) ở trên với công thức vun đống Fibonacci bằng cách thực
hiện tiền xử lý nhằm làm giảm số đỉnh đồ thị trước thi thực hiện thuật toán Prim. Cụ thể
hơn, với mỗi đỉnh u, ta chọn cạnh (u,v) kề u có trọng số nhỏ nhất, (u,v) chính là một cạnh
để xây dựng cây khung nhỏ nhất. Sau đó ta sẽ nối tất cả các cạnh (u,v) đã được chọn. Mỗi
lần kết nối một cạnh, ta sẽ tìm ra được một tập các đỉnh kết nối với cùng một cạnh mới
được chọn. Một đồ thị mới sẽ được hình thành sau mồi lần thực hiện việc kết nối các
cạnh nhờ vào việc “đổi tên” cạnh trong tập đỉnh chứa đỉnh cuối của nó. Một vài cạnh ở
đồ thị gốc ban đầu có thể được đặt tên lại. Trong trường hợp này, chỉ có một cạnh kết quả
và trọng số của nó chính là trọng số nhỏ nhất trong tập cạnh ban đầu.
Ban đầu, ta khởi tạo cây khung nhỏ nhất T là rỗng. Với mỗi cạnh (u,v) thuộc E, ta cho
orig[u,v] = (u,v) và c[u,v] = w[u,v]. Thuộc tính orig cho biết cạnh từ đồ thị khởi tạo ban
đầu có sự kết nối với một cạnh trong đồ thị rút gọn. Thuộc tính c cho biết trọng số của
cạnh, và mỗi khi có cạnh được nối kết giá trị này sẽ được cập nhật dựa vào sơ đồ lựa
chọn trọng số của cạnh. Thủ tục MST-Reduce có các giá trị input là G, orig, c, và T, giá
trị trả về là đồ thị G’ cùng với các giá trị orig’ và c’ đã được cập nhật tương ứng với G’.
Thủ tục này đồng thời cũng xác định các cạnh của G để tạo thành cây khung nhỏ nhất T.
MST-Recude( G, orig, c,T)
For each v∈V[G]
Do mark[v] false
MAKE-Set(v)
Trang 15
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
For each u∈V[G]
Do if mark[u] = FALSE
Then chooose v∈Adj[u] such that c[u,v] is minimized
UNION(u,v)
T T ∪ {orig[u,v]}
Mark[u] mark[v] TRUE
V[G’] {FIND-SET(v):v∈V[G]}
E[G’] ∅
For each (x,y) ∈ E[G]
Do u FIND-SET(x)
v FIND-SET(y)
if (u,v) ∉ E[G’]
then E[G’] E[G’] ∪ {(u,v)}
orig’[u,v] orig[x,y]
c’[u,v] c[x,y]
else if c[x,y] < c’[u,v]
then orig’[u,v] orig[x,y]
c’[u,v] c[x,y]
construct adjacency list Adj for G’
return G’, orig’, c’, and T
a. Gọi T là tập các cạnh trả về bởi thủ tục MST-Recude, A là cây khung nhỏ nhất có
được từ đồ thị G tạo bởi thủ tục MST-Prim(G’,c’,r) với r là một đỉnh bất kỳ thuộc
b.
c.
d.
e.
V[G’]. Chứng minh rằng T ∪ {orig’[x,y] : (x,y) ∈ A} là cây khung nhỏ nhất của
G.
Chứng tỏ IV[G’]I ≤ IVI/2
Chỉ ra cách thực hiện thủ tục MST-Reduce với thời gian thực hiện là O(E) hướng
dẫn: sử dụng cấu trúc dữ liệu đơn giản)
Giả sử thủ tục MST-Reduce được thực hiện k lần, sử dụng các giá trị đầu ra là G’,
orig’ và c’ có được từ một lần thực thi trước như là đầu vào G, orig và c cho lần
thực hiện tiếp theo và vun đống các cạnh trong T. Chứng tỏ rằng thời gian thực
hiện k lần MST- Reduce là O(kE).
Giả sử sau k lần thực hiện MST-Reduce ở câu d, ta thực thi thuật toán Prim bằng
lời gọi hàm MST-Prim(G’,c’,r), với G’ và c’ có được từ lần thực hiện cuối cùng
MST-Reduce và r là một đỉnh bất kỳ trong V[G’]. Hãy xác định giá trị k sao cho
Trang 16
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
tổng thời gian thực hiện là O(Elg lgV). Chứng tỏ với giá trị k đã chọn, tổng thời
gian thực hiện dần tiến tới giá trị nhỏ nhất.
f. Với giá trị nào của IEI (giới hạn bởi IVI) thì thuật toán Prim đã được tiền xử lý sẽ
tối ưu hơn thuận toán Prim không được tiền xử lý?
23-3 Cây cổ chai
Một cây cổ chai của đồ thị vô hướng G là một cây khung của G có trọng số lớn nhất
của cạnh là nhỏ nhất trong G. Ta nói rằng giá trị của cây khung cổ chai là trọng số của
cạnh có trọng số lớn nhất trong T.
a. Một cây khung nhỏ nhất là một cây khung cổ chai
Phát biểu a chỉ ra rằng để tìm một cây khung cổ chai ta tìm cây khung nhỏ nhất.
Tiếp theo, ta sẽ chỉ thời gian tìm kiếm là tuyến tính.
b. Tìm thuật toán với thời gian thực hiện tuyến tính cho kết quả là đồ thị G và một số
nguyên b, chứng tỏ giá trị của cây khung cổ chai là b
c. Sử dụng thuật toán ở câu b như là một thủ tục con trong thuật toán với thời gian
thực hiện tuyến tính cho bài toán cây khung cổ chai
23-4 Lựa chọn thuật toán cho cây khung nhỏ nhất
Trong vấn đề này, chúng tôi đưa ra ba thuật toán khác nhau. Các thuật toán có giá trị
vào là đồ thị cần xét và cho ra kết quả là tập cạnh T. Với mỗi thuật toán,ta phải chứng
minh T là cây khung nhỏ nhất hay T không phải là cây khung nhỏ nhất.
a. MAYBE-MST-A(G,w)
1. Sắp xếp các cạnh theo thứ tự giảm dần của trọng số
2. T E
3. Với mỗi cạnh e lấy từ danh sách trên
4.
Kiểm tra nếu T - {e} là một đồ thị liên thông
5.
Thì T T - {e}
6. Return T
b. MAYBE-MST-B(G,w)
1. T ∅
2. Với mỗi cạnh e lấy tùy ý
3.
Thực hiện kiểm tra nếu T ∪ {e} không có chu trình
4.
Thì T T∪{e}
5. Return T
c. MAYBE-MST-C(G,w)
Trang 17
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
1. T ∅
2. Với mỗi cạnh e lấy tùy ý
3.
Thực hiện T T∪{e}
4.
Kiểm tra nếu T có chu trình c
5.
Thì e’ là cạnh có trọng số lớn nhất trong c
6.
T T-{e}
7. Return T
Trang 18
Cây khung nhỏ nhất- Nhóm thực hiện: Nhóm 6
MỤC LỤC
Cây khung nhỏ nhất...................................................................................................1
23.1 Phát triển cây khung nhỏ nhất.......................................................................2
Bài tập....................................................................................................................6
23.2 Thuật toán Kruskal và Prim...........................................................................8
23-2-1 Bài tập......................................................................................................14
23-2 Cây khung trong đồ thị không đầy đủ.........................................................15
23-3 Cây cổ chai..................................................................................................17
Trang 19