b je * injektivní (nebo také prostá) právě když pro každé x,y E a, x ^ y platí f(x) ý f{v)'i
* surjektivní (nebo také „na") právě když pro každé y E b existuje x E a takové, že
f (x) = y,
"V—i (7)
Y
bijektivní (vzáj. jednoznačná) právě když je injektivní a současně surjektivní.
"V—i
"V
x=--
Komentář: Následují jiné ukázky vlastností funkcí.
* Funkce plus : N x N —> N je surjektivní, ale není prostá.
* Funkce g : TL —> N daná předpisem
-2x — 1 jestliže x < 0,
y w = ^ 2
je bijektivní.
v ' 1 2x jinak
46
* Funkce 0 : 0 —> 0 je bijektivní.
* Funkce 0 : 0 —?► {a, b} je injektivní, ale není surjektivní.
* Dokázali byste nalézt bijektivní funkci NxN-> N?
Inverze funkce
Komentář: Příklady inverzí pro relace-funkce (viz Oddíl 4.4).
* Inverzí bijektivní funkce f(x) = x + 1 na Z je funkce f^1(x) = x — 1.
* Inverzí prosté funkce f(x) = ex na R je parciální funkce f^1(x) = lnx.
* Funkce g(x) = x mod 3 není prostá na N, a proto její inverzí je „jen" relace g^1 = {(a,b) | a = b mod 3}. Konkr. s"1 = {(0, 0), (0, 3), (0, 6),... , (1,1), (1,4),... , (2, 2), (2, 5),... }.
Tvrzení 6.2. Mějme funkcí f : A —>• B. Pak její inverzní relace f~ľ je
a) parciální funkce právě když f je prostá,
b) funkce právě když f je bijektivní.
Důkaz vyplývá přímo z definic funkce a inverze relace. □ 6.2 Skládání funkcí, permutace
Soustřeďme se nyní na tuto další oblast, kde běžně a přirozeně používáme skládání relací, aniž si to uvědomujeme.
Fakt: Mějme zobrazení (funkce) f: A^tB&g: B^tC. Pak jejich složením coby relací v tomto pořadí vznikne zobrazení (g o /) : A —> C definované
(9° f)(x) =g(f(x))-
Komentář:
* Jak například na běžné kalkulačce vypočteme hodnotu funkce sin2 x ? Složíme (v tomto pořadí) „elementární" funkce f(x) = sin x a g(x) = x2.
* Jak bychom na „elementární" funkce rozložili aritmetický výraz 21og(x2 + 1)? Ve správném pořadí složíme funkce fi(x) = x2, f2(2) = x + 1, fs(x) = log x a f±(x) = 2x.
* A jak bychom obdobně vyjádřili složením funkcí aritmetický výraz sin x + cos x? Opět je odpověď přímočará, vezmeme „elementární" funkce g\ (x) = sin x a g2Íx) = cosx, a pak je „složíme" další funkcí h(x, y) = x + y. Vidíme však, že takto pojaté „skládání" už nezapadá hladce do našeho zjednodušeného formalismu skládání relací.
Pro nedostatek prostoru si skládání funkcí s více parametry nedefinujeme, ale sami vidíte, že obdobné skládání se v programátorské praxi vyskytuje doslova „na každém rohu" a ani se nad tím nepozastavujeme.
Skládání permutací
Po zbytek tohoto oddílu se zaměříme na permutace coby speciální případ (bijektivních) zobrazení.
47
Definice: Nechť permutace 7r množiny {1,2,... ,n} je určena seřazením jejích prvků (pi,... ,pn)- Pak 7T je zároveň bijektivním zobrazením {1,..., n} —> {1,..., n} definovaným předpisem ir(i) = Pí. Tudíž lze permutace skládat jako relace podle Definice 4.7.
Poznámka: Všechny permutace množiny {1,2,... ,n} spolu s operací skládání tvoří grupu, zvanou symetrická grupa Sn. Permutační grupy (podgrupy symetrické grupy) jsou velice důležité v algebře, neboť každá grupa je vlastně isomorfní některé permutační grupě.
Komentář: Příkladem permutace vyskytujícím se v programátorské praxi je třeba zobrazení i i—> (i + 1) mod n ("inkrement"). Často se třeba lze setkat (aniž si to mnohdy uvědomujeme) s permutacemi při indexaci prvků polí.
V kontextu pohledu na funkce a jejich skládání coby relací si zavedeme jiný, názornější, způsob zápisu permutací - pomocí jejich cyklů.
Definice: Nechť 7r je permutace na množině A. Cyklem v 7r rozumíme posloupnost {ai, a2, ■ ■ ■, Ofc) různých prvků A takovou, že 7r(<2j) = ai+1 pro i = 1,2,..., k — 1 a 7r(afc) = d\.
Jak název napovídá, v zápise cyklu (ai, a2,..., ak) není důležité, kterým prvkem začneme, ale jen dodržení cyklického pořadí. Cyklus v permutaci může mít i jen jeden prvek (zobrazený na sebe).
Komentář: Nakreslete si (vámi zvolenou) permutaci tv obrázkem, ve kterém vedete šipku vždy od prvku i k prvku tt(í). Pak uvidíte, že cykly dle naší definice jsou právě cykly tvořené šipkami ve vašem obrázku. S tímto grafickým zobrazením pro vás nebude problém pochopit následující látku.
Například permutaci (5, 3,4, 8, 6,1, 7, 2) si lze obrázkem nakreslit takto:
Reprezentace permutací jejich cykly
Věta 6.3. Každou permutací tt na konečné množině A lze zapsat jako složení cyklů na disjunktních podmnožinách (rozkladu) A.
Důkaz: Vezmeme libovolný prvek a\ G A a iterujeme zobrazení a2 = 7r(ai), 03 = Tffa), atd., až se dostaneme „zpět" k a^+i = ^(a^) = d\- Proč tento proces skončí? Protože A je konečná a tudíž ke zopakování některého prvku a^+i musí dojít. Nadto je 7r prostá, a proto nemůže nastat ^(a^) = clj pro j > 1. Takto získáme první cyklus (a1;..., a^).
Induktivně pokračujeme s hledáním dalších cyklů ve zbylé množině A' = A \ {ai,..., aj-}, dokud nezůstane prázdná. V tomto indukčním kroku si musíme uvědomit, že 7T omezené na nosnou množinu A' je stále permutací podle definice (neboli žádná prvek z A' se nezobrazí do {a1;..., a^}). □
Značení permutace jejími cykly: Nechť se permutace 7r podle Věty 6.3 skládá z cyklů (ai,..., Ofc), (&!,..., bi) až třeba (z1}..., zm). Pak zapíšeme
7T = ((ai,..., ak) (61,..., bi) ... {zu ...,zm)).
48
Komentář: Primitivní pseudonáhodné generátory v počítačích iterují z náhodného počátku permutaci danou vztahem i i—> (i + p) mod q. Je pochopitelné, že tato permutace nesmí obsahovat krátké cykly, lépe řečeno, měla by se skládat z jediného (dlouhého) cyklu. (Pro úplnost, jedná se o permutaci množiny {0,1,... , q — 1}).
Příklad 6.4. Ukázka skládání permutací daných svými cykly.
Vezměme 7-prvkovou permutaci 7r = (3,4, 5, 6, 7,1, 2). Ta se skládá z jediného cyklu (1, 3, 5, 7, 2,4, 6). Jiná permutace o = (5, 3,4, 2, 6,1, 7) se rozkládá na tři cykly (1, 5, 6), (2, 3,4} a (7). Nyní určíme složení a on těchto dvou permutací (už přímo v zápisu cykly):
((1, 5, 6)(2, 3,4}(7}) o ((1, 3, 5, 7, 2,4, 6}) = ((1,4}(2}(3, 6, 5, 7})
(Nezapomínejme, že první se ve složení aplikuje pravá permutace!)
Postup skládání jsme použili následovný: 1 se zobrazí v permutaci vpravo na 3 a pak vlevo na 4. Následně 4 se zobrazí na 6 a pak na 1. Tím „uzavřeme" první cyklus (1,4). Dále se 2 zobrazí na 4 a pak hned zpět na 2, tj. má samostatný cyklus. Zbylý cyklus (3, 6, 5, 7} určíme analogicky. □
6.3 Induktivní definice množin a funkcí
Dalším výkladem se vracíme k podstatě množin a funkcí a k jejich popisu. Vzpomeňme si na definici posloupnosti rekurentním vztahem z Oddílu 3.4. Přímým zobecněním dřívějších rekurentních definic je následující koncept.
Definice 6.5. Induktivní definice množiny.
Jedná se obecně o popis (nějaké) množiny M v následujícím tvaru:
• Je dáno několik pevných (bazických) prvků a±, a2,..., aj- G M.
• Je dán soubor induktivních pravidel typu
Jsou-li (libovolné prvky) x±,..., x p G M, pak také y G M. V tomto případě je y typicky funkcí y = fi(xi,..., x e).
Pak naše induktivně definovaná množina M je určena jako nejmenší (inkluzí) množina vyhovující těmto pravidlům.
Komentář: Několik ukázek... • Pro nejbližší příklad induktivní definice se obrátíme na množinu všech přirozených čísel, která je formálně zavedena následovně.
- 0 G N
- Je-li i G N, pak také i + 1 G N.
• Pro každé y G N můžeme definovat jinou množinu My C N induktivně takto:
- V G My
- Jestliže x G My a x + 1 je liché, pak x + 2 G My. Pak například M3 = {3}, nebo M4 = {4 + 2i | i G N}.
• Dalším příkladem induktivní definice je už známé zavedení výrokových formulí z Oddílu 1.5. Uměli byste teď přesně říci, co tam byly bázické prvky a jaká byla induktivní pravidla? A jaká byla v definici formulí role přítomných závorek? K tomu se blíže vyjádříme v Definici 6.6.
49
Jednoznačnost induktivních definic
Definice: Řekneme, že daná induktivní definice množiny M je jednoznačná, právě když každý prvek M lze odvodit z bázických prvků pomocí induktivních pravidel právě jedním způsobem.
Komentář: Definujme například množinu M C N induktivně takto:
- 2,3 G M
- Jestliže x, y G M a x < y, pak také x2 + y2 a x ■ y jsou prvky M.
Proč tato induktivní definice není jednoznačná? Například číslo 8 G M lze odvodit způsobem 8 = 2 • (2 • 2), ale zároveň zcela jinak 8 = 22 + 22.
V čem tedy spočívá důležitost jednoznačných induktivních definic množin? Je to především v dalším možném využití induktivní definice množiny jako „základny" pro odvozené vyšší definice, viz následující Definice 6.6 a třeba doplňková Věta 6.9. Stručně a neformálně řečeno, hlavní role jednoznačnosti induktivní definice je v možnosti pak přiřadit prvkům této induktivní množiny nějaký „jednoznačný význam".
Induktivně definovaná množina povětšinou nemá význam sama o sobě, avšak poskytuje defíniční obor pro následnou induktivně definovanou funkci:
Definice 6.6. Induktivní definice funkce z induktivní množiny.
Nechť množina M je dána jednoznačnou induktivní definicí. Pak říkáme, že funkce ÍF :
M —> X je definována induktivně (vzhledem k induktivní definici M), pokud je řečeno:
• Pro každý z bázických prvků ai,a,2,... ,a,k G M je určeno ÍF(ai) = q, kde q je konstanta.
• Pro každé induktivní pravidlo typu
"Jsou-li (libovolné prvky) x±,... ,xe G M, pak také f(xi,..., x i) G M" je definováno
f(xi,..., Xi)) na základě hodnot ÍF(xi),..., ÍF(xe).
Komentář: Ilustrujme si induktivní definici funkce dětskou hrou na „tichou poštu". Definičním oborem je řada sedících hráčů, kde ten první je bázickým prvkem a každý následující (mimo posledního) odvozuje hráče sedícího hned za ním jako další prvek hry. Hodnotou bázického prvku je první (vymyšlené) posílané slovo. Induktivní pravidlo pak následujícímu hráči přiřazuje slovo, které je odvozeno ze („zkomolením") slova předchozího hráče. Výsledkem hry pak je hodnota-slovo posledního hráče.
Pro další příklad se podívejme třeba do manuálových stránek unixového příkazu test EXPRESSION:
EXPRESSION is true or falše and sets exit status. It is one of:
( EXPRESSION ) EXPRESSION is true
! EXPRESSION EXPRESSION is falše
EXPRESSI0N1 -a EXPRESSI0N2 both EXPRESSI0N1 and EXPRESSI0N2 are true
EXPRESSI0N1 -o EXPRESSI0N2 either EXPRESSI0N1 or EXPRESSI0N2 is true
[-n] STRING the length of STRING is nonzero
STRING1 = STRING2 the strings are equal
Vidíte, jak tato ukázka koresponduje s Definicí 6.6 ? No, ne úplně, poněkud problematická je otázka jednoznačnosti této definice - jednoznačnost není vynucena (jen umožněna) syntaktickými pravidly, jinak je pak dána nepsanými konvencemi implementace příkazu. To je pochopitelně z matematického hlediska velmi špatně, ale přesto jde o pěknou ukázku z praktického života informatika.
50
Induktivní definice se „strukturální" indukcí
Závěrem ještě doplňkově zařazujeme malou ukázku, kterak přirozeně zkombinovat induktivní definice s „pokročilou formou matematické indukce" v dokazování, s tzv. strukturální indukcí.
Příklad 6.7. Jednoduché aritmetické výrazy a jejich význam.
Nechť je dána abeceda E = {0,1, 2, 3,4, 5, 6, 7, 8, 9, 0, ©, (,)}. Definujme množinu jednoduchých výrazů SExp C S* induktivně takto:
- Dekadický zápis každého přirozeného čísla n je prvek SExp.
- Jestliže x,y G SExp, pak také (x) 0 (y) a (x) © (y) jsou prvky SExp.
- Jak vidíme, díky nucenému závorkování je tato induktivní definice jednoduchých výrazů (nikoliv jejich „hodnot") jednoznačná.
Tímto jsme aritmetickým výrazům přiřadili jejich „formu", tedy syntaxi.
Pro přiřazení „významu", tj. sémantiky aritmetického výrazu, následně definujme funkci Val: SExp —> N induktivně takto:
- Bázické prvky: Val(n) = n, kde n je dekadický zápis přirozeného čísla n.
- První induktivní pravidlo: Val((x) © (y)) = Val(x) + Val(y).
- Druhé induktivní pravidlo: Val((x) 0 (y)) = Val(x) ■ Val(y).
Co je tedy správným významem („hodnotou") uvedených aritmetických výrazů? (Příklad 6.8) □
Příklad 6.8. Důkaz správnosti přiřazeného „významu" Val: SExp —> N.
Věta. Pro každý výraz s G SExp je hodnota Val(s) z Příkladu 6.7 číselně rovna výsledku vyhodnocení výrazu s podle běžných zvyklostí aritmetiky.
Jelikož pojednáváme o induktivně definované funkci Val, je přirozené pro důkaz jejích vlastností aplikovat matematickou indukci. Na rozdíl od dříve probíraných příkladů zde nevidíme žádný celočíselný „parametr n", a proto si jej budeme muset nejprve definovat. Naši indukci tedy povedeme podle „délky l odvození výrazu s" definované jako počet aplikací induktivních pravidel potřebných k odvození s G SExp.
Důkaz: V bázi indukce ověříme vyhodnocení bázických prvků, kteréžto jsou zde dekadické zápisy přirozených čísel. Platí Val(n) = n, což skutečně odpovídá zvyklostem aritmetiky.
V indukčním kroku se podíváme na vyhodnocení Val((x) © (y)) = Val(x) + Val(y). Podle běžných zvyklostí aritmetiky by hodnota Val((x) © (y)) měla být rovna součtu vyhodnocení výrazu x, což je podle indukčního předpokladu rovno Val(x) (x má zřejmě kratší délku odvození), a vyhodnocení výrazu y, což je podle indukčního předpokladu rovno Val(y). Takže skutečně Val((x) ©(?/)) = Val(x) + Val(y).
Druhé pravidlo Val((x) 0 (y)) se dořeší analogicky. □
Dodatek: důkaz pro normální tvar formule
V Oddíle 1.5 jsme stručně zavedli výrokovou matematickou logiku a výrokové formule. Nyní si snadno můžeme všimnout, že jak definice syntaxe, tak i definice sémantiky výrokové logiky jsou induktivní ve smyslu (po řadě) Definic 6.5 a 6.6. Také Metoda 1.18
51
pro převod formule do normálního tvaru je induktivní, a proto je na místě následující ilustrativní ukázka důkazu strukturální indukcí:
Věta 6.9. Pro libovolnou výrokovou formuli ip platí (viz Metoda 1.18), že
a) Jr(ip) je ekvivalentní formule k ip v normálním tvaru
b) a Q(íp) je formule v normálním tvaru ekvivalentní negaci ~np.
Důkaz povedeme indukcí ke struktuře formule, neboli indukci povedeme podle „délky" l - počtu aplikací induktivních pravidel při sestavování formule ip.
• Báze indukce (l = 0): Pro všechny atomy, tj. výrokové proměnné, zřejmě platí, že F(Á) = A je ekvivalentní A a Q (A) = ->A je ekvivalentní —i A.
• V indukčním kroku předpokládejme, že a) i b) platí pro všechny formule ip délky nejvýše l. Vezmeme si formuli ip délky £+1, která je utvořená jedním z následujících způsobů:
* ifj = -np (= je „definiční rovnítko" pro formule). Podle výše uvedeného induktivního předpisu je ^(ip) = ^(—np) = Q(- ip2). Podle výše uvedeného induktivního předpisuje ^(ip) = Fifi =>• (P2) = Fifi) =>• Jr(\ a ip2. Potom i Ti^px) =>• J-'(^2) je v normálním tvaru dle definice a podle sémantiky =>- je ta ekvivalentní formuli (• ¥2) = J^i^i) A G (^2)- Jelikož A je pro nás jen zkratka, výraz dále rozepíšeme G{ip) = ^{^{^1) =^ ~^G(- ip2, což jsme zde měli dokázat.
* ip = (tpi\/tp2). Zde si musíme opět uvědomit, že spojka V je pro nás jen zkratka, a přepsat ip = (-1^1 =>• ?2)- Potom podle předchozích dokázaných případů víme, že ^(ip) = ^(-ii^i =>• 2) = .F(-i?i) =>• ^(^2) je ekvivalentní formuli (->• ^2) = ip, což bylo třeba dokázat. Stejně tak G{ip) = G(~"fi =>• f 2) = ^ľ{~l(-Pi) A G{$2) je podle předchozích případů důkazu ekvivalentní (—upi A -1^2) = ~''lP-
* ip = (tpi A ip2) a ip = (ipi (p2) už dokončíme analogicky. 6.4 Uzávěry relací
Posledním bodem našeho výkladu je vysvětlení postupu, jak danou relaci můžeme „obohatit" o zvolenou vlastnost (například proto, že naše data o relaci jsou neúplná a vlastnost je tak poškozena). Toto se pochopitelně týká pouze vlastností, které lze nějak ustanovit prostým přidáním dvojic do existující relace, jak říká následující definice.
Definice: Buď V (nějaká) vlastnost binárních relací. Řekneme, že V je uzavíratelná, pokud splňuje následující podmínky:
52
* Pro každou množinu M a každou relaci R C M x M existuje alespoň jedna relace S C M x M, která má vlastnost V a pro kterou platí R C S.
* Nechť J je množina a nechť Ri C M x M je relace mající vlastnost V pro každé i E I. Pak relace P|ieí ma vlastnost V.
Fakt: Libovolná kombinace vlastností reňexivita, symetrie, tranzitivita je uzavíratelná vlastnost. Ireflexivita a antisymetrie nejsou uzavíratelné vlastnosti.
Věta 6.10. Nechť V je uzavíratelná vlastnost binárních relací. Buď M množina a R libovolná binární relace na M. Pak pro množinu všech relací S D R na M majících vlastnost V existuje infímum Ry (vzhledem k množinové inkluzi), které samo má vlastnost V.
Definice: Tuto „nejmenší" relaci Ry s vlastností V nazýváme V-uzávěrrelace R.
Zmíněný V-uzávěr relace je vlastně daný induktivní definicí (viz Definice 6.5), kde báze je původní relace a induktivní pravidla odpovídají vlastnosti V.
Tvrzení 6.11. Nechť R je binární relace na M. Pak platí následující poznatky.
* Reflexivní uzávěr R je přesně relace R U {{x, x) \ x G M}.
* Symetrický uzávěr R je přesně relace R= {(x, y) | (x, y) G R nebo (y, x) G R}.
* Tranzitivní uzávěr R je přesně relace R+ = T1 {R), kde T je funkce, která pro každou binární relaci S vrátí relaci
ľ (S) = S U {(x, z) | existuje y takové, že (x, y), (y, z) G S}
a T% = X ° ''' °Ty Je í-krát iterovaná aplikace funkce T.
i
* Reflexivní a tranzitivní uzávěr R je přesně relace R* = Q+, kde Q je reflexivní uzávěr R.
* Reflexivní, symetrický a tranzitivní uzávěr R (tj. nejmenší ekvivalence obsahující R) je přesně relace (Q)+, kde Q je reflexivní uzávěr R.
* Na pořadí aplikování uzávěrů vlastností záleží! (Zhruba řečeno, tranzitivní uzávěr aplikujeme coby poslední.)
Komentář: Význam reflexivních a symetrických uzávěrů je z předchozího docela zřejmý. Význam tranzitivního uzávěru R+ je následovný: Do R+ přidáme všechny ty dvojice (x, z) takové, že v i? se lze „dostat po šipkách" z x do z. Nakreslete si to na papír pro nějakou jednoduchou relaci, abyste význam tranzitivního uzávěru lépe pochopili.
•-í=—•-í=—•-5=—»
A jak bylo dříve řečeno, antisymetrický uzávěr relace prostě nedává smysl. Například buď fiCNxN definovaná takto: R = {(i, i +1) | i G N}. Pak R* je běžné lineární uspořádání < přirozených čísel.
53
Příklad 6.12. Proč při výpočtu tranzitivního uzávěru relace na konečné množině podle vzorce R+ = \Jt*L1T"t(R) vždy stačí uvažovat konečně mnoho členů tohoto sjednocení?
Pro odpověď si uvědomme zásadní fakt — pokud 7~í+1 = T\ tak už platí 7~í+fc = T% pro všechna přirozená k. Neboli je potřeba sjednotit jen tolik prvních členů, dokud se ony „zvětšují", což může nastat jen konečně krát nad konečnou množinou. Mimo jiné tak vidíme, že uvedený popis tranzitivního uzávěru je konstruktivní. □
Rozšiřující studium
S formalizací pojmu funkce a jejími vlastnostmi se setkáváte především v matematice, avšak například na bijektivní funkce narazíte při ukládání dat při volbě klíče apod. Našim cílem bylo ukázat práci s funkcemi v jejich abstraktní podobě, tj. bez vazby na nějaký konkrétní analytické vzoreček.
Poslední částí látky o množinách a relacích je problematika induktivních deňnic, které ač ve formálním podání mohou nejprve vypadat nepochopitelně, jsou ve skutečnosti zcela přirozenou popisnou metodou v mnoha aplikačních sférách informatiky a jejich alespoň intuitivní chápání pro vás bude v dalším studiu nezbytné. Schválně, zkuste se podívat zrovna do vaší oblíbené oblasti informatiky, kde všude induktivní definice, tj. ty odvolávající se rekurzivně samy na sebe pro „menšípřípady", najdete (třeba nepřímo).
54
7 Pojem grafu, ve zkratce
Úvod
Třebaže grafy jsou jen jednou z mnoha struktur v matematice a vlastně pouze speciálním případem binárních relací, vydobyly si svou užitečností a názorností důležité místo na slunci. Dá se bez nadsázky říci, že teorie grafů je asi nejvýznamnější součástí soudobé diskrétní matematiky, a proto se jí budeme věnovat po tři následující lekce. Avšak pozor, nepleťme si graf s grafem funkce!
Neformálně řečeno, graf se skládá z vrcholů (představme si je jako nakreslené „puntíky") a z hran, které spojují dvojice vrcholů mezi sebou. Své důležité místo v informatice si grafy získaly dobře vyváženou kombinací svých vlastností - snadno pochopitelným názorným nakreslením a zároveň jednoduchým zpracováním na počítačích. Díky těmto vlastnostem se grafy prosadily jako vhodný matematický model pro popis různých vztahů mezi daty a objekty.
Cíle
Deňnujeme, co je graf a jaké jsou nejzákladnější grafové pojmy (třeba hrany a stupně, podgrafy, souvislost). Klademe důraz na to, aby se čtenář naučil grafy „uchopit" a pracovat s nimi, také aby správně viděl „stejnost" (isomorňsmus) grafů. Poté se věnujeme nej jednoduššímu druhu grafů, totiž stromům. Jedná se vesměs o pojmy, které se hojně vyskytují v obvyklých informatických aplikacích grafů.
7.1 Definice grafu
Hned na úvod přistoupíme k formální definici grafu. Bude se jednat o definici tzv. jednoduchého neorientovaného grafu, který budeme považovat za základní, pokud neřekneme jinak. Svým způsobem navazujeme na reprezentace relací v Oddíle 4.2.
Definice 7.1. Graf je uspořádaná dvojice G = (V, E),
kde V je konečná množina vrcholů a E je množina hran - množina vybraných dvouprvkových podmnožin množiny vrcholů; tj. E C .
Značení: Hranu mezi vrcholy uati píšeme jako {u, v}, nebo zkráceně uv. Vrcholy spojené hranou jsou sousední a, hrana uv vychází z vrcholů u a v. Na množinu vrcholů známého grafu G odkazujeme jako na V(G), na množinu hran E(G).
Komentář: Grafy se často zadávají přímo názorným obrázkem, jinak je lze formálně zadat výčtem vrcholů a výčtem hran. Například:
1 _
2 3 4
V = {1,2,3,4}, e = {{1,2}, {1,3}, {1,4}, {3,4}}
Na graf se lze dívat také jako na symetrickou ireflexivní relaci, kde hrany tvoří právě dvojice prvků z této relace.
55
Stupně vrcholů v grafu
Máme-li graf, často nás zajímá, kolik z kterého vrcholu vychází hran-spojnic, neboli kolik má vrchol „sousedů". Proto jedním z prvních definovaným pojmů bude stupeň vrcholu v grafu.
Definice 7.2. Stupněm vrcholu v v grafu G
rozumíme počet hran vycházejících z v. Stupeň v v grafu G značíme de (v).
Komentář: Slovo „vycházející" zde nenaznačuje žádný směr; je totiž obecnou konvencí u neorientovaných grafů říkat, že hrana vychází z obou svých konců zároveň.
Například v nakreslené ukázce jsou stupně přímo zapsány u vrcholů.
Definice: Graf je d-regulární, pokud všechny jeho vrcholy mají stejný stupeň d.
Značení: Nejvyššístupeň v grafu G značíme A(G) a nejnižší b~(G).
Věta 7.3. Součet stupňů v grafu je vždy sudý, roven dvojnásobku počtu hran.
Důkaz. Při sčítání stupňů vrcholů v grafu započítáme každou hranu dvakrát - jednou za každý její konec. Proto výsledek vyjde sudý. □
Příklad 7.4. Zodpovězte si sami následující otázky:
* Kolik hran má graf se 17 vrcholy stupňů 4?
* Existují dva „různé" grafy se 6 vrcholy stupňů 2? □ Běžné typy grafů
Pro snadnější vyjadřování je zvykem některé běžné typy grafů nazývat popisnými jmény. Jde čistě o věc konvence a autoři se mohou v některých názvech lišit (i přicházet s novými názvy), avšak následujících pět názvů patří k všeobecným základům teorie grafů.
Kružnice délky n má n > 3 různých vrcholů spojených „do jednoho cyklu" n hranami:
56
Cesta délky n > O má n + 1 různých vrcholů spojených „za sebou" n hranami:
pn •-•-•-•-•-•
1 2 3 4 • • • n ra + 1
Úplný graf na n > 1 vrcholech má n různých vrcholů spojených po všech dvojicích (tj. celkem Q) hran):
4 i 3 i 2
t: 1
6 i ■ r?.
Úplný bipartitní graf nam> lan> 1 vrcholech má m+n vrcholů ve dvou skupinách (partitách), přičemž hranami jsou spojeny všechny m ■ n dvojice z různých skupin:
1 2 3 4 ... m V 2' 3' • • • rí
Hvězda s n > 1 rameny je zvláštní název pro úplný bipartitní graf KijTl:
Definice: Formálně nechť kružnice délky n > 3 je graf Cn, kde V(Cn) = {1, 2,..., n} a E(Cn) = {{i,i + 1} : 1 < i < n) U {{n, 1}}. Nechť cesto délky n > 0 je graf Pn, kde V(Pn) = {1,2,... ,n + l} aE(Pn) = {{i,i + l} : 1 < i < n+l}. Nechť úplný graf na n > 1 vrcholech je i^, kde V(Kn) = {1, 2,..., n} a E(Kn) = {{i,j} : l lan > 1 vrcholech je Km,n, kde V(Km,n) = {1,2,... ,m, m+ 1,..., m + n} a E(Km^n) = {{i,j} '■ 1 < * < m, m + 1 < j < m + n}.
Příklad 7.5. Zodpovězte si sami následující otázky:
* Pro jakou hodnotu n je úplný graf iín zároveň cestou?
* Pro jakou hodnotu n je úplný graf Kn zároveň kružnicí?
* Pro jaké hodnoty m,n > 0 je úplný bipartitní graf Km,n zároveň kružnicí?
* Kolik hran musíte přidat do kružnice délky 6, aby vznikl úplný graf na 6 vrcholech?
* Pro jaké hodnoty m,n > 0 úplný bipartitní graf Km,n neobsahuje žádnou kružnici?□
57
Zmínka o zobecněných grafech
Komentář: Všimněme si, že v definici grafu (Def. 7.1) vůbec neuvažujeme možnosti vícenásobných hran (mezi stejnou dvojicí vrcholů) a tzv. „smyček" (hrana se stejným jedním koncem)—takovému zobecnění by se říkalo multigraf; ani zatím nepřisuzujeme hranám žádný směr.
V Lekci 9 si však ještě zavedeme orientované grafy, které každé hraně přiřazují jistý směr. Orientované grafy budou mít množinu orientovaných hran A C V (G) x V (G) a zobrazíme je třeba takto...
7.2 Podgrafy a Isomorfismus
Dva základní nástroje pro práci s grafy jsou následující; možnost popisovat „část grafu" (podobně jako podmnožinu množiny, avšak je nutno se vyvarovat nekorektních situací) a poznávat „stejnost" dvou grafů.
Definice: Podgrafem grafu G rozumíme libovolný graf H na podmnožině vrcholů V(H) C V (G), který má za hrany libovolnou podmnožinu hran grafu G majících oba vrcholy ve V(H).
Píšeme H C G, tj. stejně jako množinová inkluze (ale význam je trochu jiný).
Komentář: Na následujícím obrázku vidíme zvýrazněné podmnožiny vrcholů hran. Proč se vlevo nejedná o podgraf? Obrázek vpravo už podgrafem je.
Definice: Indukovaným podgrafem je podgraf H C G takový, který obsahuje všechny hrany grafu G mezi dvojicemi vrcholů z V(H).
„Stejnost" grafů
Pozorný čtenář si možná již při čtení předchozího oddílu položil otázku: Co když vezmeme jeden graf (třeba kružnici délky 4) a nakreslíme nebo zapíšeme jej jednou tak, podruhé zase jinak - je to stále tentýž graf nebo ne? Viz obrázky dole.
58
Přísně formálně řečeno, každé další nakreslení jistého grafu, třeba této kružnice C4, je jiným grafem, ale přitom bychom rádi řekli, že různá nakreslení téhož grafu jsou „stále stejná". Pro tuto stejnost grafů se vžil pojem isomorfní grafy.
Definice 7.6. Isomorfismus ~ grafů G a, H
je bijektivní (vzájemně jednoznačné) zobrazení / : V(G) —> V(H), pro které platí, že každá dvojice vrcholů u,v G V (G) je spojená hranou v G právě tehdy, když je dvojice f(u),f(v) spojená hranou v H.
Grafy G a H jsou isomorfní, pokud mezi nimi existuje isomorfismus. Píšeme G ~ H.
Fakt: Mějme isomorfismus / grafů G a H. Pak platí následující
* G a H mají stejný počet hran,
* / zobrazuje na sebe vrcholy stejných stupňů, tj. de (v) = du(f(v)).
U výše zakreslených dvou grafů objevíme isomorfismus velmi snadno - podíváme se, jak si odpovídají vrcholy stejných stupňů.
Naopak v této trojici grafů (se stejnými počty vrcholů i hran) žádné dva nejsou isomorfní. Proč? Ten vlevo má vrchol stupně 4, čímž se od obou zbylých liší. Prostřední graf pak má jediné dva vrcholy stupně 2 spojené hranou, kdežto v pravém takové dva vrcholy spojené nejsou (isomorfismus by je však i s hranou musel zachovat).
Příklad 7.7. Jsou následující dva grafy isomorfní?
59
Pokud mezi nakreslenými dvěma grafy hledáme isomorfismus, nejprve se podíváme, zda mají stejný počet vrcholů a hran. Mají. Pak se podíváme na stupně vrcholů a zjistíme, že oba mají stejnou posloupnost stupňů 2, 2, 2, 2, 3, 3. Takže ani takto jsme mezi nimi nerozlíšili a mohou (nemusejí!) být isomorfní. Dále tedy nezbývá, než zkoušet všechny přípustné možnosti zobrazení isomorfismu z levého grafu do pravého.
Na levém grafu si pro ulehčení všimněme, že oba vrcholy stupně tři jsou si symetrické, proto si bez újmy na obecnosti můžeme vybrat, že nejlevější vrchol prvního grafu, označme jej 1, se zobrazí na nejlevější vrchol ľ v druhém grafu (taky stupně tři). Očíslujme zbylé vrcholy prvního grafu 2,... ,6 v kladném smyslu, jak je ukázáno na následujícím obrázku. Druhý vrchol stupně tři, označený 4, se musí zobrazit na analogický vrchol druhého grafu (pravý spodní). Pak je již jasně vidět, že další sousedé 2, 6 vrcholu 1 se zobrazí na analogické sousedy 2', 6' vrcholu ľ v druhém grafu, a stejně je to i se zbylými vrcholy 3, 5. Výsledný isomorfismus vypadá v odpovídajícím značení vrcholů takto:
Abychom mohli s isomorfismem grafů přirozeně pracovat, je potřeba vědět následující fakt:
Věta 7.8. Relace „být isomorfní" ~ na třídě všech grafů je ekvivalencí.
Důkaz. Relace ~ je reflexivní, protože graf je isomorfní sám sobě identickým zobrazením. Relace je také symetrická, neboť bijektivní zobrazení lze jednoznačně obrátit. Tranzitivita ~ se snadno dokáže skládáním zobrazení-isomorfismů. □
Důsledkem je, že všechny možné grafy se rozpadnou na třídy isomorfismu. V praxi pak, pokud mluvíme o grafu, myslíme tím obvykle jeho celou třídu isomorfismu, tj. nezáleží nám na konkrétní prezentaci grafu.
Komentář: Je uvedený přístup, tj. zaměňování konkrétního grafu za celou jeho třídu isomorfismu, v matematice neobvyklý? Ne, například už v geometrii jste říkali „čtverec o straně 2" či „jednotkový kruh" a podobně, aniž jste měli na mysli konkrétní obrázek, nýbrž celou třídu všech těchto shodných objektů.
Další grafové pojmy
Definice: Mějme libovolný graf G.
* Podgrafu H C G, který je isomorfní nějaké kružnici, říkáme kružnice v G.
* Speciálně říkáme trojúhelník kružnici délky 3.
* Podgrafu H C G, který je isomorfní nějaké cestě, říkáme cesta v G.
* Podgrafu H C G, který je isomorfní nějakému úplnému grafu, říkáme klika v G. (Někdy se za kliku považuje pouze takový úplný podgraf, který je maximální vzhledem k uspořádání inkluzí.)
60
* Podmnožině vrcholů X C V(G), mezi kterými nevedou v G vůbec žádné hrany, říkáme nezávislá množina X v G.
* Indukovanému podgrafu H C G, který je isomorfní nějaké kružnici, říkáme indukovaná kružnice v G.
Komentář: Uvažujme následující ukázky grafů:
První z ukázaných grafů například neobsahuje žádný trojúhelník, ale obsahuje kružnici délky 4, dokonce indukovanou. Druhý graf trojúhelník obsahuje a kružnici délky 4 taktéž. První graf obsahuje cestu délky 4 na vrcholech 1, 2, 3,4, 5, ale ta není indukovaná. Indukovaná cesta délky 4 v něm je třeba 2,3,4,5,6. Druhý graf tyto cesty také obsahuje, ale naopak žádná z nich není indukovaná. První graf má největší kliku velikosti 2 - jedinou hranu, kdežto druhý graf má větší kliku na vrcholech 3,4, 5. Největší nezávislá množina u obou grafů má 3 vrcholy 2,4, 6.
Fakt: Mějme isomorfismus / grafů G a H. Pokud G obsahuje podgraf F, pak H také musí obsahovat podgraf isomorfní F. Obecněji lze tvrdit, že počet podgrafu v grafu G isomorfních zvolenému F je vždy roven takovému počtu v grafu H.
Příklad 7.9. Jsou následující dva grafy isomorfní?
Postupovat budeme jako v Příkladě 7.7, nejprve ověříme, že oba grafy mají stejně mnoho vrcholů i stejnou posloupnost stupňů 2, 2, 2, 2, 3, 3. Pokud se však budeme snažit najít mezi nimi isomorfismus, něco stále nebude vycházet, že? Co nám tedy v nalezení isomorfismu brání? Podívejme se, že v druhém grafu oba vrcholy stupně tři mají svého společného souseda, tvoří s ním trojúhelník. V prvním grafu tomu tak není, první graf dokonce nemá žádný trojúhelník. Proto zadané dva grafy nejsou isomorfní. □
Poznámka: Výše uvedené příklady nám ukazují některé cesty, jak poznat (tj. najít nebo vyloučit) isomorfismus dvou grafů. Ty však ne vždy musí fungovat. Čtenář se může ptát, kde tedy najde nějaký univerzální postup pro nalezení isomorfismu? Bohužel vás musíme zklamat, žádný rozumný univerzální postup není znám a zatím platí, že jediná vždy fungující cesta pro nalezení či nenalezení isomorfismu mezi dvěma grafy je ve stylu vyzkoušejte všechny možnosti bijekcí mezi vrcholy těchto grafů. (Těch je, jak známo, až n\)
7.3 Souvislost grafů, komponenty
Důležitou globální vlastností grafů je souvislost, tedy možnost se v nich pohybovat odkudkoliv kamkoliv podél jeho hran, neboli po cestách v grafu. Tuto vlastnost si nyní upřesníme.
61
Tvrzení 7.10. Mějme relací ~ na množině vrcholů V(G) libovolného grafu G takovou, že pro dva vrcholy x ~ y právě když existuje v G cesta začínající v x a koněící v y. Pak ~ je relací ekvivalence.
Důkaz. Relace ~ je reflexivní, neboť každý vrchol je spojený sám se sebou cestou délky 0. Symetrická je také, protože cestu z x do y snadno v neorientovaném grafu obrátíme na cestu z y do x. Důkaz tranzitivity však není takto triviální—pokud vezmeme cestu z x do y a cestu z y do z, tak se tyto dvě cesty mohou protínat i jinde než v y a nelze je prostě „navázat" na sebe.
Pro důkaz tranzitivity si označme P cestu z x do y a Q cestu z y do z. Pokud označíme P' C P tu část první cesty z x do prvního vrcholu p v průniku s Q (tj. p G V (P) H V (Q)) a označíme Q' C Q zbytek druhé cesty od p do z, tak P' U Q' vždy je cestou z x do z. □
Dennice 7.11. Komponentami souvislosti grafu G nazveme
třídy ekvivalence výše popsané (Tvrz. 7.10) relace ~ na V(G). Jinak se také komponentami souvislosti myslí podgrafy indukované na těchto třídách ekvivalence.
Komentář: Podívejte se, kolik komponent souvislosti má tento graf:
Vidíte v obrázku všechny tři komponenty? Jedna z nich je izolovaným vrcholem, druhá hranou (tj. grafem isomorfním K2) a třetí je to zbývající.
Definice 7.12. Graf G je souvislý
pokud je G tvořený nejvýše jednou komponentou souvislosti, tj. pokud každé dva vrcholy G jsou spojené cestou.
Poznámka: Prázdný graf je souvislý a má 0 komponent. Komentář: Který z těchto dvou grafů je souvislý?
Příklad 7.13. Dokažme si, že každý souvislý jednoduchý 2-regulární graf G je kružnicí (tj. isomorfní některé kružnici Cn z Oddílu 7.1).
Nechť e je hranou mezi vrcholy u,v grafu G a vezměme graf G' = G — e vzniklý odebráním hrany e. Pokud by u a v náležely v G' různým komponentám souvislosti, tyto
62
komponenty by každá měla lichý součet stupňů, což nelze podle Věty 7.3. Proto u a, v jsou spojeny cestou v G', nechť vrcholy této cesty jsou po řadě značeny ui = u, u2,... ,Uk = v. Toto značení nám nyní udává isomorfismus zobrazující vrchol u,i na vrchol i z definice kružnice Ck- Nyní už zbývá jen drobnost; dokázat, že jiné vrcholy než ui,... ,Uk v grafu G nejsou. Pokud bychom měli další vrchol x, pak x je spojen cestou Q do u a první vrchol z V(Q) H {ui,..., Uk} by měl stupeň větší než 2, spor. □
7.4 Stromy — grafy bez kružnic
Podrobnější studium některých užitečných aspektů grafů začneme u toho nej jednoduššího typu grafu - na stromech, jež jsou mimo jiné základem mnoha datových typů používaných v informatice.
Komentář:
Charakteristickými znaky stromů je absence kružnic a souvislost...
Definice 7.14. Strom je jednoduchý souvislý graf T bez kružnic.
Komentář: Obecněji ies je jednoduchý graf bez kružnic (nemusí být souvislý). Komponenty souvislosti lesa jsou stromy. Jeden vrchol bez hran a prázdný graf jsou také stromy. Grafy bez kružnic také obecně nazýváme acyklické.
Vlastnosti stromů
Přehled základních vlastností stromů je pro nás zároveň příležitostí si ukázat několik nových hezkých matematických důkazů a naučit se správně zdůvodňovat v oblasti grafů.
Tvrzení 7.15. Strom s více než jedním vrcholem obsahuje vrchol stupně 1.
Důkaz: Souvislý graf s více než jedním vrcholem nemůže mít vrchol stupně 0. Proto vezmeme libovolný strom Tav něm libovolný vrchol v. Sestrojíme nyní co nejdelší cestu S v T začínající ve v: S začne libovolnou hranou vycházející z v; v každém dalším vrcholu u, do kterého se dostaneme a má stupeň větší než 1, lze pak pokračovat cestu S další novou hranou. ^
Pokud by se v S poprvé zopakoval některý vrchol, získali bychom kružnici, což ve stromě nelze. Proto cesta S musí jednou skončit v nějakém vrcholu stupně 1 v T. □
Komentář: Zamyslete se, proč v každém stromě s více než jedním vrcholem jsou alespoň dva vrcholy stupně 1 (odpověď je skrytá už v předchozím důkaze). Zároveň si odpovězte, jestli lze tvrdit, že každý strom s více než jedním vrcholem obsahuje tři vrcholy stupně 1.
63
Věta 7.16. Strom na n vrcholech má přesně n — 1 hran pro n > 1.
Důkaz: Toto tvrzení dokážeme indukcí podle n. Strom s jedním vrcholem má n — 1 = 0 hran. Nechť T je strom na n > 1 vrcholech. Podle Tvrzení 7.15 má T vrchol v stupně 1. Označme T' = T — v graf vzniklý z T odebráním vrcholu -u. Pak T" je také souvislý bez kružnic, tudíž strom na n — 1 vrcholech. Dle indukčního předpokladu T" má n — 1 — 1 hran, a proto T má n — 1 — l + l = n—1 hran. □
Věta 7.17. Mezí každými dvěma vrcholy stromu vede právě jediná cesta.
Jelikož strom T je souvislý dle definice, mezi libovolnými dvěma vrcholy u,v vede nějaká cesta. Pokud by existovaly dvě různé cesty P\,p2 mezi u,v, tak bychom vzali jejich symetrický rozdíl, podgraf H = p1ap2 s neprázdnou množinou hran, kde H zřejmě má všechny stupně sudé. Na druhou stranu se však podgraf stromu musí opět skládat z komponent stromů, a tudíž obsahovat vrchol stupně 1 podle Tvrzení 7.15, což je spor. Proto cesta mezi u a v existuje jen jedna. □
Důsledek 7.18. Přidáním jedné nové hrany do stromu vznikne právě jedna kružnice.
Důkaz: Nechť mezi vrcholy u,v ve stromu T není hrana. Přidáním hrany e = uv vznikne právě jedna kružnice z e a jediné cesty mezi u,v v T podle Věty 7.17. □
Alternativní charakterizace stromů
Z předchozích tvrzení vyplývá následující alternativní charakterizace stromů, která ukazuje důležitost jich samotných i jako tzv. koster obecných grafů (viz Oddíl 8.4).
Na dané množině vrcholů je (vzhledem k inkluzi množin hran) strom
• minimální souvislý graf (plyne z Věty 7.17)
• a zároveň maximální acyklický graf (plyne z Důsledku 7.18).
Jen tak mimochodem, kolik dokážete nalézt neisomorfních stromů na 4 nebo 5 vrcholech? Vidíte, že jich není mnoho? Nakreslete si je všechny.
7.5 Použití a implementace grafů
Závěrem si v našem studijním textu nastíníme některé základní motivace pro zavedení a použití grafů při popisu a řešení problémů například v informatice.
Příklad 7.19. Ukázky některých problémů „ze života" popsatelných grafy. Podotýkáme, že tyto ukázky jsou často velmi zjednodušené (pro jejich lepší přístupnost širokému okruhu čtenářů), ale to neubírá jejich motivačnímu potenciálu.
Důkaz:
u ®---
'® v
64
Vyjádření mezilidských vztahů - „mají se rádi", „kamarádí se", „nesnesou jeden druhého", apod:
Zde jednotlivé osoby tvoří vrcholy grafu a vztahy jsou hranami (často neorientované, ale i orientace je přípustná). Všimněme si coby zajímavosti, jak tento model přirozeně preferuje „párový" pohled na vztahy - hrany přece spojují jen dvojice vrcholů. Třebaže například vztah „kamarádí se" může být obecně platný pro větší skupinky lidí než dvojice, stejně se obvykle vyjadřuje klikou v grafu (každí dva v našem družstvu jsou dobří kamarádi...). Tato obecně pojímaná tendence vyjadřovat i složitější vztahy těmi párovými je vodou na mlýn použití teorie grafů jako téměř univerzálního vyjadřovacího prostředku v podobných případech.
Na druhou stranu i teorie grafů disponuje pojmem tzv. hypergmfu umožňujícího použití hran libovolné arity (počtu koncových vrcholů), ale rozsah výskytu hypergrafů v teorii i aplikacích je oproti grafům vskutku zanedbatelný.
Vyjádření závislostí mezi objekty nebo procesy:
Představme si situace, ve kterých jednotlivé entity (modelované jako vrcholy) závisí na výstupech jiných entit a naopak poskytují výstupy další entitám. Typickým příkladem mohou být závislosti jednotlivých kroků výrobního nebo rozhodovacího procesu. Ty pak vedou k definici orientovaného grafu na dané množině vrcholů/entit, tj. použití hran „se šipkami". Všimněme si, že závislosti často bývají časového charakteru (přičemž směr závislosti je implicitně jasný) a pak je nezbytnou doplňkovou podmínkou vyloučení výskytu orientovaných cyklů v modelovém grafu. Na druhou stranu existují i situace, kdy cyklické závislosti jsou dovoleny a mají svůj význam.
Pro ještě jednu ukázku závislostí z běžného života informatika se podíváme na správu balíčků softwaru například v Linuxových distribucích. V tom případě jsou jednotlivé balíčky vrcholy grafu, jejich vyžadované závislosti popisují odchozí hrany a jejich poskytované vlastnosti jsou příchozími hranami grafu závislostí. Korektní instalace zvoleného balíčku pak řeší problém zahrnutí všech dalších vrcholů „dosažitelných" ze zvoleného. Vše je navíc komplikováno správou verzí balíčků, ale to už je mimo rámec našeho úvodního slova.
Modelování technických či dopravních sítí grafy:
V takových případech bývají vrcholy grafu jednotlivá technická zařízení jako třeba rozvodny, routery, křižovatky a podobně, kdežto hrany jsou tvořeny spojnicemi/vedením mezi vrcholy. Často se zde setkáváme s orientovanými grafy a obecně multigrafy. K této problematice se blíže vyjadřuje Lekce 9.
Vizualizace vztahů a závislostí pro lidského pozorovatele:
Nejen při řešení cvičných příkladů v naší učebnici, ale i v mnoha reálných aplikacích využívajících grafy jako modely, je velmi potřebné tyto grafy vizualizovat (tj. hezky nakreslit) pro lidského pozorovatele. Jedná se obecně o poměrně obtížný úkol, který přesahuje hranice našeho textu. n
65
Zpracování grafu počítačem
Mějme jednoduchý graf G na n vrcholech a značme vrcholy jednoduše čísly V(G) = {0,1,..., n — 1}. Pro počítačovou implementaci grafu G se nabízejí dva základní způsoby, které budeme implicitně využívat i v některých algoritmech následujících lekcí.
• Implementace maticí sousednosti, tj. dvourozměrným polem g[][], ve kterém g [i] [j]=l znamená hranu mezi vrcholy i a j.
• Implementace výčtem sousedů, tj. zjednodušeně opět použitím dvourozměrné pole h[] [] a navíc pole d[] stupňů vrcholů. Zde prvky h [i] [0] ,h[i] [1] , . . . ,h[i] [d[i]-l] udávají seznam sousedů vrcholu i.
Poznámka: Dávejte si pozor na symetrii hran v implementaci! To znamená, že pokud uložíte hranu g [i] [j]=l, tak musíte zároveň uložit i hranu g[j] [i]=l, jinak se dočkáte nepříjemných překvapení. Totéž se týká i seznamů sousedů.
Komentář: Implementace maticí sousednosti je hezká svou jednoduchostí. Druhá možnost se však mnohem lépe hodí pro grafy s malým počtem hran, což nastává ve většině praktických aplikací. (Navíc je implementace výčtem sousedů vhodná i pro multigrafy.) Pochopitelně je pak vhodnější místo polí používat různé spojové seznamy. Ke grafům lze do zvláštních polí přidat také ohodnocení vrcholů a hran libovolnými čísly či značkami...
Rozšiřující studium
Grafy můžeme v informatice potkat doslova na každém kroku, mimo jiné hojně už v základních kurzech algoritmizace. Nejen že grafy (především stromy) jsou základem mnoha programátorských datových struktur, ale představují i vhodný model pro spoustu praktických problémů. Oněch pár lekcí teorie grafů v našem učebním textu je jen lehkým úvodem, přičemž na FI MU lze pokračovat v jejím studiu v předmětu MA010.
Rozsáhlý matematický úvod do teorie grafů je zahrnut ve skvělé knize Kapitoly z diskrétní matematiky autorů Jiřího Matouška a Jaroslava Nešetřila. Vřele ji doporučujeme jako doplňkový studijní zdroj všem, kteří chtějí lépe pochopit grafy z jejich matematické stránky.
66
8 Procházení grafu a odvozené úlohy
Úvod
JVa rozdíl od předchozí lekce, která se zjednodušeně řečeno zabývala grafy z pohledu matematika, tedy podáním dehnice a obrázků, nyní se hlouběji podíváme na grafy z algoritmické či programátorské perspektivy Proto se v prvé řadě podíváme na obecné schéma procházení grafu, které je základem mnoha užitečných algoritmů na grafech. Poté se hlouběji zaměříme na dvě specihcké grafové úlohy - hledání nejkratší cesty a minimální kostry, hojně se vyskytující v mnoha praktických obměnách. Na základě obecného schématu si uvedeme jejich jednoduché a velmi efektivní algoritmy
Cíle
Zjednodušeně podáme obecné schéma algoritmu procházení grafu. Dehnujeme poté dvě konkrétní grafové úlohy, hledání nejkratší cesty mezi dvěma vrcholy a hledání nejmenší kostry, obojí v grafu s hranami ohodnocenými reálnými délkami. Na základě předchozího pak vysvětlíme Dijkstrův algoritmus pro nejkratší cesty a Kruskalův a Jarníkův algoritmus pro minimální kostru.
8.1 Jak obecně projít souvislý graf
S úlohou procházení grafu se svým způsobem setkávají už děti, když hledají cestu z bludiště (jejich naivní postup se dá přirovnat k procházení „do hloubky"). Celý problém má ale mnohem širší záběr a s vhodnou implementací dodatečných lokálních funkcí lze pouhým prohledáním grafu podat odpověď na jiné zajímavé otázky, jako najít nejkratší cestu, minimální kostru, komponenty vyšší souvislosti, apod. Navíc se procházení grafu vyskytuje jako podúloha v jiných algoritmech.
Metoda 8.1. Schéma algoritmu pro procházení grafem
Pro vytvoření co nejobecnějšího schématu si pomůžeme následujícími datovými stavy a pomocnou strukturou:
• Vrchol grafu: má stavy ...
* iniciační - dostane na začátku,
* nalezený - implicitní stav poté, co jsme jej přes některou hranu nalezli (a odložili ke zpracování později),
* zpracovaný - poté, co jsme už probrali všechny hrany z něj vycházející,
* (případně ještě stav „post-zpracovaný", po dokončení všech jeho následníků).
• Úschovna: je pomocná datová struktura (množina s dodatečnými atributy),
* udržuje odložené, tj. nalezené a ještě nezpracované vrcholy, spolu s dodatečnou specifickou informací.
• Postup procházení: zjednodušeně lze říci, že
* nalézáme z vybraných vrcholů jejich sousedy, ukládáme je do úschovny a
* pak zase vybíráme a nalézáme dále dokola, až je vše projito.
• Způsob, kterým se vybírají vrcholy z úschovny ke zpracování, určuje variantu algoritmu procházení grafu.
67
• V prohledávaných vrcholech a hranách se volitelně provádějí dodatečné programové akce pro prohledáni a zpracováni našeho grafu.
Samotný algoritmus pak popíšeme v následujících obecných bodech. (V této souvislosti dodáváme, že podrobněji se budeme způsobu formálního matematického zápisu algoritmů věnovat v Lekci 10, ale zde si vystačíme s běžným jazykem.)
Algoritmus 8.2. Generické procházení souvislé komponenty G grafu
• Vstup: Souvislý graf G, daný seznamem vrcholů a seznamy vycházejících hran z každého vrcholu, plus případné ohodnocení vrcholů a hran.
• Vybereme libovolný počátek prohledávání u E V (G); úschovna U V :
h 4--_ J/\ __-=* c
N — _ - "t _ '
K * \ '
a ®------k b
Značení v prohledávaném grafu: barevně aktuálně zpracovávaný vrchol a jeho hrany objevující nové vrcholy, kroužkem a plnou čarou již zpracované vrcholy a hrany, tlustě výsledný strom prohledávání.
h
■V' b
c /i
C /l
9 h
9 í 9 d
h d t-----------^l—c h d
69
JJl 9 d 9 c h d i) c h d
□
Příklad 8.4. Ukázka průchodu předchozím grafem do hloubky z vrcholu a.
—-• j d P f:: ""\ i y
/i i... /i i...
d
c
—-i J/ ) d \ \ v p d 9 f^z —® .T?
D c /i i-. i) c h i-.
9 dG(u, w) .
Důkaz. Postupujeme podobně jako v důkaze Tvrzení 7.10 - pokud máme cesty P,P' mezi u,v a mezi v,w, tak existuje cesta Q C P U P' mezi u,w, jež má zřejmě délku nejvýše dG(u,v) + dG(v,w). Skutečná vzdálenost mezi u,w pak už může být jen menší.
□
BFS a zjištění vzdálenosti
Jak nejsnadněji určíme vzdálenost v grafu? Stačí si povšimnout hezkých vlastností procházení grafu do šířky.
Věta 8.7. Algoritmus procházení grafu do šířky lze použít pro výpočet grafové vzdálenosti z daného vrcholu u.
Toto je poměrně jednoduchá aplikace, kdy počátečnímu vrcholu u přiřadíme vzdálenost 0, a pak vždy každému dalšímu nalezenému vrcholu v přiřadíme vzdálenost o 1 větší než byla vzdálenost vrcholu, ze kterého byl nalezen. Důkaz se opírá o následující tvrzení:
* Nechť u,v,w jsou vrcholy souvislého grafu G takové, že dG(u,v) < dG(u,w). Pak při algoritmu procházení grafu G do šířky z vrcholu u je vrchol v nalezen dříve než vrchol w.
Poté přirozeně postupujeme indukcí podle vzdálenosti dG(u,v): Pro dG(u,v) = 0, tj. u = v je tvrzení jasné - vrchol u jako počátek prohledávání byl nalezen první. Proto nechť dG(u,v) = d > 0 a označme v' souseda vrcholu v bližšího k u, tedy de (u, v') = d — 1. Obdobně uvažme libovolného souseda w' vrcholu w. Pak
dG{u, w') > dG(u, w)-l> dG(u, v)-l = dG(u, v'),
a tudíž vrchol v' byl nalezen v prohledávání do šířky dříve než vrchol w' podle indukčního předpokladu. To znamená, že v' se dostal do fronty úschovny dříve než w'. Proto sousedé v' (mezi nimiž je v, ale ne w neboť v'w není hranou) jsou při pokračujícím prohledávání také nalezeni dříve, než w coby soused w'. □
8.3 Hledání nejkratší cesty
V dalším textu se již budeme věnovat grafům s „obecně dlouhými" hranami. Zároveň předesíláme, že přednášená látka stejně dobře může stavět na orientovaných grafech.
Definice: Vážený graf je graf G spolu s ohodnocením w hran reálnými čísly w : E(G) —> R. Kladné vážený graf (G,w) je takový, že w(e) > 0 pro všechny hrany e.
Definice 8.8. (vážená vzdálenost) Mějme (kladně) vážený graf (G,w). Váženou délkou cesty P je
dg(P) = V w(e). Váženou vzdáleností v (G,w) mezi dvěma vrcholy u,v pak je
d'G(u,v) = min{cř^(P) : P je cesta s konci u,v} .
71
Tvrzení 8.9. Vážená vzdálenost v nezáporně vážených grafech (i orientovaných grafech) splňuje trojúhelníkovou nerovnost.
Příklad 8.10. Podívejme se na následující ohodnocený graf (čísla u hran udávají jejich váhy-délky.)
Vzdálenost mezi vrcholy a, c je 3, stejně tak mezi b, c. Co ale mezi a, b! Je jejich vzdálenost 6? Kdepak, vzdálenost a, b je 5, její cesta vede po „horních" vrcholech, jak je vyznačeno. Povšimněte si, že tento příklad zároveň ukazuje, že postup prohledáváním do šířky není korektní pro hledání vzdáleností ve váženém grafu. □
Problém nejkratší cesty
Problém nejkratší cesty mezi dvojicí vrcholů prostě hledá váženou vzdálenost vrcholů a příslušnou cestu. Jedná se patrně o nejznámější „grafový" problém v praktických aplikacích, jenž nalezneme od vyhledávání dopravních spojení, GPS navigací, plánování pohybů robota, až po třeba rozhodovací systémy.
Tento problém se nejčastěji řeší implementací klasického Dijkstrova algoritmu, který je vhodnou úpravou procházení grafu do šířky - vybírá vždy vrchol s nejmenší vzdáleností mezi uschovanými vrcholy.
Dijkstrův algoritmus
Algoritmus 8.11. Hledání nejkratší cesty mezi u a v v kladně váženém grafu.
Tento algoritmus využívá proměnnou hodnotu (pole) d(x) k ukládání nalezených vzdáleností do každého vrcholu x, vedle samotného vrcholu, přičemž tuto hodnotu postupně „vylepšuje" až do finálního zpracování vrcholu.
• Vstup: Souvislý graf G, daný seznamem vrcholů a seznamy vycházejících hran z každého vrcholu, plus váhy w hran. Počáteční vrchol u a koncový v.
• Úschovna U G- {(u, d(u) = 0)}.
• Dokud U Ý 0? opakujeme:
* Zvolíme (x, d(x)) G U takové, že d(x) je minimální. Odebereme U G- U \ {(x, d(x))} a zafíxujeme hodnotu d(x).
* Pokud x = v, algoritmus může skončit.
* Pro všechny hrany / G E (G) vycházející z x provedeme:
- Nechť y je druhý konec hrany / = xy;
a nechť ď(y) = d(x) + w(f) (nová cesta do y přes x).
- Pokud (y, d(y)) £ U, nebo (y, d(y)) G U pro d(y) > ď(y), odložíme U(e2) <
• • • < w(em).
74
Inicializujeme prázdnou kostru T = (V(G),0).
Po řadě pro i = 1,2,... , m provedeme následující:
* Pokud T + Ci nevytváří kružnici, tak E(T) +- E(T) U {ej}.
(Neboli pokud e,i spojuje různé komponenty souvislosti dosavadního T.)
Na konci T obsahuje minimální kostru grafu G (případně jednu z několika takových).
Komentář: Pro ilustraci si ukážeme postup hladového algoritmu pro vyhledání kostry následujícího grafu:
Hrany si nejprve seřadíme podle jejich vah 1,1,1,1, 2, 2, 2, 2, 3, 3, 3,4,4.
V obrázku průběhu algoritmu používáme tlusté čáry pro vybrané hrany kostry a tečkované čáry pro zahozené hrany. Hrany teď postupně přidáváme do kostry / zahazujeme. ..
J O A O O A O
co #»* M.
1 3 4 2 4 3
Získáme tak minimální kostru velikosti 1 + 2 + 2 + 3 + 1 + 1 + 2 = 12, která je v tomto případě (náhodou) cestou, na posledním obrázku vpravo.
Poznamenáváme, že při jiném seřazení hran stejné váhy by kostra mohla vyjít jinak, ale vždy bude mít stejnou velikost 12.
Věta 8.16. Hladový postup korektně spočítá minimální kostru váženého grafu (G,w).
Důkaz (náznak): Pro spor předpokládejme, že T\ je kostra spočítaná Metodou 8.15 a T2 nějaká minimální kostra, kde <Í£(T2) < cř^(Ti) a rozdíl \E(T\)Í\E(t2)\ je nejmenší. Nechť i je nejmenší index takový, že e« G E(Ti)AE(t2). Pak nutně e« G E(Ti) \ E(t2) (proč?), a tudíž T2 + podle Důsledku 7.18 obsahuje kružnici procházející také hranou e j pro j > i. Potom však T3 = (T2 + e^) \ {e,-} je další kostrou mající váhu cř^(T2) + w(cí) — w(cj) > dg(T2), a proto w(cí) = w(cj). Tudíž T3 je minimální kostra „bližší" T\ ve smyslu symetrického rozdílu, což je spor s volbou T2. □
75
Jarníkův (Primův) algoritmus
Ač koncepčně velmi jednoduchá, má Metoda 8.15 některé problematické implementační detaily, pro které je mnohem častěji používán následující algoritmus (často připisován Američanu Primoví, ale mnohem dříve publikován Vojtěchem Jarníkem v 1930), založený na běžném procházení grafu.
Algoritmus 8.17. Hledání minimální kostry ve váženém grafu (G,w).
Opět mějme dán souvislý vážený graf G s ohodnocením hran w. Níže uvedená specifická implementace procházení grafu využívá úschovnu rozšířeným způsobem, kdy ukládá i příchozí hranu do vrcholu.
• Vstup: Souvislý graf G, daný seznamem vrcholů a seznamy vycházejících hran z každého vrcholu, plus váhy w hran.
• Vybereme libovolný počátek prohledávání u G V (G); úschovna U w(f), odložíme U O je následujícím grafem nan + 1 vrcholech
1 2 3 ' ' ' n 7i + l
a orientovaná kružnice (také cyklus) délky n > 1 vypadá takto:
4 ^-^e^ 2
5 / \ 1
6 ... n
Definice: Počet hran začínajících ve vrcholu u orientovaného grafu D nazveme výstupním stupněm d^(u) a počet hran končících v u nazveme vstupním stupněm d^(u).
Komentář: Součet všech výstupních stupňů je přirozeně roven součtu všech vstupních stupňů orientovaného grafu. Důkaz viz Věta 7.3.
Všimněte si, že některá literatura používá opačná znaménka ( — /+) při značení výstupních a vstupních stupňů, ale s tím nic nenaděláme a čtenář se prostě vždy musí zorientovat a zjistit aktuální situaci.
Definice: Symetrizací orientovaného grafu D rozumíme neorientovaný graf G vzniklý „zapomenutím směru hran" v D, přesněji V(G) = V(D) a uv G E (G) právě když
Souvislost na orientovaných grafech
Pojem orientované souvislosti grafu D je natolik fundamentálně odlišný od neorientovaného případu (což je dáno právě jeho „směrovostí"), že si zaslouží samostatnou diskusi i v našem zběžném pohledu na orientované grafy. Uvedeme si na ni odstupňovaně tři základní pohledy:
• Slabá souvislost. Jedná se o tradiční souvislost na symetrizací grafu D
Komentář: Zjednodušeně a názorně se dá říci, že při cestování grafem „zapomeneme" směr šipek. Na obrázku:
Tento přístup sice může vypadat poněkud nesmyslně - proč šipky zavádět a pak zapomínat jejich směr, avšak brzy u tzv. nenasycených cest uvidíme smysl představy, že cesta v orientovaném grafu se „tlačí" proti směru hrany.
• Dosažitelnost (směrem „ven"). Orientovaný graf D je dosažitelný směrem ven, pokud v něm existuje vrchol v G V (D) takový, že každý vrchol x G V (D) je dosažitelný orientovaným sledem z v.
®—5>
79
Komentář: Podrobným zkoumáním následujícího obrázku zjistíme, že jeho graf není dosažitelný směrem ven, neboť chybí možnost dosáhnout vrchol b úplně vpravo. Na druhou stranu po vypuštění b je zbylý graf dosažitelný ven z vrcholu a vlevo.
• Silná souvislost. Nechť »2 je binární relace na vrcholové množině V(D) orientovaného grafu D taková, že u ~ v právě když existuje dvojice orientovaných cest - jedna z u do v a druhá z v do u v grafu D. Pak »2 je relace ekvivalence.
Definice 9.2. Silné komponenty orientovaného grafu D
jsou třídy ekvivalence relace »2 uvedené v předchozím. Orientovaný graf D je silně souvislý pokud má nejvýše jednu silnou komponentu.
Komentář: Pro ilustraci si mírně upravíme dříve prezentovaný orientovaný graf tak, že bude dosažitelný z nejlevějšího vrcholu. Je výsledek silně souvislý?
Ne, na obrázku jsou vyznačené jeho 4 silné komponenty. Vpravo zároveň uvádíme pro ilustraci obrázek kondenzace silných komponent tohoto grafu, což je acyklický orientovaný graf s vrcholy reprezentujícími zmíněné silné komponenty a směry hran mezi nimi.
Pro zvídavé čtenáře poznamenáváme, že si mohou definici silné komponenty porovnat s jádrem předuspořádání v Oddíle 5.4. Kde vidíte drobný rozdíl?
9.2 Definice sítě a toku
Základní strukturou pro reprezentaci sítí je vážený orientovaný graf (přičemž implicitní směr hran je v tomto kontextu nezbytný). Váhy (hran) v takovém modelu vyjadřují „kapacity" jednotlivých spojů a nás zajímá, jak mnoho uvažované substance dokážeme (různými cestami) přenést z daného zdroje do stoku. Podstata substance není důležitá, ale ta musí být vhodně rozdělitelná.
Definice 9.3. Síť je čtveřice S = (D,z,s,w), kde * D je orientovaný graf,
80
* vrcholy z G V (D), s G V (D) jsou zdroj a stok,
* w : E(D) —> R+ je kladné ohodnocení hran, zvané kapacita hran.
Komentář:
a ._ä_
2
Na obrázku je zakreslena síť s vyznačeným zdrojem z a stokem s, jejíž kapacity hran jsou zapsány čísly u hran. Šipky udávají směr hran, tedy směr proudění uvažované substance po spojnicích. Pokud směr proudění není důležitý, vedeme mezi vrcholy dvojici opačně orientovaných hran se stejnou kapacitou. Kapacity hran pak omezují maximální množství přenášené substance.
Poznámka: V praxi může být zdrojů a stoků více, ale v definici stačí pouze jeden zdroj a stok, z něhož / do nějž vedou hrany do ostatních zdrojů / stoků. (Dokonce pak různé zdroje a stoky mohou mít své kapacity.)
Velikost toku v síti
V souladu s praktickými aspekty nás u toku v síti zajímá především to, jaké „množství" substance (velikost toku) se skutečně přenese od zdroje ke stoku.
Značení: Pro jednoduchost píšeme ve výrazech značku e —y v pro hranu e končící ve vrcholu v a e v pro hranu e začínající z v.
Definice 9.4. Tok v síti S = (D,z,s,w) je funkce / : E(D) —> splňující
* Ve G E (D) : 0 < f (e) < w(e),
* Vv(=V(D),vŕz,s: £/(e)= E /(e)-
e—>v e<—v
Velikost toku / je dána výrazem ||/|| = E f(e) ~ E f(e)-
e<—z e—>z
Značení: Tok a kapacitu hran v obrázku sítě budeme zjednodušeně zapisovat ve formátu F/C, kde F je hodnota toku na hraně a C je její kapacita.
Komentář: Neformálně tok znamená, kolik substance je každou hranou zrovna přenášeno (ve směru této hrany, proto hrany musí být orientované). Tok je pochopitelně nezáporný a dosahuje nejvýše dané kapacity hrany. Navíc je nutno v každém vrcholu mimo z, s splnit podmínku „zachování substance".
Ve vyobrazeném příkladě vede ze zdroje vlevo do stoku vpravo tok o celkové velikosti 5.
81
Poznámka: Obdobně se dá velikost toku definovat u stoku (či i na obecném řezu v síti, viz dále), neboť platí následující identita odvozená z vlastnosti zachování substance v definici toku
Proto velikost toku počítaná u zdroje je rovna opačné velikosti toku počítaného u stoku
9.3 Nalezení maximálního toku
Naším úkolem je najít co největší přípustný tok v dané síti. Pro jeho nalezení existují jednoduché a velmi rychlé algoritmy. Navíc tyto algoritmy mají zajímavé teoretické souvislosti a důsledky uvedené později.
maximalizuje velikost ||/||.
Komentář: Tok velikosti 5 uvedený v ukázce v předchozí části nebyl optimální, neboť v této síti najdeme i tok velikosti 6:
Jak však poznáme, že větší tok již v dané síti neexistuje? V této konkrétní ukázce to není obtížné, vidíme totiž, že obě dvě hrany přicházející do stoku mají součet kapacit 2+4 + 6, takže více než 6 do stoku ani přitéct nemůže. V obecnosti lze použít obdobnou úvahu, kdy najdeme podmnožinu hran, které nelze tokem „obejít" a které v součtu kapacit dají velikost našeho toku. Existuje však taková množina hran vždy? Odpověď nám dá následující definice a věta.
Pojem řezu v síti
Definice 9.6. Rez v síti S = (D, z, s,w) je podmnožina hran X C E(D)
taková, že v podgrafu D — X (tj. po odebrání hran X z D) nezbude žádná orientovaná
cesta ze z do s. Velikostí řezu X rozumíme součet kapacit hran z X, tj. ||X|| = z^2eex w(e)-
Zcela klíčovým poznatkem síťových úloh je následující velmi hezká charakterizace jejich optimálního řešení
Věta 9.7. Maximální velikost přípustného toku v síti je vždy rovna minimální velikosti
o = E (m - m) = E í E - E m) = E í E ^ - E m
řezu v ní.
82
Komentář: Na následujícím obrázku vidíme trochu jinou síť s ukázkou netriviálního minimálního řezu velikosti 5, naznačeného svislou čárkovanou čarou. Všimněte si dobře, že definice řezu mluví o přerušení všech orientovaných cest ze z do s, takže do řezu stačí započítat hrany jdoucí přes svislou čáru od z do s, ale ne hranu jdoucí zpět. Proto je velikost vyznačeného řezu 1+4 = 5.
Důkaz Věty 9.7 bude proveden následujícím Algoritmem 9.9.
Nenasycené cesty v síti
Definice: Mějme síť S a v ní tok /. Nenasycená cesta P (v S vzhledem k /) je neorientovaná cesta v D mezi určenými vrcholy (obvykle ze z do s), tj. posloupnost navazujících libovolně orientovaných hran e1; e2,..., em, kde /(e^) < w(cí) pro ve směru ze z do s a f(cj) > 0 pro e j v opačném směru.
Hodnotě w(cí) — /(e^) > 0 pro hrany e« ve směru z u do v a hodnotě /(e,) > 0 pro hrany e,- v opačném směru říkáme rezerva kapacity hran. Nenasycená cesta je tudíž cesta s kladnými rezervami kapacit všech hran.
Komentář: Zde vidíme příklad nenasycené cesty ze zdroje do stoku s minimální rezervou
kapacity +1.
rezerva kapacity:
1/2 1/1
+1 +1
+1
2/3
+2 +2
5®
> 0
Všimněte si dobře, že cesta není orientovaná, takže hrany na ní jsou v obou směrech.
Metoda 9.8. Maximální tok vylepšováním nenasycených cest.
Základní myšlenkou této jednoduché metody hledání maximálního toku v dané síti je prostě opakovaně vylepšovat tok podél nalezených nenasycených cest.
Komentář: Ve výše zakresleném obrázku nenasycené cesty byla minimální rezerva kapacity ve výši +1, a tudíž nasycením této cesty o velikost toku 1 vzniká následující fragment přípustného toku v síti:
4/4 2/2 0/1 0^
1/3 3/4
Zajímavé je se podívat, co se stalo s prostředními zpětně orientovanými hranami - fakticky byl jejich zpětný tok o 1 snížen/zastaven, přičemž toto množství nyní „teče doprava" (velmi neformálně řečeno).
Fakt: Je-li minimální rezerva kapacity hran nenasycené cesty P ze z do s ve výši r > 0, pak tok ze z do s zvýšíme o hodnotu r následovně;
83
• pro hrany G E (P) ve směru ze z do s zvýšíme tok na /'(e^) = f(eí) + r>
• pro hrany e,- G E (P) ve směru ze s do z snížíme tok na /'(e,) = /(e,) — r. Výsledný tok /' pak bude opět přípustný.
Základní algoritmus nenasycených cest
Rámcové implementační podrobnosti Metody 9.8 následují v popise konkrétního algoritmu.
Algoritmus 9.9. Ford-Fulkersonův pro tok v síti.
• Vstup: Síť S = (D,z,s,w) podle Definice 9.3.
. Tok /<- (0,0,... 0).
• Dále opakujeme následující:
* Prohledáváním grafu najdeme množinu U vrcholů D, do kterých se dostaneme ze z po nenasycených cestách.
* Pokud s G U, nechť P značí nalezenou nenasycenou cestu v S ze z do s.
- Zvětšíme tok / o minimální rezervu kapacity hran v P.
• Opakujeme kroky výše, dokud nenastane s U.
• Výstup: Vypíšeme maximální tok / a také minimální řez jako množinu všech hran vedoucích z U do V(D) — U.
Příklad 9.10. Ukázka průběhu Algoritmu 9.9
Následují obrázky jednotlivých kroků algoritmu, kde vždy levý obrázek zvýrazní nenasycenou cestu a vpravo se nasycením zvýší celkový tok.
84
1/2
4/4
2/4 j, : k\
s) nasyceno
l 4/4
Závěrečný obrázek pak ukazuje výsledný tok velikosti 5 zároveň se zvýrazněným minimálním řezem stejné velikosti. □
Důkaz a důsledky Ford Fulkersonova algoritmu
Důkaz správnosti Algoritmu 9.9: Pro každý tok / a každý řez X v síti S platí ||/|| < ||X||. Jestliže po zastavení algoritmu s tokem / nalezneme v síti S řez o stejné velikosti 11*11 = 11/11) Je Jasné, že jsme našli maximální možný tok v síti S. (Pozor, zastavení algoritmu jsme zatím nezdůvodnili, to není tak jednoduché.)
Takže dokažme, že po zastavení algoritmu nastane rovnost ||/|| = ||X||, kde X je vypsaný řez mezi U a zbytkem grafu D. Vezměme tok f v S bez nenasycené cesty ze z do s. Pak množina U z algoritmu neobsahuje s. Schematicky vypadá situace takto:
/(e) = w(e)
©
U
0
Jelikož z U žádné nenasycené cesty dále nevedou, má každá hrana e G- U (odcházející z U) plný tok /(e) = w(é) a každá hrana e —> U (přicházející do U) tok /(e) = 0, takže
E - E /(e) = E /(e) = E»(g) = 11*11 •
e-f-t/ e-^U e^-V eeX
Na druhou stranu, když v sumě uvažujeme všechny hrany grafu indukované na naší množině U, tj. e G E (D \ U), analogicky dostaneme požadované
0
E (/(e) - m = E f E /(e) - E /(e)) - í E /(e) - E /(f
eeE(D\U) veU \e^v e^v J \e^U e-^U
\e*^z e—>z J \e<-U e^U
- 11*11 , tj.
Z důkazu Algoritmu 9.9 pak odvodíme několik zajímavých faktů:
\X\\ .
□
85
Fakt: Pokud zajistíme, že Algoritmus 9.9 vždy skončí, zároveň tím dokážeme i platnost Věty 9.7.
Fakt: Pro celočíselné kapacity hran sítě S Algoritmus 9.9 vždy skončí.
Fakt: Existují snadná vylepšení Algoritmu 9.9 (jako Edmonds-Karp či Dinitz), u kterých je zaručeno, že výpočet vždy skončí. Obecně k dosažení tohoto cíle postačí vždy uvažovat pouze nejkratší nenasycené cesty, což je ale mimo dosah našeho kurzu.
Pro další využití v teorii grafů je asi nej důležitější tento poznatek:
Důsledek 9.11. Pokud jsou kapacity hran sítě S celočíselné, optimální tok také vyjde celočíselně.
Důkaz: Postupujeme jednoduchou indukcí podle iterací Algoritmu 9.9: Algoritmus začíná s celočíselným tokem 0. V každé další iteraci bude na počátku tok všemi hranami celočíselný, tudíž i rezervy kapacit hran vyjdou (rozdílem od celočíselné kapacity) celočíselně. Proto i hodnoty toku budou změněny jen celočíselně, což zakončuje indukční krok. □
9.4 Zobecněné použití sítí
Pojmy sítě a toků v ní lze v kombinatorické optimalizaci zobecnit a využít několika směry. My si zde stručně uvedeme následující možnosti.
• Sítě s kapacitami vrcholů:
U sítě můžeme zadat kapacity vrcholů, neboli kapacitní váhová funkce je dána jako w : E(D) U V (D) —> r+. Takovou síť „zdvojením" vrcholů snadno převedeme na běžnou síť, ve které kapacity původních vrcholů budou uvedeny u nových hran spojujících zdvojené vrcholy. Viz neformální schéma:
• Sítě s dolními kapacitami:
Pro hrany sítě lze zadat také jejich minimální kapacity, tedy dolní meze přípustného toku, jako váhovou funkci l : E(D) —> rq". Přípustný tok pak musí splňovat l(e) < /(e) < w(e) pro všechny hrany e. V této modifikaci úlohy již přípustný tok nemusí vůbec existovat, takže postup řešení musí zavést počáteční fázi, ve které se nějaký tok splňující minimální kapacity nalezne vhodnou úpravou zadané sítě. Poté se pokračuje metodou nenasycených cest.
5
5
5
86
Bipartitní párování
Bipartitní grafy jsou grafy, jejichž vrcholy lze rozdělit do dvou množin tak, že všechny hrany vedou jen mezi těmito množinami, neboli podgrafy úplných bipartitních grafů.
Definice: Bárovánív (nyní bipartitním) grafu G je podmnožina hran M C E (G) taková, že žádné dvě hrany z M nesdílejí koncový vrchol.
Komentář: Úlohu nalézt v daném bipartitním grafu co největší párování lze poměrně snadno vyřešit pomocí toků ve vhodně definované síti. Uvedená metoda použití toků v síti na řešení problému párování přitom hezky ilustruje obecný přístup, jakým toky v sítích pomohou řešit i úlohy, které na první pohled se sítěmi nemají nic společného.
Metoda 9.12. Nalezení bipartitního párování
Bro daný bipartitní graf G s vrcholy rozdělenými do množin A, B sestrojíme síť S následovně:
1
• Všechny hrany sítě S orientujeme od zdroje do stoku a přiřadíme jim kapacity 1.
• Nyní najdeme (celočíselný) maximální tok v S Algoritmem 9.9. Do párování vložíme ty hrany grafu G, které mají nenulový tok.
Důkaz správnosti Metody 9.12: Podle Důsledku 9.11 bude maximální tok celočíselný, a proto každou hranou poteče buď 0 nebo 1. Jelikož však do každého vrcholu v A může ze zdroje přitéct jen tok 1, bude z každého vrcholu A vybrána do párování nejvýše jedna hrana. Stejně tak odvodíme, že z každého vrcholu B bude vybrána nejvýše jedna hrana, a proto vybraná množina skutečně bude párováním. Zároveň to bude největší možné párování, protože z každého párování lze naopak vytvořit tok příslušné velikosti a větší než nalezený tok v S neexistuje. □
Poznámka: Popsaná metoda je základem tzv. Maďarského algoritmu pro párování v bipartitních grafech. Úlohu nalezení maximálního párování lze definovat i pro obecné grafy a také ji efektivně algoritmicky vyřešit, ale příslušný algoritmus [Edmondsův] není jednoduchý.
Výběr různých reprezentantů
Definice: Nechť Mi,M2,...,Mk jsou neprázdné množiny. Systémem různých reprezentantů množin Mi,M2,...,Mk nazýváme takovou posloupnost různých prvků (x1}x2,...,Xk), že Xi G Mi pro i = 1,2,... ,k.
Důležitým a dobře známým výsledkem v této oblasti je Hallova věta plně popisující, kdy lze systém různých reprezentantů daných množin nalézt.
87
Věta 9.13. Nechť M1; M2,..., jsou neprázdné množiny. Pro tyto množiny existuje systém různých reprezentantů, právě když platí
VJC{l,2,...,fc}: |M Mj
> \ J\
neboli pokud sjednoceni libovolné skupiny z těchto množin má alespoň tolik prvků, kolik množin je sjednoceno.
Důkaz: Označme X\, x2, ■ ■ ■, xm po řadě všechny prvky ve sjednocení MiUil^U- • -UM^. Definujeme si bipartitní graf G na množině vrcholů {1,2,..., k}U{x1,x2,..., xm}U{u, v}, ve kterém jsou hrany {u, i} pro i = 1, 2,..., k, hrany {v, Xj} pro j = 1, 2,..., m a hrany {i,Xj} pro všechny dvojice pro které Xj G Mj.
Komentář: Konstrukce našeho grafu G je obdobná konstrukci sítě v Metodě 9.12: Vrcholy u a v odpovídají zdroji a stoku, ostatní hrany přicházející do vrcholu x j znázorňují všechny z daných množin, které obsahují prvek Xj.
Cesta mezi u a v má tvar u, i, Xj, v, a tudíž ukazuje na reprezentanta x j G Mj. Systém různých reprezentantů tak odpovídá k disjunktním cestám mezi u a, v. Nechť X je nyní libovolná minimálnímnožina vrcholů v G, neobsahující samotné u a v, po jejímž odebrání z grafu nezbude žádná cesta mezi u a, v. Podle této úvahy mají naše množiny systém různých reprezentantů, právě když každá taková oddělující množina X má aspoň k prvků.
Položme J = {1, 2,..., k} \ X. Pak každá hrana z J (mimo u) vede do vrcholů z X H {xi,..., xm} (aby nevznikla cesta mezi u,v), a proto
|l I Mj =\xn{x1,...,xm}\ = \x\-\xn{i,...,k}\ = \x\-k + \j\.
(První rovnost vyplývá z minimality množiny X.) Vidíme tedy, že |X| > k pro všechny (minimální) volby oddělující X, právě když \J-eJMj > \J\ pro všechny volby J, což je dokazovaná podmínka naší věty. □
Poznámka: Tento důkaz nám také dává návod, jak systém různých reprezentantů pro dané množiny nalézt - stačí použít Algoritmus 9.9 na vhodně odvozenou síť.
Rozšiřující studium
Orientované grafy v obvyklých učebnicích teorie grafů mnoho místa nemají a speciálně v češtině není mnoho zdrojů věnujících se přímo orientovaným grafům. Mnohé aspekty grafů (včetně některých grafových algoritmů) však zůstávají stejné i v orientovaném podání, jak můžeme vidět třeba v otázkách isomorňsmu či hledání nejkratší cesty. Otázky síťových toků a silné souvislosti studované v této lekci však dostávají na orientovaných grafech "nový rozměr"nemající v neorientovaných grafech rozumné obdoby - pro ně je směr hran podstatný. My se zde hlouběji orientovanými grafy nezabýváme, ale zájemce odkazujeme především na algoritmické zdroje a kurzy, neboť úloha síťových toků je jednou ze základních praktických úloh kombinatorické optimalizace.
88
10 Formalizace a důkazy pro algoritmy
Úvod
Po předchozí převážně matematické látce se náš výklad obrací bezprostředně k informatice. Mnozí z vás si asi již všimli, že umění programovat není zdaleka jen o tom naučit se syntaxi programovacího jazyka, ale především o schopnosti vytvářet a správně formálně zapisovat algoritmy. Přitom třeba situace, kdy programátorem zapsaný kód ve skutečnosti počítá něco trochu jiného, než si autor představuje, je snad nejčastější programátorskou chybou - o to zákeřnější, že ji žádný „chytrý" překladač nemůže odhalit.
Proto již na počátku studia informatiky je žádoucí klást důraz na správné chápání zápisu algoritmů i na přesné důkazy jejich vlastností a správnosti. A to je téma, kterému se budeme věnovat následující dvě lekce.
Cíle
Bude zaveden způsob formálního zápisu algoritmů pro potřeby dalšího výkladu, nezávisle na konkrétních programovacích jazycích. Na tomto formalismu pak bude ukazováno správné chápání chování algoritmů a příklady důkazů na konkrétních „malých" algoritmech. Nejdůležitější technikou důkazů bude matematická indukce. Na druhou stranu je třeba dodat, že uváděné algoritmy jsou pouze bezvýznamné ilustrativní ukázky pro cvičení důkazů a není úkolem tohoto textu učit čtenáře návrhu algoritmů.
10.1 Formální popis algoritmu
Před samotným závěrem našeho matematického kurzu si položme klíčovou otázku, co je vlastně algoritmus? Když se na tím zamyslíte, asi zjistíte, že to není tak jednoduché přesně říci. Dokonce je to natolik obtížná otázka, že si zde můžeme podat jen docela zjednodušenou (či naivní?) odpověď, přesto však dostatečnou pro zamýšlenou demonstraci matematických důkazů pro běžné algoritmy.
Poznámka: Za definici algoritmu je obecně přijímána tzv. Church-Turingova teze tvrdící, že všechny algoritmy lze „simulovat" na Turingově stroji. Jedná se sice o přesnou, ale značně nepraktickou definici. Mimo Turingova stroje existují i jiné matematické modely výpočtů, jako třeba stroj RAM, který je abstrakcí skutečného strojového kódu, nebo také třeba tzv. neprocedurální (neimperativní) modely zahrnující funkcionální a logické programování.
Konvence 10.1. Zjednodušeně zde algoritmem rozumíme konečnou posloupnost elementárních výpočetních kroků, ve které každý další krok vhodné1 využívá (neboli závisí na) vstupní údaje či hodnoty vypočtené v předchozích krocích. Tuto závislost přitom pojímáme zcela obecně nejen na operandy, ale i na vykonávané instrukce v krocích.
Pro zápis algoritmu a jeho zpřehlednění a zkrácení využíváme řídící konstrukce -podmíněná větvení a cykly.
Komentář: Vidíte, jak blízké si jsou konstruktivní matematické důkazy a algoritmy v našem pojetí? Jedná se nakonec o jeden ze záměrů našeho přístupu...
zvídaví studenti si mohou na tomto místě uvědomit, že ve slůvku „vhodně" se skrývá celá hloubka Church-Turingovy teze. V žádném případě tak nelze mechanicky bez zamyšlení obracet, že by každá posloupnost kroků atd ... byla algoritmem ve smyslu této teze (viz také Lekce 12).
89
Příklad 10.2. Zápis algoritmu pro výpočet průměru daného pole a[] s n prvky. Algoritmus.
• Inicializujeme sum 0 ;
• postupně pro i=0,l,2, . . . ,n-l provedeme
* sum 0 vypočítáme x-té Fibonacciho číslo následovně:
if x < 2 then t x;
else t fibonacci(x-l)+fibonacci(x-2); return t
Komentář: Správnost Algoritmu 10.13 je víceméně zřejmá z jeho přímé podoby s rekurentním vzorcem v definici Fibonacciho čísel. Zamyslete se však, jak je to s praktickou „proveditelností1 takového algoritmu... Vidíte (případně si zkuste naprogramovat), že čas výpočtu roste velmi rychle? Třebaže hodnotu fibonacci(30) tímto algoritmem spočítáte poměrně rychle, s výpočtem fibonacci(40) už budete mít větší problémy a fibonacci(50) asi bude mimo vaše možnosti. To skutečně není dobrý algoritmus! Podívejte se také na budoucí Příklad 11.5, který odhaduje, jak mnoho (exponenciálně) kroků výpočtu je potřeba.
Proto si v dalším Příkladu 10.14 uvedeme poněkud (ve skutečnosti velmi výrazně) lepší algoritmus výpočtu, podobající se přirozenému lidskému postupu psaní členů posloupnosti „do řádku na papír". Doporučujeme si oba algoritmy zkusit implementovat a mezi sebou porovnat.
Příklad 10.14. Nerekurzivní algoritmus pro Fibonacciho čísla.
Dokažte, že následující algoritmus pro každé přirozené n počítá tutéž hodnotu jako rekurentní funkce f ibonacci(n) v Algoritmu 10.13 (ale mnohem mnohem rychleji).
Algoritmus . input n;
b[0] <- 0; b[l] <- 1; foreach i 2 předpokládáme platnost indukčního předpokladu b[j] = fibonacci(j) pro j G {i — 1, i — 2}. V i-té iteraci cyklu pak nastane b[i] b[i— l] + b[i — 2] = fibonacci(i — 1) + fibonacci(i — 2) = fibonacci(i) podle definice. Tím je důkaz hotov pro hodnotu i = n. □
94
Rozšiřující studium
Náš výklad pohlíží na algoritmy a programování tzv. procedurálním neboli imperativním paradigmatem. Vedle toho existují i jiné přístupy k programování, jako zmíněné funkcionální nebo logické. JVa FI se s jinými přístupy studenti seznámí třeba v předmětu Neimperativní programování. Pro náš předmět však výběr výpočetního paradigmatu není nejdůležitější.
Smyslem této lekce bylo především ukázat, že u jednoduchých algoritmů lze (a je vhodné) je matematicky formálně zapisovat i dokazovat jejich správnost. Samozřejmě je iluzorní předpokládat, že obdobné důkazy správnosti podáme i pro velké softwarové projekty čítající až milióny řádků, ale postupy a techniky naučené při ověřování jednoduchých algoritmů s úspěchem využijete i při kontrole a ladění jednotlivých kousků velkých projektů.
O mnoha různých pokročilých technikách formální verifikace programů se v případě zájmu dozvíte v pokračujícím studiu. Tyto techniky jsou schopny na vhodném „modelu" rutinně a matematicky přesně ověřovat (ne)existenci mnoha běžných programátorských chyb.
95
11 Pokročilé dokazování nad algoritmy
Úvod
Přímo navazujeme na Lekci 10 a pokračujeme v ukázkách matematického dokazování nad vybranými krátkými algoritmy Výklad již bude trochu náročnější a místo uměle přichystaných (a v podstatě triviálních) příkladů se budeme věnovat i několika obecným dobře známým algoritmům. Dá se říci, že tato lekce je „vrcholem" v naší snaze o matematické dokazování algoritmů v informatice. Soustřeďte se v ukázkách důkazů na pochopení, jak jednotlivé formální matematické kroky korespondují s průběhem algoritmů.
Cíle
Naší snahou v těchto dvou lekcích je čtenáři ukázat poměrně vyčerpávající přehled způsobů a triků, které lze využít k analýze a dokazování správnosti rozumně krátkých algoritmů. Tyto poznatky by měly základem toho, aby si čtenář jako programátor uměl po sobě své algoritmy „přečíst" a ověřit jejich skutečnou správnost na lokální úrovni.
11.1 Dokazování konečnosti algoritmu
Co bývá snad ještě horší, než chybný výsledek algoritmu? Je to situace, kdy spuštěný algoritmus běží „do nekonečna" a vůbec se nezastaví.
Komentář: Všimněte si, že jsme se zatím v důkazech Lekce 10 vůbec nezamýšleli nad tím, zda naše algoritmy vůbec skončí. (To není samozřejmé a důkaz konečnosti je nutno v obecnosti podávat!) Prozatím jsme však ukazovali algoritmy využívající jen foreach cykly, přitom podle naší konvence obsahuje foreach cyklus předem danou konečnou množinu hodnot pro řídící proměnnou, neboli náš foreach cyklus vždy musí skončit. Ale už v příštím algoritmu využijeme while cyklus, u kterého vůbec není jasné kdy a jestli skončí, a tudíž bude potřebný i důkaz konečnosti.
Právě nad takovou situací a její možnou prevencí se v tomto oddíle zamyslíme. Předesíláme, že další podnětná látka k témuž tématu se nachází ještě v Lekci 12.
Příklad 11.1. Zastaví se vždy výpočet následujícího primitivního algoritmu? Algoritmus 11.2. input x; while x>5 do x «— x+1;
done
output x
Odpověď je samozřejmě NE, jak každý vidí pro jakýkoliv vstup x větší než 5. Jak však tuto negativní odpověď matematicky dokázat? To není zcela jednoduché, a proto si pomůžeme následujícím trikem:
• Předpokládejme pro spor, že Algoritmus 11.2 někdy skončí pro x > 5. Nechť přirozené n > 5 je zvoleno tak, že Algoritmus 11.2 skončí pro x = n po nejmenším možném počtu l průchodů cyklem while.
Pak jistě l > 0, neboť na začátku je podmínka x>5 splněna z definice n. Po prvním průchodu pak x = n + 1 > 5, avšak nyní již Algoritmus 11.2 musí skončit po l — 1 < l dalších průchodech cyklu. To je spor s volbou x = n coby vstupní hodnoty s nejmenším
96
možným počtem průchodů (pro x = n + 1 totiž do ukončení výpočtu proběhne o jeden průchod méně - o ten jeden vykonaný na začátku naší úvahy). □
Když algoritmus vždy končí
Na rozdíl od předchozí ukázky se budeme dále věnovat pozitivním případům, kdy algoritmy poslušně končí své výpočty.
Metoda 11.3. Jednoduchý důkaz konečnosti.
Máme-li za úkol dokázat, že algoritmus skončí, vhodný postup je následující:
* Sledujeme zvolený celočíselný a zdola ohraničený parametr algoritmu (třeba přirozené číslo) a dokážeme, že se jeho hodnota v průběhu algoritmu neustále ostře zmenšuje.
* Případně předchozí přístup rozšíříme na zvolenou k-tici přirozených parametrů a dokážeme, že se jejich hodnoty v průběhu algoritmu lexikograficky ostře zmenšují.
Jedná se zde vlastně o vhodné (a zjednodušené pro daný účel) využití principu matematické indukce. Pozor, naše „parametry" vůbec nemusejí být proměnnými v programu, a přesto jsou s programem implicitně nerozlučně svázány.
Komentář: Například pro rekurzivní funkci factorial(x) z Příkladu 10.12 přímo využijeme parametr x, který se ostře zmenšuje, pro snadný důkaz ukončenosti.
Zamyslíme-li se nad Metodou 11.3 do hloubky (matematické), zjistíme, že stejně jako matematická indukce je založená na této vlastnosti: V každé podmnožině přirozených čísel existuje jedno nejmenší (tomu se říká dobré uspořádání). Proto garance zmenšování přirozené hodnoty parametru algoritmu prostě musí znamenat ukončenost jeho výpočtu, bez ohledu na to, co náš vymyšlený parametr znamená. Nejlépe je to ilustrovat názornými příklady.
Příklad 11.4. Dokažte, že následující algoritmus vždy skončí pro jakýkoliv přirozený vstup x.
Algoritmus .
input x;
while x<100 do
y 0 a v každém průchodu vnějšího i vnitřního cyklu se p(x, y) ostře zmenší. Čtenář nechť si toto ověří sám. □
97
Příklad 11.5. Dokažte, že následující algoritmus (viz dřívější 10.13) vždy skončí pro jakýkoliv přirozený vstup x.
Algoritmus . Rekurzivní výpočet funkce fibonacci(x) pro přirozené x. if x < 2 then t G- x;
else t G- fibonacci(x-l)+fibonacci(x-2); return t
Nyní je na první pohled přirozené sledovat přímo parametr x. Indukcí podle něj pak snadno odvodíme, že výpočet fibonacci(x) vždy skončí, neboť jsou rekurzivně volány jen menší hodnoty parametru. V čem je tedy možný nedostatek tohoto přímého přístupu? V zásadě pouze jediný; nezískáme z něj žádný rozumný horní odhad počtu kroků algoritmu. Pro vysvětlení, problém spočívá zhruba v tom, že v bodě fibonacci(x-l)+fibonacci(x-2) se výpočet „rozvětvuje" a my musíme vhodným způsobem umět sečíst počty kroků obou větví.
Na druhou stranu při trikové volbě parametru p(x) = 2X pro použití Metody 11.3 v každé iteraci rekurzivního volání fibonacci(x) pro x >2 v součtu nastane
p(x - 1) + p(x - 2) = 2X-1 + 2X-2 < 2 ■ 2X-1 -1<2X.
Co přesně znamenají slova „v součtu"? To je, že všechny větve rekurzivního výpočtu dohromady na jedné úrovni sníží sledovaný parametr. Počet iterací výpočtu fibanacci(n) tak bude vždy nejen konečný, ale podle uvedené úvahy přímo striktně menší než p(n) = 2n.
Přesto, tento algoritmus je velmi pomalý a mnohem lepšího výpočetního času výpočtu Fibonacciho čísel dosáhneme třeba s alternativním algoritmem Příkladu 10.14. □
Dodatek: Jak konstruovat cykly permutace
Pro mírně složitější ilustraci výše uvedeného konceptu dokazování konečnosti se podíváme na snadný postup nalezení rozkladu permutace na cykly, u kterého však vůbec není na první pohled jasné, zda má skončit.
Algoritmus 11.6. Cykly permutace.
Pro danou permutací tt na n-prvkové neprázdné množině A = {1,2,... ,n} vypíšeme její cykly (víz Oddíl 6.2) takto:
U 1 cyklů. Po první iteraci while cyklu zbude v restrikci permutace 7T na množinu U celkem l — 1 cyklů. Podle indukčního předpokladu pak tyto zbylé cykly budou správně vypsány a algoritmus skončí. □
Komentář: Vidíte, že v tomto důkaze indukcí je indukční krok zcela triviální a důležitý je zde především základ indukce?
Věta. Pokud 7r je permutace, tak vnitřní while cyklus vždy skončí a nalezne v 7T cyklus obsahující libovolný počáteční prvek x G U. Navíc všechny prvky nalezeného cyklu odebere z množiny U.
Důkaz: Zde přímo zopakujeme argument důkazu Věty 6.3: Vezmeme libovolný prvek x = x\ G U a iterujeme zobrazení Xi+i = tv(xí) pro i = 1, 2..., až dojde ke zopakování prvku Xk = Xj pro k > j > 1. (To musí nastat, neboť A je konečná.) Jelikož prvek x j byl již odebrán z U, v kroku x = x^ dojde k ukončení našeho while cyklu. Nadto je 7r prostá, a proto nemůže nastat x\~ = x j = tt(xj_i) pro j > 1. Takto byl nalezen a odebrán z U cyklus (ai,..., cifc-i) a důkaz je hotov. □
11.2 Přehled technik důkazu indukcí
Doposud v našem textu byla matematická indukce představována ve své přímočaré formě, kdy dokazované tvrzení obvykle přímo nabízelo celočíselný parametr, podle nějž bylo potřebné indukci vést. Indukční krok pak prostě zpracoval přechod „n = i —> n = i +1". To však u dokazování správnosti algoritmů typicky neplatí a našim cílem zde je ukázat možné techniky, jak správně indukci na dokazování algoritmů aplikovat. Uvidíme, jak si z nabízejících se parametrů správně vybrat a jak je případně kombinovat.
Technika fixace parametru
První technika důkazu prostě dopředu za některé parametry dosazuje (obecně zvolené) konstanty. Tato technika je vhodná pro případy, kdy je sice v algoritmu více parametrů, ale „zjevně" dochází ke změně jen jednoho (nebo části) z nich a chování algoritmu ke zbylým „neměnným" parametrům je dobře předvídatelné.
Příklad 11.7. Mějme následující algoritmus. Co je jeho výsledkem výpočtu?
Algoritmus . input x, y; res G- 0; while x>0 do
res 0. Prvním průchodem cyklem se uloží res res + y = r0 + hy = rx a, x <^ x — 1 = i. Počáteční hodnota pracovní proměnné res nyní (pro naše indukční úvahy) tudíž je f o + hy = ri a podle indukčního předpokladu je pak výsledkem výpočtu hodnota
Komentář: Všimněte si, že techniku fixace parametru jsme mlčky použili již v Příkladě 10.8. Indukce k součtu parametrů
Druhou techniku je vhodné použít především v případech, kdy se v průběhu algoritmu vždy některý parametr zmenšuje, ale pokaždé je to některý jiný parametr, takže v indukci se nelze zaměřit jen na jeden z nich. Jedná se spíše o situaci u rekurzivních algoritmů.
Příklad 11.8. Je dán následující rekurentní algoritmus.
Algoritmus. Funkce kombinační (m,n) pro přirozená m, n. res <— 1;
if m>0 A n>0 then
res 0. Nyní je podmínka algoritmu splněna a vykonají se rekurentní volání
kombinační(m-1,n) + kombinační(m,n-l).
Rekurentní volání se vztahují k výběru podmnožin m — l+n = m + n — 1 = i-prvkové množiny, například M = {1,2,...,«}. Výsledkem tedy je, podle indukčního předpokladu pro součet i, počet (m — l)-prvkových plus m-prvkových podmnožin množiny M.
Kolik nyní je m-prvkových podmnožin (i + l)-prvkové množiny M' = M U {i + 1}? Pokud ze všech podmnožin odebereme prvek i + 1, dostaneme právě m-prvkové podmnožiny (z těch neobsahujících i + 1) plus (m — l)-prvkové podmnožiny (z těch původně obsahujících i + 1). A to je v součtu rovno kombinační(m-l,n) + kombinační (m,n-l), jak jsme měli dokázat. □
Zesílení dokazovaného tvrzení
Velmi častou situací při dokazování algoritmu je, že se zajímáme o hodnoty některých proměnných nebo „výstupy" některé funkce, ale ke správnému matematickému důkazu musíme „postihnout" i chování jiných funkcí a proměnných v algoritmu. Taková situace pak typicky vede na potřebu zesílení požadovaného tvrzení v matematické indukci.
Příklad 11.9. Zjistěte, kolik znaků 'z' v závislosti na celočíselné hodnotě n vstupního parametru n vypíše následující algoritmus.
Algoritmus 11.10.
st <-"z";
foreach i«—1,2,3,...,n-l,n do
vytiskni řetězec st;
st ^— st . st ; (zřetězení dvou kopií st za sebou)
done
Zkusíme-li si výpočet simulovat pro n = 0,1, 2, 3,4..., postupně dostaneme počty 'z' jako 0,1,3,7,15.... Na základě toho již není obtížné „uhodnout", že počet 'z' bude (asi) obecně určen vztahem 2n — 1. Toto je však třeba dokázat!
Komentář: Jak záhy zjistíme, matematická indukce na naše tvrzení přímo „nezabírá", ale mnohem lépe se nám povede s následujícím přirozeným zesílením dokazovaného tvrzení:
Věta. Pro každé přirozené n Algoritmus 11.10 vypíše právě 2n — 1 znaků 'z' a proměnná st bude na konci výpočtu obsahovat řetězec 2n znaků ' z'.
101
Důkaz: Postupujeme indukcí podle n. ~Báze pro n = 0 je zřejmá, neprovede se ani jedna iterace cyklu a tudíž bude vytištěno 0 = 2° — 1 znaků 'z', což bylo třeba dokázat. Mimo to proměnná st iniciálně obsahuje 1=2° znak 'z'.
Nechť tedy tvrzení platí pro jakékoliv uq a položme n = uq + 1. Podle indukčního předpokladu po prvních uq iteracích bude vytištěno 2n° — 1 znaků ' z' a proměnná st bude obsahovat řetězec 2n° znaků 'z'. V poslední iteraci cyklu (pro i n=n0+l) vytiskneme dalších 2n° znaků 'z' (z proměnné st) a dále řetězec st „zdvojnásobíme". Proto po n iteracích bude vytištěno celkem 2n° — 1 + 2n° = 2n°+1 — 1 = 2n — 1 znaků ' z' a v st bude uloženo 2 • 2n° = 2no+1 = 2n znaků 'z'. □
11.3 Zajímavé algoritmy aritmetiky
Pro další ukázky důkazových technik pro algoritmy se podíváme na některé krátké algoritmy z oblasti aritmetiky. Například „zbytkové" umocňování na velmi vysoké exponenty je podkladem známé RSA šifry:
Algoritmus 11.11. Binární postup umocňování.
Pro daná čísla a, b vypočteme jejich celočíselnou mocninu (omezenou na zbytkové třídy modulo m kvůli prevenci přetečení rozsahu celých čísel v počítači), tj. ab mod m, následujícím postupem.
res <— 1;
while b > 0 do
if b mod 2 > 0 then res (res-a) mod m ; b 1 a uvažme l = £q + 1. Pak zřejmě 6 > 2 a vykonají se alespoň dvě iterace cyklu. Po první iteraci budou hodnoty proměnných po řadě
ai = a2, 6i = [6/2J a res = n = (ab mod 2) mod m .
Tudíž délka binárního zápisu bi bude jen £q a podle indukčního předpokladu zbylé iterace algoritmu skončí s výsledkem
res = ri ■ abl mod m = (ab mod 2 • a2^2-!) mod m = ab mod m.
□
Euklidův algoritmus
Již z dávných dob antiky pochází následující zajímavý a koneckonců velmi jednoduchý postup-algoritmus pro nalezení největšího společného dělitele dvou čísel.
102
Algoritmus 11.12. Euklidův pro největšího společného dělitele.
Pro zadaná přirozená čísla p, q počítá následovně: input p, q; while p>0 A q>0 do
if p>q then p p-q; else q q_p;
done
output p+q;
Věta. Pro každé p,q G N na vstupu algoritmus vrátí hodnotu největšího společného dělitele čísel pag, nebo 0 pro p = q = 0.
Důkaz opět povedeme indukcí podle součtu i = p + q vstupních hodnot. (Jak jsme psali, je to přirozená volba v situaci, kdy každý průchod cyklem algoritmu sníží jedno z p,q, avšak není jasné, které z nich.)
• Báze indukce pro i=p + q = 0]e zřejmá; cyklus algoritmu neproběhne a výsledek ihned bude 0.
• Ve skutečnosti je zase výhodné uvažovat rozšířenou bázi, která zahrnuje i případy, kdy jen jedno z p, q je nulové (Proč? Jedná se o všechny případy, kdy průchod cyklem neproběhne, neboli touto indukcí sledujeme počet průchodů cyklem.) Pak výsledek p + q bude roven tomu nenulovému z obou sčítanců, což jev tomto případě zároveň jejich největší společný dělitel.
• Indukční krok. Mějme nyní vstupní hodnoty p = /ip>0ag = /íg>0 - tehdy dojde k prvnímu průchodu tělem cyklu našeho algoritmu, přičemž hp + hq = i + 1. Předpokládejme hp > hq; poté po prvním průchodu tělem cyklu budou hodnoty p = hp — hq a q = hq, přičemž nyní p + q = hp < hp + hq — 1 = i.
Podle indukčního předpokladu (jelikož nyní p + q < i) tudíž výsledkem algoritmu pro vstupy p = hp — hq a q = hq bude největší společný dělitel NSD(hp — hq, hq). Symetricky pro hp < hq algoritmus vrátí NSD(hp, hq — hp). (Kde NSD() krátce označuje největšího společného dělitele.) Důkaz proto bude dokončen následujícím Lematem 11.13. □
Lema 11.13. Pro každá přirozená a, b platí NSD(a,b) = N SD(a — b,b) = NSD(a,b—a). Komentář: Všimněte si, že dělitelnost je dobře definována i na záporných celých číslech.
Důkaz: Ověříme, že c = NSD(a — b,b) je také největší společný dělitel čísel a a b (druhá část je pak symetrická).
• Jelikož číslo c dělí čísla a — b a b, dělí i jejich součet (a — b) + b = a. Potom c je společným dělitelem a a b.
• Naopak nechť d nějaký společný dělitel čísel a a b. Pak d dělí také rozdíl a — b. Tedy d je společný dělitel čísel a — b a b. Jelikož c je největší společný dělitel těchto dvou čísel, nutně d dělí c a závěr platí. □
Relativně rychlé odmocnění
Na závěr oddílu si ukážeme jeden netradiční krátký algoritmus a jeho analýzu a důkaz ponecháme zde otevřené. Dokážete popsat, na čem je algoritmus založen?
103
Algoritmus 11.14. Celočíselná odmocnina.
Pro dané přirozené číslo x vypočteme dolní celou část jeho odmocniny [^/x\:
p ^— x; res 0; while p > 0 do
while (res + p)2 < x do res res + p;
p <- Lp/2J ;
done
output res ;
Poznámka: Zamysleli jste se, jaký mají algoritmy v tomto oddíle vlastně význam? Vždyť stejné úlohy jistě sami vyřešíte každý jednou jednoduchou f oreach smyčkou. Podívejte se však (alespoň velmi zhruba) na počet kroků, které zde uvedené algoritmy potřebují vykonat k získání výsledku, a srovnejte si to s počty kroků oněch „jednoduchých" algoritmů.
Pro skutečně velká vstupní čísla zjistíte propastný rozdíl - s takovým „jednoduchým" algoritmem, třeba 'f oreach i <— 1, . . .b do res <— res-a mod m done', se pro obrovské hodnoty b výsledku nikdy nedočkáte, kdežto Algoritmus 11.11 stále poběží velmi rychle. (Spočítáte, jak rychle?) Obdobně je tomu u Algoritmu 11.14.
11.4 Dynamický algoritmus
Lekci zakončíme krátkou, ale velmi hezkou ukázkou tzv. dynamického algoritmu, který je znám pod jmény Floyd-Warshallův.
Komentář: Klíčovou myšlenkou dynamických algoritmů je rozklad problému na pod-problémy, jejichž řešení jsou postupně ukládána pro další možné použití. Metoda je obzvláště vhodná v případech, kdy rozložené podúlohy si jsou podobné a mohou se opakovat.
Metoda 11.15. Dynamický výpočet všech nejkratších cest
mezi vrcholy v grafu G na množině vrcholů V(G) = {v0, v1}..., i^-i}-
• Na počátku nechť d[i,j] udává 1 (případně váhu-délku hrany {ví,Vj}), nebo oo pokud hrana mezi i, j není.
• Po kroku t > 0 nechť platí, že d[i,j] udává délku nejkratší cesty mezi Ví,Vj, která užívá pouze vnitřní vrcholy z množiny {vq, v\,..., vt-±} (prázdné v t = 0).
• Při přechodu z kroku t na následující krok t + 1 upravujeme vzdálenost pro každou dvojici vrcholů vi}Vj - jsou vždy pouhé dvě možnosti:
* Buď je cesta délky d [i, j] z předchozího kroku t stále nejlepší (tj. nově povolený vrchol vt nám nepomůže),
* nebo cestu vylepšíme spojením přes nově povolený vrchol vt, čímž získáme menší vzdálenost d [i ,t] +d [t, j] —>-d[i,j]. (Nakreslete si obrázek.)
• Po N krocích úprav je výpočet hotov. Výpočet nejkratších cest
Alternativně si zapíšeme postup této metody až překvapivě krátkým symbolickým algoritmem:
104
Algoritmus 11.16. Výpočet všech nejkratších cest; Floyd-Warshall
input ' Pole d [, ] délek hran (nebo oo) grafu G' ;
foreach t G- 0,1,...,N— 1 do
foreach i G- 0,1,..., N - 1, j G- 0,1,..., N - 1 do d[i,j] • B. Množiny A a, B jsou „stejně velké" právě když mezi nimi existuje bijekce. V případech nekonečných množin pak místo "velikosti" mluvíme formálně o jejich
Komentář: Uvedená definice kardinality množin „funguje" velmi dobře i pro nekonečné množiny:
* Například N a TL mají stejnou kardinalitu (jsou „stejně velké", tzv. spočetně nekonečné).
* Lze snadno ukázat, že i (Q je spočetně nekonečná, tj. existuje bijekce / : N —> (Q, stejně
106
jako bijekce h : N —> N2.
* Existují ale i nekonečné množiny, které jsou „striktně větší" než libovolná spočetná množina (příkladem je R ve Větě 12.2).
* Později dokážeme, že existuje nekonečná posloupnost nekonečných množin, z nichž každá je striktně větší než všechny předchozí.
Pro porovnávání velikostí množin někdy s výhodou využijeme následující přirozené, ale nelehké tvrzení (bez důkazu):
Věta 12.1. Pro libovolné dvě množiny A, B (i nekonečné) platí, že pokud existuje injekce A —>• B a zároveň i injekce B —>• A, pak existuje bijekce mezí A a B.
A
Cantorova diagonála, aneb kolik je reálných čísel
Prvním klíčovým poznatkem ukazujícím na neintuitivní chování nekonečných množin je následující důkaz, který dal historicky vzniknout metodě tzv. Cantorovy diagonály.
Věta 12.2. Neexistuje žádné surjektívní zobrazení g : N —y R.
Důsledek 12.3. Neexistuje žádné ínjektívní (tudíž ani bíjektívní) zobrazení h : R —y N. Neformálně řečeno, reálnych čísel je striktně více než všech přirozených.
107
Důkaz (Věty 12.2 sporem): Nechť takové g existuje a pro zjednodušení se omezme jen na funkční hodnoty v intervalu (0,1). Podle hodnot zobrazení g si takto můžeme „uspořádat" dekadické zápisy všech reálných čísel v intervalu (0,1) po řádcích do tabulky:
9(0)
9(1) 9(2) 9(3) 4(4)
0. 0. 0. 0. 0.
1
5427578325 4
1
3
9
Nyní sestrojíme číslo a E (0,1) následovně; jeho i-tá číslice za desetinnou čárkou bude 1, pokud v 2-tém řádku tabulky na diagonále není 1, jinak to bude 2. V našem příkladě a = 0.21211...
Kde se naše číslo a v tabulce nachází? (Nezapomeňme, g byla surjektivní, takže a někde musí být.) Konstrukce však ukazuje, že a se od každého čísla v tabulce liší na aspoň jednom desetinném místě, to je spor. (Až na drobný technický detail s rozvojem
12.2 „Naivní" množinové paradoxy
Analogickým způsobem k Větě 12.2 lze dokázat následovně zobecnění vyjadřující se o jakékoliv množině a jí přiřazené striktně větší.
Věta 12.4. Nechť M je libovolná množina. Pak existuje injektivní zobrazení f : M —>• 2M, ale neexistuje žádné bijektivní zobrazení g : M —y 2M.
Důkaz: Dokážeme nejprve existenci /. Stačí ale položit f(x) = {x} pro každé x G M. Pak / : M —y 2M je zjevně injektivní.
Neexistenci g dokážeme sporem. Předpokládejme tedy naopak, že existuje bijekce g : M —>• 2M. Uvažme množinu K C M definovanou takto:
Jelikož g je bijektivní a, K E 2M, musí existovat y E M takové, že g (y) = K. Nyní rozlišíme dvě možnosti:
- y E g(y). Tj. y E K. Pak ale y £ g (y) z definice k, spor.
- y (jL g(y)- To podle definice K znamená, že y E K, tj. y E g (y), spor. ^
Komentář: Dvě navazující poznámky. • Technika použitá v důkazech Vět 12.2 a 12.4 se nazývá Cantorova diagonální metoda, nebo také zkráceně diagonalizace.
Konstrukci množiny K lze znázornit pomocí následující tabulky:
. a b c d
□
K = {x E M \ x ^ g (x)}.
g(a). 9(b)
g(c)
g(d)
108
Symbol y/ resp. — říká, že prvek uvedený v záhlaví sloupce patří resp. nepatří do množiny uvedené v záhlaví řádku. Tedy např. d G g (b) a a 0 g (d). Množina K poté obsahuje ty diagonálni prvky označené —, tj. „převrací" význam diagonály.
• Z toho, že nekonečna mohou být „různě velká", lze lehce odvodit řadu dalších faktů. V jistém smyslu je např. množina všech problémů větší než množina všech algoritmů (obě množiny jsou nekonečné), a proto nutně existují problémy, které nejsou algoritmicky řešitelné.
Cantorův paradox
Naivní teorie množin, jak jsme si ji uvedli i v tomto předmětu, trpí mnoha neduhy a nepřesnostmi, které vyplynou na povrch především při „neopatrné manipulaci" s nekonečnými množinami. Abychom se těmto „neopatrnostem" vyhnuli bez přílišné formalizace, dva základní z těchto paradoxů si nyní ukážeme.
Příklad 12.5. Uvážíme-li nyní nekonečnou posloupnost množin
A1,A2,A3,A4,---
kde A\ = N a Ai+1 = 2Ai pro každé i G N, je vidět, že všechny množiny jsou nekonečné a každá je striktně větší než libovolná předchozí.
Kde však v tomto řazení kardinalit bude „množina všech množin"? Na tuto otázku, jak sami asi cítíte, nelze podat odpověď. Co to však znamená? □
* Takto se koncem 19. století objevil první Cantorův paradox nově vznikající teorie množin.
* Dnešní moderní vysvětlení paradoxu je jednoduché, prostě „množinu všech množin" nelze definovat, taková v matematice neexistuje.
Brzy se však ukázalo, že je ještě mnohem hůř... Russelův paradox
Fakt: Není pravda, že každý soubor prvků lze považovat za množinu.
* Nechť X = {M I M je množina taková, že M £ M}. Platí X G X ?
- Ano. Tj. X G X. Pak ale X splňuje X g X.
- Ne. Pak X splňuje vlastnost X ^ X, tedy X je prvkem X, tj., X E X.
* Obě možné odpovědi vedou ke sporu. X tedy nelze prohlásit za množinu. Jak je ale něco takového vůbec možné?
Komentář: Vidíte u Russelova paradoxu podobnost přístupu s Cantorovou diagonalizací? Russelův paradox se objevil začátkem 20. století a jeho „jednoduchost" zasahující úplné základy matematiky (teorie množin) si vynutila hledání seriózního rozřešení a rozvoj formální matematické logiky.
Pro ilustraci tohoto paradoxu, slyšeli jste už, že „v malém městečku žije holič, který holí právě ty muže městečka, kteří se sami neholí"? Zmíněné paradoxy naivní teorie množin zatím v tomto kurzu nerozřešíme, ale zapamatujeme si, že většina matematických a informatických disciplín vystačí s „intuitivně bezpečnými" množinami.
109
12.3 Algoritmická neřešitelnost problému zastavení
Výše vysvětlené myšlenky diagonalizace a principů základních paradoxů naivní teorie množin sice vypadají „velmi matematicky". Přesto je však téměř beze změny lze aplikovat i na bytostně informatickou otázku, zda lze algoritmicky poznat, pro které vstupy se daný algoritmus vůbec zastaví. Negativní odpověď na tuto otázku je jedním z fundamentálních výsledků informatiky a přitom má překvapivě krátký a čistý důkaz diagonalizací.
Fakt: Uvědomme si (velmi neformálně) několik základních myšlenek.
* Program v každém programovacím jazyce je konečná posloupnost složená z konečně mnoha symbolů (písmena, číslice, mezery, speciální znaky, apod.) Nechť E je množina všech těchto symbolů. Množina všech programů je tedy jistě podmnožinou množiny UieN^1' která je spočetně nekonečná. Existuje tedy bijekce / mezi množinou N a množinou všech programů. Pro každé j G N označme symbolem Pj program f(j). Pro každý program P tedy existuje i G N takové, že P = Pí.
* Každý možný vstup každého možného programu lze zapsat jako konečnou posloupnost symbolů z konečné mnočiny T. Množina všech možných vstupů je tedy spočetně nekonečná a existuje bijekce g mezi množinou N a množinou všech vstupů. Pro každé j G N označme symbolem Vj vstup g(j).
* Předpokládejme, že existuje program H alt, který pro dané i, j G N zastaví s výstupem ano/ne podle toho, zda Pí pro vstup Vj zastaví, nebo ne.
* Tento předpoklad dále dovedeme ke sporu dokazujícímu, že problém zastavení nemá algoritmické řešení.
Věta 12.6. Neexistuje program Halt, který by pro vstup (Pí, Vj) správně rozhodl, zda se program Pí zastaví na vstupu Vj.
Důkaz: Sporem uvažme program Diag s následujícím kódem: input k;
if iJa/£(k,k) =ano then while true do ; done
(Program Diag(k) má na rozdíl od Halt jen jeden vstup k, což bude důležité.) Fungování programu Diag lze znázornit za pomocí následující tabulky:
^0 Pi p2 p3 ...
- v •••
v1 - v •••
v2 —
V3
Symbol y/ resp. — říká, že program uvedený v záhlaví sloupce zastaví resp. nezastaví pro vstup uvedený v záhlaví řádku. Program Diag „zneguje" diagonálu této tabulky.
Podle našeho předpokladu (Diag je program a posloupnost Pj zahrnuje všechny programy) existuje j G N takové, že Diag = Pj. Zastaví Diag pro vstup Vj?
110
- Ano. Podle kódu Díag pak ale tento program vstoupí do nekonečné smyčky, tedy nezastaví.
- Ne. Podle kódu Díag pak ale if test neuspěje, a tento program tedy zastaví. Předpoklad existence programu Halt tedy vede ke sporu. □
Komentář: Otázkami algoritmické (ne)řešitelnosti problémů se zabývá teorie vyčíslitelnosti. Metoda diagonalizace se také často využívá v teorii složitosti k důkazu toho, že dané dvě složitostní třídy jsou různé.
Rozšiřující studium
Látka této lekce zabrousila až do teoretických hlubin matematické logiky a teorie množin. Další studium v těchto oblastech se dá očekávat hlavně u studentů speciňcky zaměřených teoretickým směrem (a mířících spíše do akademické než aplikační sféry), zajímajících se o matematiku samotnou nebo o teorii vyčíslitelnosti. Proto také uvedené pokročilé poznatky Lekce 12 nebudou vyžadovány u zkoušky tohoto předmětu.
111
Závěrem
Gratulujeme všem, kteří se naším nelehkým učebním textem „prokousali" až sem, a přejeme mnoho úspěchů v dalším studiu informatiky.
Konečně znovu připomínáme, že nedílnou součástí našeho studijního textu je Interaktivní osnova předmětu IB000 v IS MU a v ní přiložené online odpovědníky určené k procvičování přednesené látky.
http://is.muni.cz/el/1433/podzim2014/IB000/index.qwarp
112