Zaawansowane algorytmy i struktury danych/Wykład 6: Różnice pomiędzy wersjami
Nie podano opisu zmian |
|||
Linia 16: | Linia 16: | ||
{{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 22: | ||
\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>}} | ||
Linia 30: | Linia 30: | ||
{{wzor2|1=<math> | |||
\Pi_{v,u} = \pi_v(u). | \Pi_{v,u} = \pi_v(u). | ||
</math> | </math>}} | ||
Linia 67: | Linia 67: | ||
{{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 80: | Linia 80: | ||
{{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 87: | Linia 87: | ||
{{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 97: | ||
{{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 109: | ||
{{wzor2|1=<math> I_{\min} \times_{\min} C = C \times_{\min} I_{\min} =C. </math>}} }} | |||
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>}} | |||
\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>, to 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> | = I_{i,i} + C_{i,j} = C_{i,j}. </math>}} }} | ||
=== Pomysł algorytmu === | === Pomysł algorytmu === | ||
Linia 129: | Linia 126: | ||
{{wzor2|1= | |||
<math> | <math> | ||
W^{m} = \begin{cases} | W^{m} = \begin{cases} | ||
Linia 136: | Linia 133: | ||
\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 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 mniej niż <math>m</math> krawędzi. | ||
Linia 145: | Linia 142: | ||
{{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>}} | ||
}} | }} | ||
Linia 166: | Linia 163: | ||
{{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>}} | ||
}} | }} | ||
Linia 229: | Linia 226: | ||
{{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>}} | ||
Linia 307: | Linia 304: | ||
{{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 | {{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>. }} | ||
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 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 330: | Linia 321: | ||
}} | }} | ||
Pokażemy teraz jak wyznaczyć funkcję potencjału <math>h</math> dla | Pokażemy teraz jak wyznaczyć funkcję potencjału <math>h</math> dla grafu <math>G</math>. Rozważmy następujący algorytm: | ||
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 344: | Linia 334: | ||
}} | }} | ||
{{lemat|lemat_11|11|3= Jeżeli graf <math>G=(V,E)</math> z wagami | {{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ść FALSE. Natomiast w przeciwnym wypadku algorytm zwraca TRUE i <math>d(v)</math> potencjałem dla grafu <math>G</math> z funkcją wagową <math>w</math>. }} | ||
krawędzi zadanymi funkcją <math>w</math> zawiera cykl o ujemnej | |||
wadze to Algorytm OBLICZ-POTENCJAŁ zwraca wartość FALSE. Natomiast w | |||
przeciwnym wypadku algorytm zwraca TRUE i <math>d(v)</math> | |||
potencjałem dla grafu <math>G</math> z funkcją wagową <math>w</math>. }} | |||
{{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 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 TRUE wtedy i tylko wtedy gdy <math>G</math> nie zawiera cyklu o ujemnej wadze. | ||
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 TRUE wtedy i tylko wtedy gdy | |||
<math>G</math> nie zawiera cyklu o ujemnej wadze. | |||
Zakładamy teraz, że graf <math>G</math> nie zawiera cykli | 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ą: | ||
o ujemnej wadze, wtedy wartości <math>d(v)</math> jako odległości w grafie | |||
spełniają: | |||
Linia 379: | Linia 358: | ||
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= | ||
Linia 395: | Linia 373: | ||
}} | }} | ||
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ó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>. | ||
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>. |
Wersja z 18:55, 23 lip 2006
Abstrakt
W wykładzie tym zajmiemy się problemem obliczanie odległości w grafie między wszystkimi parami wierzchołków w grafie ważonym skierowanym . Przedstawimy trzy 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 to łatwiej będzie nam używać 'macierzy poprzedników . Macierz tą definiujemy używając funkcji w następujący sposób:
W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości . Jak to zostało pokazane w Zadaniu 3 do poprzedniego wykładu znając odległości w grafie drzewo najkrótszych ścieżek można wyznaczyć w czasie , a więc drzew możemy wyliczyć w czasie . Czas ten jest mniejszy niż czas działania wszystkich prezentowanych w tym wykładzie algorytmów, więc bez straty ogólności, a zyskując na prostocie prezentacji możemy ograniczyć się tylko do wyznaczenia macierzy odległości .
Co więcej będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie przy użyciu Algorytmu Bellmana-Forda. Zobacz Zadanie 4 do Wykładu 4.
Najkrótsze ścieżki i mnożenie macierzy
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
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 io_przemienny
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 mniej 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 potrzebowali 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(C,D) 1 macierz rozmiaru 2 for to do 3 for to do 4 5 for to do 6 e_{i,j} = \min(c_{i,k} + d_{k,j}, e_{i,j}) 7 return D'
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 , 2 3 while do 4 MNOŻENIE-ODLEGŁOŚCI 5 7 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ą to i wzór zachodzi także w tym przypadku.
Wykorzystując wzór (2) możemy skonstruować następujący algorytm obliczający w czasie odległości między wszystkimi parami wierzchołków.
Algorytm Algorytm Floyda-Warshalla
ODLEGŁÓŚCI-II(W) 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ą dodanie 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ą . Funkcję 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 gafie dla funkcji wagowej .
Lemat 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 wniosek_9
Wniosek lemat_10
Dowód

Funkcję nazwiemy
potencjałem jeżeli
zachodzi:
. </math> (4)
Pokażemy teraz jak wyznaczyć funkcję potencjału dla grafu . Rozważmy następujący algorytm:
Algorytm Algorytm obliczania potencjału
OBLICZ-POTENCJAŁ(G=(V,E), w) 1 nowy wierzchołek 2 3 4 5 if BELLMAN-FORD then 6 return FALSE (graf zawiera cykl ujemnej długości) 7 return TRUE ( obliczone w algorytmie Bellmana-Forda jest potencjałem)
Lemat lemat_11
Dowód
Zakładamy teraz, że graf nie zawiera cykli 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(G=(E,V),w) 1 if OBLICZ-POTENCJAŁ then 2 return FALSE 3 for każda krawędź do 4 5 for każdy wierzchołek do 6 wywołaj DIJKSTRA do policzenia odległości dla 7 for każdy wierzchołek do 8 9 return
Poprawność tego algorytmu wynika wprost z Lematu 11. Czas działania algorytmu jest równa sumie czasu działania algorytmu Bellmana-Forda i czasowi potrzebnemu na wywołań algorytmu Dijkstry, co daje całkowity czas .