Mějme hranově ohodnocený souvislý neorientovaný graf $G = (V, E)$. Každé hraně $e \in E$ přiřadíme číselnou váhu $w(e)$, kde $w: E \rightarrow \mathbb{R}$
Váha $w(H)$ podgrafu $H \subseteq G$ je součet vah jeho hran.
Kostra hranově ohodnoceného grafu $G$ je minimální, pokud má ze všech jeho koster nejmenší váhu.
Vstup: Souvislý hranově ohodnocený graf $G = (V, E)$
Výstup: Nějaká minimální kostra graf $G$
Začneme se stromem, který obsahuje libovolný jeden vrchol a žádné hrany.
Vybereme nejlehčí hranu incidentní s tímto vrcholem.
Přidáme ji do stromu i s novým koncovým vrcholem.
Postup opakujeme: v každém dalším kroku přidáváme nejlehčí z hran, které vedou mezi vrcholy dosud vytvořeného stromu a zbytkem grafu.
Takto pokračujeme, dokud nevznikne celá kostra.
Jarníkův algoritmus se po $|V| − 1$ iteracích zastaví a vrátí nějakou kostru zadaného grafu
Graf $T$ konstruovaný algoritmem vzniká z jednoho vrcholu postupným přidáváním listů.
Takže $T$ je v každém okamžiku výpočtu strom.
V každé iteraci se $|V(T)|$ zvětší o 1.
Dokud $V(T) \neq V(G)$, musí díky souvislosti $G$ existovat hrana mezi $V(T)$ a $V(G) \setminus V(T)$, kterou může algoritmus přidat do $T$.
To znamená, že algoritmus se zastaví, až když $V(T) = V(G)$.
Tehdy je ale $T$ kostra.
$\square$
Nechť $A$ je nějaká podmnožina vrcholů grafu $G = (V, E)$ a $B$ její doplněk ($A \subseteq V$ a $B = V \setminus A$).
Množině všech hran, které leží jedním vrcholem v $A$ a druhým v $B$, budeme říkat elementární řez grafu $G$ určený množinami $A$ a $B$.
Nechť $G$ je souvislý ohodnocený graf s unikátními vahami, $R$ nějaký jeho elementární řez a $e$ nejlehčí hrana tohoto řezu.
Pak (každá) minimální kostra grafu $G$ obsahuje hranu $e$.
Dokážeme obměněnou implikaci: Pokud nějaká kostra $T$ neobsahuje hranu $e$, pak není minimální.
Označme $A$ a $B$ množiny vrcholů určující elementární řez $R$.
Hrana $e = \{a, b\}$, $a \in A, b \in B$, je nejlehčí v $R$.
Nechť T je kostra neobsahující e.
Protože $T$ je strom, existuje v něm jediná cesta $P(a, b)$ a ta musí alespoň jednou překročit elementární řez $R$.
Nechť $f = \{a', b'\}$, $a' \in A$, $b' \in B$, je libovolná hrana, kde se to stalo.
Nyní z kostry $T$ odebereme hranu $f$.
Tím se kostra rozpadne na dva stromy $T_a$, $T_b$, z nichž jeden obsahuje $a$ a druhý $b$.
Přidáním hrany e stromy opět propojíme a tím získáme jinou kostru $T'$.
Platí $w(T') = w(T) − w(f) + w(e)$.
Protože $e$ je nejlehčí hrana v elementárním řezu a váhy jsou unikátní, musí platit $w(f) > w(e)$.
Proto $w(T') < w(T)$ a tudíž $T$ není minimální kostra.
$\square$
Souvislý graf s unikátními vahami má právě jednu minimální kostru a Jarníkův algoritmus tuto kostru vytvoří.
Jarníkův algoritmus v každém kroku vybere jedinečnou nejlehčí hranu elementárního řezu mezi vrcholy dosud vytvořeného stromu a zbytkem grafu, která je vždy dle lemmatu obsažena v každé minimální kostře.
To ale znamená, že kostra vytvořená Jarníkovým algoritmem je podgrafem každé minimální kostry.
Protože ale všechny kostry daného grafu mají stejný počet hran, znamená to, že vytvořená kostra je všem minimálním kostrám rovna a je tudíž unikátní.
$\square$
Minimální kostra je jednoznačně určena uspořádáním hran podle vah, na konkrétních hodnotách vah nezáleží.
Jarníkův algoritmus váhy hran mezi sebou pouze porovnává.
$\square$
Pokud tedy pro každý elementární řez grafu $G$ existuje právě jedna nejlehčí hrana, pak má $G$ právě jednu minimální kostru.
Opačná implikace ale neplatí! Pokud má graf $G$ právě jednu minimální kostru, pak pro každý elementární řez grafu $G$ existuje právě jedna nejlehčí hrana.
Nechť $G$ je souvislý ohodnocený graf, $R$ je elementární řez v $G$ a $e$ je libovolná nejlehčí hrana v $R$. Pro každou minimální kostru $T'$ existuje minimální kostra $T$ taková, že:
$T'$ a $T$ se mohou lišit pouze na hranách obsažených v $R$ a
$T$ obsahuje $e$
Označme $A$ a $B$ množiny vrcholů, kterými je určen elementární řez $R$.
Nechť $T'$ neobsahuje $e$ a nechť $e = \{a, b\}$.
Buď $P$ unikátní cesta mezi vrcholy $a$ a $b$ v $T'$.
Cesta $P$ prochází elementárním řezem $R$.
Nechť $f$ je libovolná hrana v $E(P) \cap R$.
Potom $T := T' − f + e$ je kostra a platí, že $w(T) \le w(T')$.
$\square$
Pokud $G$ obsahuje více minimálních koster díky existenci hran se stejnou vahou, pak Jarníkův algoritmus jednu z nich zkonstruuje.
Naivní implementace Jarníkova algoritmu nad grafem $G = (V, E)$, reprezentovaným seznamem sousedů má časovou složitost $O(|V| \cdot |E|)$($|V|$ krát hledáme nejlehčí hranu v seznamu nejvýše $|E|$ hran) a paměťovou složitost $O(|V| + |E|)$.
Vrcholy grafu $G$ jsou udržovány v binární haldě $H$ uspořádané podle hodnoty klíčů $d$, určujících „vzdálenost“ vrcholů od dosud vybudovaného stromu v daném kroku algoritmu.
Na počátku je $d(v)$ nekonečno pro všechny vrcholy a zvolený $v_0$ má nulu.
Z haldy vybereme pomocí ExtractMin
vrchol $u$ s minimálním $d$,
čímž ho přidáme ke stromu a přepočteme pro jeho sousedy ve
vzdálenosti $d$.
Pokud se jejich $d$ změnilo, pomocí DecreaseKey
aktualizujeme
haldu a vrchol $u$ se stává jejich předchůdcem.
Minimum aktualizované haldy je rovno váze nejlehčí hrany v elementárním řezu mezi novým $T$ a zbytkem grafu.
Časová složitost MinKostraJarník
při použití binární haldy je $O(|E| log |V|)$
Inicializace zabere $O(|V|)$.
Operace s binární haldou:
Provedeme $|V| − 1$ krát operaci HeapExtractMin
– celkem $O(|V| \cdot log(|V|))$.
Každá hrana může způsobit volání operace HeapDecreaseKey
–
celkem $O(|E| \cdot log(|V|))$.
Dohromady dostáváme $O(|V|) + O(|V| \cdot log(|V|)) + O(|E| \cdot log(|V|)) = O(|E| \cdot log(|V|))$.
$\square$
Kruskalův algoritmus je také založen na hladovém přístupu.
Začne lesem tvořeným pouze samotnými vrcholy bez hran a zkouší přidávat hrany od nejlehčí po nejtěžší a zahazuje ty, které by vytvořily cyklus.
Vstup: Souvislý hranově ohodnocený graf $G = (V, E)$
Výstup: Nějaká minimální kostra graf $G$
Kruskalův algoritmus se zastaví a vydá minimální kostru.
Cyklus se vykoná m-krát.
$\square$
Ukážeme nejdříve, že pokud algoritmus přidá hranu $e = \{u, v\}$ do $T$, pak $e$ leží v minimální kostře.
Pokud algoritmus e přidá, stane se tak v okamžiku, kdy se vrcholy u a v nacházejí v nějakých dvou rozdílných stromech $T_u$ a $T_v$ lesa $T$.
Hrana $e$ přitom leží v elementárním řezu oddělujícím strom $T_u$ od zbytku grafu.
Hrana $e$ musí být nejlehčí hrana elementárního řezu oddělujícího strom $T_u$ od zbytku grafu, neboť případnou lehčí hranu by algoritmus potkal dříve a přidal by ji do $T$.
Hrana $e$ tedy leží v minimální kostře podle lemmatu o řezech.
Nyní si ukážeme, že výsledný $T$ je souvislý.
Pokud by nebyl, uvažme dva rozdílné stromy $T_u$ a $T_v$ lesa $T$ a elementární řez oddělující strom $T_u$ od zbytku grafu.
Protože je graf $G$ souvislý, je tento elementární řez neprázdný a má nějakou hranu $e$.
Když algoritmus zkoumal hranu $e$, nemohla tvořit cyklus (netvoří ho ani ve výsledném $T$), takže by ji algoritmus musel přidat, což je spor.
Výstupem algoritmu je tedy kostra, která je podgrafem minimální kostry – tedy minimální kostra.
$\square$
Kruskalův algoritmus musí nejprve seřadit hrany. Na to použijeme optimální řadící algoritmus.Začne s lesem izolovaných vrcholů a testuje postupně hrany, zda jejich vrcholy leží ve dvou různých stromových komponentách lesa a pokud ano, spojí tyto komponenty pomocí této hrany do větší.Proto bychom chtěli strukturu, která umí efektivně zjistit, ve které komponeně je daný vrchol a zároveň efektivně komponenty spojit.Proto zavádíme strukturu Union-Find
Reprezentuje rozklad množiny objektů $X$ a podporuje operace:
Init
$(X)$ vytvoří strukturu, ve které je každý element z $X$ ve
vlastní množině.
Find
$(u)$ vrátí identifikátor množiny obsahující element $u$.
Union
$(u, v)$ sjednotí množiny obsahující prvky $u$ a $v$ (pokud jsou
ze stejné množiny, struktura zůstane nezměněná).
Každou množinu, budeme reprezentovat stromem orientovaným směrem do kořene – budeme jim říkat keříky.
Založená struktura je les, který má jednovrcholový strom za každý element universa.
Vrcholy keříku odpovídají elementům příslušné množiny.
Jako identifikátory množin použijeme element uložený v kořeni daného keříku.
V paměti budeme keříky reprezentovat úsporně: každý element v si pamatuje „pouze“ identifikátor svého otce $p(v)$.
Kořeny keříků v mají $p(v) = \bot$.
Operace Find
($u$) vystoupá ze zadaného elementu $u$ do kořene keříku a vrátí tento kořen (který je vlastně identifikátorem
komponenty lesa)
Časová složitost Find
($u$) je $O(\text{hloubka keříku element } u)$
Do kořene $v$ každého keříku uložíme hloubku keříku $H(v)$Na počátku mají všechny keříky hloubku 1.
Při slučování různě hlubokých keříků připojíme mělčí keřík pod kořen toho hlubšího a hloubka toho hlubšího se nezmění.
Jsou-li oba keříky stejně hluboké, rozhodneme se libovolně a výsledný keřík má hloubku o jedna větší.
Algoritmus Union
($u$, $v$)
Výše popsaný algoritmus Union
zachovává invariant, že keřík s $h$ hladinami obsahuje nejméně $2^{h−1}$ vrcholů.
Indukcí podle počtu operací Union
.
Na počátku algoritmu mají všechny keříky jednu hladinu a $1$ vrchol (a $1 \ge 2^{1−1} = 1$).
Nechť nyní provádíme Union
($u$, $v$) a počet hladin obou keříků je
různý.
Připojením mělčího keříku pod kořen toho hlubšího se počet hladin nezmění a počet vrcholů neklesne, takže nerovnost stále platí.Pokud mají oba keříky h hladin, platí z indukčního předpokladu, že každý z nich obsahuje minimálně $2^{h−1}$ vrcholů.
Jejich sloučením tudíž vznikne keřík s $h + 1$ hladinami o alespoň $2 \cdot 2^{h−1} = 2^h$ vrcholech.
$\square$
Hloubka keříků během provádění výše popsaného algoritmu Union($u$, $v$) nepřekročí $\log n$.
Strom s větším počtem hladin by podle invariantu obsahoval více než $n$ vrcholů
$\square$
Časové složitosti operací na Union-Find
s keříky
Init | $T_i (n) = O(n)$ | inicializujeme pole délky $n$ |
Find | $T_f (n) = O(\log n)$ | procházíme keříkem, který má maximálně $\log n$ hladin |
Union | $T_u (n) = O(\log n)$ | my dokonce voláme jen na kořeny, takže lze počítat $O(1)$ |
Kruskalův algoritmus vytvoří minimální kostru v čase $O(m \cdot \log n + T_i(n) + m \cdot T_f(n) + n \cdot T_u(n))$, kde $T_i(n)$, $T_f(n)$ a $T_u(n)$ jsou časové složitosti operací Init
, Find
a Union
v Union-Find
struktuře nad množinou velikosti $n$.
Algoritmus nejdříve seřadí hrany v čase $O(m \cdot \log n)$
Následně strukturu Union-Find v čase $T_i(n)$.
Při testování hran se nejvýše $2m$-krát zavolá Find
($2m \cdot T_f(n)$) a $(n − 1)$-krát
se zavolá Union
($(n-1) \cdot T_u(n)$).
$\square$
Kruskalův algoritmus s Union-Find s keříky má časovou složitost:
Celkově tedy vytvoří minimální kostru v čase $O(|E| \cdot \log |V|)$