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 126: Linia 126:
}}
}}


{{dowod|||3=
{{dowod|||3=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.
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ż
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>.
<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>.


Pozostaje nam jedynie zastanowić się co się dzieje gdy wierzchołek
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 [[#algorytm_relaksacja_krawędzi|RELAKSUJ]], że istnieje ścieżka od <math>s</math> do <math>v</math>. Sprzeczność.
<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ść.
}}
}}




{{dowod|||
{{dowod|||
Dowód ten można przeprowadzić w podobny sposób do dowodu lematu
Dowód ten można przeprowadzić w podobny sposób do dowodu lematu [[#poprawnosc_1|Lematu 1]].
[[#poprawnosc_1|Lematu 1]].
}}
}}


{{twierdzenie|3|bf_poprawnosc|3=
{{twierdzenie|3|bf_poprawnosc|3=
Niech <math>G = (V,E)</math> będzie
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.
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.
}}
}}




{{dowod|||3=Załóżmy najpierw, że graf nie zawiera cykli o ujemnej
{{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ę RELAKSUJ]] to <math>\pi(v)</math> koduje najkrótsze ścieżki w grafie. Wynika to z właściwości [[algorytm_relaksacja_krawędzi|funkcji RELAKSUJ]] relaks, która wyliczając odległość wyznaczą jednocześnie przez jaki wierzchołek  prowadzi ta najkrótsza ścieżka.
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
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:
<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:




Linia 206: Linia 153:




Powyższa nierówność zachodzi ponieważ <math>s \rightsquigarrow u
Powyższa nierówność zachodzi ponieważ <math>s \rightsquidarrow u \rightsquidarrow 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.
\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
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:
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)|
{{wzor|wzor_cykl|(1)|
Linia 223: Linia 163:
}}
}}


Gdyby w tej sytuacji algorytm Bellmana-Forda zwrócił wartość TRUE to
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.
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.




Linia 247: Linia 183:




Wiemy, że cykl <math>c</math> jest osiągalny a zatem dla każdego
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:
<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:




Linia 258: Linia 191:




co stoi w sprzeczności z [[#wzor_cykl|nierównością (1)]]. Jeżeli więc w grafie
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.
istnieje cykl o ujemnej wadze osiągalny z <math>s</math>, to algorytm zwróci FALSE.
}}
}}


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

Wersja z 17:35, 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 Inicjacja algorytmu najkrótszych ścieżek


 INICJACJA(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.

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 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 RELAKSUJ, ż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ę RELAKSUJ to π(v) koduje najkrótsze ścieżki w grafie. Wynika to z właściwości funkcji RELAKSUJ 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ż Parser nie mógł rozpoznać (nieznana funkcja „\rightsquidarrow”): {\displaystyle s \rightsquidarrow u \rightsquidarrow v} 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