Přechod na menu, Přechod na obsah, Přechod na patičku

Průnik polorovin

V této kapitole si ukážeme, jak efektivně popsat a najít průnik $n$ polorovin v rovině. Chceme postupovat rekurentně podle strategie „rozděl a panuj“. To znamená, že množinu

$$H=\{h_1,h_2,\dots,h_n\}$$

zadaných polorovin rozdělíme na dvě přibližně stejně velké části $H_1$ a $H_2$ a průnik

$$C=\bigcap_{h_i\in H}h_i$$

počítáme jako jako průnik $C_1\cap C_2$, kde

$$C_1=\bigcap_{h_i\in H_1}h_i,\qquad C_2=\bigcap_{h_i\in H_2}h_i.$$

Zásadní roli pro postupné počítání průniků $C_1\cap C_2$ má způsob, kterým budeme průniky polorovin popisovat.

Popis průniku polorovin

Průnik polorovin je konvexní množina, která může být jak omezená, tak neomezená. Vylučme případ, že mezi polorovinami jsou dvě navzájem opačné. V tomto případě by průnik byl podmnožinou jejich společné přímky a šlo by o jednodimenzionální úlohu o průniku polopřímek na přímce.

Pokud je tedy průnik polorovin omezený a dvoudimenzionální, jde o konvexní mnohoúhelník a ten umíme popsat pomocí dvojitě souvislého seznamu s dvěma oblastmi, jednou omezenou a jednou neomezenou. Pro případ, že je průnik neomezený musíme tento popis modifikovat. Za tímto účelem použijeme lexikografické uspořádání bodů v rovině definované takto:

$$p\gt q \quad\text{právě když}\quad p_y\gt q_y \ \text{nebo}\ p_y=q_y\ \text{a}\ p_x\lt q_x.$$

Uvažujme nyní neprázdnou konvexní množinu $C$, která je průnikem polorovin a přitom není podmnožinou přímky. Nastane právě jedna z následujících možností:

  1. Množina C má v daném lexikografickém uspořádání maximální bod $p$ a minimální bod $q$. Oba leží na hranici a dělí ji na levou a pravou část, zkráceně na levou a pravou hranici. Každá z nich je lomená čára určená posloupností vrcholů a úseček, tyto posloupnosti budeme označovat $L(C)$ a $P(C)$.
    Obrázek 5.1
    Obrázek 5.1
    Levá hranice množiny $C$ je $L(C)=(p=v_1,e_1,v_2,e_2,v_3,e_3,q=v_4)$, pravá hranice je $P(C)=(p=v_1,e_7,v_7,e_6,v_6,e_5, v_5,e_4,q=v_4)$.
  2. Množina $C$ obsahuje maximální bod $p$, ale neobsahuje minimální bod. V tomto případě dělí bod $p$ hranici množiny opět na dvě části, levou a pravou. Každá z nich je lomená čára. Určuje ji posloupností vrcholů a úseček zakončená polopřímkou.
    Obrázek 5.2
    Obrázek 5.2
    Levá hranice $L(C)=(p=v_1,e_1,v_2,e_2,v_3,e_3)$, pravá hranice $P(C)=(p=v_1,e_7,v_7,e_6,v_6,e_5, v_5,e_4)$.
  3. Množina $C$ obsahuje minimální bod $q$, ale neobsahuje maximální bod. V tomto případě dělí bod $q$ hranici množiny opět na dvě části, levou a pravou. Jde o lomené čáry určené posloupnostmi, které začínají polopřímkou, za kterou následují vrcholy a úsečky.
    Obrázek 5.3
    Obrázek 5.3
    $L(C)=(e_1,v_2,e_2,v_3,e_3,q=v_4)$, $P(C)=(e_7,v_7,e_6,v_6,e_5, v_5,e_4,q=v_4)$.
  4. Množina $C$ neobsahuje maximální bod ani minimální bod. V tomto případě má hranice levou a pravou část jenom v případě, že jde o rovnoběžné přímky. V ostatních případech má hranice pouze jedinou část, buď levou nebo pravou. Ta je určena buď jedinou přímkou nebo posloupností začínající a končící polopřímkou, mezi nimiž je posloupnost vrcholů a úseček. O druhé části hranice budeme mluvit jako o prázdné.
    Obrázek 5.4
    Obrázek 5.4
    Vlevo: $L(C)=(e_1)$, $L(C)=(e_2)$. Vpravo: $L(C)=(e_1,v_2,e_2,v_3,e_3)$, $P(C)=(\ )$.

Algoritmus pro určení průniku

Nechť $C_1$ a $C_2$ jsou konvexní množiny, které vznikly jako průniky disjunkních množin polorovin. Proto jsou určeny svou levou a pravou hranicí. Popíšeme algoritmus, který z těchto čtyř posloupností vytvoří dvě posloupnosti popisující levou a pravou hranici průniku $C_1\cap C_2$.

K tomu si stačí uvědomit, že vrcholy v levé hranici $C_1\cap C_2$ jsou následující body:

Obrázek 5.5
Obrázek 5.5
Vrcholy levé hranice průniku jsou $p$ – průsečík $L(C_2)$ a $P(C_1)$, $w_2\in L(C_2)$ ležící v $C_1$, $q$ – průsečík $L(C_1)$ a $L(C_2)$, $v_3\in L(C_1)$ ležící v $C_2$ a $r$ – průsečík $L(C_1)$ a 

Analogicky vrcholy v pravé hranici $C_1\cap C_2$ jsou:

K vytvoření seznamů $L(C_1\cap C_2)$ a $P(C_1\cap C_2)$ musíme tedy vybrat vhodné hraniční vrcholy $C_1$ a $C_2$, spočítat průsečíky hranic a vybrané vrcholy lexikograficky uspořádat. Náš algoritmus se tedy bude podobat algoritmu pro nalezení průsečíků úseček z kapitoly 1. Událostmi budou vrcholy hranic $C_1$ a $C_2$ a vypočtené průsečíky hranic. Na začátku algoritmu uspořádáme vrcholy hranic lexikograficky do fronty. Vzhledem k tomu, že v obou levých a pravých hranicích jsou vrcholy již uspořádány, tak vytvoření fronty trvá čas úměrný počtu vrcholů. Postupně budeme do fronty událostí také zařazovat vypočtené průsečíky hranic $C_1$ a $C_2$. Vzhledem k tomu, že budeme vědět, na které úsečce, resp. polopřímce, resp. přímce hranice leží, jejich zařazení do fronty bude trvat pouze konstantní čas.

V případě, že ani jedna z konvexních množin $C_1$ a $C_2$ nemá maximální bod, spočteme průniky polopřímek (přímek), kterými levé i pravé hranice obou oblastí začínají. Protože $C_1$ a $C_2$ jsou průniky disjunkních množin polorovin, tak průniky hranic budou buď prázdné konečné množiny bodů. Takto získané body zařadíme do fronty.

Zametací horizontální přímka $l$ postupuje shora dolů. Začíná v poloze nad nejvyšší událostí. U každé události ve frontě budeme evidovat, na které leží hranici a které úsečky, polopřímky nebo přímky (pro všechny tři typy objektů budeme používat společné označení hrana) jí procházejí. Rovněž budeme evidovat v jakém pořadí protínají hrany jednotlivých hranic zametací přímku. Vzhledem k tomu, že jde o pořadí nejvýše čtyř objektů, není potřeba uvažovat strom. Při průchodu přímky událostí $v$ provádíme následující akce:

Algoritmus končí v okamžiku, kdy je fronta událostí prázdná.

Pseudokódy a jejich časová náročnost

Algoritmus 1: HalfplanesIntersection($H$)

Input. Množina $n$ polorovin $H=\{h_1,h_2,\dots,h_n\}$.

Output. Průnik $C$ všech polorovin popsaný pomocí levé a pravé hranice.

  1. if $n=1$ then
  2. urči levou a pravou hranici.
  3. else
  4. polož $H_1=\{h_1,h_2,\dots,h_{[n/2]}\}$, $H_2=H\setminus H_1$.
  5. $C_1 \leftarrow $ HalfplanesIntersection($H_1$).
  6. $C_2 \leftarrow $ HalfplanesIntersection($H_2$).
  7. $C \leftarrow $ IntersectionOfTwo($C_1,C_2$).
  8. end

Průnik dvou konvexních množin získáme takto:

Algoritmus 2: IntersectionOfTwo($C_1,C_2$)

Input. Konvexní množiny $C_1$ a $C_2$ popsané pomocí levé a pravé hranice.

Output. Průnik $C=C_1\cap C_2$ popsaný pomocí seznamu $L(C)$ pro levou hranici a seznamu $P(C)$ pro pravou hranici.

  1. Polož $L(C)=(\ )$ a $P(C)=(\ )$.
  2. if $C_1$ a $C_2$ jsou poloroviny then
  3. spočítej $L(C)$ a $P(C)$.
  4. else
  5. vytvoř z vrcholů $C_1$ a $C_2$ frontu událostí.
  6. end
  7. if $C_1$ a $C_2$ nejsou omezené shora then
  8. spočítej průsečíky hraničních polopřímek nebo přímek, kterými začínají levé a pravé hranice obou množin, a zařaď je do fronty.
  9. end
  10. while je fronta událostí neprázdná do
  11. vezmi její největší vrchol $v$
  12. HandleEvent($C_1,C_2,v$)
  13. end
  14. return $L(C_1\cap C_2)$ a $P(C_1\cap C_2)$.

Průchod zametací přímky přes událost $v$ zachycuje následující pseudód:

Algoritmus 3: HandleEvent($C_1,C_2,v$)

Input. Vrchol $v$ na hranici $C_1$ nebo $C_2$ a seznamy $L(C_1\cap C_2)$ a $P(C_1\cap C_2)$ pro levou a pravou hranici průniku nad $v$.

Output. Aktualizované seznamy $L(C_1\cap C_2)$ a $L(C_1\cap C_2)$.

  1. Polož $L(C)=(\ )$ a $P(C)=(\ )$.
  2. if $v\in L(C_i)$ leží mezi pravou a levou hranicí $C_j$, $i\neq j$ then
  3. zařaď $v$ do $L(C_1\cap C_2)$.
  4. end
  5. if $v\in P(C_i)$ leží mezi pravou a levou hranicí $C_j$, $i\neq j$ then
  6. zařaď $v$ do $P(C_1\cap C_2)$.
  7. end
  8. if $v$ je v průniku levých hranic then
  9. zařaď $v$ do $L(C_1\cap C_2)$.
  10. end
  11. if $v$ je v průniku pravých hranic then
  12. zařaď $v$ do $P(C_1\cap C_2)$.
  13. end
  14. if $v$ je v průniku levé hranice $C_i$ a pravé hranice $C_j$, $i\neq j$ then
  15. zařaď $v$ do $L(C_1\cap C_2)$ i $P(C_1\cap C_2)$.
  16. end
  17. if $v$ leží $L(C_1\cap C_2)$ nebo v $P(C_1\cap C_2)$ then
  18. if $v$ je prvý vrchol v $L(C_1\cap C_2)$ nebo v $P(C_1\cap C_2)$ then
  19. zjisti, které z polopřímek s dolním vrcholem $v$ patří do $L(C_1\cap C_2)$ nebo $P(C_1\cap C_2)$.
  20. end
  21. Zjisti, která z hran s horním vrcholem $v$ patří do $L(C_1\cap C_2)$ nebo $P(C_1\cap C_2)$.
  22. end
  23. Mezi hranami pod bodem $v$, které jím procházejí, vyber tu nejvíce vlevo, $e_l$, a tu nejvíce vpravo, $e_p$. K $e_l$ najdi levou sousední hranu $s_l$ z hranice druhé oblasti. K $e_p$ najdi z hranice druhé oblasti pravou sousední hranu $s_p$.
  24. Spočítej průsečíky $s_l\cap e_l$ a $s_p\cap e_p$ pod bodem $v$ a zařaď je do fronty.
  25. if $v$ je poslední člen posloupnosti $L(C_1\cap C_2)$ (tj. není následován hranou) then
  26. vymaž všechny události z fronty
  27. else
  28. vymaž $v$ z fronty
  29. end
  30. return $L(C_1\cap C_2)$ a $P(C_1\cap C_2)$.

Časová náročnost posledního pseudokódu je konstantní. Nechť konvexní množiny $C_1$ a $C_2$ jsou popsány $n_1$ a $n_2$ vrcholy. Potom časová náročnost pseudokódu IntersectionOfTwo($C_1,C_2$) je $O(n_1+n_2)$.

Časová náročnost $T(n)$ celého algoritmu pro výpočet průniku $n$ polorovin je dána rekurentně vztahem

$$T(n)=2T\left(\frac{n}{2}\right)+O(n).$$

Ten vede k výsledné časové náročnosti

$$T(n)=O(n\log n).$$

Animace

Výpočet průniku dvou konvexních množin $C_1$ a $C_2$ podle druhého a třetího algoritmu je zachycen v následující animaci.