Zaawansowane algorytmy i struktury danych/Wykład 6: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
m Zastępowanie tekstu – „<math> ” na „<math>”
 
(Nie pokazano 20 wersji utworzonych przez 3 użytkowników)
Linia 1: Linia 1:
== Abstrakt ==
== Abstrakt ==
 
W wykładzie tym zajmiemy się problemem obliczania odległości w grafie między wszystkimi parami wierzchołków w grafie ważonym
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 <math>G=(V,E)</math>. Przedstawimy trzy algorytmy rozwiązujące ten problem:
skierowanym <math>G=(V,E)</math>. Przedstawimy trzy algorytmy rozwiązujące ten problem:
* algorytm wykorzystujący mnożenie macierzy działający w czasie <math>O(|V|^3\log |V|)</math>,
* algorytm wykorzystujący mnożenie macierzy, działający w czasie <math>O(|V|^3\log |V|)</math>,
* algorytm Floyda-Warshalla działający w czasie <math>O(|V|^3)</math>,
* algorytm Floyda-Warshalla, działający w czasie <math>O(|V|^3)</math>,
* algorytm Johnsona działający w czasie <math>O(|V|^2 \log |V| + |V||E|)</math>.
* algorytm Johnsona, działający w czasie <math>O(|V|^2 \log |V| + |V||E|)</math>.


== Problem najkrótszych ścieżek między wszystkimi parami wierzchołków ==
== 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 <math>|V|</math> 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ć [[Algorytmy i struktury danych/ASD Moduł 11#algorytm_dijkstry|algorytmu Dijkstry]]. Najszybsza implementacja algorytmu Dijskstry wykorzystująca kopce Fibonacciego działa w czasie <math>O(|V| \log |V| + |E|)</math>, co daje nam algorytm rozwiązujący problem policzenia odległości między wszystkimi parami wierzchołków działający w czasie <math>O(|V|^2 \log |V| + |V||E|)</math>.
Problem najkrótszych ścieżek między wszystkimi parami wierzchołków można rozwiązać, wykonując <math>|V|</math> 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ć [[Algorytmy i struktury danych/ASD Moduł 11#algorytm_dijkstry|algorytmu Dijkstry]]. Najszybsza implementacja algorytmu Dijskstry wykorzystująca kopce Fibonacciego działa w czasie <math>O(|V| \log |V| + |E|)</math>, co daje nam algorytm rozwiązujący problem policzenia odległości między wszystkimi parami wierzchołków, działający w czasie <math>O(|V|^2 \log |V| + |V||E|)</math>.


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ć [[../Wykład 5#algorytm_Bellmana-Forda|algorytm Bellmana-Forda]]. Otrzymamy wtedy algorytm działający w czasie <math>O(|V|^2|E|)</math>. W rozdziale tym zaprezentujemy bardziej efektywne rozwiązania dla tego problemu.
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ć [[../Wykład 5#algorytm_Bellmana-Forda|algorytm Bellmana-Forda]]. Otrzymamy wtedy algorytm działający w czasie <math>O(|V|^2|E|)</math>. W rozdziale tym zaprezentujemy bardziej efektywne rozwiązania dla tego problemu.


W rozdziale tym będziemy zakładać, że algorytmy na wejściu otrzymują {{kotwica|macierz_wag|''macierz wag''}} <math>W</math> rozmiaru <math>n\times n</math> reprezentującą wagi krawędzi <math>n</math>-wierzchołkowego grafu <math>G = (V,E)</math>. Dla macierzy tej zachodzi:
W rozdziale tym będziemy zakładać, że algorytmy na wejściu otrzymują {{kotwica|macierz_wag|''macierz wag''}} <math>W</math> rozmiaru <math>n\times n</math> reprezentującą wagi krawędzi <math>n</math>-wierzchołkowego grafu <math>G = (V,E)</math>. Dla macierzy tej zachodzi:
Linia 25: Linia 24:




W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków  chcemy wyznaczyć macierz <math>D</math> rozmiaru <math>n \times n</math> taką, że <math>d_{i,j}</math> jest równe odległości <math>\delta(i,j)</math> z wierzchołka <math>i</math> do wierzchołka <math>j</math>. Chcemy także wyznaczyć dla każdego wierzchołka <math>v</math> [[../Wykład 5#drzewo_najkrótszych_ścieżek|drzewo najkrótszych ścieżek]] <math>T_v</math> ukorzenione w <math>v</math>. Podobnie jak w poprzednim rozdziale drzewo <math>T_v</math> możemy kodować dla każdego wierzchołka przy pomocy funkcji poprzedników <math>\pi_{v}</math>. Ponieważ tutaj interesuje nas wiele drzew to łatwiej będzie nam używać {{kotwica|macierz_poprzedników|'''macierzy poprzedników'''}} <math>\Pi</math>. Macierz tą definiujemy używając funkcji <math>\pi_v</math> w następujący sposób:
W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków  chcemy wyznaczyć macierz <math>D</math> rozmiaru <math>n \times n</math>, taką że <math>d_{i,j}</math> jest równe odległości <math>\delta(i,j)</math> z wierzchołka <math>i</math> do wierzchołka <math>j</math>. Chcemy także wyznaczyć dla każdego wierzchołka <math>v</math> [[../Wykład 5#drzewo_najkrótszych_ścieżek|drzewo najkrótszych ścieżek]] <math>T_v</math> ukorzenione w <math>v</math>. Podobnie jak w poprzednim rozdziale drzewo <math>T_v</math> możemy kodować dla każdego wierzchołka przy pomocy funkcji poprzedników <math>\pi_{v}</math>. Ponieważ tutaj interesuje nas wiele drzew, łatwiej będzie nam używać {{kotwica|macierz_poprzedników|'''macierzy poprzedników'''}} <math>\Pi</math>. Macierz tą definiujemy używając funkcji <math>\pi_v</math> w następujący sposób:




Linia 33: Linia 32:




W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości <math>D</math>. [[../Ćwiczenia 6#Zadanie 3|Zadaniu 3]] do tego wykładu polega na pokazaniu jak znając odległości w grafie policzyć drzewo najkrótszych ścieżek w czasie <math>O(|E|)</math>. Tak więc <math>|V|</math> drzew możemy wyliczyć w czasie <math>O(|E||V|)</math>. 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 <math>D</math>.
W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości <math>D</math>. [[../Ćwiczenia 6#Zadanie 3|Zadaniu 3]] do tego wykładu polega na pokazaniu, jak znając odległości w grafie policzyć drzewo najkrótszych ścieżek w czasie <math>O(|E|)</math>. Tak więc <math>|V|</math> drzew możemy wyliczyć w czasie <math>O(|E||V|)</math>. 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 <math>D</math>.




Co więcej będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie <math>O(|V||E|)</math> przy użyciu [[../Wykład 5#algorytm_Bellmana-Forda|Algorytmu Bellmana-Forda]]. Zobacz [[../Ćwiczenia 5#Zadanie 3| Zadanie 3]] do Wykładu 4.
Co więcej, będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie <math>O(|V||E|)</math> przy użyciu [[../Wykład 5#algorytm_Bellmana-Forda|Algorytmu Bellmana-Forda]]. Zobacz [[../Ćwiczenia 5#Zadanie 3| Zadanie 3]] do Wykładu 4.


== Najkrótsze ścieżki i mnożenie macierzy ==
== Najkrótsze ścieżki i mnożenie macierzy ==
Linia 57: Linia 56:
}}
}}


Wniosek ten jest przedstawiony na poniższej animicji, gdzie zostały zaznaczone dwa zbiory ścieżek, pierwszy zaznaczony na zielono reprezentowany przez macierz <math>A</math> oraz graf <math>G_A</math> oraz drugi zaznaczony na niebiesko reprezentowany przez macierz <math>B</math> oraz graf <math>G_B</math>. W wyniku wykonania mnożenia otrzymujemy macierz <math>C</math> oraz graf <math>G_C</math>
Wniosek ten jest przedstawiony na poniższej animicji, gdzie zostały zaznaczone dwa zbiory ścieżek, pierwszy, zaznaczony na zielono, reprezentowany przez macierz <math>A</math> oraz graf <math>G_A</math>, oraz drugi, zaznaczony na niebiesko, reprezentowany przez macierz <math>B</math> oraz graf <math>G_B</math>. W wyniku wykonania mnożenia otrzymujemy macierz <math>C</math> oraz graf <math>G_C</math>
<flash>file=Zasd_Ilustr_f.swf|width=600|height=500</flash>
[[File:Zasd_ilustr_f.svg|600x500px|thumb|center]]
 


Pokażemy teraz, że produkt odległości jest operacją łączną.
Pokażemy teraz, że produkt odległości jest operacją łączną.
Linia 68: Linia 66:


{{wzor2|1=<math>
{{wzor2|1=<math>
\left(C \times_{\min} D \right) \times_{min}  E = C \times_{\min} \left( D  \times_{min} E \right).
\left(C \times_{\min} D \right) \times_{min}  E = C \times_{\min} \left( D  \times_{min} E \right)
</math>}}
</math>}}
}}
}}
Linia 75: Linia 73:
}}
}}


Co więcej produkt odległości jest przemienny względem dodawania.
Co więcej, produkt odległości jest przemienny względem dodawania.


{{lemat|3|io_przemienny|3= Dla macierzy <math>C</math>, <math>D</math> i <math>E</math> rozmiaru <math>n\times n</math> zachodzi:
{{lemat|3|io_przemienny|3= Dla macierzy <math>C</math>, <math>D</math> i <math>E</math> rozmiaru <math>n\times n</math> zachodzi:




{{wzor2|1=<math> C \times_{\min} \left(D  + E \right)= C \times_{\min}
{{wzor2|1=<math>C \times_{\min} \left(D  + E \right)= C \times_{\min}
D +  C  \times_{min} E, </math>}}
D +  C  \times_{min} E</math>}}




Linia 88: Linia 86:


{{wzor2|1=<math>
{{wzor2|1=<math>
  \left(D  + E \right) \times_{\min} C = D \times_{\min} C +  E  \times_{min} C.
  \left(D  + E \right) \times_{\min} C = D \times_{\min} C +  E  \times_{min} C
</math>}} }}
</math>}} }}


Linia 97: Linia 95:




{{wzor2|1=<math> \left(I_{\min}\right)_{i,j} =
{{wzor2|1=<math>\left(I_{\min}\right)_{i,j} =
\begin{cases} 0, & \mbox{jeśli } i=j,\\ \infty, & \mbox{jeśli } i \neq j.
\begin{cases} 0, & \mbox{jeśli } i=j,\\ \infty, & \mbox{jeśli } i \neq j.
\end{cases}
\end{cases}
Linia 109: Linia 107:




{{wzor2|1=<math> I_{\min} \times_{\min} C = C \times_{\min} I_{\min} =C. </math>}} }}
{{wzor2|1=<math>I_{\min} \times_{\min} C = C \times_{\min} I_{\min} =C</math>}} }}


{{dowod||| Mamy
{{dowod||| Mamy


{{wzor2|1=<math> \left(I_{\min} \times_{\min} C\right)_{i,j} = \min_{k = 1,\ldots,n} \left(I_{\min}\right)_{i,k} + C_{k,j} = </math>}}
{{wzor2|1=<math>\left(I_{\min} \times_{\min} C\right)_{i,j} = \min_{k = 1,\ldots,n} \left(I_{\min}\right)_{i,k} + C_{k,j} =</math>}}


ponieważ wszystkie elementy <math>\left(I_{\min}\right)_{i,k}</math> równe są <math>\infty</math> oprócz elementu <math>i = k</math>, to możemy je pominąć w operacji <math>\min</math> i:
ponieważ wszystkie elementy <math>\left(I_{\min}\right)_{i,k}</math> równe są <math>\infty</math> oprócz elementu <math>i = k</math>, możemy je pominąć w operacji <math>\min</math> i:




{{wzor2|1=<math> = \min_{k = i} \left(I_{\min}\right)_{i,k} + C_{k,j}
{{wzor2|1=<math>= \min_{k = i} \left(I_{\min}\right)_{i,k} + C_{k,j}
= I_{i,i} + C_{i,j} = C_{i,j}. </math>}} }}
= I_{i,i} + C_{i,j} = C_{i,j}</math>}} }}


=== Pomysł algorytmu ===
=== Pomysł algorytmu ===


Łączność iloczynu odległości ma dla nas bardzo ważne konsekwencje i pozwoli nam na konstrukcję algorytmu obliczania odległości w grafie między wszystkimi parami wierzchołków działającego w czasie <math>O(|V|^{3}\log |V|)</math>. Niech <math>W</math> będzie [[#macierz_wag|macierzą wag]] grafu <math>G = (V,E)</math>. Rozważmy macierz <math>W^m</math> zdefiniowaną jako:
Łączność iloczynu odległości ma dla nas bardzo ważne konsekwencje i pozwoli nam na konstrukcję algorytmu obliczania odległości w grafie między wszystkimi parami wierzchołków, działającego w czasie <math>O(|V|^{3}\log |V|)</math>. Niech <math>W</math> będzie [[#macierz_wag|macierzą wag]] grafu <math>G = (V,E)</math>. Rozważmy macierz <math>W^m</math> zdefiniowaną jako:




Linia 135: Linia 133:
}}
}}


Pokażemy teraz, że macierz <math>W^m</math> opisuje odległości między wierzchołkami grafu ale tylko dla ścieżek używających nie więcej niż <math>m</math> krawędzi.
Pokażemy teraz, że macierz <math>W^m</math> opisuje odległości między wierzchołkami grafu, ale tylko dla ścieżek używających nie więcej niż <math>m</math> krawędzi.


{{lemat|5|potęgi_odległości|3=
{{lemat|5|potęgi_odległości|3=


Element <math>W_{i,j}^{m}</math> macierzy <math>W^{m}</math> zadaje najmniejszą wagę ścieżki wychodzącej z wierzchołka <math>i</math> do wierzchołka <math>j</math> spośród ścieżek, które zawierają nie więcej niż <math>m</math> krawędzi, tzn.:
Element <math>W_{i,j}^{m}</math> macierzy <math>W^{m}</math> zadaje najmniejszą wagę ścieżki, wychodzącej z wierzchołka <math>i</math> do wierzchołka <math>j</math> spośród ścieżek, które zawierają nie więcej niż <math>m</math> krawędzi, tzn.:




Linia 150: Linia 148:
}}
}}


{{dowod|||3= Tezę udowodnimy przez indukcję po <math>m</math>. Ścieżki używające <math>0</math> krawędzi istnieją tylko z każdego wierzchołka do niego samego i mają długość <math>0</math>, a więc dla <math>m=0</math> teza wynika wprost z definicji macierzy <math>W^0</math>.
{{dowod|||3= Tezę udowodnimy przez indukcję po <math>m</math>. Ścieżki używające <math>0</math> krawędzi istnieją tylko z każdego wierzchołka do niego samego i mają długość <math>0</math>, a więc dla <math>m=0</math> teza wynika wprost z definicji macierzy <math>W^0</math>.


Załóżmy teraz, że teza zachodzi dla <math>m >0</math>. Mamy wtedy <math>W^{m+1} = W \times_{\min} W^{m}</math>. Zauważmy, że definicja [[#macierz_wag|macierzy wag]] <math>W</math> opisuje ścieżki używające <math>\le 1</math> krawędź. Korzystając teraz z [[#wniosek_konkatenacja|Wniosku 1]] otrzymujemy tezę dla <math>m+1</math>.
Załóżmy teraz, że teza zachodzi dla <math>m >0</math>. Mamy wtedy <math>W^{m+1} = W \times_{\min} W^{m}</math>. Zauważmy, że definicja [[#macierz_wag|macierzy wag]] <math>W</math> opisuje ścieżki używające <math>\le 1</math> krawędź. Korzystając teraz z [[#wniosek_konkatenacja|Wniosku 1]] otrzymujemy tezę dla <math>m+1</math>.
Linia 157: Linia 155:




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.
Zajmiemy się teraz konstrukcją algorytmu obliczającego najkrótsze ścieżki w grafie. W tym celu będziemy musieli jeszcze udowodnić następujące dwa lematy.


{{lemat|6|lemat_6|3=
{{lemat|6|lemat_6|3=
Linia 169: Linia 167:
}}
}}


{{dowod|||3= Jeżeli w grafie nie istnieje cykl o ujemnej wadze, to wszystkie najkrótsze ścieżki są ścieżkami prostymi, a więc mają długość co najwyżej <math>n-1</math>. Z [[#potęgi_odległości|Lematu 5]] wynika więc że odległości tych ścieżek są dobrze wyznaczone w <math>W^{k}</math> dla <math>k \ge n-1</math>. }}
{{dowod|||3= Jeżeli w grafie nie istnieje cykl o ujemnej wadze, to wszystkie najkrótsze ścieżki są ścieżkami prostymi, a więc mają długość co najwyżej <math>n-1</math>. Z [[#potęgi_odległości|Lematu 5]] wynika więc, że odległości tych ścieżek są dobrze wyznaczone w <math>W^{k}</math> dla <math>k \ge n-1</math>. }}


=== Algorytm ===
=== Algorytm ===
Linia 190: Linia 188:
}}
}}


Ponieważ operacja iloczynu odległości jest łączna to możemy wykorzystać [[algorytm_szybkiego_potęgowania|algorytm szybkiego
Ponieważ operacja iloczynu odległości jest łączna, możemy wykorzystać [[algorytm_szybkiego_potęgowania|algorytm szybkiego
potęgowania]] i policzyć odległości przy pomocy następującego algorytmu.
potęgowania]] i policzyć odległości przy pomocy następującego algorytmu.


Linia 199: Linia 197:
   3  '''while''' <math>n-1 > m</math> '''do'''
   3  '''while''' <math>n-1 > m</math> '''do'''
   4  '''begin'''
   4  '''begin'''
   5    <math>D = </math>MNOŻENIE-ODLEGŁOŚCI<math>(D,D)</math>
   5    <math>D =</math>MNOŻENIE-ODLEGŁOŚCI<math>(D,D)</math>
   6    <math>m = 2m</math>
   6    <math>m = 2m</math>
   7  '''end'''
   7  '''end'''
Linia 212: Linia 210:
[[#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_wewnętrzny|'''wewnętrznym'''}} ś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_wewnętrzny|'''wewnętrznym'''}} ś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 = \{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>\{1, \ldots,k\}</math>. Pokażemy następujący rekurencyjny wzór na <math>D^{(k)}</math>.
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>\{1, \ldots,k\}</math>. Pokażemy następujący rekurencyjny wzór na <math>D^{(k)}</math>.


{{lemat|7|lemat_7|3=
{{lemat|7|lemat_7|3=
Linia 236: Linia 234:


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:
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:
* 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 <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.
* 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ą, <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 algorytm obliczający w czasie <math>O(|V|^3)</math> odległości między wszystkimi parami wierzchołków.
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|Algorytm Floyda-Warshalla|algorytm_Floyda-Warshalla|3=
{{algorytm|Algorytm Floyda-Warshalla|algorytm_Floyda-Warshalla|3=
Linia 256: Linia 254:
== Algorytm Johnsona ==
== Algorytm Johnsona ==


W algorytmie Johnsona wykorzystamy spostrzeżenie uczynione przez nas na początku wykładu, że  odległości w grafie w którym wszystkie wagi krawędzi są dodanie można obliczyć korzystając z [[Algorytmy i struktury danych/ASD Moduł 11#algorytm_dijkstry|algorytmu Dijkstry]] w czasie <math>O(|V|^2\log |V| + |V||E|)</math>. Pokażemy tutaj jak zmienić wagi w grafie tak, aby stały się one dodatnie, przy zachowaniu najkrótszych ścieżek.
W algorytmie Johnsona wykorzystamy spostrzeżenie uczynione przez nas na początku wykładu, że  odległości w grafie, w którym wszystkie wagi krawędzi są dodatnie, można obliczyć korzystając z [[Algorytmy i struktury danych/ASD Moduł 11#algorytm_dijkstry|algorytmu Dijkstry]] w czasie <math>O(|V|^2\log |V| + |V||E|)</math>. Pokażemy tutaj, jak zmienić wagi w grafie tak, aby stały się one dodatnie, przy zachowaniu najkrótszych ścieżek.


Niech będzie dany graf skierowany <math>G=(V,E)</math> wraz z funkcją wagową <math>w:E \to \mathcal{R}</math>. Niech funkcja <math>h:V \to \mathcal{R}</math> będzie dowolną funkcją ze zbioru wierzchołków w liczby rzeczywiste. Dla funkcji <math>h</math> oraz <math>w</math> definiujmy nową funkcję wagową oznaczoną <math>w_h</math> w następujący sposób:
Niech będzie dany graf skierowany <math>G=(V,E)</math> wraz z funkcją wagową <math>w:E \to \mathcal{R}</math>. Niech funkcja <math>h:V \to \mathcal{R}</math> będzie dowolną funkcją ze zbioru wierzchołków w liczby rzeczywiste. Dla funkcji <math>h</math> oraz <math>w</math> definiujmy nową funkcję wagową oznaczoną <math>w_h</math> w następujący sposób:


{{wzor|wzor_3|3|3=<math>w_h(u,v) = w(u,v) + h(u) - h(v).</math>}}
{{wzor|wzor_3|3|3=<math>w_h(u,v) = w(u,v) + h(u) - h(v)</math>}}


Oznaczmy, przez <math>\delta(u,v)</math> odległości w grafie <math>G</math> dla funkcji wagowej <math>w</math> oraz przez <math>\delta_h(u,v)</math> odległości w gafie <math>G</math> dla funkcji wagowej <math>w_h</math>.
Oznaczmy, przez <math>\delta(u,v)</math> odległości w grafie <math>G</math> dla funkcji wagowej <math>w</math> oraz przez <math>\delta_h(u,v)</math> odległości w grafie <math>G</math> dla funkcji wagowej <math>w_h</math>.


{{lemat|8|lemat_8|3=Dla funkcji <math>w</math>, <math>w_h</math>, oraz dowolnej ścieżki <math>p= (v_0,\ldots,v_k)</math>  zachodzi:
{{lemat|8|lemat_8|3=Dla funkcji <math>w</math>, <math>w_h</math> oraz dowolnej ścieżki <math>p= (v_0,\ldots,v_k)</math>  zachodzi:


{{wzor2|1=
{{wzor2|1=
<math>w_h(p) = w(p) + h(v_0) - h(v_k).</math>
<math>w_h(p) = w(p) + h(v_0) - h(v_k)</math>
}}
}}


Linia 288: Linia 286:


{{wzor2|1=
{{wzor2|1=
<math>= w(p) + h(v_0) - h(v_k).</math>
<math>= w(p) + h(v_0) - h(v_k)</math>
}}
}}
}}
}}
Linia 308: Linia 306:




{{wniosek|10|lemat_10|3= Ścieżka <math>p</math> z wierzchołka <math>u</math> do wierzchołka <math>v</math> jest najkrótszą ścieżką w <math>G= (V,E)</math> dla funkcji wagową <math>w</math> wtedy i tylko wtedy gdy jest najkrótszą ścieżką w <math>G</math> dla funkcji wagowej <math>w_h</math>. }}
{{wniosek|10|lemat_10|3= Ścieżka <math>p</math> z wierzchołka <math>u</math> do wierzchołka <math>v</math> jest najkrótszą ścieżką w <math>G= (V,E)</math> dla funkcji wagową <math>w</math> wtedy i tylko wtedy, gdy jest najkrótszą ścieżką w <math>G</math> dla funkcji wagowej <math>w_h</math>. }}


{{dowod|||3= Wniosek ten wynika wprost z [[#lemat_8|Lematu 8]] i [[#wniosek_9|Wniosku 9]], który pokazuje, że odległości transformują się tak samo jak wagi ścieżek, a więc równość <math>w(p) = \delta(u,v)</math> jest równoważna równości <math>w_h(p) = \delta_h(u,v)</math>.
{{dowod|||3= Wniosek ten wynika wprost z [[#lemat_8|Lematu 8]] i [[#wniosek_9|Wniosku 9]], który pokazuje, że odległości transformują się tak samo jak wagi ścieżek, a więc równość <math>w(p) = \delta(u,v)</math> jest równoważna równości <math>w_h(p) = \delta_h(u,v)</math>.
Linia 324: Linia 322:




Pokażemy teraz jak wyznaczyć funkcję potencjału <math>h</math> dla grafu <math>G</math>. Rozważmy następujący algorytm:
Pokażemy teraz, jak wyznaczyć funkcję potencjału <math>h</math> dla grafu <math>G</math>. Rozważmy następujący algorytm:


{{algorytm|Algorytm obliczania potencjału|algorytm_potenciału|3=
{{algorytm|Algorytm obliczania potencjału|algorytm_potenciału|3=
Linia 339: Linia 337:


Działanie tego algorytmu przedstawione jest na poniższej animacji.
Działanie tego algorytmu przedstawione jest na poniższej animacji.
<flash>file=Zasd_Ilustr_c.swf |width=600|height=300</flash>
[[File:Zasd_ilustr_c.svg|600x300px|thumb|center]]
 
{{lemat|11|lemat_11|3= Jeżeli graf <math>G=(V,E)</math> z wagami krawędzi zadanymi funkcją <math>w</math> zawiera cykl o ujemnej wadze, to [[#algorytm_potenciału|algorytm OBLICZ-POTENCJAŁ]] zwraca wartość <math>NIL</math>. Natomiast w przeciwnym wypadku algorytm zwraca potencjał <math>d(v)</math> dla grafu <math>G</math> z funkcją wagową <math>w</math>. }}
{{lemat|11|lemat_11|3= Jeżeli graf <math>G=(V,E)</math> z wagami krawędzi zadanymi funkcją <math>w</math> zawiera cykl o ujemnej wadze to [[#algorytm_potenciału|algorytm OBLICZ-POTENCJAŁ]] zwraca wartość <math>NIL</math>. Natomiast w przeciwnym wypadku algorytm zwraca potencjał <math>d(v)</math> dla grafu <math>G</math> z funkcją wagową <math>w</math>. }}


{{dowod|||3= Zauważmy, że dodanie wierzchołka <math>s</math> do grafu <math>G</math> nie wprowadza nowych cykli, a jedynie powoduje, że wszystkie wierzchołki są osiągalne z <math>s</math>. Dlatego algorytm Bellmana-Forda uruchomiany dla <math>G'</math> i wierzchołka <math>s</math> zwraca <math>NIL</math> wtedy i tylko wtedy gdy <math>G</math> zawiera cyklu o ujemnej wadze.
{{dowod|||3= Zauważmy, że dodanie wierzchołka <math>s</math> do grafu <math>G</math> nie wprowadza nowych cykli, a jedynie powoduje, że wszystkie wierzchołki są osiągalne z <math>s</math>. Dlatego algorytm Bellmana-Forda uruchamiany dla <math>G'</math> i wierzchołka <math>s</math> zwraca <math>NIL</math> wtedy i tylko wtedy, gdy <math>G</math> zawiera cykl o ujemnej wadze.


Zakładamy teraz, że graf <math>G</math> nie zawiera cyklu o ujemnej wadze, wtedy wartości <math>d(v)</math> jako odległości w grafie spełniają:
Zakładamy teraz, że graf <math>G</math> nie zawiera cyklu o ujemnej wadze, wtedy wartości <math>d(v)</math> jako odległości w grafie spełniają:
Linia 357: Linia 354:


<center><math>
<center><math>
w_d(u,v) = w(u,v) + d(u) - d(v) \ge 0,
w_d(u,v) = w(u,v) + d(u) - d(v) \ge 0</math>,</center>
</math></center>




Linia 369: Linia 365:
{{algorytm|Algorytm Johnsona|algorytm_johnsona|3=
{{algorytm|Algorytm Johnsona|algorytm_johnsona|3=
   JOHNSON<math>(G=(E,V),w)</math>
   JOHNSON<math>(G=(E,V),w)</math>
   1  <math>d = </math>[[#algorytm_potenciału|OBLICZ-POTENCJAŁ]]<math>(G,w)</math>
   1  <math>d =</math>[[#algorytm_potenciału|OBLICZ-POTENCJAŁ]]<math>(G,w)</math>
   1  '''if''' <math>d = NIL</math> '''then''' '''return''' <math>NIL</math>
   1  '''if''' <math>d = NIL</math> '''then''' '''return''' <math>NIL</math>
   3  '''for''' każda krawędź <math>(u,v) \in E</math> '''do'''
   3  '''for''' każda krawędź <math>(u,v) \in E</math> '''do'''

Aktualna wersja na dzień 22:16, 11 wrz 2023

Abstrakt

W wykładzie tym zajmiemy się problemem obliczania odległości w grafie między wszystkimi parami wierzchołków w grafie ważonym skierowanym G=(V,E). Przedstawimy trzy algorytmy rozwiązujące ten problem:

  • algorytm wykorzystujący mnożenie macierzy, działający w czasie O(|V|3log|V|),
  • algorytm Floyda-Warshalla, działający w czasie O(|V|3),
  • algorytm Johnsona, działający w czasie O(|V|2log|V|+|V||E|).

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 |V| 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 implementacja algorytmu Dijskstry wykorzystująca kopce Fibonacciego działa w czasie O(|V|log|V|+|E|), co daje nam algorytm rozwiązujący problem policzenia odległości między wszystkimi parami wierzchołków, działający w czasie O(|V|2log|V|+|V||E|).

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 O(|V|2|E|). 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 W rozmiaru n×n reprezentującą wagi krawędzi n-wierzchołkowego grafu G=(V,E). Dla macierzy tej zachodzi:


wi,j={0,jeśli i=j,waga krawędzi (i,j),jeśli ij i (i,j)E,,jeśli ij i (i,j)E.


W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków chcemy wyznaczyć macierz D rozmiaru n×n, taką że di,j jest równe odległości δ(i,j) z wierzchołka i do wierzchołka j. Chcemy także wyznaczyć dla każdego wierzchołka v drzewo najkrótszych ścieżek Tv ukorzenione w v. Podobnie jak w poprzednim rozdziale drzewo Tv możemy kodować dla każdego wierzchołka przy pomocy funkcji poprzedników πv. Ponieważ tutaj interesuje nas wiele drzew, łatwiej będzie nam używać macierzy poprzedników Π. Macierz tą definiujemy używając funkcji πv w następujący sposób:


Πv,u=πv(u).


W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości D. Zadaniu 3 do tego wykładu polega na pokazaniu, jak znając odległości w grafie policzyć drzewo najkrótszych ścieżek w czasie O(|E|). Tak więc |V| drzew możemy wyliczyć w czasie O(|E||V|). 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 D.


Co więcej, będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie O(|V||E|) przy użyciu Algorytmu Bellmana-Forda. Zobacz Zadanie 3 do Wykładu 4.

Najkrótsze ścieżki i mnożenie macierzy

Iloczyn odległości i jego właściwości

Załóżmy, że dane mamy dwie macierze wag C oraz D rozmiaru n×n. Dla macierzy tych definiujemy operację ×min iloczyn odległości, której wynikiem jest także macierz rozmiaru n×n, zdefiniowana jako:

(C×minD)i,j=mink=1,,nCi,k+Dk,j.      (1)


Wniosek 1

Jeżeli założymy, że C i D opisują minimalne wagi zbioru ścieżek odpowiednio ΠC i ΠD w pewnym grafie G, to iloczyn odległości wyznacza minimalne wagi zbioru ścieżek powstałego z konkatenacji ścieżek ze zbioru ΠC ze ścieżkami ze zbioru ΠD.

Wniosek ten jest przedstawiony na poniższej animicji, gdzie zostały zaznaczone dwa zbiory ścieżek, pierwszy, zaznaczony na zielono, reprezentowany przez macierz A oraz graf GA, oraz drugi, zaznaczony na niebiesko, reprezentowany przez macierz B oraz graf GB. W wyniku wykonania mnożenia otrzymujemy macierz C oraz graf GC

Plik:Zasd ilustr f.svg

Pokażemy teraz, że produkt odległości jest operacją łączną.

Lemat 2

Dla macierzy C, D i E rozmiaru n×n zachodzi:
(C×minD)×minE=C×min(D×minE)

Dowód

Powyższa równość wynika wprost z wzoru (1) oraz przemienności operacji min.

Co więcej, produkt odległości jest przemienny względem dodawania.

Lemat 3

Dla macierzy C, D i E rozmiaru n×n zachodzi:


C×min(D+E)=C×minD+C×minE


oraz


(D+E)×minC=D×minC+E×minC

Dowód

Te dwie równości wynikają ponownie z wzoru (1) oraz przemienności operacji min względem dodawania.


Zdefiniujmy macierz Imin rozmiaru n×n jako:


(Imin)i,j={0,jeśli i=j,,jeśli ij.


Macierz ta jest jedynką dla iloczynu odległości.


Lemat 4

Dla macierzy C rozmiaru n×n zachodzi:


Imin×minC=C×minImin=C

Dowód

Mamy
(Imin×minC)i,j=mink=1,,n(Imin)i,k+Ck,j=

ponieważ wszystkie elementy (Imin)i,k równe są oprócz elementu i=k, możemy je pominąć w operacji min i:


=mink=i(Imin)i,k+Ck,j=Ii,i+Ci,j=Ci,j

Pomysł algorytmu

Łączność iloczynu odległości ma dla nas bardzo ważne konsekwencje i pozwoli nam na konstrukcję algorytmu obliczania odległości w grafie między wszystkimi parami wierzchołków, działającego w czasie O(|V|3log|V|). Niech W będzie macierzą wag grafu G=(V,E). Rozważmy macierz Wm zdefiniowaną jako:


Wm={Imin,jeżeli m=0,W×minWm1,jeżeli m>0.

Pokażemy teraz, że macierz Wm opisuje odległości między wierzchołkami grafu, ale tylko dla ścieżek używających nie więcej niż m krawędzi.

Lemat 5

Element Wi,jm macierzy Wm zadaje najmniejszą wagę ścieżki, wychodzącej z wierzchołka i do wierzchołka j spośród ścieżek, które zawierają nie więcej niż m krawędzi, tzn.:


wi,jm={min{w(p):p ścieżka o długości m z u do v},jeżeli istnieje ścieżka o długości m z u do v,w przeciwnym przypadku.

Dowód

Tezę tę udowodnimy przez indukcję po m. Ścieżki używające 0 krawędzi istnieją tylko z każdego wierzchołka do niego samego i mają długość 0, a więc dla m=0 teza wynika wprost z definicji macierzy W0. Załóżmy teraz, że teza zachodzi dla m>0. Mamy wtedy Wm+1=W×minWm. Zauważmy, że definicja macierzy wag W opisuje ścieżki używające 1 krawędź. Korzystając teraz z Wniosku 1 otrzymujemy tezę dla m+1.


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

Lemat 6

Jeżeli w grafie G=(V,E), w którym wagi krawędzi zadane są macierzą W nie istnieje cykl o ujemnej wadze to:


δ(u,v)=Wu,v(k), dla kn1.

Dowód

Jeżeli w grafie nie istnieje cykl o ujemnej wadze, to wszystkie najkrótsze ścieżki są ścieżkami prostymi, a więc mają długość co najwyżej n1. Z Lematu 5 wynika więc, że odległości tych ścieżek są dobrze wyznaczone w Wk dla kn1.

Algorytm

Zauważmy, że iloczyn odległości dwóch macierzy możemy policzyć w czasie O(|V|3) wykorzystując następujący algorytm.


Algorytm Mnożenia macierzy odległości


 MNOŻENIE-ODLEGŁOŚCI(C,D)
 1  E macierz rozmiaru n×n
 2  for i=0 to n1 do
 3    for j=0 to n1 do
 4    begin
 5      ei,j=
 6      for k=0 to n1 do
 7        ei,j=min(ci,k+dk,j,ei,j)
 8    end
 9  return E

Ponieważ operacja iloczynu odległości jest łączna, możemy wykorzystać algorytm szybkiego potęgowania i policzyć odległości przy pomocy następującego algorytmu.

Algorytm Algorytm obliczania odległości między wszystkimi parami wierzchołków I


 ODLEGŁÓŚCI-I(W)
 1  D=W
 2  m=1
 3  while n1>m do
 4  begin
 5    D=MNOŻENIE-ODLEGŁOŚCI(D,D)
 6    m=2m
 7  end
 8  return D

Poprawność tego algorytmu wynika wprost z Lematu 6 ponieważ na zakończenie algorytmu D=Wm i m>n1.

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 wewnętrznym ścieżki p=(v0,,vl) jest każdy wierzchołek na ścieżce p różny od jej początku v0 i końca vl.

Niech zbiorem wierzchołków grafu G będzie V={1,,n}. Niech di,j(k) dla k=0,,n oznacza najmniejszą wagę ścieżki z i do j spośród ścieżek, których wierzchołki wewnętrzne należą do zbioru {1,,k}. Pokażemy następujący rekurencyjny wzór na D(k).

Lemat 7

Dla k=0,,n zachodzi:

di,j(k)={wi,j,jeżeli k=0,min(di,j(k1),di,k(k1)+dk,j(k1)),jeżeli k1.      (2)

Dowód

Dla k=0 poprawność powyższego wzoru wynika bezpośrednio z definicji D0. Dla k>0 musimy pokazać, że


di,j(k)=min(di,j(k1),di,k(k1)+dk,j(k1)).


Niech p będzie najkrótszą ścieżką z i do j, której wierzchołki wewnętrzne należą do zbioru {v1,,vk}. Mamy dwa przypadki:

  • Wierzchołek vk nie leży na ścieżce p. Wtedy zachodzi di,j(k)=p(w)=di,j(k1). Ponieważ p jest najkrótszą ścieżką, to także p(w)di,k(k1)+dk,j(k1) i powyższy wzór zachodzi.
  • Jeżeli wierzchołek vk należy do ścieżki p, to występuje on dokładnie raz i możemy podzielić p na dwie ścieżki p1 z i do k oraz p2 z k do j. Ścieżki p1 i p2 nie zawierają wierzchołka vk 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 w(p1)=di,k(k1) oraz w(p2)=dk,j(k1). Otrzymujemy więc di,j(k)=w(p)=w(p1)+w(p2)=di,k(k1)+dk,j(k1). Ponieważ p jest najkrótszą ścieżką, p(w)di,j(k1) 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 O(|V|3) odległości między wszystkimi parami wierzchołków.

Algorytm Algorytm Floyda-Warshalla


 ODLEGŁÓŚCI-II(W)
 1  D(0)=W,
 2  for k=1 to n do
 3    for i=1 to n do
 4      for j=1 to n do
 5        di,j(k)=min(di,j(k1),di,k(k1)+dk,j(k1))
 6  return D(n)


Algorytm Johnsona

W algorytmie Johnsona wykorzystamy spostrzeżenie uczynione przez nas na początku wykładu, że odległości w grafie, w którym wszystkie wagi krawędzi są dodatnie, można obliczyć korzystając z algorytmu Dijkstry w czasie O(|V|2log|V|+|V||E|). Pokażemy tutaj, jak zmienić wagi w grafie tak, aby stały się one dodatnie, przy zachowaniu najkrótszych ścieżek.

Niech będzie dany graf skierowany G=(V,E) wraz z funkcją wagową w:E. Niech funkcja h:V będzie dowolną funkcją ze zbioru wierzchołków w liczby rzeczywiste. Dla funkcji h oraz w definiujmy nową funkcję wagową oznaczoną wh w następujący sposób:

wh(u,v)=w(u,v)+h(u)h(v)      (3)

Oznaczmy, przez δ(u,v) odległości w grafie G dla funkcji wagowej w oraz przez δh(u,v) odległości w grafie G dla funkcji wagowej wh.

Lemat 8

Dla funkcji w, wh oraz dowolnej ścieżki p=(v0,,vk) zachodzi:
wh(p)=w(p)+h(v0)h(vk)

Dowód

Mamy:


wh(p)=i=0k1wh(vi,vi+1)=
=i=0k1(w(vi,vi+1)+h(vi)h(vi+1))=
=i=0k1w(vi,vi+1)+i=0k1h(vi)i=0k1h(vi+1)=
=w(p)+h(v0)h(vk)


Widzimy więc, że zmiana długości ścieżki zależy tylko od jej końców. Otrzymujemy stąd wprost dwa wnioski.


Wniosek 9

Dla funkcji w, wh, oraz dowolnej pary wierzchołków zachodzi:
δh(u,v)=δ(u,v)+h(u)h(v).


Wniosek 10

Ścieżka p z wierzchołka u do wierzchołka v jest najkrótszą ścieżką w G=(V,E) dla funkcji wagową w wtedy i tylko wtedy, gdy jest najkrótszą ścieżką w G dla funkcji wagowej wh.

Dowód

Wniosek ten wynika wprost z Lematu 8 i Wniosku 9, który pokazuje, że odległości transformują się tak samo jak wagi ścieżek, a więc równość w(p)=δ(u,v) jest równoważna równości wh(p)=δh(u,v).


Funkcję h nazwiemy potencjałem jeżeli zachodzi:

wh(u,v)0, dla (u,v)E.      (4)


Pokażemy teraz, jak wyznaczyć funkcję potencjału h dla grafu G. Rozważmy następujący algorytm:

Algorytm Algorytm obliczania potencjału


 OBLICZ-POTENCJAŁ(G=(V,E),w)
 1  s nowy wierzchołek
 2  V=V{s}
 3  E=E{(s,v):vV}
 4  w(u,v)={w(u,v),jeżeli (u,v)E0jeżeli u=s0w pozostałych przypadkach
 5  (d,π)=BELLMAN-FORD(G,w,s)
 6  if (d,π)=NIL then
 7    return NIL (graf zawiera cykl ujemnej długości)
 8  return d (d(v) obliczone w algorytmie Bellmana-Forda jest potencjałem)

Działanie tego algorytmu przedstawione jest na poniższej animacji.

Plik:Zasd ilustr c.svg

Lemat 11

Jeżeli graf G=(V,E) z wagami krawędzi zadanymi funkcją w zawiera cykl o ujemnej wadze, to algorytm OBLICZ-POTENCJAŁ zwraca wartość NIL. Natomiast w przeciwnym wypadku algorytm zwraca potencjał d(v) dla grafu G z funkcją wagową w.

Dowód

Zauważmy, że dodanie wierzchołka s do grafu G nie wprowadza nowych cykli, a jedynie powoduje, że wszystkie wierzchołki są osiągalne z s. Dlatego algorytm Bellmana-Forda uruchamiany dla G i wierzchołka s zwraca NIL wtedy i tylko wtedy, gdy G zawiera cykl o ujemnej wadze.

Zakładamy teraz, że graf G nie zawiera cyklu o ujemnej wadze, wtedy wartości d(v) jako odległości w grafie spełniają:


d(v)d(u)+w(u,v).


Innymi słowy:


wd(u,v)=w(u,v)+d(u)d(v)0,


co kończy dowód lematu.


Powyższy lemat jest ostatnim składnikiem potrzebnym nam do konstrukcji algorytmu Johnsona.

Algorytm Algorytm Johnsona


 JOHNSON(G=(E,V),w)
 1  d=OBLICZ-POTENCJAŁ(G,w)
 1  if d=NIL then return NIL
 3  for każda krawędź (u,v)E do
 4     wd(u,v)=w(u,v)+d(u)d(v)
 5  for każdy wierzchołek uV do
 6    (dh,π) = DIJKSTRA(G,wh,u)
 7    for każdy wierzchołek vV do
 8      d(u,v)=dh(v)+h(v)h(u)
 9  return D

Poprawność tego algorytmu wynika wprost z Lematu 11. Czas działania algorytmu jest równy sumie czasu działania algorytmu Bellmana-Forda i czasu potrzebnego na O(|V|) wywołań algorytmu Dijkstry, co daje całkowity czas O(|V||E|+|V|2log|V|).