Recepty z programátorské kuchařky
Rovinné grafy

Zobraz historii verzí Skryj historii verzí

Aktuální verze kuchařky: 2016

Aktuální verze – 2016
* Výměna příkladů použití barvení (vysílače)
* Změna některých cvičení k zamyšlení
* Reformulace a sazečské úpravy textu
Kuchařková knížka, 1. vydáníčervenec 2011(Pavel Veselý, Martin Mareš, Petr Škoda)
+ Motivační příklad barvení mapy
+ Barvení grafů
+ Cvičení
+ Natíráme 6 barvami
+ Třešnička na dortu: 5 barev stačí
- Prvních několik částí kuchařky bylo odstraněno kvůli stejnému obsahu s kuchařkou grafy
- Ingredience
- Orientované grafy
- Reprezentace grafů
- Recepty
- Progledávání do hloubky
- Prohledávání do šířky
- Topologické uspořádání
- Hranová a vrcholová souvislost
* Reformulace některých částí textu
Leták 17-3listopad 2004(Martin Mareš, Petr Škoda)
* První verze

Na úvod položme otázku: „Stačí čtyři barvy na obarvení libovolné politické mapy, aby žádné dva sousedící státy neměly stejnou barvu?“ Za sousedící státy se nepovažují ty, které sousedí jen v jediném bodě (ba ani v konečně mnoha).

Na první pohled jednoduchá otázka, že? Matematici se s ní však trápili více jak století (od první formulace v roce 1852 do vyřešení v roce 1976) a nikdo nebyl schopen přijít s důkazem ani s protipříkladem, tedy mapou, na níž je potřeba pět barev. Třeba i na tuto mapu jsou potřeba jen čtyři barvy:

Mapa obarvitelná čtyřmi barvami

Nebudeme dlouho tajit odpověď: čtyři barvy stačí. Důkaz se spoléhá na strojové probírání stovek případů (fragmentů rovinných grafů) a ve své době pro svou domnělou nematematičnost vzbudil velké pozdvižení. Dodnes se snaží mnoho vědců najít jednodušší důkaz, podobně jako u Velké Fermatovy věty.

My si ukážeme, jak každou politickou mapu obarvit šesti barvami, a od toho přejdeme k pěti barvám. Nejdříve si však převedeme politické mapy na rovinné grafy a předvedeme si několik jejich užitečných vlastností.

Cvičení

Rovinné grafy

Rovinný graf (někdy též nazývaný planární) je graf, který můžeme nakreslit do roviny bez křížení hran. To znamená, že vrcholům přiřadíme vhodné body a hrany nakreslíme jako křivky spojující příslušné body tak, že se žádné dvě křivky neprotínají mimo své krajní body.

Ne každý graf lze takto nakreslit – sami si rozmyslete, že například graf K5, což je 5 vrcholů spojených každý s každým, žádné rovinné nakreslení nemá. Na druhou stranu například každý strom určitě rovinný je.

Vezměme si tedy nějaký graf a jeho rovinné nakreslení, například tento:

Rovinné nakreslení grafu

Hrany nakreslení dělí rovinu na několik oblastí, těm budeme říkat stěny. Náš graf má 6 stěn: jednu čtvercovou, čtyři „trojúhelníkové“ (tedy ohraničené třemi hranami, byť to nejsou vždy úsečky) a jednu 6-úhelníkovou (to je celý zbytek roviny okolo grafu, tzv. vnější stěna).

Například libovolné rovinné nakreslení stromu by mělo pouze jednu stěnu, a to tu vnější. Všimněte si, že pokud v grafu nejsou mosty ani artikulace, je každá stěna ohraničena nějakou kružnicí. (Pozor, to, jak vypadají stěny, závisí na konkrétním nakreslení do roviny!)

Barvení grafů

Jistě byste dokázali vymyslet převod politické mapy se státy na graf. Jen pro úplnost: samotné státy budou vrcholy a hrana povede mezi vrcholy právě tehdy, když odpovídající státy sousedí.

Podobně jako se barví politické mapy, lze barvit i grafy. Samozřejmě ne doslova, barvením se zpravila myslí přiřazování přirozených čísel jednotlivým vrcholům pod podmínkou, že sousední vrcholy nesmí mít stejnou barvu. Důležitou vlastností grafu je pak jeho barevnost, neboli nejmenší počet barev, kterými se dá obarvit. Úvodní problém tedy vlastně říká, že barevnost každého rovinného grafu je nejvýše čtyři.

V praxi má barvení grafů (nejen rovinných) velké využití. Jako příklad si můžeme vzít určování frekvencí vysílačů mobilního signálu, kdy dva na sebe vidící vysílače nemohou dostat stejnou frekvenci. Zároveň chceme jako operátor použít co možná nejméně frekvencí to jde, a tak pro mapu sousedících vysílačů chceme vysílače „obarvit“ frekvencemi tak, aby měly každé dva sousedící vysílače jinou.

Dobré je poznamenat, že tato úloha může být chápána jako úloha na rovinných i nerovinných grafech – ve městské zástavbě docela často najdeme alespoň pětici vysílačů, kde na sebe každé dva vysílače vidí.

Cvičení k zamyšlení

Vlastnosti rovinných grafů

O rovinných grafech platí několik důležitých vět, které se často hodí při vytváření grafových algoritmů.

Je zřejmé, že každý strom je rovinný. Navíc pro každý strom platí, že má o jedna méně hran než vrcholů (tedy e=v-1, kde v je počet vrcholů a e počet hran). Proč tomu tak je? Abychom tvrzení dokázali, použijeme indukci podle počtu vrcholů – ukážeme platnost tvrzení pro strom s jedním vrcholem a potom s použitím indukčního předpokladu (že tvrzení platí pro všechny stromy s méně jak v vrcholy) dokážeme tvrzení i pro strom s v vrcholy.

Pro strom s jedním vrcholem formulka určitě platí. Strom s v>1 vrcholy má jistě list, tak jej odtrhneme (poněkud vandalské, nicméně účinné), čímž získáme strom s menším počtem vrcholů, pro který podle indukčního předpokladu formulka platí, a opětovným přidáním listu platit nepřestane, protože k oběma stranám přičteme jedničku. Dokázáno.

Vztah počtu vrcholů, hran a stěn

Počet stěn souvislého rovinného grafu je pevně určen počtem vrcholů a hran, aniž by záleželo na konkrétním nakreslení do roviny nebo dokonce na tom, mezi kterými vrcholy hrany vedou. Pro každý souvislý rovinný graf nakreslený do roviny totiž platí tzv. Eulerova formule uvádějící do vztahu počet vrcholů v, počet hran e a počet stěn f:

v+f=e+2

Důkaz: Opět indukcí, tentokráte podle počtu hran. Každý souvislý graf má alespoň v-1 hran, a pokud jich má právě tolik, je to strom. Protože každé rovinné nakreslení stromu má právě jednu stěnu, tak bude v tomto případě Eulerova formule platit.

Pokud máme nakreslení grafu, který je souvislý a není to strom, znamená to, že obsahuje alespoň jednu kružnici. A každá hrana na kružnici jistě odděluje nějaké dvě stěny. Zvolme si tedy nějakou takovou hranu h a z grafu ji odeberme. Tím získáme graf s menším počtem hran (opět nakreslený do roviny), použijeme indukční předpoklad, Eulerova formule pro něj tedy již platí, a vrátíme hranu zpět. Levá strana rovnosti se tím zvětší o 1 (přidali jsme stěnu), pravá také (přidali jsme hranu), tedy rovnost stále platí.

Cvičení k zamyšlení

Omezení počtu hran

Intuicí snadno odhalíte, že velké rovinné grafy nemohou mít spoustu hran, protože by nešly nakreslit bez křížení. Hran je dokonce lineárně, protože platí následující nerovnost (pro grafy s alespoň třemi vrcholy):

e ≤ 3v-6

Nejprve jednoduchá aplikace: výše jsme zmínili, že K5 (úplný graf na 5 vrcholech) není rovinný. Má totiž 10 hran, ale naše formulka mu dovoluje jen 9. Takto se dá o spoustě „hustých“ grafů dokázat, že nejsou rovinné, bohužel však tvrzení neplatí obráceně a existují grafy s 3v-6 vrcholy (nebo méně), které nejsou rovinné.

Pěkným příkladem je vzít si třeba nerovinný K5 a přidat mu k jednomu vrcholu ocásek. I ocásek o pouze jednom vrcholu způsobí, že hran bude 11, vrcholů 6 a nerovnost tak bude splněna, ale graf je nerovinný.

Důkaz: Jak tuto nerovnost dokázat? Zvolme si libovolné nakreslení grafu do roviny. Nejprve předpokládejme, že je to triangulace, čili že každá stěna je trojúhelník. V takovém grafu patří každá hrana k právě dvěma trojúhelníkovým stěnám, takže e=f·3/2, čili f=e·2/3. Dosazením do Eulerovy formule získáme v+(2/3)e=e+2, tedy e=3v-6.

Není-li náš graf triangulace, může to mít několik důvodů. Není souvislý (pak ale stačí větu dokázat pro jednotlivé komponenty a nerovnosti sečíst), nebo je moc malý (má nejvýše dva vrcholy, ale tak malé grafy neuvažujeme) anebo obsahuje nějakou stěnu ohraničenou více než třemi hranami. Dovnitř takové stěny ovšem můžeme dokreslit další hrany a tím ji rozdělit na trojúhelníčky. Tím tedy dokážeme graf doplnit hranami na triangulaci a pro tu, jak už víme, platí dokonce rovnost. Když přidané hrany opět odebereme, snížíme pouze počet hran a uděláme tak z rovnosti nerovnost.

Cvičení k zamyšlení

Vrchol nízkého stupně

Dokážeme, že v každém rovinném grafu existuje vrchol stupně maximálně 5 (stupeň vrcholu je počet hran, které do vrcholu vedou). Proč tomu tak musí být? Kdyby všechny vrcholy měly stupeň alespoň 6, byl by součet stupňů alespoň 6v. Jenže součet stupňů je přesně dvojnásobek počtu hran (každá hrana má dva konce), takže e≥ 3v, což je spor s předchozí větou.

Cvičení

Natíráme 6 barvami

Konečně máme všechny potřebné ingredience (i se zdůvodněním, abyste nám věřili) a můžeme se pustit do barvení. Jelikož máme zaručený vrchol stupně maximálně 5, vezmeme ho, odebereme z grafu a zařadíme na zásobník. Odebráním se určitě neporušila rovinnost grafu, takže vezmeme další vrchol stupně maximálně 5. Takto pokračujeme rekurzivně, dokud nerozebereme celý graf a nenaskládáme všechny vrcholy na zásobník.

Jelikož jsme odebírali vrcholy stupně maximálně 5, má každý vrchol na zásobníku nad sebou nejvýše 5 sousedů v původním grafu. Z toho už je patrný barvící algoritmus: budeme postupně odebírat z vrchu zásobníku a u každého vrcholu máme jistotu, že mezi jeho sousedy chybí jedna barva (některé sousední vrcholy jsou samozřejmě ještě neobarvené, ale obarvených je maximálně 5).

Co se týče implementace, jediným problémem je hledání vrcholů stupně 5 a méně. Řešení však není těžké na vymyšlení, ani na programování: stačí na začátku naskládat všechny vrcholy stupně maximálně 5 do nějaké datové struktury (hodí se třeba fronta) a potom si uvědomit, že při odebírání vrcholu z grafu je potřeba se podívat jen na jeho sousedy, jestli jim neklesl stupeň na 5.

Jak rychle tento algoritmus poběží na grafu s N vrcholy a M hranami? Nejprve si trochu zjednodušíme odhady, protože víme, že počet hran je v rovinných grafech omezený počtem vrcholů – stačí nám tak v odhadech počítat pouze s N.

Na začátku si potřebujeme u každého vrcholu spočítat stupeň a všechny vrcholy stupně maximálně 5 přidat do fronty, což zvládneme v čase O(N). Pak již jen bereme vrcholy z fronty, přidáváme je do zásobníku a přitom aktualizujeme stupně sousedů. Když se nějaký soused dostane také na stupeň 5, tak ho přidáme do fronty.

Každý vrchol přidáme i odebereme z fronty právě jednou, takže přitom strávíme také čas O(N). A nakonec vybírání vrcholů ze zásobníku a jejich barvení také zvládneme v O(N), tedy i celý algoritmus stihneme za čas O(N).

Třešnička na dortu: 5 barev

Danger!Algoritmus na obarvení rovinného grafu 5 barvami má stejný průběh jako předchozí představený, tedy se postupně rozebírá graf (mimo jiné se odebírají vrcholy) a potom se barví vrcholy v obráceném pořadí, než se zpracovávaly. Jenže tentokrát nelze přímočaře obarvit vrcholy stupně 5 (s vrcholy s menšími stupni můžeme zacházet stejně).

K vyřešení problému se nám bude hodit operace kontrakce hrany, která jednu danou hranu odstraní a spojí její dva koncové vrcholy u,v do nového vrcholu w. Hrany vedoucí z u a v do jiných vrcholů nyní povedou z w, násobné hrany se smažou (tzn. pokud uv měly společného souseda, z w do něj povede jen jedna hrana).

Operace kontrakce hrany

Prvně je důležité pozorování, že mezi sousedy vrcholu v stupně 5 v rovinném grafu, existuje alespoň jedna dvojice vrcholů, mezi kterými nevede hrana. (Kdyby tomu tak nebylo, obsahuje tento graf K5 jako podgraf, a tudíž nemůže být rovinný.) Najdeme tedy dvojici x,y sousedů v, která není spojena hranou, a místo odstranění v provedeme kontrakci hran xv a yv do vrcholu w. Vrchol v přidáme na zásobník (při implementaci se hodí také uložit, jaké hrany se zkontrahovaly) a pokračujeme rekurzivně s kontrahovaným grafem.

Při samotném obarvování, narazíme-li na zkontrahovaný vrchol v, máme už obarvený vrchol w vzniklý kontrakcí (nechť má například barvu 1). Jelikož sousedi w zahrnují sousedy vrcholů x a y, dáme těmto dvěma vrcholům barvu 1 a žádný jejich soused určitě už nedostal stejnou barvu. Vrcholu v pak přidělíme jinou barvu, kterou nemají jeho 3 zbývající sousedi, ani x (tedy ani y). Barev je 5, takže to akorát vyjde.

Tím jsme zakončili povídání o barvicích algoritmech, samotnou implementaci ponecháme čtenáři jako cvičení.

Poznámky

Pavel Veselý, Martin Mareš a Petr Škoda