Start
Baza Wiedzy
Wersja offline serwisu przeznaczona na urządzenia z systemem Android.

Darowizny
darowiznaWspomóż rozwój serwisu


Nagłówki RSS
Kanał artykuły
Kanał implementacje
Kanał komentarze
Kanał forum


Bookmarki









Sonda
Implementacji w jakim języku programowania poszukujesz?
 
Algorytm Forda-Bellmana
Ocena użytkowników:+++-- / 27
SłabyŚwietny 
Wpisany przez Michał Knasiecki
wtorek, 09 sierpnia 2005 21:23
Algorytm ten służy do wyznaczania najmniejszej odległości od ustalonego wierzchołka s do wszystkich pozostałych w skierowanym grafie bez cykli o ujemnej długości.
Warunek nieujemności cyklu jest spowodowany faktem, że w grafie o ujemnych cyklach najmniejsza odległość między niektórymi wierzchołkami jest nieokreślona, ponieważ zależy od liczby przejść w cyklu.
Dla podanego grafu macierz A dla każdej pary wierzchołków u i v zawiera wagę krawędzi (u,v), przy czym jeśli krawędź (u,v) nie istnieje, to przyjmujemy, że jej waga wynosi nieskończoność i wpisujemy *.
Algorytm Forda-Bellmana w każdym kroku oblicza górne oszacowanie D(vi) odległości od wierzchołka s do wszystkich pozostałych wierzchołków vi. W pierwszym kroku przyjmujemy D(vi)=A(s,vi).
Gdy stwierdzimy, że D(v)>D(u)+A(u,v), to każdorazowo polepszamy aktualne oszacowanie i podstawiamy D(v):=D(u)+A(u,v). Algorytm kończy się, gdy żadnego oszacowania nie można już poprawić, macierz D(vi) zawiera najkrótsze odległości od wierzchołka s do wszystkich pozostałych.

Pseudokod wygląda następująco:(n- liczba wierzchołków)

begin;
for v:=[1..n] do D(v):=A(s,v); //przyjmujemy, że najkrótszą drogą z u do v jest krawędź (u,v)
for k:=1 to (n-2) do //w (n-2) krokach można zbadać każdą drogę o (n-1) krawędziach i wybrać najkrótszą
begin
for v:=[1..n]-{s} do //odległość od s do s wynosi 0 i już się na pewno nie zmieni
for u:=[1..n] do
D(v):=min{D(v), D(u)+A(u,v)}; //wybierz krótszą drogę
end;

Algorytm można ulepszyć sprawdzając w każdej iteracji, czy coś się zmieniło od poprzedniej i jeśli nie, to można zakończyć obliczenia.
Dla pełnej jasności podam teraz prosty przykład: oto graf i jego reprezentacja w postaci macierzy wag krawędzi.
Przyjmujemy s=1, symbol "*" oznacza nieskończoność:

ImageImage
Oto przebieg obliczeń:
kD(1)D(2)D(3)D(4)D(5)D(6)
0024***
10242a6b4c
202425d4
3024254
Objaśnienia:
W pierwszym kroku (k=0) D(vi)=A(1,vi). Przepisujemy pierwszy wiersz macierzy wag krawędzi.
a). Pierwsze skrócenie drogi: w poprzednim kroku D(4)=*, gdyż nie istnieje krawędź od 1 do 4. Teraz jednak możemy przejść przez wierzchołek 3 (odległość od 1 do 3 wynosi 4) a następnie do 4 (waga krawędzi [3,4]=-2), długość drogi od 1 do 4 wynosi więc 4-2 = 2.
b). Podobnie jest tu, do wierzchołka 5 możemy dojść przez 2, 3, lub 6. Wybieramy oczywiście drogę o mniejszej długości:
  • D(2)+A(2,5)=2+4=6 (ta wartość jest najmniejsza)
  • D(3)+A(3,5)=4+3=7
  • D(6)+A(6,5)=*+1 (ta wartość jest największa)
Wybieramy opcję z wierzchołkiem nr. 2.
c). Do wierzchołka 6 możemy dojść przez 4 (do którego dochodzimy przez 3) droga jest więc następująca: 1, 3, 4, 6 a jej długość wynosi D(4)+A(4,6)=2+2=4
d). Jak wynika z punktu b), do wierzchołka 5 możemy dojść także poprzez wierzchołek 6. W poprzednim kroku poznaliśmy odległość do wierzchołka 6 i nie wynosi ona już nieskończoność. Sprawdźmy więc, jaka byłaby długość drogi do wierzchołka 5 poprzez 6: D(6)+A(6,5) = 4+1 = 5. Jest to wartość mniejsza niż aktualna (6), więc znaleźliśmy krótszą drogę.
W kroku k=3 nic się nie zmieniło od kroku k=2. Kończymy obliczenia i mamy wektor najkrótszych dróg od wierzchołka s=1 do wszystkich pozostałych.
Złożoność obliczeniowa: O(n3).
Uwaga:
Dla grafów z wagami o nieujemnych wartościach lepiej jest stosować Algorytm Dijkstry.
Po znalezieniu najkrótszej odległości między wierzchołkami możemy znaleźć drogę łączącą te wierzchołki za pomocą algorytmu konstrukcji drogi.



Autor Język programowania Komentarz Otwórz Pobierz Ocena
Michał Knasiecki C/C++
Implementacja w C/C++
Implementacja w C/C++
+++-- / 14
Michał Knasiecki Delphi/Pascal Borland Delphi 5
Implementacja w Delphi/Pascal
Implementacja w Delphi/Pascal
++--- / 3
Tomasz Lubiński Java
Implementacja w Java
Implementacja w Java
++--- / 13
 
Dodaj własną implementację tego algorytmu
  • Zaloguj się na stronie
Plik:
Język programowania:
Komentarz:
  By móc dodać implementacje zaloguj się na stronie



Poprawiony: środa, 16 listopada 2011 20:40

Komentarze

 
photo
0 # emil3566 2012-03-01 21:34
Nie zgodzę się z tą złożonością obliczeniową ! Czyli jaką według Ciebie ma złożoność Floyd ? n^4 ? To właśnie Floyd ma złożoność n^3.

Algorytm Forda-Bermama wykonuje się w czasie O(m(n-1)). Można zapytać , czemu ? Nie bede przytaczac dowodu ,jednak jest właściwośc iż przy każdorazowym sprawdzaniu wieszchołkow i ich krawedzi oraz wartości nie wykonamy tej czynności wiecej niz n-1 razy , wiec wykonujemy (n-1) po m razy, m- ponieważ za każdym razem przeszukujemy wszystkie krawędzie. Ni jak nie wiedzę tu sześcianu !!! Proszę o wyjaśnienie lub konfrontacje zdań :)
Odpowiedz | Odpowiedz z cytatem | Cytować
 
 
photo
0 # Tomasz Lubiński 2012-03-05 10:01
Myślę, że autor po prostu uogólnił liczbę krawędzi, których w grafie może być n*n, czyli m=n*n, co daje n*n*(n-1) co równe jest O(n^3).
Odpowiedz | Odpowiedz z cytatem | Cytować
 
 
photo
0 # emil3566 2012-03-05 16:57
Przydałoby się wyjaśnienie , ponieważ graf nieskierowany może już miec tylko n(n-1)/2 krawedzi n^3 zachodzi tylko w grafie skierowanym zakładając pesymistycznie ze wszystkie krawędzi są użyte
Odpowiedz | Odpowiedz z cytatem | Cytować
 
 
photo
0 # emil3566 2012-03-01 21:45
W ciągu najbliższych dni postaram się zrobić własny artykuł o Bermanie ponieważ uważam iż nie masz racji i wiele kwestii jest przedstawiony w bardzo nieprzystępny sposób a inne są gorszymi rozwiązanami z tych możliwych
Odpowiedz | Odpowiedz z cytatem | Cytować
 

Dodaj komentarz

Kod antysapmowy
Odśwież