1.1 Úvod Algoritmus pro hledání nejkratší cesty orientovaným grafem Naprogramoval jsem v Matlabu funkci, která dokáže určit nejkratší cestu v orientovaném grafu mezi libovolnými dvěma vrcholy. Nastudoval jsem si postupně Dijkstrův a Floydův-Warshallův algoritmus pro hledání cesty v grafu s ohodnocenými hranami a uvážil, že v Matlabu se bude lépe implementovat ten druhý, protože více využívá operace s maticemi, které jsou pro Matlab přirozené. 1.2 Teorie Pro maticovou reprezentaci orientovaného grafu se často používá tzv. matice vzdáleností. Tato matice má rozměry, kde n je celkový počet vrcholů v grafu. Pro jednoduchost budeme předpokládat, že máme jednotlivé vrcholy v grafu očíslované pomocí prvků z množiny * +. V této matici víme, že na pozici (i, j) bude pro buď kladné reálné číslo, nebo nekonečno. Kladné reálné číslo v matici říká, že v grafu existuje hrana z vrcholu i do vrcholu j a jeho hodnota udává přímou vzdálenost z vrcholu i do vrcholu j. Na pozici bude vždy 0, protože předpokládáme, že vzdálenost vrcholu od něj samého je rovna 0. Na základě slovního popisu bychom mohli zkonstruovat následující definici: Nechť je dán orientovaný graf G s vrcholy V =* + a nechť. Potom matici A nazvu matici vzdáleností, pokud * + * + platí, že A(i,j) = 0, pokud i = j A(i,j) = r, pokud vede hrana z i do j a její ohodnocení je rovno r A(i,j) =, jinak S takovou maticí bude muset umět funkce pracovat. Floydův-Warshallův algoritmus funguje takzvaně iteračně, což znamená, že pracuje po jednotlivých krocích, kde se při každém opakování stejného kroku více přiblíží finálnímu řešení. Ukažme si to na následujícím příkladu, kde budeme mít zadaný následující graf a jeho matici vzdáleností A: 1
Pro takový graf bude vypadat matice vzdáleností: 1 0 3 2 0 2 3 3 4 1 1 4 5 6 V každém kroku algoritmu budeme hledat, jestli neexistuje cesta mezi dvěma vrcholy ještě přes nějaký další vrchol. To by obecně znamenalo, že pokud budeme hledat cestu mezi i a j v k-té iteraci, hledáme alternativní cestu přes dalších k vrcholů. Matice se v jedné iteraci s iteračním indexem k přepočítá dle následujícího schématu: A(i,j) =inf{a(i,j), inf * ( ) ( ) ( ) ( ) ( ) ( )+} To se dá také zapsat, že budeme procházet všechna * + a budeme hledat min A(i,j) = inf{a(i,j) ; inf * ( ) ( ) * +++ Toto je nutné udělat pro všechny prvky (i,j) z matice A. Otázkou ještě je, kolikrát musíme tento přepočet provést, tj. kolik iterací program projde tak, aby úloha dospěla ke svému řešení. Je dokázáno, že výpočet je nutné provádět, dokud počet iterací k splňuje následující podmínku: kde n je celkový počet vrcholů Například prvek na pozici (3,4) přepočítáme v první iteraci (k=1) následovně: 1 0 3 2 0 2 3 0 3 4 1 1 0 5 6 0 A(3,4) = inf{ ;inf{,,,,9}}=inf{ ;9}=9 Pokud bychom tento postup aplikovali na všechna (i,j) dostaneme tabulku: 1 0 3 5 2 0 2 5 3 0 9 3 4 1 4 1 0 4 5 7 7 6 0 2
Vidíme například, že již po prvním kroku se dá dostat z vrcholu 4 do všech ostatních vrcholů. Nelze však tvrdit, že tyto cesty jsou nejkratší, protože by mohl existovat vrchol, přes který by se cesta mohla ještě dále zkrátit. Matice v konečné fázi výpočtu (tj. pro k=3, protože n=6 a 2 4-1 >6) vypadá následovně: 1 0 3 5 14 8 2 12 0 2 11 5 3 10 13 0 9 3 4 1 4 1 0 4 5 7 10 7 6 0 Výstupem funkce je nejen tato matice R, ale také druhá matice M, která udává, jakým způsobem se lze dostat z vrcholu i do vrcholu j. Na pozici M(i,j) je 0, pokud je i=j nebo vede orientovaná hrana z vrcholu i do vrcholu j, na pozici M(i,j) je r * +, pokud cesta mezi i a j vede přes vrchol r. Pro náš příklad vypadá matice M následovně: 1 0 3 2 3 2 2 5 0 0 3 3 3 4 4 4 5 0 4 0 1 0 0 3 5 4 1 4 0 3 Můžeme z ní vyčíst, přes jaké vrcholy vede nejkratší cesta z vrcholu i do vrcholu j. Př. Jaká je nejkratší cesta z vrcholu 3 do vrcholu 4? Protože M(3,4) = 5, vede přes vrchol 5, zároveň M(3,5) = M(5,4) = 0, což znamená, že posloupnost orientovaných hran 3 5 4 je hledanou nejkratší cestou. Tímto způsobem je možné jednoduše odečíst délku cesty mezi vrcholem i a j z matice R, a posloupnost vrcholů, kterými se prochází, z matice M. 1.3 Program Funkce na vstupu dostane matici vzdáleností a pomocí Floydova-Warshallova algoritmu vypočítá matici R nejkratších vzdáleností mezi zadanými vrcholy, a určí také zmíněnou matici M. Počet iterací k nikdy nepřekročí hodnotu. To je také podmínka v cyklu while, který určuje, jestli je již výpočet ukončen, nebo ne. 3
function [R,M] = FloydW(A) %spočítá na základě matice vzdáleností nejkratší cestu mezi všemi uzly grafu % na začátku zjistíme počet vrcholů, dozvíme se ho z rozměru tabulky n = size(a,1); % iterační index nastavíme na hodnotu 1 k=1; %pro výstupní matice M a R vytvoříme místo v paměti ze znalosti počtu vrcholů R = zeros(n,n); M = zeros(n,n); while (exp((k-1)*log(2)) < n) % dokud není splněna podmínka o maximálním počtu iterací for i=1:n for j=1:n s = A(i,j); index = 0; for l = 1:n % pro každý řádek % pro každý sloupec % hodnota, která se bude zlepšovat % uchová index, ve kterém se našlo minimum % pro každou dvojici ve dvou sloupcích if (A(i,l)~=inf)&&(A(l,j)~=inf) if s > (A(i,l)+A(l,j)) % pokud jsme našli lepší hodnotu cesty z i do j přes % k+1 vrcholů s = A(i,l)+A(l,j); index = l; R(i,j) = s; % konstruujeme matici R po prvcích if index~=0 %pokud bylo nalezeno reálné minimum, existuje cesta o délce k+1 M(i,j) = index; k = k+1; A = R; % zvýšíme iterační index % v dalším kroku budeme počítat již s novou maticí R = A; for i=1:n R(i,i)=0; 4
1.4 Výstupy na obrazovku pro různé vstupy Pro naše zadání, které sloužilo jako příklad v teorii, vypadá graf následovně: Jeho matice vzdáleností: Výstup do konzole vypadá následovně: 5
Jiný příklad, náš graf bude vypadat následovně: Jeho matice vzdáleností: Výstup do konzole vypadá následovně: 6
1.5 Závěr Podařilo se mi naprogramovat funkci, která by měla najít nejkratší cestu mezi všemi vrcholy v orientovaném grafu. Jak jsem již zmiňoval v úvodu, bylo vhodné použít právě Floyd-Warshallův algoritmus, i kvůli tomu, že často prohledáváme všechny prvky matice a ve vstupu i výstupu se nachází také matice. Výhodou oproti ostatním algoritmům může být, že známe přesný počet kroků již ze zadání, tudíž můžeme hned odhadnout, jak složitý výpočet bude. Složitost takového algoritmu při zadání n prvků s předpokládaným počtem iterací je úměrná ( ) ) ( ). Tato o trochu vyšší složitost než u Dijkstrova algoritmu (která je ( ) je však vyvážena faktem, že Floyd-Warshall je univerzálnější - v případě potřeby spočítá nejkratší cestu i v grafu se záporným ohodnocením hran. 1.6 Reference [1] http://kam.mff.cuni.cz/~kuba/ka/min_cesta.pdf [2] http://www.pms.ifi.lmu.de/lehre/compgeometry/gosper/shortest_path/shortest_path.html [3] http://stackoverflow.com/questions/4212431/dijkstra-vs-floyd-warshall-finding-optimalroute-on-all-node-pairs [4] http://www.algoritmy.net/article/36597/nejkratsi-cesta 7