From: Martin Mares Date: Sun, 22 May 2011 12:09:45 +0000 (+0200) Subject: Kostry: prvni verze zapisku od Paliho X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=182c773e9123036973eb35abb64a4f2634c8dd36;p=ads1.git Kostry: prvni verze zapisku od Paliho --- diff --git a/2009/6-kostry/6-kostry.tex b/2009/6-kostry/6-kostry.tex deleted file mode 100644 index 3c1a111..0000000 --- a/2009/6-kostry/6-kostry.tex +++ /dev/null @@ -1,192 +0,0 @@ -\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)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)<...), a~$(n-1)$-krát spojíme - dvì komponenty do jedné (\). -\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 \ a $T_f$ na~operaci \. - -\s{Jednoduchá struktura pro komponenty:} -Budeme si pamatovat v~poli èísla komponent, ve~kterých le¾í jednotlivé -vrcholy. \ zvládneme v~èase $\O(1)$, ale \ 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 \ vystoupá z~obou vrcholù ke~koøeni a koøeny porovná. \ -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:} \ strom hloubky $h$ má alespoò $2^h$ prvkù. - -\proof -Indukcí: Pokud \ 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 diff --git a/2009/6-kostry/Makefile b/2009/6-kostry/Makefile deleted file mode 100644 index b86ea6f..0000000 --- a/2009/6-kostry/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -P=6-kostry - -include ../Makerules diff --git a/7-kostry/7-kostry.tex b/7-kostry/7-kostry.tex new file mode 100644 index 0000000..c3105ae --- /dev/null +++ b/7-kostry/7-kostry.tex @@ -0,0 +1,193 @@ +\input lecnotes.tex + +\prednaska{8}{Problém minimální (nejkrat¹í) 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)$ ($w$ je prostá). +\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 existuji vrcholy mimo $T$: +\::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 A\subset V$ : +$F=\left\{\left\{u,v\right\}\in E:u\in A, v\notin A \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)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)$. +\:S pou¾itím haldy: $D(v)$ ukladáme do haldy. Potom provedeme nanejvý¹ $n$ krát ExtractMin, nanejvý¹ $n$ krát Insert a nanejvý¹ $m$ krát Decrease. Pro binární haldu to má èasovú slo¾itos» $\O(m \log(n))$. +\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 ($F$ není souvislý): +\::Pro ka¾dou komponentu $F_i$ lesa $F$ vybereme nejlehèí incidentní hranu $e_i$. +\::V¹echny hrany $e_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)<...), a~$(n-1)$-krát spojíme + dvì komponenty do jedné (\). +\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 \ a $T_f$ na~operaci \. + +\s{Jednoduchá struktura pro komponenty:} +Budeme si pamatovat v~poli èísla komponent, ve~kterých le¾í jednotlivé +vrcholy. \ zvládneme v~èase $\O(1)$, ale \ 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 \ vystoupá z~obou vrcholù ke~koøeni a koøeny porovná. \ +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:} \ strom hloubky $h$ má alespoò $2^h$ prvkù. + +\proof +Indukcí: Pokud \ 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 diff --git a/7-kostry/Makefile b/7-kostry/Makefile new file mode 100644 index 0000000..31a6fd7 --- /dev/null +++ b/7-kostry/Makefile @@ -0,0 +1,3 @@ +P=7-kostry + +include ../Makerules