4.2 Minimální kostra grafu

Definice 4.2 (Minimální kostra)

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.

4.2.1 Jarníkův algoritmus

Definice 4.3 (Jarníkův algoritmus)

Vstup: Souvislý hranově ohodnocený graf $G = (V, E)$

Výstup: Nějaká minimální kostra graf $G$

\begin{algorithm}
\begin{algorithmic}
\FUNCTION {MinKostraJarník}{$G$, $w$}
    \STATE $v_0$ := libovolný vrchol grafu
    \STATE $T$ := strom obsahující vrchol $v_0$ a žádné hrany
    \WHILE { existuje hrana $\{u, v\}$ taková, že $u \in V(T)$ a $v \notin V(T)$ }
        \STATE Přidej nejlehčí takovou hranu spolu s $v$ do $T$
    \ENDWHILE
    \STATE Vrať $T$
\ENDFUNCTION\end{algorithmic}
\end{algorithm}

Algoritmus 4.1: Jarníkův algoritmus

Definice 4.4 (Princip Jarníkova algoritmu)

  1. Začneme se stromem, který obsahuje libovolný jeden vrchol a žádné hrany.

  2. Vybereme nejlehčí hranu incidentní s tímto vrcholem.

  3. Přidáme ji do stromu i s novým koncovým vrcholem.

  4. 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.

  5. Takto pokračujeme, dokud nevznikne celá kostra.

Lemma 4.1 (O konečnosti Jarníkova algoritmu)

Jarníkův algoritmus se po $|V| − 1$ iteracích zastaví a vrátí nějakou kostru zadaného grafu

Zobrazit důkaz

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$

Definice 4.5 (Elementární řez)

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$.

Lemma 4.2 (O řezech v grafu s unikátními váhami)

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$.

Zobrazit důkaz

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$

Věta 4.2 (O minimální kostře)

Souvislý graf s unikátními vahami má právě jednu minimální kostru a Jarníkův algoritmus tuto kostru vytvoří.

Zobrazit důkaz

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$

Důsledek 4.1

Minimální kostra je jednoznačně určena uspořádáním hran podle vah, na konkrétních hodnotách vah nezáleží.

Zobrazit důkaz

Jarníkův algoritmus váhy hran mezi sebou pouze porovnává.

$\square$

Důsledek 4.2

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.

Lemma 4.3 (O řezech v grafu s opakujícími se váhami)

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:

  1. $T'$ a $T$ se mohou lišit pouze na hranách obsažených v $R$ a

  2. $T$ obsahuje $e$

Zobrazit důkaz

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$

Důsledek 4.3

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.

Pozorování 4.2

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|)$.

Definice 4.6 (Jarníkův algoritmus pomocí binární haldy)

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.

Věta 4.3 (O časové složitosti Jarníkova algoritmu s binární haldou)

Časová složitost MinKostraJarník při použití binární haldy je $O(|E| log |V|)$

Zobrazit důkaz

Inicializace zabere $O(|V|)$.

Operace s binární haldou:

  1. Provedeme $|V| − 1$ krát operaci HeapExtractMin – celkem $O(|V| \cdot log(|V|))$.

  2. 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$

4.2.2 Kruskalův algoritmus

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.

Definice 4.7 (Kruskalův algoritmus)

Vstup: Souvislý hranově ohodnocený graf $G = (V, E)$

Výstup: Nějaká minimální kostra graf $G$

\begin{algorithm}
\begin{algorithmic}
\FUNCTION {MinKostraKruskal}{$G = (V, E)$, $w: E \rightarrow \mathbb{R}$}
    \STATE Uspořádej hrany podle vah: $w(e_1) \le ... \le w(e_m)$
    \STATE $T$ := $(V, \emptyset)$
    \FOR { $i$ := $1, ..., m$ }
        \STATE Označme krajní vrcholy hrany $e_i$ jako $u, v$
        \IF { $u$ a $v$ leží v různých komponentách lesa $T$ }
            \STATE $E(T)$ := $E(T) \cup \{e_i\}$
        \ENDIF
    \ENDFOR
    \RETURN $T$
\ENDFUNCTION\end{algorithmic}
\end{algorithm}

Algoritmus 4.2: Kruskalův algoritmus

Lemma 4.4 (Správnost Kruskalova algoritmu)

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$

Pozorování 4.3

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

Definice 4.8 (Sturktura 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á).

Definice 4.9 (Struktura Union-Find pomocí keříků)

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)

\begin{algorithm}
\begin{algorithmic}
\FUNCTION {Find}{vrchol $u$}
    \WHILE { $p(u) \neq \bot$ }
        \STATE Označme krajní vrcholy hrany $e_i$ jako $u, v$
        \STATE $u$ := $p(u)$
    \ENDWHILE
    \RETURN $u$
\ENDFUNCTION\end{algorithmic}
\end{algorithm}

Algoritmus 4.3: Operace Find($u$) pro Union-Find s keříky

Pozorování 4.4

Č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$)

\begin{algorithm}
\begin{algorithmic}
\FUNCTION {Union}{vrchol $u$, vrchol $v$}
    \STATE $a$ := Find($u$)
    \STATE $b$ := Find($v$)
    \IF { $a = b$ }
        \STATE \textbf{return}
    \ENDIF
    \IF { $H(a) = H(b)$ }
        \STATE $H(a)$ := $H(a) + 1$ // a pokračuj řádky (13) - (14)
    \ENDIF
    \IF { $H(a) \lt H(b)$ }
        \STATE $p(a)$ := $b$
    \ENDIF
    \IF { $H(a) \gt H(b)$ }
        \STATE $p(b)$ := $a$
    \ENDIF
\ENDFUNCTION\end{algorithmic}
\end{algorithm}

Algoritmus 4.4: Operace Union($u$, $v$) pro Union-Find s keříky

Lemma 4.5 (O hloubce keříků)

Výše popsaný algoritmus Union zachovává invariant, že keřík s $h$ hladinami obsahuje nejméně $2^{h−1}$ vrcholů.

Zobrazit důkaz

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$

Důsledek 4.4

Hloubka keříků během provádění výše popsaného algoritmu Union($u$, $v$) nepřekročí $\log n$.

Zobrazit důkaz

Strom s větším počtem hladin by podle invariantu obsahoval více než $n$ vrcholů

$\square$

Důsledek 4.5

Č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)$

\begin{algorithm}
\begin{algorithmic}
\FUNCTION {Kruskal}{$G = (V, E)$, $w: E \rightarrow \mathbb{R}$}
    \STATE Uspořádej hrany podle vah: $w(e_1) \le ... \le w(e_m)$
    \STATE $T$ := $(V, \emptyset)$
    \STATE $U$ := Init($V$)
    \FOR { $i$ := $1, ..., m$ }
        \STATE Označme krajní vrcholy hrany $e_i$ jako $u, v$
        \STATE $a$ := $U \rightarrow$ Find($u$)
        \STATE $b$ := $U \rightarrow$ Find($v$)
        \IF { $a \neq b$ }
            \STATE $E(T)$ := $E(T) \cup \{e_i\}$
            \STATE $U \rightarrow$ Union($a$, $b$)
        \ENDIF
    \ENDFOR
    \RETURN $T$
\ENDFUNCTION\end{algorithmic}
\end{algorithm}

Algoritmus 4.5: Kruskalův algoritmus s Union-Find

Věta 4.4 (O časové složitosti Kruskalova algoritmu s Union-Find s keříky)

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 UnionUnion-Find struktuře nad množinou velikosti $n$.

Zobrazit důkaz

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$

Důsledek 4.6

Kruskalův algoritmus s Union-Find s keříky má časovou složitost:

\begin{gather*} O(m \cdot \log n + T_i(n) + m \cdot T_f(n) + n \cdot T_u(n)) = \\ O(m \cdot \log n + n + m \cdot \log n + n \cdot \log n) \\ \in O(m \cdot log(n))\end{gather*}

Celkově tedy vytvoří minimální kostru v čase $O(|E| \cdot \log |V|)$