Zaawansowane algorytmy i struktury danych/Wykład 6: Różnice pomiędzy wersjami
m Zastępowanie tekstu – „<math> ” na „<math>” |
|||
(Nie pokazano 47 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 | |||
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ć algorytmu Dijkstry. Najszybsza | 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: | ||
{{wzor2|1=<math> | |||
w_{i,j} = \begin{cases} | w_{i,j} = \begin{cases} | ||
0, & \mbox{jeśli } i=j,\\ | 0, & \mbox{jeśli } i=j,\\ | ||
Linia 22: | Linia 21: | ||
\infty, & \mbox{jeśli } i\neq j \mbox{ i } (i,j)\neq E. | \infty, & \mbox{jeśli } i\neq j \mbox{ i } (i,j)\neq E. | ||
\end{cases} | \end{cases} | ||
</math> | </math>}} | ||
W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków chcemy wyznaczyć macierz <math>D</math> rozmiaru | 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: | ||
<math>n \times n</math> taką | |||
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 | |||
{{wzor2|1=<math> | |||
\Pi_{v,u} = \pi_v(u). | \Pi_{v,u} = \pi_v(u). | ||
</math> | </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 [[ | 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 44: | Linia 42: | ||
Załóżmy, że dane mamy dwie [[#macierz_wag|macierze wag]] <math>C</math> oraz <math>D</math> rozmiaru <math>n\times n</math>. | Załóżmy, że dane mamy dwie [[#macierz_wag|macierze wag]] <math>C</math> oraz <math>D</math> rozmiaru <math>n\times n</math>. | ||
Dla macierzy tych definiujemy operację <math>\times_{\min}</math> {{kotwica| | Dla macierzy tych definiujemy operację <math>\times_{\min}</math> {{kotwica|iloczyn_odległości|'''iloczyn odległości'''}}, której wynikiem jest także macierz rozmiaru <math>n \times n</math>, zdefiniowana jako: | ||
{{wzor|wzór_1|1|3= | {{wzor|wzór_1|1|3= | ||
Linia 54: | Linia 52: | ||
{{wniosek|1|wniosek_konkatenacja|3= | {{wniosek|1|wniosek_konkatenacja|3= | ||
Jeżeli założymy, że <math>C</math> i <math>D</math> opisują minimalne wagi zbioru ścieżek odpowiednio | |||
Jeżeli założymy, że <math>C</math> i <math>D</math> opisują minimalne wagi | <math>\Pi_{C}</math> i <math>\Pi_{D}</math> w pewnym grafie <math>G</math>, to iloczyn odległości wyznacza minimalne wagi zbioru ścieżek powstałego z konkatenacji ścieżek ze zbioru <math>\Pi_{C}</math> ze ścieżkami ze zbioru <math>\Pi_{D}</math>. | ||
<math>\Pi_{C}</math> i <math>\Pi_{D}</math> w pewnym grafie <math>G</math>, to iloczyn odległości wyznacza minimalne wagi zbioru ścieżek powstałego z konkatenacji ścieżek ze zbioru <math>\Pi_{C}</math> ze ścieżkami zbioru <math>\Pi_{D}</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> | |||
[[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ą. | ||
{{wzor2|1=}} | |||
{{lemat|2|io_łączny|3= | {{lemat|2|io_łączny|3= | ||
Dla macierzy <math>C</math>, <math>D</math> i <math>E</math> rozmiaru <math>n\times n</math>zachodzi: | Dla macierzy <math>C</math>, <math>D</math> i <math>E</math> rozmiaru <math>n\times n</math> zachodzi: | ||
{{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|io_przemienny | {{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} | |||
D + C \times_{min} E | D + C \times_{min} E</math>}} | ||
Linia 87: | Linia 85: | ||
{{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>}} }} | ||
{{dowod||| Te dwie równości wynikają ponownie z [[#wzór_1|wzoru (1)]] oraz przemienności operacji <math>\min</math> względem dodawania. }} | {{dowod||| Te dwie równości wynikają ponownie z [[#wzór_1|wzoru (1)]] oraz przemienności operacji <math>\min</math> względem dodawania. }} | ||
Linia 97: | Linia 95: | ||
{{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} | ||
</math> | </math>}} | ||
Linia 109: | Linia 107: | ||
{{wzor2|1=<math>I_{\min} \times_{\min} C = C \times_{\min} I_{\min} =C</math>}} }} | |||
C | |||
{{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>}} | |||
\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>, 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} | |||
= 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 | Łą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: | ||
{{wzor2|1= | |||
<math> | <math> | ||
W^{m} = \begin{cases} | W^{m} = \begin{cases} | ||
Linia 137: | Linia 131: | ||
\end{cases} | \end{cases} | ||
</math> | </math> | ||
}} | |||
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 | 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ą | 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.: | ||
{{wzor2|1=<math> | |||
w_{i,j}^{m} = \begin{cases} | w_{i,j}^{m} = \begin{cases} | ||
\min\{w(p): p \mbox{ ścieżka o długości } \le m \mbox{ z } u \mbox{ do } v\}, & \mbox{jeżeli istnieje ścieżka o długości } \le m \mbox{ z } u \mbox{ do } v,\\ | \min\{w(p): p \mbox{ ścieżka o długości } \le m \mbox{ z } u \mbox{ do } v\}, & \mbox{jeżeli istnieje ścieżka o długości } \le m \mbox{ z } u \mbox{ do } v,\\ | ||
\infty & \mbox{w przeciwnym przypadku.} | \infty & \mbox{w przeciwnym przypadku.} | ||
\end{cases} | \end{cases} | ||
</math> | </math>}} | ||
}} | }} | ||
{{dowod|||3= Tezę | {{dowod|||3= Tezę tę 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 | 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>. | ||
}} | }} | ||
Zajmiemy się teraz konstrukcją algorytmu obliczającego najkrótsze ścieżki w grafie. W tym celu będziemy | 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 167: | Linia 161: | ||
{{wzor2|1=<math> | |||
\delta(u,v) = W^{(k)}_{u,v}, \mbox{ dla } k \ge n-1. | \delta(u,v) = W^{(k)}_{u,v}, \mbox{ dla } k \ge n-1. | ||
</math> | </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 \ | {{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 182: | Linia 176: | ||
{{algorytm|Mnożenia macierzy odległości|algorytm_iloczyn_odległości|3= | {{algorytm|Mnożenia macierzy odległości|algorytm_iloczyn_odległości|3= | ||
MNOŻENIE-ODLEGŁOŚCI(C,D) | MNOŻENIE-ODLEGŁOŚCI<math>(C,D)</math> | ||
1 <math>E</math> macierz rozmiaru <math>n \times n</math> | 1 <math>E</math> macierz rozmiaru <math>n \times n</math> | ||
2 '''for''' <math>i = 0</math> '''to''' <math>n-1</math> '''do''' | 2 '''for''' <math>i = 0</math> '''to''' <math>n-1</math> '''do''' | ||
3 '''for''' <math>j = 0</math> '''to''' <math>n-1</math> '''do''' | 3 '''for''' <math>j = 0</math> '''to''' <math>n-1</math> '''do''' | ||
4 <math>e_{i,j} = \infty</math> | 4 '''begin''' | ||
5 <math>e_{i,j} = \infty</math> | |||
6 '''for''' <math>k =0</math> '''to''' <math>n-1</math> '''do''' | |||
7 <math>e_{i,j} = \min(c_{i,k} + d_{k,j}, e_{i,j})</math> | |||
8 '''end''' | |||
9 '''return''' E | |||
}} | }} | ||
Ponieważ operacja iloczynu odległości jest łączna | 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. | ||
{{algorytm|Algorytm obliczania odległości między wszystkimi parami wierzchołków I|algorytm_apsp_mnozenie|3= | {{algorytm|Algorytm obliczania odległości między wszystkimi parami wierzchołków I|algorytm_apsp_mnozenie|3= | ||
ODLEGŁÓŚCI-I(W) | ODLEGŁÓŚCI-I<math>(W)</math> | ||
1 <math>D = W</math> | 1 <math>D = W</math> | ||
2 <math> | 2 <math>m = 1</math> | ||
3 '''while''' <math>n-1 > | 3 '''while''' <math>n-1 > m</math> '''do''' | ||
4 <math>D = </math>MNOŻENIE-ODLEGŁOŚCI<math>(D,D)</math> | 4 '''begin''' | ||
5 <math>D =</math>MNOŻENIE-ODLEGŁOŚCI<math>(D,D)</math> | |||
7 '''return''' <math>D</math> | 6 <math>m = 2m</math> | ||
7 '''end''' | |||
8 '''return''' <math>D</math> | |||
}} | }} | ||
Poprawność tego algorytmu wynika wprost z [[#lemat_6|Lematu 6]] ponieważ na zakończenie algorytmu <math>D = W^{m}</math> i <math>m > n-1</math>. | |||
== Algorytm Floyda-Warshalla == | == Algorytm Floyda-Warshalla == | ||
W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych ścieżek niż ta użyta w algorytmie z wykorzystaniem | W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych ś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| | [[#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> | 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 221: | Linia 219: | ||
d_{i,j}^{(k)} = \begin{cases} | d_{i,j}^{(k)} = \begin{cases} | ||
w_{i,j}, & \mbox{jeżeli } k=0,\\ | w_{i,j}, & \mbox{jeżeli } k=0,\\ | ||
\min( d_{i,j}^{(k-1)}, d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}, & \mbox{jeżeli } k \ge 1. | \min( d_{i,j}^{(k-1)}, d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}), & \mbox{jeżeli } k \ge 1. | ||
\end{cases} | \end{cases} | ||
</math> | </math> | ||
Linia 230: | Linia 228: | ||
{{wzor2|1=<math> | |||
d_{i,j}^{(k)} = \min( d_{i,j}^{(k-1)}, d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}). | d_{i,j}^{(k)} = \min( d_{i,j}^{(k-1)}, d_{i,k}^{(k-1)} + d_{k,j}^{(k-1)}). | ||
</math> | </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: | 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>, | * 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= | ||
ODLEGŁÓŚCI-II(W) | ODLEGŁÓŚCI-II<math>(W)</math> | ||
1 <math>D^{(0)} = W</math>, | 1 <math>D^{(0)} = W</math>, | ||
2 '''for''' <math>k = 1</math> '''to''' <math>n</math> '''do''' | 2 '''for''' <math>k = 1</math> '''to''' <math>n</math> '''do''' | ||
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ą | 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) | 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) | {{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 | 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|lemat_8 | {{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>w_h(p) = w(p) + h(v_0) - h(v_k)</math> | ||
}} | }} | ||
Linia 286: | Linia 284: | ||
<math>= \sum_{i=0}^{k-1} w(v_i, v_{i+1}) + \sum_{i=0}^{k-1}h(v_i) - \sum_{i=0}^{k-1}h(v_{i+1}) =</math> | <math>= \sum_{i=0}^{k-1} w(v_i, v_{i+1}) + \sum_{i=0}^{k-1}h(v_i) - \sum_{i=0}^{k-1}h(v_{i+1}) =</math> | ||
}} | }} | ||
{{wzor2|1= | {{wzor2|1= | ||
<math>= w(p) + h(v_0) - h(v_k) | <math>= w(p) + h(v_0) - h(v_k)</math> | ||
}} | }} | ||
}} | }} | ||
Linia 298: | Linia 295: | ||
{{wniosek|wniosek_9 | {{wniosek|9|wniosek_9|3=Dla funkcji <math>w</math>, <math>w_h</math>, oraz dowolnej pary wierzchołków zachodzi: | ||
{{wzor2|1= | {{wzor2|1= | ||
Linia 309: | Linia 306: | ||
{{wniosek|lemat_10 | {{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>. }} | ||
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 | {{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>. | ||
[[#wniosek_9|Wniosku 9]], który pokazuje, że odległości transformują | |||
się tak samo jak wagi ścieżek, a | |||
\delta(u,v)</math> jest równoważna równości <math>w_h(p) = | |||
\delta_h(u,v)</math>. | |||
}} | }} | ||
Funkcję <math>h</math> nazwiemy | Funkcję <math>h</math> nazwiemy {{kotwica|potencjał|'''potencjałem'''}} jeżeli zachodzi: | ||
{{kotwica|potencjał|'''potencjałem'''}} jeżeli | |||
zachodzi: | |||
{{wzor|wzor_4|4|3= | {{wzor|wzor_4|4|3= | ||
<math> | <math> | ||
w_h(u,v) \ge 0, \mbox{ dla } | w_h(u,v) \ge 0, \mbox{ dla } (u,v) \in E. | ||
</math> | </math> | ||
}} | }} | ||
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= | ||
OBLICZ-POTENCJAŁ(G=(V,E), w) | OBLICZ-POTENCJAŁ<math>(G=(V,E), w)</math> | ||
1 <math>s</math> nowy wierzchołek | 1 <math>s</math> nowy wierzchołek | ||
2 <math>V' = V \cup \{s\}</math> | 2 <math>V' = V \cup \{s\}</math> | ||
3 <math>E' = E \cup \{(s,v): v \in V\}</math> | 3 <math>E' = E \cup \{(s,v): v \in V\}</math> | ||
4 <math>w'(u,v) = \begin{cases}w(u,v), & \mbox{jeżeli} (u,v)\in E\\ 0 | 4 <math>w'(u,v) = \begin{cases}w(u,v), & \mbox{jeżeli } (u,v)\in E\\ 0 & \mbox{jeżeli } u=s\\0& \mbox{w pozostałych przypadkach}\end{cases}</math> | ||
5 | 5 <math>(d,\pi)=</math>[[../Wykład 5#algorytm_Bellmana-Forda|BELLMAN-FORD]]<math>(G',w,s)</math> | ||
6 '''if''' <math>(d,\pi) = NIL</math> '''then''' | |||
7 '''return''' <math>NIL</math> ''(graf zawiera cykl ujemnej długości)'' | |||
8 '''return''' <math>d</math> ''(<math>d(v)</math> obliczone w algorytmie Bellmana-Forda jest potencjałem)'' | |||
}} | }} | ||
{{lemat|lemat_11 | Działanie tego algorytmu przedstawione jest na poniższej animacji. | ||
krawędzi zadanymi funkcją <math>w</math> zawiera cykl o ujemnej | [[File:Zasd_ilustr_c.svg|600x300px|thumb|center]] | ||
wadze to | {{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>. }} | ||
przeciwnym wypadku algorytm zwraca | |||
{{dowod|||3= Zauważmy, że dodanie wierzchołka <math>s</math> do | {{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. | ||
grafu <math>G</math>nie wprowadza nowych cykli | |||
powoduje, że wszystkie wierzchołki są osiągalne z <math>s</math>. | |||
Dlatego algorytm Bellmana-Forda | |||
wierzchołka <math>s</math> zwraca | |||
<math>G</math> | |||
Zakładamy teraz, że graf <math>G</math> nie zawiera | 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ą: | ||
o ujemnej wadze, wtedy wartości <math>d(v)</math> jako odległości w grafie | |||
spełniają: | |||
Linia 373: | 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 381: | Linia 361: | ||
Powyższy lemat jest ostatnim składnikiem potrzebnym nam do konstrukcji | Powyższy lemat jest ostatnim składnikiem potrzebnym nam do konstrukcji algorytmu Johnsona. | ||
algorytmu Johnsona. | |||
{{algorytm|Algorytm Johnsona|algorytm_johnsona|3= | {{algorytm|Algorytm Johnsona|algorytm_johnsona|3= | ||
JOHNSON(G=(E,V),w) | JOHNSON<math>(G=(E,V),w)</math> | ||
1 | 1 <math>d =</math>[[#algorytm_potenciału|OBLICZ-POTENCJAŁ]]<math>(G,w)</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''' | ||
4 <math>w_d(u,v) = w(u,v) + d(u) - d(v)</math> | 4 <math>w_d(u,v) = w(u,v) + d(u) - d(v)</math> | ||
5 '''for''' każdy wierzchołek <math>u \in V</math> '''do''' | 5 '''for''' każdy wierzchołek <math>u \in V</math> '''do''' | ||
6 | 6 <math>(d_h,\pi)</math> = [[DIJKSTRA]]<math>(G,w_h,u)</math> | ||
7 '''for''' każdy wierzchołek <math>v \in V</math> '''do''' | 7 '''for''' każdy wierzchołek <math>v \in V</math> '''do''' | ||
8 <math>d(u,v) = d_h( | 8 <math>d(u,v) = d_h(v) + h(v) - h(u)</math> | ||
9 '''return''' <math>D</math> | 9 '''return''' <math>D</math> | ||
}} | }} | ||
Poprawność tego algorytmu wynika wprost z [[#lemat_11|Lematu 11]]. | Poprawność tego algorytmu wynika wprost z [[#lemat_11|Lematu 11]]. Czas działania algorytmu jest równy sumie czasu działania algorytmu Bellmana-Forda i czasu potrzebnego na <math>O(|V|)</math> wywołań algorytmu Dijkstry, co daje całkowity czas <math>O(|V||E| + |V|^2 \log |V|)</math>. | ||
Czas działania algorytmu jest | |||
Bellmana-Forda i | |||
algorytmu Dijkstry, co |
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 . Przedstawimy trzy algorytmy 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 implementacja 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, ł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 . 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 . Tak 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 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 oraz rozmiaru . Dla macierzy tych definiujemy operację iloczyn odległości, której wynikiem jest także macierz rozmiaru , zdefiniowana jako:
(1)
Wniosek 1
Wniosek ten jest przedstawiony na poniższej animicji, gdzie zostały zaznaczone dwa zbiory ścieżek, pierwszy, zaznaczony na zielono, reprezentowany przez macierz oraz graf , oraz drugi, zaznaczony na niebiesko, reprezentowany przez macierz oraz graf . W wyniku wykonania mnożenia otrzymujemy macierz oraz graf
Pokażemy teraz, że produkt odległości jest operacją łączną.
Lemat 2
Dowód

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

Zdefiniujmy macierz rozmiaru jako:
Macierz ta jest jedynką dla iloczynu odległości.
Lemat 4
Dowód
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 . Niech będzie macierzą wag grafu . Rozważmy macierz zdefiniowaną jako:
Pokażemy teraz, że macierz opisuje odległości między wierzchołkami grafu, ale tylko dla ścieżek używających nie więcej niż krawędzi.
Lemat 5
Dowód

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
Dowód

Algorytm
Zauważmy, że iloczyn odległości dwóch macierzy możemy policzyć w czasie wykorzystując następujący algorytm.
Algorytm Mnożenia macierzy odległości
MNOŻENIE-ODLEGŁOŚCI 1 macierz rozmiaru 2 for to do 3 for to do 4 begin 5 6 for to do 7 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 1 2 3 while do 4 begin 5 MNOŻENIE-ODLEGŁOŚCI 6 7 end 8 return
Poprawność 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 wewnętrznym ś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 7
(2)
Dowód
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ą, 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
ODLEGŁÓŚCI-II 1 , 2 for to do 3 for to do 4 for to do 5 6 return
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 . 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 wraz z funkcją wagową . Niech funkcja będzie dowolną funkcją ze zbioru wierzchołków w liczby rzeczywiste. Dla funkcji oraz definiujmy nową funkcję wagową oznaczoną w następujący sposób:
(3)
Oznaczmy, przez odległości w grafie dla funkcji wagowej oraz przez odległości w grafie dla funkcji wagowej .
Lemat 8
Dowód
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
Wniosek 10
Dowód

Funkcję nazwiemy potencjałem jeżeli zachodzi:
(4)
Pokażemy teraz, jak wyznaczyć funkcję potencjału dla grafu . Rozważmy następujący algorytm:
Algorytm Algorytm obliczania potencjału
OBLICZ-POTENCJAŁ 1 nowy wierzchołek 2 3 4 5 BELLMAN-FORD 6 if then 7 return (graf zawiera cykl ujemnej długości) 8 return ( obliczone w algorytmie Bellmana-Forda jest potencjałem)
Działanie tego algorytmu przedstawione jest na poniższej animacji.
Lemat 11
Dowód
Zakładamy teraz, że graf nie zawiera cyklu o ujemnej wadze, wtedy wartości jako odległości w grafie spełniają:
Innymi słowy:

Powyższy lemat jest ostatnim składnikiem potrzebnym nam do konstrukcji algorytmu Johnsona.
Algorytm Algorytm Johnsona
JOHNSON 1 OBLICZ-POTENCJAŁ 1 if then return 3 for każda krawędź do 4 5 for każdy wierzchołek do 6 = DIJKSTRA 7 for każdy wierzchołek do 8 9 return
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 wywołań algorytmu Dijkstry, co daje całkowity czas .