]> mj.ucw.cz Git - ads1.git/commitdiff
Nulta verze koster (vesmes prevzata z predlonska)
authorMartin Mares <mj@ucw.cz>
Sun, 24 May 2009 14:56:47 +0000 (16:56 +0200)
committerMartin Mares <mj@ucw.cz>
Sun, 24 May 2009 14:56:47 +0000 (16:56 +0200)
6-kostry/6-kostry.tex [new file with mode: 0644]

diff --git a/6-kostry/6-kostry.tex b/6-kostry/6-kostry.tex
new file mode 100644 (file)
index 0000000..3c1a111
--- /dev/null
@@ -0,0 +1,192 @@
+\input lecnotes.tex
+
+\prednaska{6}{Problém minimální kostry}{}
+
+\s{Zadání úlohy:} Pro neorientovaný graf $G$ s~ohodnocením hran {\I váhami} $w: E(G) \rightarrow \bb R$,
+chceme najít kostru $T$ s minimálním ohodnocením $w(T)=\sum_{e\in E(T)} w(e)$.
+
+\s{Navíc pøedpokládáme:} (bez újmy na~obecnosti)
+\itemize\ibull
+\:Graf $G$ je souvislý (jinak ho nejprve rozlo¾íme na komponenty).
+\:$\forall e,f \in E(G$) : $e\neq f \Rightarrow w(e)\neq w(f)$.
+\endlist
+
+Nyní si uká¾eme tøi algoritmy pro hledání minimální kostry, konkrétnì se jedná
+o~Jarníkùv, Borùvkùv a Kruskalùv algoritmus.
+
+\h{Jarníkùv algoritmus}
+
+\s{Algoritmus:}
+
+\algo
+\algin Graf~$G$ s~ohodnocením~$w$.
+\:Zvolíme libovolný vrchol $v_0\in V(G)$.
+\:$T\leftarrow(\left\{v_0\right\},\emptyset)$ (zatím jednovrcholový strom)
+\:Dokud $\vert V(T) \vert \neq n$:
+\::Vybereme hranu $uv\in E(G) : u\in V(T), v\notin V(T)$ tak, aby $w(uv)$ byla minimálni.
+\::$T\leftarrow T+uv$.
+\algout Minimální kostra~$T$.
+\endalgo
+
+\s{Vìta:} Jarníkùv algoritmus se zastaví po maximálnì $n$ iteracích a vydá minimální kostru grafu $G$.
+
+\proof
+Pøi ka¾dé iteraci algoritmus pøidá jeden vrchol do~$T$, a~proto se po~maximálnì $n$ iteracích zastaví.
+Vydaný graf je strom, proto¾e se stále pøidává list k ji¾ existujícímu stromu, a~jeliko¾ má $n$~vrcholù,
+je to kostra. Zbývá nám u¾ jen dokázat, ¾e nalezená kostra je minimální. K~tomu pomu¾e následující lemma:
+
+{\narrower
+
+\s{Definice:} {\I Øez} v~grafu $G=(V,E)$ je mno¾ina hran $F\subseteq E$ taková, ¾e $\exists  U\subset V$ :
+$F=\left\{uv\in E:u\in U, v\notin U \right\}$.
+
+\s{Lemma (øezové):} Pokud $G$ je graf, $w$ jeho prosté ohodnocení, $F$ je øez v
+grafu $G$ a $f$ je nejlehèí hrana v øezu $F$, pak pro ka¾dou minimální kostru
+$T$ grafu $G$ je $f\in E(T)$.
+
+\proof
+Buï $T$ kostra a $f=uv\notin E(T)$. Pak existuje cesta $P\subseteq T$ spojující $u$ a $v$.
+Cesta musí øez alespoò jednou pøekroèit. Proto existuje $e\in P \cap F$ a navíc víme, ¾e $w(e) > w(f)$. Uva¾me $T'=T-e+f$.
+Tento graf je rovnì¾ kostra grafu $G$, proto¾e odebraním hrany $e$ se graf rozpadne na dvì komponenty a pøidáním
+hrany $f$ se tyto komponenty opìt spojí. Navíc $w(T')=w(T)-w(e)+w(f)<w(T)$.
+\qed
+
+}
+
+\>V~dùkazu korektnosti Jarníkova algoritmu toto lemma vyu¾ijeme tak, ¾e si v¹imneme, ¾e hrany mezi
+vrcholy stromu~$T$ a zbytkem grafu tvoøí øez a algoritmus nejlehèí hranu tohoto øezu pøidá
+do~$T$. Podle lemmatu tedy v¹echny hrany~$T$ musí být souèástí ka¾dé minimální kostry a jeliko¾~$T$ je strom,
+musí být minimální kostrou.
+
+\qed
+
+
+\s{Dùsledky:} Graf $G$ s prostým ohodnocením má pravì jednu minimální kostru. Minimální kostra je
+jednoznaènì urèená lineárním uspoøádáním hran.
+
+\s{Implementace:}
+\itemize\ibull
+\:Pøímoèará: pamatujeme si, které vrcholy a hrany jsou v kostøe $T$ a které ne. Èasová slo¾itost je $\O(nm)$.
+\:Chytøej¹í: Pro $v\notin V(T)$ si pamatujeme $D(v)=\min\left\{w(uv):u\in T\right\}$. Pøi ka¾dém
+prùchodu hlavním cyklem pak procházíme v¹echna~$D(v)$ (to v¾dy trvá $\O(n)$) a pøi pøidání vrcholu do~$T$ kontrolujeme
+okolní~$D(w)$ pro $vw\in E$ a pøípadnì je sni¾ujeme (za~ka¾dou hranu~$\O(1)$). Èasovou slo¾itost tím celkovì
+zlep¹íme na~$\O(n^2+m)=\O(n^2)$.
+\:Také se dá pou¾ít halda pro uchovávání hran nebo hodnot~$D(v)$.
+\endlist
+
+\h{Borùvkùv algoritmus}
+
+\s{Algoritmus:}
+
+\algo
+\algin Graf~$G$ s~ohodnocením~$w$.
+\:$F\leftarrow(V(G),\emptyset)$
+\:Dokud $F$ má alespoò dvì komponenty:
+\::Pro ka¾dou komponentu $T_i$ grafu $F$ vybereme nejlehèí incidentní hranu $t_i$.
+\::V¹echny hrany $t_i$ pøidáme do $F$.
+\algout Minimální kostra~$F$.
+\endalgo
+
+\s{Vìta:} Borùvkùv algoritmus se zastaví po $\left\lceil \log_2 n\right\rceil$ iteracích a vydá minimální kostru grafu $G$.
+
+\proof
+V¹imnìme si nejprve, ¾e po~$k$ iteracích mají v¹echny komponenty grafu~$F$ minimálnì $2^k$ vrcholù
+(indukcí -- na~poèátku jsou v¹echny komponenty jednovrcholové, v~ka¾dé dal¹í
+iteraci se komponenty sluèují do~vìt¹ích,
+ka¾dá s~alespoò jednou sousední, tak¾e se velikosti komponent minimálnì zdvojnásobí).
+Proto nejpozdìji po~$\left\lceil \log_2 n\right\rceil$ iteracích u¾~velikost komponenty dosáhne poètu v¹ech vrcholù a algoritmus
+se zastaví.
+
+Hrany mezi ka¾dou komponentou a~zbytkem grafu tvoøí øez, tak¾e podle øezového
+lemmatu v¹echny hrany pøidané do~$F$ musí být souèástí (jednoznaènì
+urèené) minimální kostry. Graf $F\subseteq G$ je tedy v¾dy les a a¾ se
+algoritmus zastaví, bude roven minimální kostøe.
+\qed
+
+\s{Implementace:}
+\itemize\ibull
+\:Inicializace pøímoèará.
+\:Pomocí DFS rozlo¾íme les na komponenty. Pro ka¾dý vrchol si pamatujeme èíslo komponenty.
+\:Pro ka¾dou hranu zjistíme, do které komponenty patøí, a pro ka¾dou komponentu
+si uchováme nejlehèí hranu.
+\endlist
+
+\>Takto doká¾eme ka¾dou iteraci provést v~èase $\O(m)$ a celý algoritmus dobìhne v~$\O(m\log n)$.
+
+\h{Kruskalùv neboli hladový algoritmus}
+
+\s{Algoritmus:}
+
+\algo
+\algin Graf~$G$ s~ohodnocením~$w$.
+\:Setøídíme v¹echny hrany z $E(G)$ tak, aby: $w(e_1)<...<w(e_m)$.
+\:$F\leftarrow (V(G),\emptyset)$.
+\:Pro $i=1$ do $m$:
+\::Pokud $F+e_i$ je acyklický, provedeme $F\leftarrow F+e_i$.
+\algout Minimální kostra~$F$.
+\endalgo
+
+\s{Vìta:} Kruskalùv algoritmus se zastaví po~$m$ iteracích a vydá minimální kostru.
+
+\proof
+Ka¾dá iterace algoritmu zpracovává jednu hranu, tak¾e iterací je~$m$. Indukcí doká¾eme,
+¾e~$F$ je v¾dy podgrafem minimální kostry: prázdné poèáteèní~$F$ je podgrafem èehokoliv,
+ka¾dá hrana, kterou pak pøidáme, je minimální v~øezu oddìlujícím nìjakou
+komponentu~$F$ od~zbytku grafu (ostatní hrany tohoto øezu je¹tì nebyly
+zpracovány, a~tudí¾ jsou tì¾¹í). Naopak ¾ádná hrana, kterou jsme se rozhodli
+do~$F$ nepøidat, nemù¾e být souèástí minimální kostry, jeliko¾ s~hranami,
+o~kterých ji¾ víme, ¾e v~minimální kostøe le¾í, tvoøí kru¾nici. \qed
+
+% Toto jsme na pøedná¹ce dìlali sporem a mì se to líbí více, ale oba dùkazy
+% urèitì fungují.
+
+\s{Implementace:}
+\itemize\ibull
+\:Setøídìní v èase $\O(m\log m)=\O(m\log n)$.
+\:Pak potøebujeme udr¾ovat komponenty souvislosti grafu~$F$, abychom umìli rychle
+  urèit, jestli právì zpracovávaná hrana vytvoøí kru¾nici. Potøebujeme tedy strukturu
+  pro udr¾ování komponent souvislosti, které se $m$-krát zeptáme, zda dva vrcholy
+  le¾í v~té¾e komponentì (tomu budeme øíkat operace \<Find>), a~$(n-1)$-krát spojíme
+  dvì komponenty do jedné (\<Union>).
+\endlist
+
+\>Kruskalùv algoritmus tedy pobì¾í v~èase $\O(m\log n + mT_f + nT_u)$, kde~$T_u$ je
+èas na~provedení jedné operace \<Union> a $T_f$ na~operaci \<Find>.
+
+\s{Jednoduchá struktura pro komponenty:}
+Budeme si pamatovat v~poli èísla komponent, ve~kterých le¾í jednotlivé
+vrcholy. \<Find> zvládneme v~èase $\O(1)$, ale \<Union> bude stát $\O(n)$. Celý
+algoritmus pak pobì¾í v~èase $\O(m\log n+ m + n^2) = \O(m\log n+n^2)$.
+
+\s{Chytøej¹í struktura:} Ka¾dou komponentou si ulo¾íme jako strom orientovaný smìrem ke koøeni
+-- ka¾dý vrchol si pamatuje svého otce, navíc ka¾dý koøen si pamatuje velikost
+komponenty. 
+%Hloubku podstromu? Zaøazujeme mìlèí pod hlub¹í, ne nutnì men¹í pod vìt¹í.
+%Myslím, ¾e s hloubkami to funguje lépe, ovìøit.
+Operace \<Find> vystoupá z~obou vrcholù ke~koøeni a koøeny porovná. \<Union>
+rovnì¾ najde koøeny a pøipojí koøen men¹í komponenty pod koøen té vìt¹í. Obojí
+zvládneme v~èase lineárním v~hloubce stromu a jak si uká¾eme, tato hloubka je
+v¾dy nejvý¹e logaritmická, a proto celý Kruskalùv algoritmus pobì¾í v~èase
+$\O(m\log n + m\log n + n\log n) = \O(m\log n)$.\foot{%
+Drobnou úpravou bychom mohli dosáhnout daleko efektivnìj¹í struktury, ale tu
+bychom neupotøebili,
+jeliko¾ by nás stejnì brzdilo tøídìní, a analýza slo¾itosti by byla \dots\ inu, slo¾itìj¹í.}
+
+% V originále je jen "strom hloubky..." a to pøece pro obecný (napø.
+% zdegenerovaný) strom neplatí.
+
+% Mimochodem, zde se u¾ mluví o spojování podle hloubky, tak¾e to nahoøe je asi
+% vá¾nì chyba
+\s{Lemma:} \<Union-Find> strom hloubky $h$ má alespoò $2^h$ prvkù.
+
+\proof
+Indukcí: Pokud \<Union> spojí strom s~hloubkou $h$ s jiným s~hloubkou men¹í ne¾ $h$, pak hloubka výsledného
+stromu zùstává~$h$. Pokud spojuje dva stromy stejné hloubky~$h$, pak má výsledný strom hloubku $h+1$.
+Z~indukèního pøedpokladu víme, ¾e strom hloubky $h$ má minimálnì $2^h$ vrcholù,
+a~tedy výsledný strom hloubky $h+1$ má alespoò $2^{h+1}$ vrcholù. \qed
+
+% Union-find je jsme mìli na pøedná¹ce detailnìji rozebraný (i s pseudokódem),
+% není to nutnost, ale mù¾u ho klidnì rozepsat trochu výøeènìji, aby mìl ètenáø
+% vìt¹í jistotu. Zále¾í na tobì.
+
+\bye