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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sank (dyskusja | edycje)
Sank (dyskusja | edycje)
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 O(|V||E|). 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 G=(V,E) i funkcję wagową w:E. Algorytm Bellmana-Forda wylicza dla zadanego wierzchołka s, czy istnieje w grafie G cykl o ujemnej wadze osiągalny z s. Jeżeli taki cykl nie istniej to algorytm oblicza najkrótsze ścieżki z s 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 vV utrzymujemy wartość d(v) będącą górnym ograniczeniem wagi najkrótszej ścieżki ze s do v. W algorytmie utrzymywać będziemy także dla każdego wierzchołka v wskaźnik π(v) 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(G,s)
   for każdy wierzchołek vV do
     d(v)=
     π(v)=NIL
   d(s)=0


Ustalone przez tą procedure wartości d(v) są dobrymi ograniczeniami górnymi na odległości.

Relaksacja krawędzi (u,v) polega na sprawdzeniu, czy przechodząc krawędzią (u,v) z u do v, nie otrzymamy krótszej ścieżki z s do vniż ta dotychczas znaleziona. Jeżeli tak to aktualizowane są także wartości d(v) i π(v). W celu relaksacji krawędzi (u,v) używamy procedury RELAKSUJ.

Algorytm Relaksacja krawędzi


 RELAKSUJ(u,v,w)
   if d(v)>d(u)+w(u,v) then
     d(v)=d(u)+w(u,v)
     π(v)=u

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(G,w,s)
 1  INICJUJ(G,s)
 2  for i=1 to |V|1 do
 3    for każda krawędź (u,v)E do
 4      RELAKSUJ(u,v,w)
 5  for każda krawędź (u,v)E do
 6    if 'd(v)>d(u)+w(u,v) 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 O(|V||E|), co jest łatwo pokazać gdyż:

  • proces inicjacji linia 1 zajmuje czas O(|V|),
  • w każdym z |V| przebiegów głównej pętli w lini 2 algorytmu

przeglądane są wszystkie krawędzie grafu w linie 3 , co zajmuje czas O(|V||E|),

  • końcowa pętla algorytmu linie 5-7 działa w czasie O(|E|.

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 G=(V,E) będzie grafem skierowanym i niech funkcja w:E zadaje wagi krawędzi. Niech s 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 s, to algorytm poprawnie oblicza odległości, tzn. na koniec działania algorytmu dla każdego vV wartość d(v) jest odległością w G z s do v.

Dowód

Oznaczmy przez δ(v,u) odległość z wierzchołka v do u w grafie G. Niech v będzie wierzchołkiem osiągalnym ze źródła s i niech p=(v0,v1,,vk) oznacza najkrótszą ścieżkę z s do v, gdzie v0=s oraz vk=v. Ścieżka ta jest ścieżką prostą, bo najkrótsze ścieżki muszą być proste, więc k|V|1. Pokażemy teraz indukcyjnie, że poczynając od i-tego przebiegu zachodzi d(vi)=δ(s,vi) dla i=0,1,,k. W algorytmie wykonujemy |V|1 obrotów pętli oraz k|V|1, co oznacza, że z tej tezy indukcyjnej wynika poprawność algorytmu.

Zauważmy, że teza indukcyjna zachodzi po inicjacji algorytmu, gdyż d(v0)=d(s)=0δ(s,s)=δ(s,v0). Załóżmy, że teza indukcyjna zachodzi dla kroku k'tego. Ponieważ ścieżki p=(v0,v1,,vi) dla ik są najkrótsze jako podścieżki ścieżki p, to po k+1 wykonaniu pętli wartości d(vi) dla ik się nie zmienią. Pozostaje nam więc do pokazania to, że wartość d(vk+1) będzie dobrze policzona. W k+1 przebiegu wykonujemy między innymi relaksację krawędzi (vk,vk+1). Ponieważ d(vk) jest dobrze policzone, to po tej relaksacji wyznaczona będzie także poprawnie wartość d(vk+1), bo założyliśmy, że najkrótsza ścieżka do vk+1 przechodzi przez vk.

{{{3}}}


Wniosek

{{{3}}}

Twierdzenie

Niech G=(V,E) będzie

grafem skierowanym i niech funkcja w:E zadaje wagi krawędzi. Załóżmy, że algorytm Bellmana-Forda został wykonany dla wierzchołka s. Jeżeli graf nie zawiera cyklu o ujemnej wadze osiągalnego ze źródła s to algorytm zwraca wartość TRUE, d(v) jest odległością z s do v, a π(v) wyznacza drzewo najkrótszych ścieżek o korzeniu w s. Jeżeli natomiast G zawiera cykl o ujemnej wadze osiągalny ze źródła to algorytm zwraca wartość FALSE.