1. Trang chủ >
  2. Khoa học tự nhiên >
  3. Toán học >

2 Thuật toán Kruskal và Prim

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. QV[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



Xem Thêm
Tải bản đầy đủ (.doc) (19 trang)

×