NEJKRATŠÍ CESTY Nejkratší cesty - kap. 6
Nejkratší cesty z jednoho uzlu Seznámíme se s následujícími pojmy: w-vzdálenost (vzdálenost na ohodnoceném grafu), relaxace, strom nejkratších cest Dijkstrův algoritmus Bellman-Fordův algoritmus Skripta kap. 6, str. 110 – 122 Nejkratší cesty - odst. 6.1
Několik obecných úvah Uvažujeme nejobecnější případ - ohodnocené OG: w-délka spojení h1, h2, ..., hk = w(hi) w-vzdálenost dw(u,v) = w-délka nejkratšího spojení nebo nedostupné uzly - vzdálenost < 0 spojení se záporným cyklem – vzdálenost - počítání s nekonečny: a + (- ) = (- ) + a = - pro a a + = + a = pro a - ? Které z vlastností 0 až 4 má takováto vzdálenost ? Nejkratší cesty - odst. 6.1
v s u Varianty úlohy hledání nejkratších cest: 1 1 1 n n 1 n n Důležité zjištění: Pro libovolnou hranu (u,v)H a uzel sU platí dw(s,v) dw(s,u) + w(u,v) s v u dw(s,v) w(u,v) dw(s,u) ! Platí pro konečné i nekonečné hodnoty w-vzdáleností ! Nejkratší cesty - odst. 6.1
d[u] ... délka (dosud nalezené) minimální cesty Datové struktury: d[u] ... délka (dosud nalezené) minimální cesty p[u] ... předchůdce na (dosud nalezené) minimální cestě Q ... (prioritní) fronta otevřených uzlů (halda?) Společné operace pro základní varianty algoritmů: InitPaths(G,s) - inicializace datových struktur 1 for každý uzel uU 2 { d[u] ; p[u] nil } 3 d[s] 0 Relax(u,v,w) - (případná) úprava délky nalezené nejkratší cesty 1 if d[v] > d[u]+w(u,v) 2 { d[v] d[u]+w(u,v); p[v] u } Nejkratší cesty - odst. 6.1
V: Předpokládejme, že pro nějaký graf provedeme operaci InitPaths a pak libovolný počet operací Relax. Potom platí d[u] dw(s,u) jakmile d[u] dosáhne hodnoty dw(s,u), už se nemění jakmile se žádné d[u] nemění, máme strom nejkratších cest do všech dosažitelných uzlů z uzlu s 1 6 8 2 1 4 12 1 1 4 2 4 1 4 2 2 4 5 1 2 1 ? V jakém pořadí hran máme provádět relaxaci ? ? Jak dlouho máme provádět relaxaci ? Nejkratší cesty - odst. 6.1
Dijkstrův algoritmus Základní předpoklad w : H R+ (nezáporné délky hran) Jedná se o upravený algoritmus prohledávání do šířky – otevřené uzly se řadí do prioritní fronty (a vybírají) podle hodnoty d[u] ... aproximace dw(s,u) s 1 4 6 2 1 7 4 1 1 4 2 4 1 4 2 2 4 5 1 2 1 Dijkstrův algoritmus - odst. 6.2
Co se stane, když existují záporně ohodnocené hrany? Dijkstra(G,s,w) 1 InitPaths(G,s) 2 S ; InitQueue(Q) 3 for každý uzel uU { Enqueue(Q,u) } O(|U|) 4 while not EmptyQueue(Q) { 5 u ExtractMin(Q); S S{u} O(|U| . lg |U|) 6 for uzel vAdj[u] { Relax(u,v,w) O(|H| . lg |U|) 8 } } Možné ještě O(|U| . lg |U| + |H|) nebo O(|U|**2) (podle způsobu implementace prioritní fronty) Co se stane, když existují záporně ohodnocené hrany? Relax se musí doplnit o vracení uzlů do prioritní fronty (?? ukončení algoritmu, časová složitost ??) Dijkstrův algoritmus - odst. 6.2
Důkaz správnosti Dijkstrova algoritmu Tvrzení: Při uzavření uzlu u (řádka 5 ... S S{u}) platí d[u] = d(s,u) D: sporem - nechť je d[u] > d(s,u) pro nějaký uzavřený uzel, mějme nejkratší cestu s u, x je poslední uzavřený uzel uzavřené uzly S 0 u y s d[y] = d(s,y) d(s,u) < d[u] spor s vybráním uzlu u, když byl k dispozici uzel y s menší hodnotou x Dijkstrův algoritmus - odst. 6.2
Bellmanův-Fordův algoritmus ? Co dělat v případě záporně ohodnocených hran ? Systematicky relaxovat ... Bellman-Ford(G,s,w) 1 InitPaths(G,s) 2 for i 1 to |U|-1 { 3 for každou hranu (u,v)H { Relax(u,v,w) } 4 } 5 for každou hranu (u,v)H { 6 if d[v] > d[u] + w(u,v) { return false } } 7 return true Složitost O(|U| . |H|) ?Proč má nyní Relax konstantní časovou složitost? Bellman-Ford algoritmus - odst. 6.3
? Nelze B-F algoritmus nějak upravit / zrychlit ? Co když zavedeme frontu uzlů s úspěšným Relax a bereme jen hrany vycházející z těchto uzlů? (a máme Dijkstru!) ukončení - při vyprázdnění fronty problém - co když se fronta nevyprázdní? v nejhorším případě zase O(|U| . |H|) DAG-Paths - nejkratší cesty pro acyklické grafy 1 Topologicky uspořádáme uzly grafu G 2 InitPaths(G,s) 3 for každý uzel u v pořadí podle topologického uspořádání { 4 for každé vAdj[u] {Relax(u,v,w) } 5 } ?? Složitost ?? O(|H|+|U|) !! Bellman-Ford algoritmus - odst. 6.3
Kontrolní otázky Která část Dijkstrova algoritmu je podstatně závislá na předpokladu nezáporného ohodnocení hran? Ukažte na jednom příkladu, že pro záporně ohodnocené hrany může Dijkstrův algoritmus dát špatný výsledek, a na jiném příkladu, že může dát správný výsledek. Je možné prohlásit, že Dijkstrův algoritmus bude fungovat správně i při záporném ohodnocení hran, pokud bude zadaný graf acyklický? Je možné prohlásit, že Dijkstrův algoritmus bude fungovat správně i při záporném ohodnocení hran, pokud bude hledat vzdálenost z kořene do ostatních uzlů kořenového stromu? Navrhněte časově efektivní algoritmus pro určení celkového počtu různých orientovaných cest v daném acyklickém grafu. (Návod: Inspirujte se algoritmem DAG-Paths a za hodnotu d[u] berte počet cest končících v uzlu u.) Navrhněte algoritmus, který určí vzdálenost ze všech uzlů do uzlu s v acyklickém orientovaném grafu. Určete potřebné datové struktury a časovou složitost navrženého algoritmu. Nejkratší cesty - kapitola 6