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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
Sank (dyskusja | edycje)
Nie podano opisu zmian
Linia 3: Linia 3:
W wykładzie tym zajmiemy się problemem obliczanie 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>.
Linia 9: Linia 9:
== 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 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 25:




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 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:




Linia 33: Linia 33:




W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości <math>D</math>. W zadaniu [[../Ć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>.




Linia 53: Linia 53:


{{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 odpowiednio zbioru ścieżek odpowiednio
Jeżeli założymy, że <math>C</math> i <math>D</math> opisują minimalne wagi zbioru ścieżek odpowiednio
<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>.
<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>.
}}
}}


Wniosek ten jest przedstawiony na poniższej animicji, gdzie mamy dwa zbiory ścieżek zanzaczone, pierwszy zaznaczony na zielono reprezentowany przez macierz <math>A</math> oraz graf <math>G_A</math> oraz
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>
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>
<flash>file=Zasd_Ilustr_f.swf|width=600|height=500</flash>




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>
{{wzor2|1=<math>
Linia 78: Linia 77:
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|3|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:




Linia 101: Linia 100:
\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 124: Linia 123:
=== 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(n^{3}\log n)</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 136: Linia 135:
}}
}}


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 mniej 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ą mniej 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 151: Linia 150:
}}
}}


{{dowod|||3= Tezę tą udowodnimy przez indukcję po <math>m</math>. Dla danego wierzchołka istnieją dla nich tylko ścieżki długości zero prowadzące do niego samego, a więc dla <math>m=0</math> teza wynika wprost z definicji macierzy <math>W^0</math>.
{{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 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 170: Linia 169:
}}
}}


{{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 \le 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 179: Linia 178:


{{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'''
Linia 186: Linia 185:
   5      <math>e_{i,j} = \infty</math>
   5      <math>e_{i,j} = \infty</math>
   6      '''for''' <math>k =0</math> '''to''' <math>n-1</math> '''do'''
   6      '''for''' <math>k =0</math> '''to''' <math>n-1</math> '''do'''
   7        e_{i,j} = \min(c_{i,k} + d_{k,j}, e_{i,j})
   7        <math>e_{i,j} = \min(c_{i,k} + d_{k,j}, e_{i,j})</math>
   8    '''end'''
   8    '''end'''
   9  '''return''' E
   9  '''return''' E
Linia 195: Linia 194:


{{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>k = 1</math>
   2  <math>m = 1</math>
   3  '''while''' <math>n-1 > k</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>
Linia 213: Linia 212:
[[#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>\{v_1, \ldots,v_{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 222: Linia 221:
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 245: Linia 244:


{{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 253: Linia 252:
   6  '''return''' <math>D^{(n)}</math>
   6  '''return''' <math>D^{(n)}</math>
}}
}}


== 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 [[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ą 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.


Niech będzie dany graf skierowany <math>G(V,E)=</math> wraz z funkcją wagową <math>w:E \to \mathcal{R}</math>. Funkcję <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>}}
Linia 264: Linia 264:
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 gafie <math>G</math> dla funkcji wagowej <math>w_h</math>.


{{lemat|lemat_8|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=
Linia 286: Linia 286:
<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=
Linia 298: Linia 297:




{{wniosek|wniosek_9|9|3=Dla funkcji <math>w</math>, <math>w_h</math>, oraz dowolnej pary wierzchołków zachodzi:
{{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 308:




{{wniosek|lemat_10|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 315: Linia 314:




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 } <math>(u,v) \in E</math>.
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, & \mbox{jeżeli} u=s\\0, \mbox{w pozostałych przypadkach}\end{cases}</math>
   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  <math>(d,\pi)=</math>[[../Wykład 5#algorytm_Bellmana-Forda|BELLMAN-FORD]]<math>(G',w,s)</math>
   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'''
   6  '''if''' <math>(d,\pi) = NIL</math> '''then'''
   7    '''return''' NIL ''(graf zawiera cykl ujemnej długości)''
   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)''
  8 '''return''' <math>d</math> ''(<math>d(v)</math> obliczone w algorytmie Bellmana-Forda jest potencjałem)''
}}
}}


Linia 343: Linia 341:
<flash>file=Zasd_Ilustr_c.swf |width=600|height=300</flash>
<flash>file=Zasd_Ilustr_c.swf |width=600|height=300</flash>


{{lemat|lemat_11|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 OBLICZ-POTENCJAŁ zwraca wartość NIL. 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 do grafu, 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 nie zwraca NIL wtedy i tylko wtedy gdy <math>G</math> nie 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 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.


Zakładamy teraz, że graf <math>G</math> nie zawiera cykli 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 370: Linia 368:


{{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  <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''' NIL
   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    (d_h,\pi) = [[DIJKSTRA]]<math>(G,w_h,u)</math>
   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(v) + h(v) - h(u)</math>
   8      <math>d(u,v) = d_h(v) + h(v) - h(u)</math>
Linia 382: Linia 380:
}}
}}


Poprawność tego algorytmu wynika wprost z [[#lemat_11|Lematu 11]]. Czas działania algorytmu jest równa sumie czasu działania algorytmu Bellmana-Forda i czasowi potrzebnemu na <math>O(|V|)</math> wywołań algorytmu Dijkstry, co daje całkowity czas <math>O(|V||E| + |V|^2 \log |V|)</math>.
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>.

Wersja z 11:10, 19 wrz 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 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 to ł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 <flash>file=Zasd_Ilustr_f.swf|width=600|height=500</flash>


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, to 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 potrzebowali 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 to 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ą to 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ą dodanie 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 gafie 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. <flash>file=Zasd_Ilustr_c.swf |width=600|height=300</flash>

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 uruchomiany dla G i wierzchołka s zwraca NIL wtedy i tylko wtedy gdy G zawiera cyklu 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|).