]> mj.ucw.cz Git - ga.git/commitdiff
Prvni cast nove kapitoly o nejkratsich cestach
authorMartin Mares <mj@ucw.cz>
Sat, 16 Oct 2010 15:05:27 +0000 (17:05 +0200)
committerMartin Mares <mj@ucw.cz>
Sat, 16 Oct 2010 15:05:27 +0000 (17:05 +0200)
13-dijkstra/13-dijkstra.tex [new file with mode: 0644]
13-dijkstra/Makefile [new file with mode: 0644]

diff --git a/13-dijkstra/13-dijkstra.tex b/13-dijkstra/13-dijkstra.tex
new file mode 100644 (file)
index 0000000..8673f99
--- /dev/null
@@ -0,0 +1,277 @@
+\input ../sgr.tex
+
+\prednaska{13}{Nejkrat¹í cesty: relaxaèní metody}{}
+
+\def\ppsp{1-1}
+\def\sssp{1-$n$}
+\def\apsp{$n$-$n$}
+
+Problém hledání nejkrat¹í cesty v~(obvykle ohodnoceném orientovaném) grafu
+provází teorii grafových algoritmù od~samých poèátkù. Základní algoritmy
+pro hledání cest jsou nedílnou souèástí základních kursù programování
+a algoritmù, my se budeme vìnovat zejména rùzným jejich vylep¹ením.
+
+Mìjme tedy nìjaký orientovaný graf, jeho¾ ka¾dá hrana~$e$ je opatøena
+{\I délkou} $\ell(e)$, co¾ je nìjaké reálné èíslo. Pro libovolnou
+posloupnost hran~$P$ (speciálnì tedy pro sled nebo cestu) definujeme
+její délku $\ell(P)$ jako souèet délek v¹ech hran posloupnosti.
+Za {\I vzdálenost} $d(u,v)$ dvou vrcholù prohlásíme nejmen¹í mo¾nou
+délku cesty z~$u$ do~$v$ (jeliko¾ cest je v~grafu koneènì mnoho,
+minimum v¾dy existuje). Pokud z~$u$ do~$v$ ¾ádná cesta nevede, polo¾íme
+$d(u,v) := \infty$.
+
+Obvykle se studují následující tøi varianty problému:
+
+\itemize\ibull
+\:{\bo 1-1} neboli {\bo P2PSP} (Point to Point Shortest Path) -- chceme nalézt nejkrat¹í
+  ze~v¹ech cest z~daného vrcholu~$u$ do~daného vrcholu~$v$.
+\:{\bo 1-n} neboli {\bo SSSP} (Single Source Shortest Paths) -- pro daný vrchol~$u$ chceme
+  nalézt nejkrat¹í cesty do~v¹ech ostatních vrcholù.
+\:{\bo n-n} neboli {\bo APSP} (All Pairs Shortest Paths) -- zajímají nás nejkrat¹í cesty
+  mezi v¹emi dvojicemi vrcholù.
+\endlist
+
+Pøekvapivì, tak obecnì, jak jsme si uvedené problémy definovali, je neumíme
+øe¹it v~polynomiálním èase: pro grafy, které mohou obsahovat hrany záporných
+délek bez jakýchkoliv omezení, je toti¾ hledání nejkrat¹í cesty NP-tì¾ké
+(lze na~nìj snadno pøevést existence hamiltonovské cesty). V¹echny známé
+polynomiální algoritmy toti¾ místo nejkrat¹í cesty hledají nejkrat¹í sled
+-- nekontrolují toti¾ nijak, zda cesta neprojde jedním vrcholem vícekrát.
+
+Na¹tìstí pro nás je to v~grafech bez cyklù záporné délky toté¾: pokud se
+v~nalezeném sledu vyskytne cyklus, mù¾eme jej \uv{vystøihnout} a tím získat
+sled, který není del¹í, a~který má ménì hran. Ka¾dý nejkrat¹í sled tedy
+mù¾eme upravit na~stejnì dlouhou cestu.
+V~grafech bez záporných cyklù je tedy jedno, zda hledáme sled nebo cestu;
+naopak vyskytne-li se záporný cyklus dosa¾itelný z~poèáteèního vrcholu,
+nejkrat¹í sled ani neexistuje.
+
+Navíc se nám bude hodit, ¾e ka¾dý prefix nejkrat¹í cesty je opìt nejkrat¹í
+cesta. Jinými slovy pokud nìkterá z~nejkrat¹ích cest z~$u$ do~$v$ vede
+pøes nìjaký vrchol~$w$, pak její èást z~$u$ do~$w$ je jednou z~nejkrat¹ích
+cest z~$u$ do~$w$. (V~opaèném pøípadì bychom mohli úsek $u\ldots w$ vymìnit za~krat¹í
+cestu.)
+
+Díky této vlastnosti mù¾eme pro ka¾dý vrchol~$u$ sestrojit jeho {\I strom
+nejkrat¹ích cest}~${\cal T}(u)$. To je strom definovaný na~vrcholech zadaného
+grafu~$G$, zakoøenìný v~$u$ a orientovaný smìrem od~koøene, takový, ¾e pro ka¾dý
+vrchol~$v$ je (jediná) cesta z~$u$ do~$v$ v~tomto stromu jednou z~nejkrat¹ích
+cest z~$u$ do~$v$ v~grafy~$G$.
+
+\>{\bo Pozorování:} Strom nejkrat¹ích cest v¾dy existuje.
+
+\proof
+Nech» $u=v_1,\ldots,v_n$ jsou v¹echny vrcholy grafu~$G$. Indukcí budeme
+dokazovat, ¾e pro ka¾dé~$i$ existuje strom~${\cal T}_i$, v~nìm¾ se nacházejí nejkrat¹í
+cesty z~vrcholu~$u$ do vrcholù $v_1,\ldots,v_i$. Pro $i=1$ staèí uvá¾it
+strom obsahující pouze vrchol~$u$. Ze~stromu ${\cal T}_{i-1}$ pak vyrobíme
+strom ${\cal T}_i$ takto: Nalezneme v~$G$ nejkrat¹í cestu z~$u$ do~$v_i$
+a oznaèíme~$z$ poslední vrchol na~této cestì, který se je¹tì vyskytuje v~${\cal T}_{i-1}$.
+Úsek nejkrat¹í cesty od~$z$ do~$v_i$ pak pøidáme do~${\cal T}_{i-1}$
+a díky prefixové vlastnosti bude i cesta z~$u$ do~$v_i$ v~novém stromu
+nejkrat¹í.
+\qed
+
+Zbývá se dohodnout, v~jakém tvaru mají na¹e algoritmy vydávat výsledek.
+U~problémù typu \ppsp{} je nejjednodu¹¹í vypsat celou cestu, u~\sssp{} mù¾eme jako výstup
+vydat strom nejkrat¹ích cest z~daného poèátku (v¹imnìte si, ¾e staèí
+uvést pøedchùdce ka¾dého vrcholu), u~\apsp{} vydáme strom nejkrat¹ích cest
+pro ka¾dý ze~zdrojových vrcholù.
+
+Èasto se ov¹em uká¾e, ¾e podstatná èást problému se skrývá v~samotném
+výpoètu vzdáleností a sestrojení pøedchùdcù je triviálním roz¹íøením algoritmu.
+Budeme tedy obvykle jen poèítat vzdálenosti a samotnou rekonstrukci cest
+ponecháme ètenáøi jako snadné cvièení.
+
+\h{Relaxaèní algoritmus}
+
+Zaènìme problémem \sssp{} a oznaème~$u$ výchozí vrchol. Vìt¹ina známých
+algoritmù funguje tak, ¾e pro ka¾dý vrchol~$v$ udr¾ují ohodnocení $h(v)$,
+které v~ka¾dém okam¾iku odpovídá délce nìjakého sledu z~$u$ do~$v$. Postupnì
+toto ohodnocení upravují, a¾ se z~nìj stane vzdálenost $d(u,v)$ a algoritmus
+se mù¾e zastavit.
+
+Vhodnou operací pro vylep¹ování ohodnocení je takzvaná {\I relaxace.}
+Vybereme si nìjaký vrchol~$v$ a pro v¹echny jeho sousedy~$w$ spoèítáme
+$h(v) + \ell(v,w)$, tedy délku sledu, který vznikne roz¹íøením aktuálního
+sledu do~$v$ o~hranu $(v,w)$. Pokud je tato hodnota men¹í ne¾~$h(w)$,
+tak jí $h(w)$ pøepí¹eme.
+
+Relaxace tedy zachovává to, ¾e ohodnocení odpovídá délkám nìjakých sledù,
+a~souèasnì toto ohodnocení mù¾e zlep¹ovat. Budeme se tedy sna¾it nìjaké
+poèáteèní ohodnocení (nabízí se $h(u)=0$, $h(v)=\infty$ pro $v\ne u$)
+postupnými relaxacemi pøetvoøit na~ohodnocení vzdálenostmi.
+
+Abychom zabránili opakovaným relaxacím tého¾ vrcholu, které nic nezmìní,
+budeme rozli¹ovat tøi stavy vrcholù: {\I nevidìn} (je¹tì jsme ho nenav¹tívili),
+{\I otevøen} (zmìnilo se ohodnocení, èasem chceme relaxovat) a {\I uzavøen}
+(u¾ jsme relaxovali a není potøeba znovu).
+
+Ná¹ algoritmus bude fungovat následovnì:
+
+\algo
+\:$h(*)\leftarrow \infty$, $h(u)\leftarrow 0$.
+\:$\<stav>(*)\leftarrow\<nevidìn>$, $\<stav>(u)\leftarrow\<otevøen>$.
+\:Dokud existují otevøené vrcholy, opakujeme:
+\::$v\leftarrow\hbox{libovolný otevøený vrchol}$.
+\::$\<stav>(v)\leftarrow\<uzavøen>$.
+\::Relaxujeme~$v$:
+\:::Pro v¹echny hrany $(v,w)$ opakujeme:
+\::::Je-li $h(w) < h(v) + \ell(v,w)$:
+\:::::$h(w)\leftarrow h(v) + \ell(v,w)$.
+\:::::$\<stav>(w)\leftarrow\<otevøen>$.
+\:Vrátíme výsledek $d(u,v)=h(v)$ pro v¹echna~$v$.
+\endalgo
+
+Podobnì jako u~minimálních koster, i zde se jedná o~meta-algoritmus, proto¾e
+v~kroku~4 nespecifikuje, podle jakého pravidla se vrchol~$v$ vybírá. Pøesto
+ale mù¾eme dokázat nìkolik zajímavých tvrzení, která na~konkrétním zpùsobu
+výbìru nezávisejí.
+
+\>\s{Vìta:} Spustíme-li meta-algoritmus na graf bez záporných cyklù, pak:
+
+\numlist\nparen
+\:Ohodnocení $h(v)$ v¾dy odpovídá délce nìjakého sledu -- doká¾eme indukcí podle poètu krokù algoritmu.
+\:$h(v)$ dokonce odpovídá délce nìjaké cesty -- staèí rozmyslet, v~jaké situaci by vytvoøený sled mohl obsahovat cyklus.
+\:Algoritmus se v¾dy zastaví -- cest, a~tím pádem i mo¾ných hodnot~$h(v)$ pro
+  ka¾dý~$v$, je koneènì mnoho.
+\:Po zastavení jsou oznaèeny jako uzavøené právì ty vrcholy, které jsou dosa¾itelné z~$u$ --
+  implikace $\Rightarrow$ je triviální, pro $\Leftarrow$ staèí uvá¾it neuzavøený vrchol,
+  který je dosa¾itelný z~$u$ cestou o~co nejmen¹ím poètu hran.
+\:Po zastavení mají koneèné~$h(v)$ právì v¹echny uzavøené vrcholy.
+\:Pro ka¾dý dosa¾itelný vrchol je na~konci $h(v)$ rovno $d(u,v)$ -- kdyby to nebyla pravda,
+  vyberme si ze~\uv{¹patných} vrcholù~$v$ takový, pro nìj¾ obsahuje nejkrat¹í cesta z~$u$ do~$v$
+  nejmen¹í mo¾ný poèet hran. Vrchol~$v$ je zajisté rùzný od~$u$, tak¾e má na~této cestì nìjakého
+  pøedchùdce~$w$. Pøitom~$w$ u¾ musí být ohodnocen správnì a relaxace, která mu toto ohodnocení
+  nastavila, ho musela prohlásit za~otevøený. Jen¾e ka¾dý otevøený vrchol je pozdìji uzavøen,
+  tak¾e~$w$ poté musel být je¹tì alespoò jednou relaxován, co¾ muselo sní¾it~$h(v)$ na správnou
+  vzdálenost.
+\endlist
+
+\>Meta-algoritmus tedy pro libovolnou implementaci kroku~4 spoèítá správné vzdálenosti.
+\qed
+
+\>\s{Cvièení:}
+\itemize\ibull
+\:Nech» do algoritmu doplníme udr¾ování pøedchùdcù tak, ¾e v~kroku~9
+  pøenastavíme pøedchùdce vrcholu~$w$ na vrchol~$u$. Doka¾te, ¾e pøedchùdci
+  dosa¾itelných vrcholù budou tvoøit strom a ¾e tento strom bude stromem
+  nejkrat¹ích cest z~vrcholu~$u$.
+\:Doka¾te, ¾e pro graf, v~nìm¾ je alespoò jeden záporný cyklus dosa¾itelný
+  z~poèáteèního vrcholu, se algoritmus nezastaví a ohodnocení v¹ech vrcholù
+  na cyklu postupnì klesnou libovolnì hluboko. Nedosa¾itelné záporné cykly
+  chod algoritmu samozøejmì nijak neovlivní.
+\endlist
+
+\h{Bellmanùv-Fordùv-Mooreùv algoritmus}
+
+Bellman, Ford a Moore objevili nezávisle na sobì algoritmus (øíkejme mu BFM),
+který lze v~øeèi na¹eho meta-algoritmu formulovat takto: Otevøené vrcholy
+udr¾ujeme ve~frontì (v¾dy relaxujeme vrchol na poèátku fronty, novì otevírané
+zaøazujeme na~konec. Co toto pravidlo zpùsobí?
+
+\>\s{Vìta:} Èasová slo¾itost algoritmu~BFM je $\O(nm)$.
+
+\proof
+Bìh algoritmu rozdìlíme na~fáze. Nultá fáze sestává z~vlo¾ení vrcholu~$u$
+do~fronty. V~$(i+1)$-ní fázi relaxujeme ty vrcholy, které byly do~fronty
+ulo¾eny bìhem $i$-té fáze.
+
+V¹imneme si, ¾e na~konci $i$-té fáze je ka¾dé ohodnocení $h(v)$ shora omezeno
+délkou nejkrat¹ího ze~sledù z~$u$ do~$v$, které mají nejvý¹e~$i$ hran. Fází je
+tedy nejvý¹e~$n$.
+
+Relaxace ka¾dého vrcholu pøitom trvá lineárnì se stupnìm vrcholu, tak¾e celá
+fáze probìhne v~èase $\O(m)$.
+\qed
+
+\>\s{Cvièení:}
+\itemize\ibull
+\:Uka¾te, ¾e asymptoticky stejné èasové slo¾itosti by dosáhl algoritmus,
+  který by vrcholy oèísloval $v_1,\ldots,v_n$ a opakovanì by je v~tomto
+  poøadí relaxoval tak dlouho, dokud by se ohodnocení mìnila.
+\:Jak algoritmus upravit, aby v~$i$-té fázi spoèítal minimální délky sledù
+  o~právì~$i$ hranách?
+\:Jak lze algoritmus BFM vyu¾ít k~nalezení záporného cyklu?
+\endlist
+
+\h{Dijkstrùv algoritmus}
+
+Pokud jsou v¹echny délky hran nezáporné, mù¾eme pou¾ít efektivnìj¹í pravidlo
+pro výbìr vrcholu navr¾ené Dijkstrou. To øíká, ¾e v¾dy relaxujeme ten z~otevøených
+vrcholù, jeho¾ ohodnocení je nejmen¹í.
+
+\>\s{Vìta:} Dijkstrùv algoritmus uzavírá vrcholy v~poøadí podle neklesající
+vzdálenosti od~$u$ a ka¾dý dosa¾itelný vrchol uzavøe právì jednou.
+
+\proof
+Indukcí doká¾eme, ¾e v~ka¾dém okam¾iku mají v¹echny uzavøené vrcholy ohodnocení
+men¹í nebo rovné ohodnocením v¹ech otevøených vrcholù. Na~poèátku to jistì platí.
+Nech» nyní uzavíráme vrchol~$v$ s~minimálním $h(v)$ mezi otevøenými. Bìhem jeho
+relaxace nemù¾eme ¾ádnou hodnotu sní¾it pod~$h(v)$, jeliko¾ v~grafu s~nezápornými
+hranami je $h(v) + \ell(v,w) \ge h(v)$. Hodnota zbývajících otevøených vrcholù
+tedy neklesne pod hodnotu tohoto novì uzavøeného. Hodnoty døíve uzavøených vrcholù
+se nemohou nijak zmìnit.
+\qed
+
+Pøímoèará implementace Dijkstrova algoritmu by tedy poka¾dé v~èase $\O(n)$
+vybrala otevøený vrchol s~nejmen¹ím ohodnocením, v~èase $\O(n)$ ho relaxovala
+a toto by se opakovalo nejvý¹e $n$-krát. Algoritmus by tedy dobìhl v~èase $\O(n^2)$,
+co¾ je pro husté grafy zajisté optimální. Zkusíme tedy algoritmus zrychlit
+na~øídkých grafech.
+
+V¹echny relaxace trvají dohromady $\O(\sum_v \deg(v)) = \O(m)$, tak¾e úzkým hrdlem je
+vybírání minima. Pou¾ijeme tedy vhodnou datovou strukturu, v~ní¾ budeme udr¾ovat
+mno¾inu v¹ech otevøených vrcholù spolu s~jejich ohodnoceními. Od~datové struktury
+potøebujeme, aby umìla operace \<Insert> (vlo¾ení vrcholu), \<ExtractMin> (nalezení
+a smazání minima) a \<Decrease> (sní¾ení hodnoty vrcholu). První dvì operace pøitom
+voláme nejvý¹e $n$-krát a operaci \<Decrease> nejvý¹e $m$-krát. Celý algoritmus
+tedy dobìhne v~èase
+$$\O(nT_I(n) + nT_E(n) + mT_D(n)),$$
+kde $T_I(n)$, $T_E(n)$ a $T_D(n)$ jsou èasové slo¾itosti jednotlivých operací
+na~struktuøe o~nejvý¹e~$n$ prvcích (staèí amortizovanì).
+
+\>Jaké mo¾nosti máme pro volbu struktury?
+
+\itemize\ibull
+\:{\I pole} -- \<Insert> a \<Decrease> stojí konstantu, \<ExtractMin> trvá $\O(n)$,
+  celkem tedy $\O(n^2)$.
+\:{\I (binární) halda} -- v¹echny tøi operace umíme provést v~èase $\O(\log n)$, tak¾e celkem
+  $\O(m\log n)$. To je pro husté grafy hor¹í, pro øídké lep¹í.
+\:{\I $k$-regulární halda} -- pokud haldu upravíme tak, ¾e ka¾dý vrchol bude mít a¾ $k$ synù,
+  hloubka haldy klesne na~$\O(\log_k n)$. Operace \uv{vybublávající} prvky smìrem nahoru,
+  co¾ je \<Insert> a \<Decrease>, se zrychlí na~$\O(\log_k n)$. Ov¹em \<ExtractMin> potøebuje
+  zkoumat v¹echny syny ka¾dého nav¹tíveného prvku, tak¾e se zpomalí na $\O(k\log_k n)$.
+
+  Celková slo¾itost tedy vyjde $\O(nk\log_k n + m\log_k n)$. Oba èleny se vyrovnají
+  pro $k=m/n$, èím¾ získáme $\O(m\log_{m/n} n)$. Tento logaritmus je pøitom $\O(1)$,
+  kdykoliv je $m\ge n^{1+\varepsilon}$ pro nìjaké~$\varepsilon>0$, tak¾e pro dostateènì
+  husté grafy je algoritmus lineární.
+
+  (V¹imnìte si, ¾e pro $m\approx n^2$ algoritmus zvolí $k\approx n$, tak¾e halda degeneruje
+  na jediné patro, tedy na pole, které se opravdu ukázalo jako optimální volba pro husté grafy.)
+\:{\I Fibonacciho halda} -- \<Insert> a \<Decrease> stojí $\O(1)$, \<ExtractMin> má slo¾itost
+  $\O(\log n)$ [v¹e amortizovanì]. Dijkstrùv algoritmus tedy dobìhne v~èase $\O(m + n\log n)$.
+  To je lineární pro grafy s~hustotou $\Omega(\log n)$.
+\:{\I Datové struktury pro èísla omezeného rozsahu} -- prozkoumáme vzápìtí.
+\endlist
+
+\>\s{Cvièení:}
+
+\itemize\ibull
+\:Najdìte pøíklad nìjakého grafu se zápornými hranami (ale bez záporných cyklù),
+  na~kterém Dijkstrùv algoritmus sel¾e.
+\:Rozmyslete si, ¾e pokud nevyu¾ijeme nìjaké speciální vlastnosti èísel (celoèíselnost,
+  omezený rozsah), je mez $\O(m+n\log n)$ nejlep¹í mo¾ná, proto¾e Dijkstrovým algoritmem
+  mù¾eme tøídit $n$-tici èísel.
+\:Jsou-li délky hran celoèíselné, mù¾eme se na Dijkstrùv algoritmus dívat i takto:
+  Pøedstavme si, ¾e ka¾dou hranu nahradíme cestou tvoøenou hranami jednotkové délky
+  a na vzniklý neohodnocený graf spustíme prohledávání do~¹íøky. To samozøejmì vydá
+  správný výsledek, ale pomìrnì pomalu, proto¾e bude vìt¹inu èasu trávit posouváním
+  vlny \uv{uvnitø} pùvodních hran. Mù¾eme si tedy pro ka¾dou pùvodní hranu naøídit
+  \uv{budík}, který nám øekne, za~kolik posunutí vlny dospìjeme na~její konec.
+  Doka¾te, ¾e tento algoritmus je ekvivalentní s~Dijkstrovým.
+\endlist
+
+%\references
+\bye
diff --git a/13-dijkstra/Makefile b/13-dijkstra/Makefile
new file mode 100644 (file)
index 0000000..70b033a
--- /dev/null
@@ -0,0 +1,3 @@
+P=13-dijkstra
+
+include ../Makerules