12.2 Dijkstrův algoritmus
Hledání nejkratších cest
Fakt (bez důkazu)
Problém nalezení délky nejkratší cesty mezi dvěma vrcholy pro graf ohodnocený obecnými (tedy i zápornými) délkami je NP-těžký – proto pro něj neočekáváme existenci efektivního algoritmu.
- Pro některá speciální ohodnocení grafu efektivní algoritmy existují. Dva nejpoužívanější jsou:
- Dijkstrův, který předpokládá kladné délky hran (případně nezáporné).
- Bellmanův-Fordův, který připouští záporné délky, ale předpokládá neexistenci záporných cyklů v grafu.
Úprava BFS pro přirozené váhy
Úprava BFS pro přirozené váhy
Každou hranu "podrozdělíme" – nahradíme ji cestou tvořenou tolika jednotkovými hranami, kolik činila délka hrany.
Tím vznikne neohodneconý graf, ve kterém lze použít BFS pro hledání nejkratších cest.
- Tento algoritmus je funkční, ale neefektivní
- Označíme-li L maximální délku hrany, podrozdělením vznikne \(O(L · m)\) nových vrcholů a hran.
- Složitost BFS algoritmu tedy bude \(Θ(L · m + n)\).
Dijkstrův algoritmus
Dijkstra je zobecněním průchodu grafu do šířky.
Místo simulace průchodu BFS vlny v lineárním čase vzhledem k délce hran, Dijkstra zpracuje každou hranu v \(O(1)\) čase.
Vstup: Orientovaný graf \(G = (V, E)\) s kladnými délkami hran \(\ell : E \to \mathbb{R}^+\) a počáteční vrchol \(v_0\).
Výstup:Vzdálenosti z vrcholu \(v_0\) do všech vrcholů grafu \(G\).
Základní idea Dijkstra
- U každého původního vrcholu si udržujeme "budík" - kdy by do vrcholu dorazila BFS vlna.
- Pokaždé vybereme sousední vrchol s nejmenší hodnotou budíku a podíváme se na jeho následníky.
- Pokud by se některý z nich dostal do vrcholu dříve, aktualizujeme jeho budík.
- Toto opakujeme dokud "nezazvoní budík" všech vrcholů.
- Čas na budíku vrcholu \(v\) ozn. \(h(v)\).
- Počáteční hodnota \(h(v_0) = 0\). a \(h(v) = ∞\) pro všechny ostatní vrcholy.
- Podobně jako u BFS může mít vrchol tři stavy:
- Nenalezené
- Otevřené (budík je nastavený)
- Uzavřené (budík již zazvonil)
- Dále si pamatujeme, který vrchol je předchůdce daného vrcholu na nejkratší cestě.
Dijkstrův algoritmus (pseudokód)
Dijkstrův algoritmus (pseudokód)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Relaxace vrcholů
Relaxace vrcholů
- Přepočítání ohodnocení \(h(w)\) pro všechny následníky \(w\) vrcholu \(v\) v Dijkstra na řádcích (9) – (14) budeme nazývat relaxace vrcholu \(v\)
Konečnost a správnost Dijkstra
Věta o konečnosti Dijkstrova algoritmu
Věta o konečnosti Dijkstrova algoritmu
Dijkstra na grafu s kladnými délkami hran se v konečném čase zastaví a po jeho skončení budou všechny dosažitelné vrcholy \(v\) uzavřeny s \(h(v) = d(v_0, v)\).
Tuto větu dokážeme kombinací 4 vlastností Dijkstra:
- Vlastnost O (Ohodnocení)
- Vlastnost M (Monotonie)
- Vlastnost D (Dosažitelnost)
- Vlastnost V (Vzdálenost)
Vlastnost O (Ohodnocení)
Vlastnost O (Ohodnocení)
Ohodnocení \(h(v)\) v průběhu Dijkstra nikdy neroste a je-li konečné, rovná se délce nějakého sledu z \(v_0\) do \(v\).
Důkaz vlastnosti O
- Indukcí podle doby běhu Dijkstra.
- Na počátku výpočtu tvrzení určitě platí, protože jediné konečné ohodnocení je \(h(v_0) = 0\).
- Kdykoliv Dijkstra snižuje ohodnocení \(h(w)\), stane se tak relaxací otevřeného vrcholu \(v\) s konečným \(h(v)\), jehož následníkem je \(w\).
- Podle indukčního předpokladu tedy existuje \(v_0-v\)-sled délky \(h(v)\).
- Jeho rozšířením o hranu \(vw\) vznikne \(v_0w\)-sled délky \(h(v) + ℓ((v, w))\), což je přesně nová konečná hodnota \(h(w)\).
Vlastnost M (Monotonie)
Vlastnost M (Monotonie)
V každém kroku výpočtu platí, že \(h(z) ≤ h(o)\) pro \(z\) uzavřený vrchol a \(o\) otevřený vrchol. Speciálně pak platí, že Dijkstra nikdy neotevře již uzavřený vrchol.
Důkaz vlastnosti M
- Vždy vybereme otevřený vrchol \(v\) s nejmenším \(h(v)\).
- Před relaxací \(v\) tedy musí platit \(h(z) ≤ h(v) ≤ h(o)\) pro libovolný \(z\) uzavřený a \(o\) otevřený.
- Nyní vrchol \(v\) relaxujeme:
- Pokud \(w\) byl uzavřený, nemůže se jeho hodnota změnit, neboť již před relaxací platilo \(h(w) ≤ h(v)\).
- Pokud \(w\) byl otevřený nebo nenalezený, jeho hodnota se sice může snížit na \(h(v) + ℓ(v, w)\), ale nikdy ne pod \(h(v)\), takže ani pod \(h(z)\) žádného uzavřeného \(z\).
- Kdybychom otevřeli již uzavřený vrchol \(z\), muselo by platit \(h(v) + ℓ(v, z) ≤ h(z)\), což nelze.
Vlastnost D (Dosažitelnost)
Vlastnost D (Dosažitelnost)
Když se Dijkstra zastaví, uzavřené jsou právě vrcholy dosažitelné z \(v_0\).
Důkaz vlastnosti D
- Dokážeme stejně jako obdobnou vlastnost BFS.
- První otevřeným a následně uzavřeným vrcholem je \(v_0\).
- Vrchol je otevřen, právě když je do té doby nenalezeným následníkem dříve otevřeného vrcholu a tudíž je dosažitelný z \(v_0\).
- Protože Dijkstra dle Vlastnosti M, nikdy neotevře již uzavřený vrchol, zbytek důkazu je totožný s BFS:
- Kdyby tedy existoval nějaký dosažitelný, ale neuzavřený vrchol, existoval by ten „nejbližší“ (co do počtu hran na nejkratší cestě) a to by vedlo ke sporu.
Vlastnost V (Vzdálenost)
Vlastnost V (Vzdálenost)
Když se Dijkstra zastaví, je \(h(w) = d(v_0, w)\) pro všechny \(w ∈ V\).
Důkaz vlastnosti V
Vrchol \(w\) dosažitelný z \(v_0\) nazveme špatný, pokud \(h(w) \ne d(v0, w)\). Z Vlastnosti O víme, že \(h(w)\) odpovídá délce nějakého \(v_0w\)-sledu a tedy \(h(w) > d(v_0, w)\).
- Pro spor předpokládejme, že existuje nějaký špatný vrchol \(w\) (Podobně jako u BFS).
- Víme, že v0 není špatný, protože \(h(v_0) = 0 = d(v_0, v_0)\).
- Buď \(w\) špatný vrchol takový, že nejkratší cesta v \(G\) z \(v_0\) do \(w\) používá nejmenší možný počet hran.
- Buď \(v\) předchůdce \(w\) na této cestě z \(v_0\).
- Kdyby \(v\) byl špatný, volili bychom \(v\) namísto \(w\). Tedy platí \(h(v) = d(v_0, v)\).
- Vrchol \(v\) byl jistě někdy otevřený a později relaxovaný. Při jeho relaxaci byla aktuální hodnota \(h(w)\) větší než \(d(v_0, w)\) (neboť toto platí dokonce až po zastavení Dijkstra).
- V tom případě ale po relaxaci \(v\) muselo platit \(h(w) = d(v_0, v) + ℓ((v, w)) = d(v_0, w)\). Spor.
Vlastnost sledů v Dijkstra
Lemma
Je-li po uzavření vrcholu v algoritmu Dijkstra \(h(v)\) konečné pro nějaký vrchol \(v\), rovná se délce nejkratší \(v_0v\)-cesty, která jako vnitřní vrcholy používá pouze uzavřené vrcholy.
Důkaz vlastnosti sledů v Dijkstra
- Indukcí podle počtu uzavřených vrcholů.
- Pro \(k = 0\) platí, neboť jediné konečné je \(h(v_0) = 0\).
- Pro indukční krok, kdy relaxujeme a tedy uzavíráme \(v\), uvážíme dva případy:
- Relaxace \(v\) nezměnila \(h(w)\). Pak z IP tvrzení platí.
- Relaxace \(v\) změnila \(h(w)\). Pak dle Vlastnosti O \(h(w)\) odpovídá délce nejkratší \(v_0v\)-cesty protažené o hranu \((v, w)\).
- Protože nyní ale je \(v\) uzavřený a \(v_0v\)-cesta (dle IP) používala jako vnitřní vrcholy jen uzavřené vrcholy, platí tato vlastnost i pro \(w\).
Složitost Dijkstra bez binární haldy (priority queue)
Pokud jsou délky hran kladné, potom Dijkstra nad souvislým grafem o \(n\) vrcholech běží v čase \(O(n^2)\).
V grafech s malým počtem hran je odhad \(O(n^2)\) zbytečně nadhodnocený. Celkový počet operací na řádku (11) je pouze \(O(m)\), ale brzdí nás hledání minima: \(O(n)\).
Důkaz složitosti Dijkstrova algoritmu
- Inicializace trvá \(O(n)\).
- Každý vrchol uzavřeme nejvýše jednou.
- Vnějším cyklem projdeme nejvýše \(n\)-krát.
- Pokaždé hledáme minimum až z \(n\) ohodnocení vrcholů a procházíme až \(n\) následníků.
Dijkstra s binární haldou
Podobně jako u Jarníkova algoritmu, použijeme (binární) haldu, klíčem \(v\) bude hodnocení \(h(v)\).
Dijkstra s binární haldou
Dijkstra s binární haldou
Věta o časové složitosti Dijkstra s binární haldou
Věta o časové složitosti Dijkstra s binární haldou
Časová složitost DijkstraHalda je \(O(|E| \log |V|)\).
Důkaz
- Řádky (2)-(5) trvají \(O(|V|)\).
- Celková složitost na řádku (7) je \(O(|V| \log |V|)\).
- Celková složitost na řádku (11) je \(O(|E| \log |V|)\), neboť počet volání operace
HeapDecreaseKey
je nejvýše \(|E|\).