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)
Nie podano opisu zmian
Linia 8: Linia 8:
obliczania odległości między wszystkimi parami wierzchołków.
obliczania odległości między wszystkimi parami wierzchołków.
Pokażemy związki tego problemu z mnożeniem macierzy.
Pokażemy związki tego problemu z mnożeniem macierzy.
== Definicja problemu ==
W wykładzie tym zajmiemy się problemem obliczania najkrótszych
ścieżek w grafie wychodzących z jednego wierzchołka. Załóżmy, że
mamy dany graf <math>G = (V,E)</math>, funkcję <math>w: E \to
\mathcal{R}</math> przypisującą wagi krawędziom oraz jeden wybrany
wierzchołek <math>s</math>. '''Wagę''' ścieżki
<math>p=(v_0,v_1,\ldots,v_k)</math> definiujemy jako wagę tworzących
ją krawędzi:
<center><math>
w(p) = \sum_{i=0}^{k-1} w(v_{i}, v_{i+1}).
</math></center>
'''Odległość''' z wierzchołka <math>u</math> do wierzchołka
<math>v</math> definiujemy jako
<center><math>
\delta(u,v) = \begin{cases}
\min\{w(p): p \mbox{ ścieżka z } u \mbox{ do } v\}, & \mbox{jeżeli istnieje ścieżka z } u \mbox{ do } v,\\
\infty & \mbox{w przeciwnym przypadku.}
\end{cases}
</math></center>
'''Najkrótszą ścieżką''' z wierzchołka <math>u</math> do wierzchołka
<math>v</math> jest każda ścieżka <math>p</math> z <math>u</math> do
<math>v</math>, której waga <math>w(p)</math>jest równa odległości
<math>\delta(u,v)</math> z <math>u</math> do <math>v</math>.




== Algorytm Bellmana-Forda ==
== Algorytm Bellmana-Forda ==
{{kotwica|algorytm_bellmana-forda|}}


'''Algorytm Bellmana-Forda''' służy do rozwiązania problemu
'''Algorytm Bellmana-Forda''' służy do rozwiązania problemu
Linia 33: Linia 64:
algorytmie utrzymywać będziemy także dla każdego wierzchołka
algorytmie utrzymywać będziemy także dla każdego wierzchołka
<math>v</math> wskaźnik <math>\pi(v)</math> wskazujący na poprzedni
<math>v</math> wskaźnik <math>\pi(v)</math> wskazujący na poprzedni
wierzchołek przez, który prowadzi dotychczas znaleziona najkrótsza
wierzchołek przez który prowadzi dotychczas znaleziona najkrótsza
ścieżka. Na początku wielkości te inicjujemy przy pomocy
ścieżka. Na początku wielkości te inicjujemy przy pomocy
następującej procedury:
następującej procedury:




{{algorytm|Inicjalizacja algorytmu najkrótszych ścieżek|algorytm_inicjalizacjia_sssp|
{{algorytm|Inicjalizacja algorytmu najkrótszych ścieżek|algorytm_inicjalizacja_sssp|
   INICJALIZUJ<math>(G,s)</math>
   INICJALIZUJ<math>(G,s)</math>
     '''for''' każdy wierzchołek <math>v\in V</math> '''do'''
     '''for''' każdy wierzchołek <math>v\in V</math> '''do'''
Linia 75: Linia 106:
{{algorytm|Bellmana-Forda|algorytm_Bellmana-Forda|3=
{{algorytm|Bellmana-Forda|algorytm_Bellmana-Forda|3=
   BELLMAN-FORD<math>(G,w,s)</math>
   BELLMAN-FORD<math>(G,w,s)</math>
   1  INICJUJ<math>(G,s)</math>
   1  [[algorytm_inicjalizacja_sssp|INICJUJ]<math>(G,s)</math>
   2  '''for''' <math>i=1</math> '''to''' <math>|V|-1</math> '''do'''
   2  '''for''' <math>i=1</math> '''to''' <math>|V|-1</math> '''do'''
   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      RELAKSUJ<math>(u,v,w)</math>
   4      [[algorytm_relaksacja_krawędzi|RELAKSUJ]<math>(u,v,w)</math>
   5  '''for''' każda krawędź <math>(u,v) \in E</math> '''do'''
   5  '''for''' każda krawędź <math>(u,v) \in E</math> '''do'''
   6    '''if''' '<math>d(v)>d(u) + w(u,v)</math> '''then'''
   6    '''if''' '<math>d(v)>d(u) + w(u,v)</math> '''then'''
Linia 140: Linia 171:
bo założyliśmy, że najkrótsza ścieżka do <math>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>.
przechodzi przez <math>v_k</math>.
Pozostaje nam jedynie zastanowić się co się dzieje gdy wierzchołek
<math>v</math> nie jest osiągalny z <math>s</math>. Musi wtedy
zachodzić <math>d(v) = \infty</math> pod koniec działania algorytmu.
Gdyby tak nie było to oznaczało by, z właściwości procedury RELAKS,
że istnieje ścieżka od <math>s</math> do <math>v</math>. Sprzeczność.
}}
}}




{{wniosek|2||3=
{{dowod|||
Niech <math>G = (V,E)</math> będzie grafem skierowanym i
Dowód ten można przeprowadzić w podobny sposób do dowodu lematu
niech funkcja <math>w:E \to \mathcal{R}</math> zadaje wagi krawędzi.
[[#poprawnosc_1|Lematu 1]].
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>.
}}
}}


Linia 166: Linia 199:




{{dowod|||
{{dowod|||3=Załóżmy najpierw, że graf nie zawiera cykli o ujemnej
wadze, które byłyby osiągalne z <math>s</math>. Wtedy z
[[#poprawność_1|Lematu 1]] wiemy, że <math>d(v)</math> są poprawnie
policzonymi odległościami. Jeżeli odległości <math>d(v)</math>
zostały poprawnie policzone przez [[algorytm_relaksacja_krawędzi|
funkcję RELAKS]] to <math>\pi(v)</math> koduje najkrótsze ścieżki w
grafie. Wynika to z właściwości [[algorytm_relaksacja_krawędzi|
funkcji RELAKS]] relaks, która wyliczając odległość wyznaczą
jednocześnie przez jaki wierzchołek  prowadzi ta najkrótsza ścieżka.
 
Musimy teraz pokazać, że algorytm poprawnie wykrywa, czy w grafie
<math>G</math> istnieje cykl ujemnej długości osiągalny z
<math>s</math>. Jeżeli nie ma takiego cyklu to wtedy
<math>d(v)</math> są poprawnie policzone przed wykonaniem testu w
liniach 5-8 [[algorytm_Bellmana-Forda|Algorytmu Bellmana-Forda]]. W takim
razie zachodzi:
 
 
<center><math>
d(v) = \delta(s,v) \le \delta(s,u) + w(u,v) = d(u) + w(u,v).
</math></center>
 
 
Powyższa nierówność zachodzi ponieważ <math>s \rightsquigarrow u
\rightsquigarrow v</math> jest ścieżką w grafie, a więc jest nie
krótsza niż najkrótsza ścieżka <math>s \rightdquidarrow v</math>.
Widzimy więc, że w tym przypadku żaden z testów w linijce 6 algorytmu
nie będzie spełniony i algorytm zwróci TRUE.
 
Załóżmy teraz, że w grafie <math>G</math> istnieje cykl  o ujemnej
wadze osiągalny z <math>s</math>. Oznaczmy ten cykl jako <math>c
=(v_0, v_1,\ldots, v_k</math>, gdzie <math>v_0 = v_k</math>. Dla
cyklu tego mamy
 
{{wzor|wzor_cykl|(1)|
<math>
\sum_{i=0}^{k} w(v_{i},v_{i+1}) <0.
</math>
}}
 
Gdyby w tej sytuacji algorytm Bellmana-Forda zwrócił wartość TRUE to
dla każdej krawędzi <math>(v_i, v_{i+1})</math> musiałaby zachodzić
nierówność <math>d(v_{i}) + w(v_i, v_{i+1}) \ge d(v_{i+1}) </math>.
Sumując tą nierówność stronami po wszystkich <math>i = 0,\ldots,
k-1</math> otrzymujemy.
 
 
<center><math>
\sum_{i=0}^{k-1} \left[d(v_i) + w(v_i, v_{i+1})\right] \ge \sum_{i=0}^{k-1} d(v_{i+1}),
</math></center>
 
<center><math>
\sum_{i=0}^{k-1} d(v_i) + \sum_{i=0}^{k-1} w(v_i, v_{i+1}) \ge \sum_{i=1}^{k} d(v_{i}),
</math></center>
 
 
ponieważ <math>v_0 = v_k</math> to
 
 
<center><math>
\sum_{i=0}^{k-1} d(v_i) + \sum_{i=0}^{k-1} w(v_i, v_{i+1}) \ge \sum_{i=0}^{k-1} d(v_{i}).
</math></center>
 
 
Wiemy, że cykl <math>c</math> jest osiągalny a zatem dla każdego
<math>i = 0,\ldots,k</math> mamy <math>d(v)<\infty</math>. Możemy więc
skrócić <math>\sum_{i=0}^{k-1} d(v_i)</math> po obydwu stronach równania i
otrzymujemy:
 
 
<center><math>
\sum_{i=0}^{k-1} w(v_i, v_{i+1}) \ge 0,
</math></center>
 


co stoi w sprzeczności z [[#wzor_cykl|nierównością (1)]]. Jeżeli więc w grafie
istnieje cykl o ujemnej wadze osiągalny z <math>s</math>, to algorytm zwróci FALSE.
}}
}}
== Mnożenie macierzy i najkrótsze ścieżki ==

Wersja z 17:24, 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.

Definicja problemu

W wykładzie tym zajmiemy się problemem obliczania najkrótszych ścieżek w grafie wychodzących z jednego wierzchołka. Załóżmy, że mamy dany graf G=(V,E), funkcję w:E przypisującą wagi krawędziom oraz jeden wybrany wierzchołek s. Wagę ścieżki p=(v0,v1,,vk) definiujemy jako wagę tworzących ją krawędzi:


w(p)=i=0k1w(vi,vi+1).


Odległość z wierzchołka u do wierzchołka v definiujemy jako


δ(u,v)={min{w(p):p ścieżka z u do v},jeżeli istnieje ścieżka z u do v,w przeciwnym przypadku.


Najkrótszą ścieżką z wierzchołka u do wierzchołka v jest każda ścieżka p z u do v, której waga w(p)jest równa odległości δ(u,v) z u do v.


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|algorytm_Bellmana-Forda|3=

 BELLMAN-FORD(G,w,s)
 1  [[algorytm_inicjalizacja_sssp|INICJUJ](G,s)
 2  for i=1 to |V|1 do
 3    for każda krawędź (u,v)E do
 4      [[algorytm_relaksacja_krawędzi|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 1

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.

Pozostaje nam jedynie zastanowić się co się dzieje gdy wierzchołek v nie jest osiągalny z s. Musi wtedy zachodzić d(v)= pod koniec działania algorytmu. Gdyby tak nie było to oznaczało by, z właściwości procedury RELAKS,

że istnieje ścieżka od s do v. Sprzeczność.


Dowód

Dowód ten można przeprowadzić w podobny sposób do dowodu lematu Lematu 1.

Twierdzenie 3

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.


Dowód

Załóżmy najpierw, że graf nie zawiera cykli o ujemnej

wadze, które byłyby osiągalne z s. Wtedy z Lematu 1 wiemy, że d(v) są poprawnie policzonymi odległościami. Jeżeli odległości d(v) zostały poprawnie policzone przez funkcję RELAKS to π(v) koduje najkrótsze ścieżki w grafie. Wynika to z właściwości funkcji RELAKS relaks, która wyliczając odległość wyznaczą jednocześnie przez jaki wierzchołek prowadzi ta najkrótsza ścieżka.

Musimy teraz pokazać, że algorytm poprawnie wykrywa, czy w grafie G istnieje cykl ujemnej długości osiągalny z s. Jeżeli nie ma takiego cyklu to wtedy d(v) są poprawnie policzone przed wykonaniem testu w liniach 5-8 Algorytmu Bellmana-Forda. W takim razie zachodzi:


d(v)=δ(s,v)δ(s,u)+w(u,v)=d(u)+w(u,v).


Powyższa nierówność zachodzi ponieważ suv jest ścieżką w grafie, a więc jest nie krótsza niż najkrótsza ścieżka Parser nie mógł rozpoznać (nieznana funkcja „\rightdquidarrow”): {\displaystyle s \rightdquidarrow v} . Widzimy więc, że w tym przypadku żaden z testów w linijce 6 algorytmu nie będzie spełniony i algorytm zwróci TRUE.

Załóżmy teraz, że w grafie G istnieje cykl o ujemnej wadze osiągalny z s. Oznaczmy ten cykl jako c=(v0,v1,,vk, gdzie v0=vk. Dla cyklu tego mamy

i=0kw(vi,vi+1)<0.

      ((1))

Gdyby w tej sytuacji algorytm Bellmana-Forda zwrócił wartość TRUE to dla każdej krawędzi (vi,vi+1) musiałaby zachodzić nierówność d(vi)+w(vi,vi+1)d(vi+1). Sumując tą nierówność stronami po wszystkich i=0,,k1 otrzymujemy.


i=0k1[d(vi)+w(vi,vi+1)]i=0k1d(vi+1),
i=0k1d(vi)+i=0k1w(vi,vi+1)i=1kd(vi),


ponieważ v0=vk to


i=0k1d(vi)+i=0k1w(vi,vi+1)i=0k1d(vi).


Wiemy, że cykl c jest osiągalny a zatem dla każdego i=0,,k mamy d(v)<. Możemy więc skrócić i=0k1d(vi) po obydwu stronach równania i otrzymujemy:


i=0k1w(vi,vi+1)0,


co stoi w sprzeczności z nierównością (1). Jeżeli więc w grafie

istnieje cykl o ujemnej wadze osiągalny z s, to algorytm zwróci FALSE.

Mnożenie macierzy i najkrótsze ścieżki