Zaawansowane algorytmy i struktury danych/Wykład 5: Różnice pomiędzy wersjami
Linia 72: | Linia 72: | ||
Po przypomnieniu czym była relaksacja gotowi jesteśmy na zapisanie algorytm | Po przypomnieniu czym była relaksacja gotowi jesteśmy na zapisanie algorytm | ||
Bellmana-Forda, a następnie udowodnienie jego poprawności. | Bellmana-Forda, a następnie udowodnienie jego poprawności. | ||
{{algorytm|Bellmana-Forda|algorytm_Bellmana-Forda| | {{algorytm|Bellmana-Forda|algorytm_Bellmana-Forda| | ||
Linia 91: | Linia 90: | ||
Algorytm ten działa w czasie <math>O(|V||E|)</math>, co jest łatwo | Algorytm ten działa w czasie <math>O(|V||E|)</math>, co jest łatwo | ||
pokazać gdyż: | pokazać gdyż: | ||
* proces inicjacji zajmuje czas <math>O(|V|)</math>, | * proces inicjacji linia 1 zajmuje czas <math>O(|V|)</math>, | ||
* w każdym z <math>|V|</math> przebiegów głównej pętli algorytmu | * w każdym z <math>|V|</math> przebiegów głównej pętli w lini 2 algorytmu | ||
przeglądane są wszystkie krawędzie grafu, co zajmuje czas <math>O(|V||E|)</math>, | przeglądane są wszystkie krawędzie grafu w linie 3 , co zajmuje czas | ||
* końcowa pętla algorytmu działa w czasie <math>O(|E|</math>. | <math>O(|V||E|)</math>, | ||
* końcowa pętla algorytmu linie 5-7 działa w czasie <math>O(|E|</math>. | |||
Dowód poprawności algorytmu Bellmana-Forda zaczniemy od pokazania, | Dowód poprawności algorytmu Bellmana-Forda zaczniemy od pokazania, | ||
Linia 110: | Linia 110: | ||
<math>s</math> do <math>v</math>. | <math>s</math> do <math>v</math>. | ||
}} | }} | ||
{{dowod| | |||
Oznaczmy przez <math>\delta(v,u)</math> odległość z wierzchołka | |||
<math>v</math> do <math>u</math> w grafie <math>G</math>. Niech | |||
<math>v</math> będzie wierzchołkiem osiągalnym ze źródła | |||
<math>s</math> i niech <math>p = (v_0, v_1, \ldots, v_k)</math> | |||
oznacza najkrótszą ścieżkę z <math>s</math> do <math>v</math>, gdzie | |||
<math>v_0 = s</math> oraz <math>v_k = v</math>. Ścieżka ta jest | |||
ścieżką prostą, bo najkrótsze ścieżki muszą być proste, więc | |||
<math>k\le |V|-1</math>. Pokażemy teraz indukcyjnie, że poczynając | |||
od <math>i</math>-tego przebiegu zachodzi <math>d(v_i) = | |||
\delta(s,v_i)</math> dla <math>i = 0,1,\ldots, k</math>. W | |||
algorytmie wykonujemy <math>|V|-1</math> obrotów pętli oraz <math>k | |||
\le |V|-1</math>, co oznacza, że z tej tezy indukcyjnej wynika | |||
poprawność algorytmu. | |||
Zauważmy, że teza indukcyjna zachodzi po inicjacji algorytmu, gdyż | |||
<math>d(v_0) = d(s) = 0 \delta(s,s) = \delta(s,v_0).</math> Załóżmy, | |||
że teza indukcyjna zachodzi dla kroku <math>k</math>'tego. Ponieważ | |||
ścieżki <math>p = (v_0, v_1, \ldots, v_i)</math> dla <math>i \le | |||
k</math> są najkrótsze jako podścieżki ścieżki <math>p</math>, to | |||
po <math>k+1</math> wykonaniu pętli wartości <math>d(v_i)</math> dla | |||
<math>i \le k</math> się nie zmienią. Pozostaje nam więc do | |||
pokazania to, że wartość <math>d(v_{k+1})</math> będzie dobrze | |||
policzona. W <math>k+1</math> przebiegu wykonujemy między innymi | |||
relaksację krawędzi <math>(v_{k}, v_{k+1})</math>. Ponieważ | |||
<math>d(v_k)</math> jest dobrze policzone, to po tej relaksacji | |||
wyznaczona będzie także poprawnie wartość <math>d(v_{k+1})</math>, | |||
bo założyliśmy, że najkrótsza ścieżka do <math>v_{k+1}</math> | |||
przechodzi przez <math>v_k</math>. | |||
}} | |||
{{wniosek|| Niech <math>G = (V,E)</math> będzie grafem skierowanym i | |||
niech funkcja <math>w:E \to \mathcal{R}</math> zadaje wagi krawędzi. | |||
Niech <math>d(v)</math> to będą wartości wyznaczone przez algorytm | |||
Bellmana-Forda uruchomiano dla wierzchołka <math>s</math>. W | |||
<math>G</math> istnieje ścieżka z <math>s</math> do <math>v</math> | |||
wtedy i tylko wtedy gdy <math>d(v)<\infty</math>. | |||
}} | |||
{{twierdzenie||bf_poprawnosc| Niech <math>G = (V,E)</math> będzie | |||
grafem skierowanym i niech funkcja <math>w:E \to \mathcal{R}</math> | |||
zadaje wagi krawędzi. Załóżmy, że algorytm Bellmana-Forda został | |||
wykonany dla wierzchołka <math>s</math>. Jeżeli graf nie zawiera | |||
cyklu o ujemnej wadze osiągalnego ze źródła <math>s</math> to | |||
algorytm zwraca wartość TRUE, <math>d(v)</math> jest odległością z | |||
<math>s</math> do <math>v</math>, a <math>\pi(v)</math> wyznacza | |||
drzewo najkrótszych ścieżek o korzeniu w <math>s</math>. Jeżeli | |||
natomiast <math>G</math> zawiera cykl o ujemnej wadze osiągalny ze | |||
źródła to algorytm zwraca wartość FALSE. | |||
}} |
Wersja z 13:06, 20 lip 2006
Abstrakt
Pierwsza część tego wykładu poświęcona będzie problemowi obliczania najkrótszych ścieżek w grafie z jednego źródła w przypadku, w którym wagi krawędzi mogą być ujemne. Zaprezentujemy algorytm Bellmana-Forda, który rozwiązuje ten problem w czasie . W drugiej części zajmiemy się problemem obliczania odległości między wszystkimi parami wierzchołków. Pokażemy związki tego problemu z mnożeniem macierzy.
Algorytm Bellmana-Forda
Algorytm Bellmana-Forda służy do rozwiązania problemu
znalezienia najkrótszych ścieżek w grafie, w którym wagi krawędzi
mogą być ujemne. W problemie tym mamy dany graf
i funkcję wagową . Algorytm
Bellmana-Forda wylicza dla zadanego wierzchołka , czy
istnieje w grafie cykl o ujemnej wadze osiągalny z
. Jeżeli taki cykl nie istniej to algorytm oblicza
najkrótsze ścieżki z do wszystkich pozostałych
wierzchołków wraz z ich wagami.
Relaksacja
Podobnie ja to było w Algorytmie Dijkstry użyjemy metody relaksacji. Metoda ta polega na tym, że w trakcie działania algorytmu dla każdego wierzchołka utrzymujemy wartość będącą górnym ograniczeniem wagi najkrótszej ścieżki ze do . W algorytmie utrzymywać będziemy także dla każdego wierzchołka wskaźnik wskazujący na poprzedni wierzchołek przez, który prowadzi dotychczas znaleziona najkrótsza ścieżka. Na początku wielkości te inicjujemy przy pomocy następującej procedury:
Algorytm Inicjalizacja algorytmu najkrótszych ścieżek
INICJALIZUJ for każdy wierzchołek do
Ustalone przez tą procedure wartości są dobrymi ograniczeniami
górnymi na odległości.
Relaksacja krawędzi polega na sprawdzeniu, czy przechodząc krawędzią z do , nie otrzymamy krótszej ścieżki z do niż ta dotychczas znaleziona. Jeżeli tak to aktualizowane są także wartości i . W celu relaksacji krawędzi używamy procedury RELAKSUJ.
Algorytm Relaksacja krawędzi
RELAKSUJ if then
Algorytm
Po przypomnieniu czym była relaksacja gotowi jesteśmy na zapisanie algorytm Bellmana-Forda, a następnie udowodnienie jego poprawności.
Po przypomnieniu czym była relaksacja gotowi jesteśmy na zapisanie algorytm Bellmana-Forda, a następnie udowodnienie jego poprawności.
Algorytm Bellmana-Forda
BELLMAN-FORD 1 INICJUJ 2 for to do 3 for każda krawędź do 4 RELAKSUJ 5 for każda krawędź do 6 if ' then 7 return FALSE 8 return TRUE
Poniższa animacja przedstawia działanie algorytmu dla grafu o pięciu wierzchołkach.
Algorytm ten działa w czasie , co jest łatwo pokazać gdyż:
- proces inicjacji linia 1 zajmuje czas ,
- w każdym z przebiegów głównej pętli w lini 2 algorytmu
przeglądane są wszystkie krawędzie grafu w linie 3 , co zajmuje czas ,
- końcowa pętla algorytmu linie 5-7 działa w czasie .
Dowód poprawności algorytmu Bellmana-Forda zaczniemy od pokazania, że algorytm działa poprawnie przy założeniu, że w grafie nie ma cykli o ujemnych wagach.
Lemat
Niech będzie grafem skierowanym i niech funkcja zadaje wagi krawędzi. Niech będzie wierzchołkiem z którego liczymy odległości algorytmem Bellmana-Forda. Jeżeli w grafie nie ma cykli o ujemnej wadze osiągalnych z , to algorytm poprawnie oblicza odległości, tzn. na koniec działania algorytmu dla każdego wartość jest odległością w z do .
Dowód
Oznaczmy przez odległość z wierzchołka do w grafie . Niech będzie wierzchołkiem osiągalnym ze źródła i niech oznacza najkrótszą ścieżkę z do , gdzie oraz . Ścieżka ta jest ścieżką prostą, bo najkrótsze ścieżki muszą być proste, więc . Pokażemy teraz indukcyjnie, że poczynając od -tego przebiegu zachodzi dla . W algorytmie wykonujemy obrotów pętli oraz , co oznacza, że z tej tezy indukcyjnej wynika poprawność algorytmu.
Zauważmy, że teza indukcyjna zachodzi po inicjacji algorytmu, gdyż Załóżmy, że teza indukcyjna zachodzi dla kroku 'tego. Ponieważ ścieżki dla są najkrótsze jako podścieżki ścieżki , to po wykonaniu pętli wartości dla się nie zmienią. Pozostaje nam więc do pokazania to, że wartość będzie dobrze policzona. W przebiegu wykonujemy między innymi relaksację krawędzi . Ponieważ jest dobrze policzone, to po tej relaksacji wyznaczona będzie także poprawnie wartość , bo założyliśmy, że najkrótsza ścieżka do przechodzi przez .
Wniosek
Twierdzenie
grafem skierowanym i niech funkcja zadaje wagi krawędzi. Załóżmy, że algorytm Bellmana-Forda został wykonany dla wierzchołka . Jeżeli graf nie zawiera cyklu o ujemnej wadze osiągalnego ze źródła to algorytm zwraca wartość TRUE, jest odległością z do , a wyznacza drzewo najkrótszych ścieżek o korzeniu w . Jeżeli natomiast zawiera cykl o ujemnej wadze osiągalny ze źródła to algorytm zwraca wartość FALSE.