Zaawansowane algorytmy i struktury danych/Wykład 6: Różnice pomiędzy wersjami
Linia 275: | Linia 275: | ||
{{ | {{wzor2|||3= | ||
<math>w_h(p) = \sum_{i=0}^{k-1} w_h(v_i, v_{i+1}) =</math> | <math>w_h(p) = \sum_{i=0}^{k-1} w_h(v_i, v_{i+1}) =</math> | ||
}} | }} | ||
{{ | {{wzor2|||3= | ||
<math>= \sum_{i=0}^{k-1} \left(w(v_i, v_{i+1}) + h(v_i) - h(v_{i+1}) \right) =</math> | <math>= \sum_{i=0}^{k-1} \left(w(v_i, v_{i+1}) + h(v_i) - h(v_{i+1}) \right) =</math> | ||
}} | }} | ||
{{ | {{wzor2|||3= | ||
<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|||3= | ||
<math>= w(p) + h(v_0) - h(v_k).</math | <math>= w(p) + h(v_0) - h(v_k).</math> | ||
}} | }} | ||
}} | }} | ||
Linia 341: | Linia 341: | ||
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) = \ | 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 '''if''' [[Wykład 5#algorytm_Bellmana-Forda|BELLMAN-FORD]]<math>(G',w,s) = FALSE</math> '''then''' | 5 '''if''' [[Wykład 5#algorytm_Bellmana-Forda|BELLMAN-FORD]]<math>(G',w,s) = FALSE</math> '''then''' | ||
6 '''return''' FALSE ''(graf zawiera cykl ujemnej długości)'' | 6 '''return''' FALSE ''(graf zawiera cykl ujemnej długości)'' | ||
Linia 394: | Linia 394: | ||
6 wywołaj DIJKSTRA<math>(G,w_h,u)</math> do policzenia odległości <math>\delta_h(u,v)</math> dla <math>v\in V</math> | 6 wywołaj DIJKSTRA<math>(G,w_h,u)</math> do policzenia odległości <math>\delta_h(u,v)</math> dla <math>v\in V</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> | 8 <math>d(u,v) = d_h(u,v) + h(v) - h(u)</math> | ||
9 '''return''' <math>D</math> | 9 '''return''' <math>D</math> | ||
}} | }} |
Wersja z 18:13, 22 lip 2006
Abstrakt
W wykładzie tym zajmiemy się problemem obliczanie odległości w grafie między wszystkimi parami wierzchołków w grafie ważonym skierowanym . Przedstawimy trzy algorytmu rozwiązujące ten problem:
- algorytm wykorzystujący mnożenie macierzy działający w czasie ,
- algorytm Floyda-Warshalla działający w czasie ,
- algorytm Johnsona działający w czasie .
Problem najkrótszych ścieżek między wszystkimi parami wierzchołków
Problem najkrótszych ścieżek między wszystkimi parami wierzchołków można rozwiązać, wykonując razy algorytm dla problemu najkrótszych ścieżek z jednego wierzchołka. Jeżeli w grafie wagi krawędzi są nieujemne to możemy użyć algorytmu Dijkstry. Najszybsza implementacji algorytmu Dijskstry wykorzystująca kopce Fibonacciego działa w czasie , co daje nam algorytm rozwiązujący problem policzenia odległości między wszystkimi parami wierzchołków działający w czasie .
Jednakże tego rozwiązania nie możemy użyć jeżeli w grafie wagi krawędzi mogą być ujemne. W takim przypadku możemy użyć algorytm Bellmana-Forda. Otrzymamy wtedy algorytm działający w czasie . W rozdziale tym zaprezentujemy bardziej efektywne rozwiązania dla tego problemu.
W rozdziale tym będziemy zakładać, że algorytmy na wejściu otrzymują macierz wag rozmiaru reprezentującą wagi krawędzi -wierzchołkowego grafu . Dla macierzy tej zachodzi:
W problemie najkrótszych ścieżek między wszystkimi parami wierzchołków chcemy wyznaczyć macierz rozmiaru
taką, że jest równe odległości z wierzchołka do wierzchołka . Chcemy także wyznaczyć dla każdego wierzchołka drzewo najkrótszych ścieżek ukorzenione w . Podobnie jak w
poprzednim rozdziale drzewo możemy kodować dla każdego wierzchołka przy pomocy funkcji poprzedników . Ponieważ tutaj interesuje nas wiele drzew to łatwiej będzie nam używać 'macierzy poprzedników . Macierz tą definiujemy używając funkcji w następujący sposób:
W pozostałej części tego wykładu zajmiemy się tylko wyznaczaniem macierzy odległości . Jak to zostało pokazane w Zadaniu 3 do poprzedniego wykładu znając odległości w grafie drzewo najkrótszych ścieżek można wyznaczyć w czasie , a więc drzew możemy wyliczyć w czasie . Czas ten jest mniejszy niż czas działania wszystkich prezentowanych w tym wykładzie algorytmów, więc bez straty ogólności, a zyskując na prostocie prezentacji możemy ograniczyć się tylko do wyznaczenia macierzy odległości .
Co więcej będziemy zakładać, że w grafie nie ma ujemnych cykli. Ujemne cykle można wykryć w czasie przy użyciu Algorytmu Bellmana-Forda. Zobacz Zadanie 4 do Wykładu 4.
Najkrótsze ścieżki i mnożenie macierzy
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 konsekwencję i pozwoli nam na konstrukcję algorytmu obliczania odległości w grafie między wszystkimi parami wierzchołków działającego w czasie . Niech będzie macierzą wag grafu . Rozważmy macierz zdefiniowaną jako:
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ści tego algorytmu wynika wprost z Lematu 6 ponieważ na zakończenie algorytmu i .
Algorytm Floyda-Warshalla
W algorytmie Floyda-Warshalla wykorzystamy inną cechę najkrótszych ścieżek niż ta użyta w algorytmie z wykorzystaniem iloczynu odległości. W poprzednim algorytmie konstruowaliśmy coraz dłuższe ścieżki, natomiast tutaj będziemy konstruować ścieżki przechodzące przez coraz większy zbiór wierzchołków. Wierzchołkiem wewnetrznym ścieżki jest każdy wierzchołek na ścieżce różny od jej początku i końca .
Niech zbiorem wierzchołków grafu będzie . Niech dla oznacza najmniejszą wagę ścieżki z do , spośród ścieżek których wierzchołki wewnętrzne należą do zbioru . Pokażemy następujący rekurencyjny wzór na .
Lemat 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
tylko wtedy gdy jest najkrótszą ścieżką w dla funkcji
wagowej .Dowód
Wniosku 9, który pokazuje, że odległości transformują
się tak samo jak wagi ścieżek, a wiec równość jest równoważna równości .
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
krawędzi zadanymi funkcją zawiera cykl o ujemnej wadze to Algorytm OBLICZ-POTENCJAŁ zwraca wartość FALSE. Natomiast w przeciwnym wypadku algorytm zwraca TRUE i
potencjałem dla grafu z funkcją wagową .Dowód
grafu nie wprowadza nowych cykli do grafu, a jedynie powoduje, że wszystkie wierzchołki są osiągalne z . Dlatego algorytm Bellmana-Forda uruchomiany dla i wierzchołka zwraca TRUE wtedy i tylko wtedy gdy nie zawiera cyklu o ujemnej wadze.
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 doje całkowity czas .
}}