3 \prednaska{8}{Základní grafové algoritmy}{(Zapsali M. Petr, O.Tichý, ¥. Magic)}
6 Oznaème vrcholy grafu na následujícím obrázku písmeny A, B, C, D.
7 Pokud bychom chtìli tento graf uchovat v pamìti poèítaèe, máme na výbìr
8 hned nìkolik zpùsobù, jak to udìlat.
9 \figure{img1_stvorec.eps}{}{\epsfxsize}
13 Jednodu¹e vypí¹eme seznam v¹ech dvojic vrcholù grafu spojených hranou.
18 \s{2. matice sousednosti}
20 Matice sousednosti je pole $A$ o velikosti $n \times n$, jeho¾ prvky na
21 souøadnicích $i, j$ jsou dány následujícím pøedpisem:
23 $$ A_{i,j} = \left\{ \matrix {0 \Leftrightarrow \{i,j\} \notin E \cr
24 1 \Leftrightarrow \{i,j\} \in E \cr
28 Ná¹ graf z obrázku vý¹e by tedy v maticové reprezentaci vypadal takto:
38 S touto matici se pracuje velmi snadno (napø. v¹echny sousedy i-tého vrcholu
39 zjistíme jednodu¹e tak, ¾e projdeme i-tý øádek matice, co¾ pøedstavuje èasovou
40 slo¾itost $O(n)$), ale má i jednu zøejmou nevýhodu: její velikost je v¾dy
41 kvadratická bez ohledu na to, jak "øídký" je graf. U grafu s mnoha vrcholy, ale
42 s malým poètem hran, tedy budeme zbyteènì plýtvat místem v pamìti.
44 Nabízí se proto tøetí, úspornìj¹í, zpùsob, a to:
50 %A&\rightarrow&BC\quad \cr
53 %D&\rightarrow&BC\quad \cr
56 V pamìti poèítaèe by se dal seznam sousedù uchovávat dvìma poli: polem vrcholù
57 $V$ grafu, jeho¾ prvky postupnì pro ka¾dý vrchol udávají index na zaèátek
58 odpovídajícího úseku v poli $E$, ve kterém by byli ulo¾eni jeho sousedé.
59 \figure{img4_susedia.eps}{Znázornìní polí seznamu sousedù.}{\epsfxsize}
61 Na tuto reprezentaci u¾ staèí prostor $O(n + m)$, co¾ u¾ je, na rozdíl od
62 pøedchozího kvadratického prostoru, docela pøíjemné.
64 Je¹tì dodejme, ¾e aèkoliv jsme jednotlivé reprezentace ukazovali na pøíkladì
65 neorientovaného grafu, orientované grafy se dají reprezentovat prakticky stejnì. U
66 orientovaných grafù je toti¾ jediný rozdíl: existuje-li hrana z vrcholu $u$ do
67 vrcholu $v$, neznamená to, ¾e existuje i hrana z $v$ do $u$ (tedy $(u, v)$ a $(v, u)$
68 tvoøí uspoøádané dvojice).
72 \s{Definice:} Vrchol je dosa¾itelný, pokud do nìj vede cesta z poèáteèního vrcholu.
74 \s{Efektivní prùchod by mìl splòovat tyto podmínky:}
76 \:ka¾dou hranu projdu právì jednou (resp. maximálnì dvakrát - 1x tam, 1x zpìt)
77 \:hranou se vracím zpìt, a¾ kdy¾ u¾ z vrcholu, na kterém momentálnì jsem, nevede
78 dosud neprozkoumaná hrana
79 \:pokud jsem do¹el po hranì do ji¾ døíve nav¹tíveného vrcholu, hned se vrátím
88 \s{Korektnost} (algoritmus projde celý graf)
91 Sporem: Nech» existuje vrchol, který je dosa¾itelný, ale algoritmus ho nepro¹el.
92 Pak jsme ale pøi prùchodu narazili na $\{u, v\}\in E$ takovou, ¾e vrchol $u$ je
93 dosa¾itelný a $w$ dosa¾itelný není. Tzn., ¾e $\{u, w\}$ tvoøí neprozkoumanou
94 hranu $\Rightarrow$ spor s druhým bodem.
99 Z toho, ¾e ¾ádná hrana ani vrchol se neprojde vícekrát (první podmínka
100 efektivního prùchodu), plyne èasová slo¾itost $O(n + m)$.
102 \>Nyní si nìco povíme o dvou zpùsobech, kterak mù¾eme procházet grafy.
104 \s{Prùchod do hloubky} (Depth First Search, DFS)
106 Prùchod do hloubky je prvním základním postupem pøi procházení grafem. Pokud bychom
107 chtìli DFS trochu pøiblí¾it, mohli bychom ho pøirovnat k Théseovì postupu
108 pøi prùchodu Minotaurovho bludi¹te za pomoci Ariadniny nitì.
110 \s{Prùchod do ¹íøky} (Breadth First Search, BFS)
112 Na rozdíl od prohledávání do hloubky vyu¾ívá prohledávání do ¹íøky namísto zásobníku
113 frontu. Motivaèní úlohou by mohlo být napø. hledání nejkrat¹í cesty mezi dvìma vrcholy
114 v grafu, nebo známý pøevozníkùv problém.
115 \figure{img6_BFS.eps}{}{\epsfxsize}
117 \s{Pø.} Koza, vlk a zelí
118 \figure{img8_kvz.eps}{}{\epsfxsize}
120 Øe¹ení ulohy by se dalo popsat jako hledání cesty grafem stavù od poèáteèního stavu
121 (koza, vlk i zelí jsou na jednom bøehu) do koncového (v¹ichni byli bez újmy pøevezeni
124 \h{DFS na neorientovaném grafu}
126 Pøi prùchodu grafu do hloubky pou¾íváme zásobník. Na zaèátku se v nìm nachází pouze
127 vstupní vrchol v. Dokud není zásobník prázdný, tak z nìj odebíráme vrchol; ten oznaèíme
128 jako zpracovaný (abychom ho v budoucnu, kdybychom na nìj je¹tì nìkdy narazili,
129 nezpracovávali znovu) a do zásobníku pøidáme v¹echny jeho sousedy takové, kteøí
130 je¹tì nebyli oznaèeni jako zpracovaní.
132 \>Vrcholy znaèíme tìmito barvami
134 \:bílá - dosud nenav¹tívìné vrcholy (na zaèátku jsou tedy bílé v¹echny)
135 \:¹edá - oznaèuje právì zpracovávaný vrchol
136 \:èerná - u¾ zpracované vrcholy
139 \>U ka¾dého vrcholu si dále také zapamatujeme èas pøíchodu a èas odchodu
140 ($in[v]$, $out [v]$).
145 \:procedure Projdi(v)
149 \::$\forall$ w $\in$ Sousedi(v):
150 \:::if color[w] = bílá $\Rightarrow$
157 \::$\forall$ v: color[v] := bílá
159 \::$\forall$ v $\in$ V :
160 \:::if color[v] = bílá $\Rightarrow$
164 Implementaci zásobníku jsme v tomto meta-algoritmu nahradili pou¾itím rekurze
165 (která ale funguje na podobném principu, kdy se na zásobník vkládají jednotlivá
166 volání rekurzivní funkce).
168 Na následujících obrázcích je znázornìno, jak probíhá prùchod grafu pomocí DFS:
170 \figure{img2_dfs.eps}{}{\epsfxsize}
171 \figure{img3_dfs.eps}{Znázornìní prùbìhu algoritmu.}{\epsfxsize}
173 \s{Hrany v tomto znázornìní dìlíme na:}
175 \:stromové - v momentì prùchodu vedou do dosud nenav¹tíveného, bílého, vrcholu
176 \:zpìtné - ostatní hrany
179 \s{Pozorování:} plné hrany tvoøí strom (DFS strom, strom prùchodu do hloubky).
182 \item{(1)} hledání kostry
183 \item{(2)} hledání komponent souvislosti
185 Èasová slo¾itost tìchto aplikací DFS je stejná jako slo¾itost pùvodního
186 meta-algoritmu, tedy $O(n + m)$.
188 \item{(3)} hledání artikulací
190 Tuto aplikaci si teï rozebereme tro¹ku podrobnìji. Nejprve v¹ak nìkolik definic.
192 \s{Definice:} Artikulace je vrchol v grafu, jeho¾ odebráním se graf rozpadne na alespoò
193 dvì komponenty souvislosti.
195 \s{Definice:} Most je hrana v grafu, jejím¾ odebráním se graf rozpadne na dvì
196 komponenty souvislosti.
198 \s{Pozorování}: Most je taková hrana, její¾ oba koncové vrcholy jsou artikulacemi.
200 \s{Definice:} Graf je 2-souvislý, jestli¾e po odstranìní libovolného vrcholu
203 \s{Definice:} 2-souvislá komponenta je maximální 2-souvislý podgraf.
205 Jak bychom tedy pøi hledání artikulací v grafu mohli postupovat? Jako první
206 se nabízí tento algoritmus:
208 \s{Hloupý algoritmus}
210 Berme si postupnì v¹echny vrcholy grafu; pro ka¾dý zjistíme, jestli se jeho
211 odebráním zvý¹il poèet komponent. K tomu bychom mohli pou¾ít prùchod do hloubky,
212 který jsme si u¾ ukázali. Procedura Projdi(v) projde a oznaèí v¹echny vrcholy
213 dosa¾itelné z v, tedy v¹echny vrcholy komponenty obsahující vrchol v. Mù¾eme
214 tedy udìlat takovou zmìnu, ¾e si budeme nav¹tívené vrcholy oznaèovat èíslem
217 Takový algoritmus by mìl slo¾itost $n \times O(n + m))$ (pro ka¾dý vrchol grafu
218 bychom n-krát spou¹tìli DFS), co¾ se nám vùbec nelíbí. Pokusme se tedy najít
219 nìco lep¹ího. Nejprve uèiòmì toto pozorování:
221 \s{Pozorování:} v je artikulace $\Leftrightarrow$ v je koøen DFS stromu a má
222 alespoò dva potomky nebo v není koøen a má syna w takového, ¾e ze ¾ádného
223 jeho potomka nevede hrana do pøedchùdce v.
225 \s{Definice:} Pøípustná cesta je taková cesta, pokud vede pøes stromové hrany
226 DFS stromu (mù¾e konèit i skokem zpìt).
228 \figure{img7_hrany.eps}{Pøíklady pøípustných cest.}{\epsfxsize}
230 \>Dále si definujme funkci low pro ka¾dý vrchol v, takto:
232 \s{low(v)} = min(in[w], z v do w vede pøípustná cesta)
234 \s{Pozorování:} v je artikulace $\Leftrightarrow$ v je koøen DFS stromu a má
235 alespoò dva potomky nebo má syna w takového, ¾e platí $low(w) \geq in[w]$.
237 \s{Jak ale hodnotu funkce low(w) spoèítat?}
239 low(v) = min(x, y, z)
243 y = min(in[w], $\{w, v\}$ je zpìtná hrana)
245 z = min(low(w), $\{v, w\}$ je stromová hrana)
247 \h{DFS na orientovaném grafu}
249 \figure{img5_dfso.eps}{Graf a znázornení prùbehu:}{\epsfxsize}
251 \s{Hrany v dìlíme na: }
253 \:stromové $\{A,B\}$, $\{B,C\}$, $\{B,D\}$
254 \:zpìtné: vedou do pøedchùdce v DFS stromì (do ¹edého vrcholu)
255 \:pøíèné: vedou do vrcholu v jiném podstromì (do èerného vrcholu)
256 \:dopøedné: vedou do svého potomka (do èerného vrcholu v tém¾e podstromì)
260 \>Na závìr nìkolik \s{pozorování:}
262 Intervaly (in[v], out[v]) $\forall v \in V $ tvoøí dobré uzávorkování.
264 v je následník u $\Leftrightarrow (in[v], out[v]) \leq (int[u], out[u]) $
266 $\{u,v\}$ je zpìtná hrana $\Leftrightarrow (in[u], out[u]) \leq (in[v], out[v])$
268 $\{u,v\}$ je pøíèná hrana $\Leftrightarrow int[v] < out[v] < in[u] < out[u]$