Zaawansowane algorytmy i struktury danych/Wykład 6: Różnice pomiędzy wersjami
Linia 203: | Linia 203: | ||
== Algorytm Floyda-Warshalla == | == Algorytm Floyda-Warshalla == | ||
W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych | W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych ścieżek niż ta użyta w algorytmie z wykorzystaniem | ||
ścieżek niż ta użyta w algorytmie z wykorzystaniem | [[#iloczyn_odległości|iloczynu odległości]]. W poprzednim algorytmie konstruowaliśmy coraz dłuższe ścieżki, natomiast tutaj będziemy konstruować ścieżki przechodzące przez coraz większy zbiór wierzchołków. Wierzchołkiem {{kotwica|wierzchołek_wewnetrzny|'''wewnetrznym'''} ścieżki <math>p = (v_0, \ldots, v_l)</math> jest każdy wierzchołek na ścieżce <math>p</math> różny od jej początku <math>v_0</math> i końca <math>v_l</math>. | ||
[[#iloczyn_odległości|iloczynu odległości]]. W poprzednim algorytmie | |||
konstruowaliśmy coraz dłuższe ścieżki, natomiast tutaj będziemy | |||
konstruować ścieżki przechodzące przez coraz większy zbiór | |||
wierzchołków. Wierzchołkiem | |||
{{kotwica|wierzchołek_wewnetrzny|'''wewnetrznym'''} ścieżki <math>p | |||
= (v_0, \ldots, v_l)</math> jest każdy wierzchołek na ścieżce | |||
<math>p</math> różny od jej początku <math>v_0</math> i końca | |||
<math>v_l</math>. | |||
Niech zbiorem wierzchołków grafu <math>G</math> będzie <math>V = | Niech zbiorem wierzchołków grafu <math>G</math> będzie <math>V = \{1,\ldots,n\}</math>. Niech <math>d_{i,j}^{(k)}</math> dla <math>k = 0,\ldots, n</math> oznacza najmniejszą wagę ścieżki z <math>i</math> do <math>j</math>, spośród ścieżek których wierzchołki wewnętrzne należą do zbioru <math>\{v_1, \ldots,v_{k}</math>. Pokażemy następujący rekurencyjny wzór na <math>D^{(k)}</math>. | ||
\{1,\ldots,n\}</math>. Niech <math>d_{i,j}^{(k)}</math> dla <math>k = | |||
0,\ldots, n</math> oznacza najmniejszą wagę ścieżki z <math>i</math> | |||
do <math>j</math>, spośród ścieżek których wierzchołki wewnętrzne | |||
należą do zbioru <math>\{v_1, \ldots,v_{k}</math>. Pokażemy następujący | |||
rekurencyjny wzór na <math>D^{(k)}</math>. | |||
{{lemat|lemat_7|7|3= | {{lemat|lemat_7|7|3= | ||
Linia 235: | Linia 222: | ||
{{ | {{dowod|||3= Dla <math>k=0</math> poprawność powyższego wzoru wynika bezpośrednio z definicji <math>D^0</math>. Dla <math>k>0</math> musimy pokazać, że | ||
bezpośrednio z definicji <math>D^0</math>. Dla <math>k>0</math> | |||
musimy pokazać, że | |||
{{wzor|wzor_2|2 | {{wzor|wzor_2|2 | ||
Linia 245: | Linia 230: | ||
}} | }} | ||
Niech <math>p</math> będzie najkrótszą ścieżką z <math>i</math> do <math>j</math>, | Niech <math>p</math> będzie najkrótszą ścieżką z <math>i</math> do <math>j</math>, której wierzchołki wewnętrzne należą do zbioru <math>\{v_1,\ldots,v_k\}</math>. Mamy dwa przypadki: | ||
której wierzchołki wewnętrzne należą do zbioru <math>\{v_1,\ldots,v_k\}</math>. Mamy dwa przypadki: | * Wierzchołek <math>v_k</math> nie leży na ścieżce <math>p</math>. Wtedy zachodzi <math>d_{i,j}^{(k)} = p(w) = d_{i,j}^{(k-1)}</math>. Ponieważ <math>p</math> jest najkrótszą ścieżką to także <math>p(w) \le d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}</math> i powyższy wzór zachodzi. | ||
* Wierzchołek <math>v_k</math> nie leży na ścieżce <math>p</math>. Wtedy zachodzi | * Jeżeli wierzchołek <math>v_k</math> należy do ścieżki <math>p</math>, to występuje on dokładnie raz i możemy podzielić <math>p</math> na dwie ścieżki <math>p_1</math> z <math>i</math> do <math>k</math> oraz <math>p_2</math> z <math>k</math> do <math>j</math>. Ścieżki <math>p_1</math> i <math>p_2</math> nie zawierają wierzchołka <math>v_k</math> jako wierzchołka wewnętrznego. Ponieważ są to podścieżki najkrótszej ścieżki, więc same też są najkrótsze. Zachodzi więc dla nich <math>w(p_1) = d_{i,k}^{(k-1)}</math> oraz <math>w(p_2) = d_{k,j}^{(k-1)}</math>. Otrzymujemy więc <math>d_{i,j}^{(k)} = w(p) = w(p_1) + w(p_2) = d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}</math>. Ponieważ <math>p</math> jest najkrótszą ścieżką to <math>p(w) \le d_{i,j}^{(k-1)}</math> i wzór zachodzi także w tym przypadku. | ||
<math>d_{i,j}^{(k)} = p(w) = d_{i,j}^{(k-1)}</math>. Ponieważ <math>p</math> jest najkrótszą | |||
ścieżką to także <math>p(w) \le d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}</math> i powyższy wzór zachodzi. | |||
* Jeżeli wierzchołek <math>v_k</math> należy do ścieżki <math>p</math>, to występuje | |||
on dokładnie raz i możemy podzielić <math>p</math> na dwie ścieżki | |||
<math>p_1</math> z <math>i</math> do <math>k</math> oraz | |||
<math>p_2</math> z <math>k</math> do <math>j</math>. Ścieżki | |||
<math>p_1</math> i <math>p_2</math> nie zawierają wierzchołka | |||
<math>v_k</math> jako wierzchołka wewnętrznego. Ponieważ są to | |||
podścieżki najkrótszej ścieżki, więc same też są najkrótsze. | |||
Zachodzi więc dla nich <math>w(p_1) = d_{i,k}^{(k-1)}</math> oraz | |||
<math>w(p_2) = d_{k,j}^{(k-1)}</math>. Otrzymujemy więc | |||
<math>d_{i,j}^{(k)} = w(p) = w(p_1) + w(p_2) = d_{i,k}^{(k-1)} + | |||
d_{k,j}^{(k-1)}</math>. Ponieważ <math>p</math> jest najkrótszą ścieżką | |||
to <math>p(w) \le d_{i,j}^{(k-1)}</math> i wzór zachodzi także w tym przypadku. | |||
<!-- TODO: może jakiś rysunek --> | <!-- TODO: może jakiś rysunek --> | ||
}} | }} | ||
Wykorzystując [[#wzor_2| wzór (2)]] możemy skonstruować następujący | Wykorzystując [[#wzor_2| wzór (2)]] możemy skonstruować następujący algorytm obliczający w czasie <math>O(|V|^3)</math> odległości między wszystkimi parami wierzchołków. | ||
algorytm obliczający w czasie <math>O(|V|^3)</math> odległości | |||
między wszystkimi parami wierzchołków. | |||
{{algorytm|algorytm_Floyda-Warshalla|Algorytm Floyda-Warshalla|3= | {{algorytm|algorytm_Floyda-Warshalla|Algorytm Floyda-Warshalla|3= |
Wersja z 23:05, 21 lip 2006
Abstrakt
W wykładzie tym zajmiemy się problemem obliczanie odległości w grafie między wszystkimi parami wierzchołków w grafie ważonym skierowanym . Przedstawimy trzy algorytmu rozwiązujące ten problem:
- algorytm wykorzystujący mnożenie macierzy działający w czasie ,
- algorytm Floyda-Warshalla działający w czasie ,
- algorytm Johnsona działający w czasie .
Problem najkrótszych ścieżek między wszystkimi parami wierzchołków
Problem najkrótszych ścieżek między wszystkimi parami wierzchołków można rozwiązać, wykonując razy algorytm dla problemu najkrótszych ścieżek z jednego wierzchołka. Jeżeli w grafie wagi krawędzi są nieujemne to możemy użyć algorytmu Dijkstry. Najszybsza implementacji algorytmu Dijskstry wykorzystująca kopce Fibonacciego działa w czasie , co daje nam algorytm rozwiązujący problem policzenia odległości między wszystkimi parami wierzchołków działający w czasie .
Jednakże tego rozwiązania nie możemy użyć jeżeli w grafie wagi krawędzi mogą być ujemne. W takim przypadku możemy użyć algorytm Bellmana-Forda. Otrzymamy wtedy algorytm działający w czasie . W rozdziale tym zaprezentujemy bardziej efektywne rozwiązania dla tego problemu.
W rozdziale tym będziemy zakładać, że algorytmy na wejściu otrzymują macierz wag rozmiaru reprezentującą wagi krawędzi -wierzchołkowego grafu . Dla macierzy tej zachodzi:
W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków chcemy wyznaczyć macierz rozmiaru
taką, że jest równe odległości z wierzchołka do wierzchołka . Chcemy także wyznaczyć dla każdego wierzchołka drzewo najkrótszych ścieżek ukorzenione w . Podobnie jak w
poprzednim rozdziale drzewo możemy kodować dla każdego wierzchołka przy pomocy funkcji poprzedników . Ponieważ tutaj interesuje nas wiele drzew to łatwiej będzie nam używać 'macierzy poprzedników . Macierz tą definiujemy używając funkcji w następujący sposób:
W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości . Jak to zostało pokazane w Zadaniu 3 do poprzedniego wykładu znając odległości w grafie drzewo najkrótszych ścieżek można wyznaczyć w czasie , a więc drzew możemy wyliczyć w czasie . Czas ten jest mniejszy niż czas działania wszystkich prezentowanych w tym wykładzie algorytmów, więc bez straty ogólności, a zyskując na prostocie prezentacji możemy ograniczyć się tylko do wyznaczenia macierzy odległości .
Co więcej będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie przy użyciu Algorytmu Bellmana-Forda. Zobacz Zadanie 4 do Wykładu 4.
Najkrótsze ścieżki i mnożenie macierzy
Załóżmy, że dane mamy dwie macierze wag oraz rozmiaru . Dla macierzy tych definiujemy operację iloczyn odległości, której wynikiem jest także macierz rozmiaru , zdefiniowana jako:
(1)
Wniosek wniosek_konkatenacja
Pokażemy teraz, że produkt odległości jest operacją łączną.
Lemat io_łączny
Dowód

Co więcej produkt odległości jest przemienny względem dodawania.
Lemat io_przemienny
oraz
Dowód

Zdefiniujmy macierz rozmiaru jako:
Macierz ta jest jedynką dla iloczynu odległości.
Lemat io_jedynka
Łączność iloczynu odległości ma dla nas bardzo ważne konsekwencję i pozwoli nam na konstrukcję algorytmu obliczania odległości w grafie między wszystkimi parami wierzchołków działającego w czasie . Niech będzie macierzą wag grafu . Rozważmy macierz zdefiniowaną jako:
Parser nie mógł rozpoznać (nieznana funkcja „\begin{cases}”): {\displaystyle W^{m} = \begin{cases} I_{\min}, &\mbox{jeżeli } m=0,\\ W \times_{\min} W^{m-1}, &\mbox{jeżeli } m>0. }
Pokażemy teraz, że macierz opisuje odległości między wierzchołkami grafu ale tylko dla ścieżek używających mniej niż krawędzi.
Lemat potęgi_odległości
Dowód

Zajmiemy się teraz konstrukcją algorytmu obliczającego najkrótsze ścieżki w grafie. W tym celu będziemy potrzebowali jeszcze udowodnić następujące dwa lematy.
Lemat lemat_6
Dowód

Zauważmy, że iloczyn odległości dwóch macierzy możemy policzyć w czasie wykorzystując następujący algorytm.
Algorytm algorytm_iloczyn_odległości
{{{3}}}
Ponieważ operacja iloczynu odległości jest łączna to możemy wykorzystać algorytm szybkiego potęgowania i policzyć odległości przy pomocy następującego algorytmu.
Algorytm algorytm_apsp_mnozenie
ODLEGŁÓŚCI-I(W) 1 , 2 3 while do 4 MNOŻENIE-ODLEGŁOŚCI 5 7 return
Poprawności tego algorytmu wynika wprost z Lematu 6 ponieważ na zakończenie algorytmu i .
Algorytm Floyda-Warshalla
W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych ścieżek niż ta użyta w algorytmie z wykorzystaniem iloczynu odległości. W poprzednim algorytmie konstruowaliśmy coraz dłuższe ścieżki, natomiast tutaj będziemy konstruować ścieżki przechodzące przez coraz większy zbiór wierzchołków. Wierzchołkiem {{kotwica|wierzchołek_wewnetrzny|wewnetrznym} ścieżki jest każdy wierzchołek na ścieżce różny od jej początku i końca .
Niech zbiorem wierzchołków grafu będzie . Niech dla oznacza najmniejszą wagę ścieżki z do , spośród ścieżek których wierzchołki wewnętrzne należą do zbioru . Pokażemy następujący rekurencyjny wzór na .
Lemat lemat_7
Dowód
{{{3}}} (2
)
Niech będzie najkrótszą ścieżką z do , której wierzchołki wewnętrzne należą do zbioru . Mamy dwa przypadki:
- Wierzchołek nie leży na ścieżce . Wtedy zachodzi . Ponieważ jest najkrótszą ścieżką to także i powyższy wzór zachodzi.
- Jeżeli wierzchołek należy do ścieżki , to występuje on dokładnie raz i możemy podzielić na dwie ścieżki z do oraz z do . Ścieżki i nie zawierają wierzchołka jako wierzchołka wewnętrznego. Ponieważ są to podścieżki najkrótszej ścieżki, więc same też są najkrótsze. Zachodzi więc dla nich oraz . Otrzymujemy więc . Ponieważ jest najkrótszą ścieżką to i wzór zachodzi także w tym przypadku.
Wykorzystując wzór (2) możemy skonstruować następujący algorytm obliczający w czasie odległości między wszystkimi parami wierzchołków.
Algorytm algorytm_Floyda-Warshalla
między wszystkimi parami wierzchołków I ODLEGŁÓŚCI-II(W) 1 , 2 for to do 3 for to do 4 for to do 5 6 return