\input lecnotes.tex

\prednaska{7}{Geometrické algoritmy}{}

\>Uká¾eme si nìkolik základních algoritmù na øe¹ení geometrických problémù v~rovinì. Proè zrovna v~rovinì? Inu, jednorozmìrné problémy bývají triviální
a naopak pro vy¹¹í dimenze jsou velice komplikované. Rovina je proto rozumným kompromisem mezi obtí¾ností a zajímavostí.

Celou kapitolou nás bude provázet pohádka ze ¾ivota ledních medvìdù. Pokusíme se vyøe¹it jejich \uv{ka¾dodenní} problémy~\dots

\h{Hledání konvexního obalu}

{\I Daleko na severu ¾ili lední medvìdi. Ve vodách tamního moøe byla hojnost ryb a jak je známo, ryby jsou oblíbenou pochoutkou ledních medvìdù.
Proto¾e medvìdi z~na¹í pohádky rozhodnì nejsou ledajací a ani chytrost jim neschází, rozhodli se v¹echny ryby pochytat. Znají pøesná místa výskytu
ryb a rádi by vyrobili obrovskou sí», do které by je v¹echny chytili. Pomozte medvìdùm zjistit, jaký nejmen¹í obvod taková sí» mù¾e mít.}

\figure{7-geom5_rybi_motivace.eps}{Problém ledních mìdvìdù: Jaký je nejmen¹í obvod sítì?}{3in}

Neboli v~øeèi matematické, chceme pro zadanou mno¾inu bodù v~rovinì nalézt její konvexní obal. Co je to konvexní obal? Mno¾ina bodù je {\I konvexní},
pokud pro ka¾dé dva body obsahuje i celou úseèku mezi nimi. {\I Konvexní obal} je nejmen¹í konvexní podmno¾ina roviny, která obsahuje v¹echny zadané
body.\foot{Pamatujete si na lineární obaly ve vektorových prostorech? Lineární obal mno¾iny vektorù je nejmen¹í vektorový podprostor, který tyto
vektory obsahuje. Není náhoda, ¾e tato definice pøipomíná definici konvexního obalu. Na druhou stranu ka¾dý vektor z~lineárního obalu lze vyjádøit
jako lineární kombinaci daných vektorù. Podobnì platí i pro konvexní obaly, ¾e ka¾dý bod z~obalu je konvexní kombinací daných bodù. Ta se li¹í od
lineární v~tom, ¾e v¹echny koeficienty jsou v~intervalu $[0,1]$ a navíc souèet v¹ech koeficientù je $1$. Tento algebraický pohled mù¾e mnohé vìci
zjednodu¹it. Zkuste si dokázat, ¾e obì definice konvexního obalu jsou ekvivalentní.} Z~algoritmického hlediska nás v¹ak bude zajímat jenom jeho
hranice, kterou budeme dále oznaèovat jako konvexní obal.

Na¹ím úkolem je nalézt konvexní obal koneèné mno¾iny bodù. To je v¾dy konvexní mnohoúhelník, navíc s~vrcholy v~zadaných bodech. Øe¹ením problému tedy
bude posloupnost bodù, které tvoøí konvexní obal. Pro malé mno¾iny je konvexní obal nakreslen na obrázku, pro více bodù je v¹ak situace mnohem
slo¾itìj¹í.

\figure{7-geom1_male_obaly.eps}{Konvexní obaly malých mno¾in.}{3in}

Pro jednoduchost budeme pøedpokládat, ¾e v¹echny body mají rùzné $x$-ové souøadnice. Tedy utøídìní bodù zleva doprava je urèené jednoznaènì.\foot{To si
mù¾eme dovolit pøedpokládat, nebo» se v¹emi body staèí nepatrnì pootoèit. Tím konvexní obal urèitì nezmìníme. Av¹ak jednodu¹¹í øe¹ení je naprogramovat
tøídìní lexikograficky (druhotnì podle souøadnice $y$) a vyøadit identické body.} Tím máme zaji¹tìné, ¾e existují dva body, nejlevìj¹í a
nejpravìj¹í, pro které platí následující invariant:

\s{Invariant:} Nejlevìj¹í a nejpravìj¹í body jsou v¾dy v~konvexním obalu.

Algoritmus na nalezení konvexního obalu funguje na následujícím jednoduchém principu, kterému se nìkdy øíká {\I zametání roviny}. Procházíme body
zleva doprava a postupnì roz¹iøujeme doposud nalezený konvexní obal o~dal¹í body. Na zaèátku bude konvexní obal jediného bodu samotný bod. Na konci
$k$-tého kroku algoritmu známe konvexní obal prvních $k$ bodù. Kdy¾ algoritmus skonèí, známe hledaný konvexní obal. Podle invariantu musíme v~$k$-tém
kroku pøidat do obalu $k$-tý nejlevìj¹í bod. Zbývá si jen rozmyslet, jak pøesnì tento bod pøidat.

Pøidání dal¹ího bodu do konvexního obalu funguje, jak je naznaèeno na obrázku. Podle invariantu víme, ¾e bod nejvíc vpravo je souèástí konvexního
obalu. Za nìj napojíme novì pøidávaný bod. Tím jsme získali nìjaký obal, ale zpravidla nebude konvexní. To lze v¹ak snadno napravit, staèí
odebírat body, v obou smìrech podél konvexního obalu, tak dlouho, dokud nezískáme konvexní obal. Na pøíkladu z obrázku nemusíme po smìru hodinových
ruèièek odebrat ani jeden bod, obal je v poøádku. Naopak proti smìru hodinových ruèièek musíme odebrat dokonce dva body.

\figure{7-geom2_pridani_bodu.eps}{Pøidání bodu do konvexního obalu.}{4.5in}

Pro pøípadnou implementaci a rozbor slo¾itosti si nyní popí¹eme algoritmus detailnìji. Aby se lépe popisoval, rozdìlíme si konvexní obal na dvì èásti
spojující nejlevìj¹í a nejpravìj¹í bod obalu. Budeme jim øíkat {\I horní obálka} a {\I dolní obálka}.

\figure{7-geom3_obalky.eps}{Horní a dolní obálka konvexního obalu.}{3.4in}

Obì obálky jsou lomené èáry, navíc horní obálka poøád zatáèí doprava a dolní naopak doleva. Pro udr¾ování bodù v~obálkách staèí dva zásobníky.
V~$k$-tém kroku algoritmu pøidáme zvlá¹» $k$-tý bod do horní i dolní obálky. Pøidáním $k$-tého bodu se v¹ak mù¾e poru¹it smìr, ve kterém obálka
zatáèí. Proto budeme nejprve body z~obálky odebírat a $k$-tý bod pøidáme a¾ ve chvíli, kdy jeho pøidání smìr zatáèení neporu¹í.

\s{Algoritmus:}

\algo

\:Setøídíme body podle $x$-ové souøadnice, oznaème body $b_1, \ldots, b_n$.
\:Vlo¾íme do horní a dolní obálky bod $b_1$: $H = D = (b_1)$.
\:Pro ka¾dý dal¹í bod $b = b_2,\ldots,b_n$:
\::Pøepoèítáme horní obálku:
\:::Dokud $\vert H\vert \ge 2$, $H = (\ldots, h_{k-1}, h_k)$ a úhel $h_{k-1} h_k b$ je orientovaný doleva:
\::::Odebereme poslední bod $h_k$ z~obálky $H$.
\:::Pøidáme bod $b$ do obálky $H$.
\::Symetricky pøepoèteme dolní obálku (s orientací doprava).
\: Výsledný obal je tvoøen body v~obálkách $H$ a $D$.

\endalgo

Rozebereme si èasovou slo¾itost algoritmu. Setøídit body podle $x$-ové souøadnice doká¾eme v~èase $\O(n \log n)$. Pøidání dal¹ího bodu do obálek
trvá lineárnì vzhledem k~poètu odebraných bodù. Zde vyu¾ijeme obvyklý postup: Ka¾dý bod je odebrán nejvý¹e jednou, a tedy v¹echna odebrání trvají
dohromady $\O(n)$. Konvexní obal doká¾eme sestrojit v~èase $\O(n \log n)$, a pokud bychom mìli seznam bodù ji¾ utøídený, doká¾eme to dokonce v
$\O(n)$.

\s{Algebraický dodatek:} Existuje jednoduchý postup, jak zjistit orientaci úhlu? Uká¾eme si jeden zalo¾ený na lineární algebøe. Budou se hodit
vlastnosti determinantu. Absolutní hodnota determinantu je objem rovnobì¾nostìnu urèeného øádkovými vektory matice. Dùle¾itìj¹í v¹ak je, ¾e znaménko
determinantu urèuje \uv{orientaci} vektorù, zda je levotoèivá èi pravotoèivá. Proto¾e ná¹ problém je rovinný, budeme uva¾ovat determinanty matic $2
\times 2$.

Uva¾me souøadnicový systém v~rovinì, kde $x$-ová souøadnice roste smìrem doprava a~$y$-ová smìrem nahoru. Chceme zjistit orientaci úhlu $h_{k-1} h_k
b$. Polo¾me $\vec u = (x_1, y_1)$ jako rozdíl souøadnic $h_k$ a~$h_{k-1}$ a podobnì $\vec v = (x_2, y_2)$ je rozdíl souøadnic $b$ a~$h_k$. Matice $M$
je definována následovnì:
$$M = \pmatrix{\vec u \cr \vec v} = \pmatrix {x_1&y_1\cr x_2&y_2}.$$
Úhel $h_{k-1} h_k b$ je orientován doleva, právì kdy¾ $\det M = x_1y_2 - x_2y_1$ je nezáporný,\foot{Neboli vektory $\vec u$ a $\vec v$ odpovídají
rozta¾ení a zkosení vektorù báze $\vec x = (1,0)$ a $\vec y = (0,1)$, pro nì¾ je determinant nezáporný.} a spoèítat hodnotu determinantu je jednoduché.
Mo¾né situace jsou nakresleny na obrázku. Poznamenejme, ¾e k~podobnému vzorci se lze také dostat pøes vektorový souèin vektorù $\vec u$ a $\vec v$.

\figure{7-geom4_determinant.eps}{Jak vypadají determinanty rùzných znamének v~rovinì.}{4.6in}

\s{©lo by to vyøe¹it rychleji?} Také vám vrtá hlavou, zda existují rychlej¹í algoritmy? Na závìr si uká¾eme nìco, co na pøedná¹ce nebylo.\foot{A také
se nebude zkou¹et.} Nejrychlej¹í známý algoritmus, jeho¾ autorem je T.~Chan, funguje v~èase $\O(n \log h)$, kde $h$ je poèet bodù le¾ících na
konvexním obalu, a pøitom je pøekvapivì jednoduchý. Zde si naznaèíme, jak tento algoritmus funguje.

Algoritmus pøichází s~následující my¹lenkou. Pøedpokládejme, ¾e bychom znali velikost konvexního obalu $h$. Rozdìlíme body libovolnì do $\lceil {n
\over h} \rceil$ mno¾in $Q_1, \ldots, Q_k$ tak, ¾e $\vert Q_i \vert \le h$. Pro ka¾dou z~tìchto mno¾in nalezneme konvexní obal pomocí vý¹e popsaného
algoritmu. To doká¾eme pro jednu v~èase $\O(h \log h)$ a pro v¹echny v~èase $\O(n \log h)$. V druhé fázi spustíme hledání konvexního obalu pomocí
provázkového algoritmu a pro zrychlení pou¾ijeme pøedpoèítané obaly men¹ích mno¾in. Nejprve popí¹eme jeho my¹lenku. Pou¾ijeme následující pozorování:

\s{Pozorování:} Úseèka spojující dva body $a$ a $b$ le¾í na konvexním obalu, právì kdy¾ v¹echny ostatní body le¾í pouze na jedné její
stranì.\foot{Formálnì je podmínka následující: Pøímka $ab$ urèuje dvì poloroviny. Úseèka le¾í na konvexním obalu, právì kdy¾ v¹echny body le¾í v jedné
z polorovin.}

Algoritmu se øíká {\I provázkový}, proto¾e svojí èinností pøipomíná namotávání provázku podél konvexního obalu.  Zaèneme s bodem, který na konvexním
obalu urèitì le¾í, to je tøeba ten nejlevìj¹í. V ka¾dém kroku nalezneme následující bod po obvodu konvexního obalu. To udìláme napøíklad tak, ¾e
projdeme v¹echny body a vybereme ten, který svírá nejmen¹í úhel s poslední stranou konvexního obalu. Novì pøidaná úseèka vyhovuje pozorování a proto
do konvexního obalu patøí. Po $h$ krocích se dostaneme zpìt k nejlevìj¹ímu bodu a výpoèet ukonèíme. V ka¾dém kroku potøebujeme projít v¹echny body a
vybrat následníka, co¾ doká¾eme v èase $\O(n)$. Celková slo¾itost algoritmu je tedy $\O(n \cdot h)$.

\twofigures{7-geom6_provazkovy_algoritmus.eps}{Provázkový algoritmus.}{1.25in}{7-geom7_naslednik_pres_konvexni_obal.eps}{Hledání kandidáta v pøedpoèítaném obalu.}{2.5in}

Provázkový algoritmus funguje, ale má jednu obrovskou nevýhodu -- je toti¾ ukrutnì pomalý. Ký¾eného zrychlení dosáhneme, pokud pou¾ijeme pøedpoèítané
konvexní obaly. Ty umo¾ní rychleji hledat následníka. Pro ka¾dou z mno¾in $Q_i$ najdeme zvlá¹» kandidáta a poté z nich vybereme toho nejlep¹ího.
Mo¾ný kandidát v¾dy le¾í na konvexním obalu mno¾iny $Q_i$. Vyu¾ijeme toho, ¾e body obalu jsou \uv{uspoøádané}, i kdy¾ trochu netypicky do kruhu.
Kandidáta mù¾eme hledat metodou pùlení intervalu, i kdy¾ detaily jsou malièko slo¾itìj¹í ne¾ je obvyklé. Jak pùlit zjistíme podle smìru zatáèení
konvexního obalu. Detaily si rozmyslí ètenáø sám.

Èasová slo¾itost pùlení je $\O(\log h)$ pro jednu mno¾inu. Mno¾in je nejvý¹e $\O({n \over h})$, tedy následující bod konvexního obalu nalezneme v èase
$\O({n \over h} \log h)$. Celý obal nalezneme ve slibovaném èase $\O(n \log h)$. 

Popsanému algoritmu schází jedna dùle¾itá vìc: Ve skuteènosti vìt¹inou neznáme velikost $h$. Budeme proto algoritmus iterovat s~rostoucí hodnotou $h$,
dokud konvexní obal nesestrojíme. Pokud pøi slepování konvexních obalù zjistíme, ¾e konvexní obal je vìt¹í ne¾ $h$, výpoèet ukonèíme. Zbývá je¹tì
zvolit, jak rychle má $h$ rùst. Pokud by rostlo moc pomalu, budeme poèítat zbyteènì mnoho fází, naopak pøi rychlém rùstu by nás poslední fáze mohla
stát pøíli¹ mnoho.

V~$k$-té iteraci polo¾íme $h = 2^{2^k}$. Dostáváme celkovou slo¾itost algoritmu:
$$\sum_{m=0}^{\O(\log \log h)} \O(n \log 2^{2^m}) = \sum_{m=0}^{\O(\log \log h)} \O(n \cdot 2^m) = \O(n \log h),$$
kde poslední rovnost dostaneme jako souèet prvních $\O(\log \log h)$ èlenù geometrické øady $\sum 2^m$.

\>Kdy¾ s geometrickými problémy poøádnì nezametete, ony vám to vrátí! Ale kdy¾ u¾ zametat, tak urèitì ne pod koberec a místo smetáku pou¾ijte pøímku.
V této pøedná¹ce nás spolu s dvìma geometrickými problémy samozøejmì èeká pokraèování pohádky o ledních medvìdech.

{\I Medvìdi vyøe¹ili rybí problém a hlad je ji¾ netrápí. Av¹ak na severu ne¾ijí sami, za sousedy mají Eskymáky. Proto¾e je rozhodnì lep¹í se sousedy
dobøe vycházet, jsou medvìdi a Eskymáci velcí pøátelé. Skoro ka¾dý se se svými pøáteli rád schází. Av¹ak to je musí nejprve nalézt~\dots}

\h{Hledání prùseèíkù úseèek}

Zkusíme nejprve Eskymákùm vyøe¹it lokalizaci ledních medvìdù.

{\I Kdy¾ takový medvìd nemá co na práci, rád se prochází. Na místech, kde se trasy protínají, je zvý¹ená ¹ance, ¾e se dva medvìdi potkají a zapovídají
-- ostatnì co byste èekali od medvìdù. To jsou ta správná místa pro Eskymáka, který chce potkat medvìda. Jenom¾e jak tato køí¾ení najít?}

Pro zjednodu¹ení pøedpokládejme, ¾e medvìdi chodí po úseèkách tam a zpìt. Budeme tedy chtít nalézt v¹echny prùseèíky úseèek v rovinì.

\bigskip
\centerline{\epsfxsize=1.5in\epsfbox{8-geom2_0_bear.eps}\hskip 4em\epsfxsize2in\epsfbox{8-geom2_1_usecky.eps}}
\smallskip
\centerline{Problém Eskymákù: Kde v¹ude se køí¾í medvìdí trasy?}
\bigskip

Pro $n$ úseèek mù¾e existovat a¾ $\Omega(n^2)$ prùseèíkù.\foot{Zkuste takový pøíklad zkonstruovat.} Tedy optimální slo¾itosti by dosáhl i algoritmus,
který by pro ka¾dou dvojici úseèek testoval, zda se protínají. Èasovou slo¾itost algoritmu v¹ak posuzujeme i vzhledem k velikosti výstupu $p$. Typické
rozmístìní úseèek mívá toti¾ prùseèíkù spí¹e pomálu. Pro tento pøípad si uká¾eme podstatnì rychlej¹í algoritmus.

Pro jednodu¹¹í popis pøedpokládejme, ¾e úseèky le¾í v obecné poloze. To znamená, ¾e ¾ádné tøi úseèky se neprotínají v jednom bodì a prùnikem ka¾dých
dvou úseèek je nejvý¹e jeden bod. Navíc pøedpokládejme, ¾e krajní bod ¾ádné úseèky nele¾í na jiné úseèce a také neexistují vodorovné úseèky. Na závìr si
uká¾eme, jak se s tìmito pøípady vypoøádat.

Algoritmus funguje na principu zametání roviny, popsaném v minulé pøedná¹ce. Budeme posouvat vodorovnou pøímku odshora dolù. V¾dy, kdy¾ narazíme na
nový prùnik, ohlásíme jeho výskyt. Samozøejmì spojité posouvání nahradíme diskrétním a pøímku v¾dy posuneme do dal¹ího zajímavého bodu.

Zajímavé události jsou {\I zaèátky úseèek}, {\I konce úseèek} a {\I prùseèíky úseèek}. Po utøídìní známe pro první dva typy událostí poøadí, v jakém
se objeví. Výskyty prùseèíkù budeme poèítat prùbì¾nì, jinak bychom celý problém nemuseli øe¹it.

V ka¾dém kroku si pamatujeme {\I prùøez} $P$ -- posloupnost úseèek aktuálnì protnutých zametací pøímkou. Tyto úseèky máme utøídìné zleva doprava.  Navíc si
udr¾ujeme kalendáø $K$ budoucích událostí. Z hlediska prùseèíkù budeme na úseèky nahlí¾et jako na polopøímky. Pro sousední dvojice úseèek si
udr¾ujeme, zda se jejich smìry nìkde protnou. Algoritmus pro hledání prùnikù úseèek funguje následovnì:

\s{Algoritmus:}

\algo

\:$P \leftarrow \emptyset$.
\:Do $K$ vlo¾íme zaèátky a konce v¹ech úseèek.
\:Dokud $K \ne \emptyset$:
\::Odebereme nejvy¹¹í událost.
\::Pokud je to zaèátek úseèky, zatøídíme novou úseèku do $P$.
\::Pokud je to konec úseèky, odebereme úseèku z $P$.
\::Pokud je to prùseèík, nahlásíme ho a prohodíme úseèky v $P$.
\::Navíc v¾dy pøepoèítáme prùseèíkové události, v¾dy maximálnì dvì odebereme a dvì nové pøidáme.
\endalgo

Zbývá rozmyslet si, jaké datové struktury pou¾ijeme, abychom prùseèíky nalezli dostateènì rychle. Pro kalendáø pou¾ijeme napøíklad haldu. Prùøez si
budeme udr¾ovat ve vyhledávacím stromì. Poznamenejme, ¾e nemusíme znát souøadnice úseèek, staèí znát jejich poøadí, které se mezi jednotlivými
událostmi nemìní. Pøi pøidávání úseèek procházíme stromem a porovnáváme souøadnice v prùøezu, které prùbì¾nì dopoèítáváme.

Kalendáø obsahuje v¾dy nejvý¹e $\O(n)$ událostí. Podobnì prùøez obsahuje v ka¾dém okam¾iku nejvý¹e $\O(n)$ úseèek.  Jednu událost kalendáøe doká¾eme
o¹etøit v èase $\O(\log n)$. V¹ech událostí je $\O(n+p)$, a tedy celková slo¾itost algoritmu je $\O((n+p) \log n)$.

Slíbili jsme, ¾e popí¹eme, jak se vypoøádat s vý¹e uvedenými podmínkami na vstup. Události kalendáøe se stejnou $y$-ovou souøadnicí budeme tøídit v
poøadí zaèátky, prùseèíky a konce úseèek. Tím nahlásíme i prùseèíky krajù úseèek a ani vodorovné úseèky nebudou vadit. Podobnì se není tøeba obávat
prùseèíkù více úseèek v jednom bodì. Úseèky jdoucí stejným smìrem, jejich¾ prùnik je úseèka, jsou komplikovanìj¹í, ale lze jejich prùseèíky o¹etøit a
vypsat tøeba souøadnice úseèky tvoøící jejich prùnik.

Na závìr poznamenejme, ¾e Balaban vymyslel efektivnìj¹í algoritmus, který funguje v èase $\O(n \log n + p)$, ale je podstatnì komplikovanìj¹í.

\h{Hledání nejbli¾¹ích bodù a Voroného diagramy}

Nyní se pokusíme vyøe¹it i problém druhé strany -- pomù¾eme medvìdùm nalézt Eskymáky.

{\I Eskymáci tráví vìt¹inu èasu doma, ve svém iglù. Takový medvìd je na své toulce zasnì¾enou krajinou, kdy¾ tu se najednou rozhodne nav¹tívit nìjakého
Eskymáka. Proto se podívá do své medvìdí mapy a nalezne nejbli¾¹í iglù. Má to ale jeden háèek, iglù jsou spousty a medvìd by dávno usnul, ne¾ by
nejbli¾¹í objevil.}\foot{Zlí jazykové by øekli, ¾e medvìdi jsou moc líní a nebo v mapách ani èíst neumí!}

Popí¹eme si nejprve, jak vypadá medvìdí mapa. Medvìdí mapa obsahuje celou Arktidu a jsou v ní vyznaèena v¹echna iglù. Navíc obsahuje vyznaèené
oblasti tvoøené body, které jsou nejblí¾e k jednomu danému iglù. Takovému schématu se øíká {\I Voroného diagram}. Ten pro zadané body $x_1, \ldots, x_n$
obsahuje rozdìlení roviny na oblasti $B_1, \ldots, B_n$, kde $B_i$ je mno¾ina bodù, které jsou blí¾e k $x_i$ ne¾ k ostatním bodùm $x_j$. Formálnì jsou
tyto oblasti definovány následovnì:
$$B_i = \left\{y \in {\bb R}^2\ \vert\ \forall j:\rho(x_i,y) \le \rho(x_j,y)\right\},$$
kde $\rho(x,y)$ znaèí vzdálenost bodù $x$ a $y$.

Uká¾eme si, ¾e Voroného diagram má pøekvapivì jednoduchou strukturu. Nejprve uva¾me, jak budou vypadat oblasti $B_a$ a $B_b$ pouze pro dva body
$a$ a $b$, jak je naznaèeno na obrázku. V¹echny body stejnì vzdálené od $a$ i $b$ le¾í na pøímce $p$ -- ose úseèky $ab$. Oblasti $B_a$ a $B_b$
jsou tedy tvoøeny polorovinami ohranièenými osou $p$. Tedy obecnì tvoøí mno¾ina v¹ech bodù bli¾¹ích k $x_i$ ne¾ k $x_j$ nìjakou polorovinu. Oblast
$B_i$ obsahuje v¹echny body, které jsou souèasnì bli¾¹í k $x_i$ ne¾ ke v¹em ostatním bodùm $x_j$ -- tedy le¾í ve v¹ech polorovinách souèasnì.
Ka¾dá z oblastí $B_i$ je tvoøena prùnikem $n-1$ polorovin, tedy je to (mo¾ná neomezený) mnohoúhelník.\foot{Sly¹eli jste u¾ o lineárním programování?
Jak název vùbec nenapoví, {\I lineární programování} je teorii zabývající se øe¹ením a vlastnostmi soustav lineárních nerovnic. Lineární program je
popsaný lineární funkcí, kterou chceme maximalizovat za podmínek popsaných soustavou lineárních nerovnic. Ka¾dá nerovnice urèuje poloprostor, ve
kterém se pøípustná øe¹ení nachází.  Proto¾e pøípustné øe¹ení splòuje v¹echny nerovnice zároveò, je mno¾ina v¹ech pøípustných øe¹ení (mo¾ná neomezený)
mnohostìn, obecnì ve veliké dimenzi ${\bb R}^d$, kde $d$ je poèet promìnných. Mno¾iny $B_i$ lze snadno popsat jako mno¾iny v¹ech pøípustných øe¹ení
lineárních programù pomocí vý¹e ukázaných polorovin. Na závìr poznamenejme, ¾e dlouho otevøená otázka, zda lze nalézt optimální øe¹ení lineárního
programu v polynomiálním èase, byla pozitivnì vyøe¹ena -- je znám polynomiální algoritmus, kterému se øíká {\I metoda vnitøního bodu}. Na druhou
stranu, pokud chceme najít pøípustné celoèíselné øe¹ení, je úloha NP-úplná a je jednoduché na ni pøevést spoustu optimalizaèních problémù. Dokázat
NP-tì¾kost není pøíli¹ tì¾ké. Na druhou stranu ukázat, ¾e tento problém le¾í v NP, není vùbec jednoduché.}
Pøíklad Voroného diagramu je naznaèen na obrázku. Zadané body jsou oznaèeny prázdnými krou¾ky a hranice oblastí $B_i$ jsou vyznaèené èernými èárami.

\twofigures{8-geom2_2_polorovina.eps}{Body bli¾¹í k $a$ ne¾ $b$.}{1.25in}{8-geom2_3_voroneho_diagram.eps}{Voroného diagram.}{2.5in}

Není náhoda, pokud vám hranice oblastí pøipomíná rovinný graf. Jeho vrcholy jsou body, které jsou stejnì vzdálené od alespoò tøí zadaných bodù. Jeho
stìny jsou oblasti $B_i$. Jeho hrany jsou tvoøeny èástí hranice mezi dvìma oblastmi -- body, které mají dvì oblasti spoleèné. Obecnì prùnik dvou
oblastí mù¾e být, v závislosti na jejich sousedìní, prázdný, bod, úseèka, polopøímka nebo dokonce celá pøímka.  V dal¹ím textu si pøedstavme, ¾e celý
Voroného diagram uzavøeme do dostateènì velkého obdélníka,\foot{Pøeci jenom i celá Arktida je omezenì velká.} èím¾ dostaneme omezený rovinný graf.

Poznamenejme, ¾e pøeru¹ované èáry tvoøí hrany duálního rovinného grafu s vrcholy v zadaných bodech. Hrany spojují sousední body na kru¾nicích, které 
obsahují alespoò tøi ze zadaných bodù. Napøíklad na obrázku dostáváme skoro samé trojúhelníky, proto¾e vìt¹ina kru¾nic obsahuje pøesnì tøi zadané
body. Av¹ak nalezneme i jeden ètyøúhelník, jeho¾ vrcholy le¾í na jedné kru¾nici.

Zkusíme nyní odhadnout, jak velký je rovinný graf popisující Voroného diagram. Podle slavné Eulerovy formule má ka¾dý rovinný graf nejvý¹e lineárnì
mnoho vrcholù, hran a stìn -- pro $v$ vrcholù, $e$ hran a $f$ stìn je $e \le 3v-6$ a navíc $v+f = e+2$. Tedy slo¾itost diagramu je lineární vzhledem k
poètu zadaných bodù $n=f$, $\O(n)$. Navíc Voroného diagram lze zkonstruovat v èase $\O(n \log n)$, napøíklad pomocí zametání roviny nebo metodou
rozdìl a panuj. Tím se v¹ak zabývat nebudeme,\foot{Pro zvídavé, kteøí nemají zkou¹ku druhý den ráno: Detaily naleznete v zápiscích z pøedloòského
ADSka.} místo toho si uká¾eme, jak v ji¾ spoèteném Voroného diagramu rychle hledat nejbli¾¹í body.

\h{Lokalizace bodu uvnitø mnohoúhelníkové sítì}

Problém medvìdù je najít v medvìdí mapì co nejrychleji nejbli¾¹í iglù. Máme v rovinì sí» tvoøenou mnohoúhelníky. Chceme pro jednotlivé body rychle
rozhodovat, do kterého mnohoúhelníku patøí. Na¹e øe¹ení budeme optimalizovat pro jeden pevný rozklad a obrovské mno¾ství rùzných dotazù, které chceme
co nejrychleji zodpovìdìt.\foot{Pøedstavujme si to tøeba tak, ¾e medvìdùm zprovozníme server. Ten jednou schroustá celou mapu a potom co nejrychleji
odpovídá na jejich dotazy. Medvìdi tak nemusí v mapách nic hledat, staèí se pøipojit na server a poèkat na odpovìï.} Nejprve pøedzpracujeme zadané
mnohoúhelníky a vytvoøíme strukturu, která nám umo¾ní rychlé dotazy na jednotlivé body.

Uka¾me si pro zaèátek øe¹ení bez pøedzpracování. Rovinu budeme zametat pøímkou shora dolù. Podobnì jako pøi hledání prùseèíkù úseèek, udr¾ujeme si prùøez
pøímkou. V¹imnìte si, ¾e tento prùøez se mìní jenom ve vrcholech mnohoúhelníkù. Ve chvíli, kdy narazíme na hledaný bod, podíváme se, do kterého
intervalu v prùøezu patøí. To nám dá mnohoúhelník, který nahlásíme. Prùøez budeme uchovávat ve vyhledávacím stromì. Takové øe¹ení má slo¾itost $\O(n
\log n)$ na dotaz, co¾ je hroznì pomalé.

Pøedzpracování bude fungovat následovnì. Jak je naznaèeno na obrázku pøeru¹ovanými èárami, rozøe¾eme si celou rovinu na pásy, bìhem kterých se prùøez
pøímkou nemìní. Pro ka¾dý z nich si pamatujeme stav stromu popisující, jak vypadal prùøez pøi procházení tímto pásem. Kdy¾ chceme lokalizovat nìjaký bod,
nejprve pùlením nalezneme pás, ve kterém se nachází. Poté polo¾íme dotaz na pøíslu¹ný strom. Strom procházíme a po cestì si dopoèítáme souøadnice
prùøezu, a¾ lokalizujeme správný interval v prùøezu. Dotaz doká¾eme zodpovìdìt v èase $\O(\log n)$. Hledaný bod je na obrázku naznaèen prázdným
koleèkem a nalezený interval v prùøezu je vyta¾ený tuènì.

\figure{8-geom2_4_pasy_mnohouhelniku.eps}{Mnohoúhelníky rozøezané na pásy.}{2.5in}

Jenom¾e na¹e øe¹ení má jeden háèek: Jak zkonstruovat jednotlivé verze stromu dostateènì rychle? K tomu napomohou {\I èásteènì perzistentní} datové
struktury. Pod perzistencí se myslí, ¾e struktura umo¾òuje uchovávat svoji historii. Èásteènì perzistentní struktury nemohou svoji historii
modifikovat.

Popí¹eme si, jak vytvoøit perzistentní strom s pamìtí $\O(\log n)$ na zmìnu. Pokud provádíme operaci na stromì, mìní se jenom malá èást stromu.
Napøíklad pøi vkládání do stromu se mìní jenom prvky na jedné cestièce z koøene do listu (a pøípadnì rotací i na jejím nejbli¾¹ím okolí). Proto si
ulo¾íme upravenou cestièku a zbytek stromu budeme sdílet s pøedchozí verzí. Na obrázku je vyznaèena cesta, její¾ vrcholy jsou upravovány.  ©edì
oznaèené podstromy navì¹ené na tuto cestu se nemìní, a proto na nì staèí zkopírovat ukazatele. Mimochodem zmìny ka¾dé operace se slo¾itostí $\O(k)$
lze zapsat v pamìti $\O(k)$, prostì operace nemá tolik èasu, aby mohla pozmìnit pøíli¹ velikou èást stromu. 

\figure{8-geom2_5_upravy_stromu.eps}{Jedna operace mìní pouze okolí cesty -- navì¹ené podstromy se nemìní.}{2in}

Celková èasová slo¾itost je tedy $\O(n \log n)$ na pøedzpracování Voroného diagramu a vytvoøení persistentního stromu. Kvùli persistenci potøebuje
toto pøedzpracování pamì» $\O(n \log n)$. Na dotaz spotøebujeme èas $\O(\log n)$, nebo» nejprve vyhledáme pùlením pøíslu¹ný pás a poté polo¾íme dotaz
na pøíslu¹nou verzi stromu. Rychleji to ani provést nepùjde, nebo» potøebujeme utøídit souøadnice bodù.

\s{Lze to lépe?} Na závìr poznamenejme, ¾e se umí provést vý¹e popsaná persistence vyhledávacího stromu v amortizované pamìti $\O(1)$ na zmìnu. Ve
struènosti naznaèíme my¹lenku. Pou¾ijeme stromy, které pøi insertu a deletu provádí amortizovanì jenom konstantnì mnoho úprav své struktury. To nám
napøíklad zaruèí 2-4 stromy z pøedná¹ky a podobnou vlastnost lze dokázat i o èerveno-èerných stromech. Pøi zmìnì potom nebudeme upravovat celou cestu,
ale upravíme jenom jednotlivé vrcholy, kterých se zmìna týká. Ka¾dý vrchol stromu si v sobì bude pamatovat a¾ dvì své verze. Pokud chceme vytvoøit
tøetí verzi, vrchol zkopírujeme stranou. To v¹ak mù¾e vyvolat zmìny v jeho rodièích a¾ do koøene. Situace je naznaèena na obrázku. Pøi vytvoøení nové
verze $3$ pro vrcholu $v$ vytvoøíme jeho kopii $v'$, do které ulo¾íme tuto verzi. Av¹ak musíme také zmìnit rodièe $u$, kterému vytvoøíme novou verzi
ukazující na $v'$. Abychom dosáhli ký¾ené konstantní pamì»ové slo¾itosti, pomù¾e potenciálový argument -- zmìn se provádí amortizovanì jenom
konstantnì mnoho. Navíc si pro ka¾dou verzi pamatujeme její koøen, ze kterého máme dotaz spustit.

\figure{8-geom2_6_rychla_perzistence.eps}{Vytvoøení nové verze vrcholu.}{2in}

\bye
