Wykład 8
Drzewo rozpinające
(minimum spanning tree)
Minimalne drzewo rozpinające - przegląd
Definicja problemu
Własności minimalnych drzew rozpinających
Algorytm Kruskala
Algorytm Prima
Literatura
– Cormen, Leiserson, Rivest, “Wprowadzenie do algorytmów”, rozdz.
24
Problem
Mamy dany zbiór wierzchołków i możliwych połączeń wraz z ich wagami, chcemy znaleźć taki podzbiór połączeń, żeby wszystkie wierzchołki były połączone oraz suma wag tych połączeń była minimalna.
Przykłady:
– Komutowanie łącza telefonicznego
– Tworzenie instalacji elektrycznej w budynku
Węzły wraz z wybranymi połączeniami tworzą drzewo!
Drzewo to nazywane jest MINIMALNYM DRZEWEM ROZPINAJĄCYM (Minimum Spanning Tree – MST)
Przykład drzewa rozpinającego (to nie jest minimalne)
b c d
h g f
i
a e
8 7
1 2
11 14
4
8
7 6
2
4
9
10
koszt: 51
Przykład drzewa rozpinającego (minimalne)
b c d
h g f
i
a e
8 7
1 2
11 14
4
8
7 6
2
4
9
10
koszt: 37
Drzewa rozpinające
Definicja: niech G=(V,E) będzie ważonym i spójnym grafem
nieskierowanym. Drzewem rozpinającym dla G nazywamy podzbiór krawędzi T ⊆⊆⊆⊆ E, taki że podgraf G’=(V,T) jest grafem spójnym, nie zawierającym cykli.
Minimalnym drzewem rozpinającym (MST) nazywamy drzewo rozpinające, dla którego suma wag wszystkich krawędzi jest minimalna :
( ) ( )
( ∑ )
∈
=
T v , u
v , u w T
w
Podstawowy algorytm MST
Strategia zachłanna: minimalne drzewo rozpinające rozrasta się poprzez dołączanie do niego w każdym kroku jednej krawędzi, przy
jednoczesnym sprawdzaniu zachowania warunków( zachowanie struktury drzewa i warunku minimalności dodawana krawędź jest
„bezpieczna” – po jej dodaniu dalej dostajemy podzbiór minimalnego drzewa).
Generic-MST(G=(V,E)) T = ∅∅∅∅;
while (T nie tworzy drzewa rozpinającego dla G) do znajdź krawędź e=(u,v) ∈∈∈∈ E bezpieczną dla T T = T ∪∪∪∪ {e}
return T
Własności MST
Pytanie: jak efektywnie odnaleźć tę bezpieczną krawędź?
Twierdzenie 1: niech U⊂⊂⊂⊂V i e=(u,v) będzie krawędzią o minimalnej wadze rozpoczynającą się w U i kończącą w V–U. Istnieje wtedy minimalne drzewo rozpinające T, takie że e∈∈∈∈T.
U V–U V
T
Własności MST
b c d
h g f
i
a e
8 7
1 2
11 14
4
8
7 6
2
4
9
10 U
podział V–U
Własności MST
Twierdzenie 2: niech G=(V,E) będzie spójnym grafem nieskierowanym, A podzbiorem E zawartym w pewnym minimalnym drzewie rozpinającym T dla G. Niech (U, V–U) będzie przekrojem G względem A (nie ma krawędzi dla wierzchołków ze zbioru A krzyżujących się z podziałem), i niech e=(u,v) będzie krawędzią lekką (o minimalnej wadze) krzyżującą się z przekrojem (U, V–U). Wtedy e jest bezpieczna dla A.
U
V–U
V
T
Własności MST
Wniosek: niech G=(V,E) będzie spójnym grafem nieskierowanym, A podzbiorem E zawartym w pewnym minimalnym drzewie
rozpinającym T dla G, niech dalej C = (VC, EC) będzie składową
(drzewem) w lesie GA = (V,A). Jeśli e jest lekką krawędzią łączącą C z pewną inną składową w GA, wtedy e jest bezpieczne dla A.
Dowód: przekrój (VC, V–VC) uwzględnia A, i e jest krawędzią lekką dla tego przekroju. Stad e jest bezpieczne.
Algorytmy wyznaczania MST
Wykorzystuje się dwa sposoby odnajdowania bezpiecznych krawędzi:
1. Algorytm Kruskala: zbiór A jest lasem i dodawana bezpieczna krawędź jest zawsze „najlżejszą” krawędzią w grafie łączącą dwa rozdzielone poddrzewa z tego lasu (Tw. 2).
2. Algorytm Prima: zbiór A jest drzewem, a dodawana bezpieczna krawędź jest „najlżejszą” krawędzią łączącą A z wierzchołkiem spoza A (Tw. 1).
Algorytm Kruskala
MST-Kruskal(G) A ∅∅∅∅
for każdy wierzchołek v∈∈∈∈V do Make-Set(v)
posortuj krawędzie z E niemalejąco względem wag for każda krawędź e = (u,v)∈∈∈∈E do
if Find-Set(u) ≠ Find-Set(v) then
A A ∪ ∪∪∪ {e}
Union(u,v)
return A Łączymy drzewa
Drzewa są rozdzielone
Każdy wierzchołek staje się osobnym
drzewem
Przykład – alg. Kruskala
b c d
h g f
i
a e
8 7
1 2
11 14
4
8
7 6
2
4
9
10 X X
koszt: 37
X
Analiza – alg. Kruskala
Poprawność: wynika wprost z Tw. 2.
Złożoność: zależy od implementacji operacji dla zbiorów rozłącznych! Dla asymptotycznie najlepszej znanej dostajemy:
– Sortowanie krawędzi zajmuje O(|E| lg |E|).
– Pętla for przebiegająca zbiór krawędzi wykonuje dwie operacje Find-Set i jedną Union. Może być to implementowane w czasie O(1).
Ostatecznie dostajemy: O(|E| lg |E|) = O(|E| lg |V|).
Dla implementacji naiwnej: O(|V| |E|
Algorytm Prima
MST-Prim(G, root)
for każdego v∈∈∈∈V do
key(v) ∞; π[v] null key(root) 0; Enqueue(Q,V) while Q nie jest pusty do
u Get-Min(Q)
for każdego v sąsiada u do if v∈∈∈∈Q i w(u,v) < key(v)
then π[v] u key(v) w(u,v)
Zmniejszamy wartość klucza
Zmniejszamy wartość klucza
Korzystamy z kolejki priorytetowej
Przykład - algorytm Prima
b c d
h g f
i
a e
8 7
1 2
11 14
4
8
7 6
2
4
9
10 0 ∞
∞ ∞ ∞
∞
∞
∞ ∞
Analiza algorytmu Prima
Poprawność: wynika bezpośrednio z Twierdzenia 1.
Złożoność: zależy od implementacji kolejko priorytetowej, dla kopca binarnego mamy:
– Budowa początkowego kopca – O(|V|).
– Extract-Min zajmuje O(lg |V|) dla każdego wierzchołka razem O(|V| lg |V|) – Pętla for jest wykonywana w czasie O(|E|).
– Test „czy jest sąsiadem” zajmuje O(1). Zmniejszanie klucza – O(lg |V|).
Ostatecznie dostajemy: O(|V| lg |V| + |E| lg |V|) = O(|E| lg |V|).
Podsumowanie: MST
MST jest drzewem zawierającym wszystkie wierzchołki o minimalnym koszcie
Stosuje się dwa zachłanne algorytmy dla znalezienia MST:
– Kruskala: oparty o krawędzie. Czas wykonania: O(|V| |E|).
– Prima: oparty o wierzchołki. Czas wykonania: O(|E| lg |V|).
Złożoność dla algorytmu Kruskala można poprawić przez zastosowanie struktur Union-Find do O(|E| lg |V|),
Złożoność dla algorytmu Prima można poprawić przez zastosowanie kopców Fibonacciego do O(|V| lg |V| + |E|).