Professional Documents
Culture Documents
WFI Algorithm
WFI Algorithm
seminarski rad
Floyd-Warshallov algoritam
1. Uvod
U ovom seminarskom radu detaljnije emo se pozabaviti Floyd-Warshallovim ili WFI algoritmom.
Kako je svrha ovog algoritama analiza grafa, najprije emo definirati osnovne pojmove iz teorije
grafova, u svrhu lakeg praenja seminarskog rada.
Graf G je ureena trojka G = (VG, EG, G) , gdje je VG konaan, neprazni skup vrhova, EG je konaan
Petljom nazivamo brid iji su krajevi u istom vrhu. Viestruki bridovi su razliiti bridovi incidentni
istom paru vrhova. Graf bez petlji i viestrukih bridova nazivamo jednostavnim grafom.
etnja u grafu G je konaan niz bridova oblika v1v2, v2v3, ..., vm-1vm u kojem su svaka dva uzastopna
brida susjedna ili identina. Staza je etnja kod koje su svi bridovi razliiti. Staza kod koje su svi
vrhovi, osim v1 i vm, meusobno razliiti naziva se ciklusom. Graf je povezan ako se svaka dva vrha
mogu povezati stazom.
Definirajmo teinsku funkciju wG : EG R koja svakom bridu e EG pridruuje jedan realan broj
wG(e) koji nazivamo teinom brida e. Ureeni par (G, wG) grafa G i teinske funkcije wG zove se
teinski graf. Za jednostavni teinski graf definiramo i kvadratnu n n teinsku matricu susjedstva,
W(G) = [wij], gdje je wij teina brida koji spaja vi i vj, ako taj brid postoji, a ukoliko ne postoji brid
izmeu vi i vj tada je wij = 0, za i = j (elementi na glavnoj dijagonali), odnosno wij = , za i j.
Usmjereni graf ili digraf D je ureena trojka D = (VD, AD, D) , gdje je VD konaan, neprazni skup
vrhova, AD je konaan skup lukova, a D : AD VD VD funkcija koja svakom luku a AD pridruuje
ureeni par vrhova iz VD, tj. D(a) = (u, v). Pri tome se vrh u naziva poetkom, a vrh v krajem luka a.
Za a kaemo da je luk od u prema v i koristimo oznaku a = uv.
Petlja je luk iji su poetak i kraj u istom vrhu. Dva luka s istim poetkom i krajem nazivaju se
viestruki lukovi. Digraf bez viestrukih lukova i petlji naziva se striktnim usmjerenim grafom.
etnja u usmjerenom grafu D je konaan niz bridova lukova oblika v1v2, v2v3, ..., vm-1vm u kojem je
kraj svakog luka (osim zadnjeg) ujedno i poetak sljedeeg. Staza u usmjerenom grafu je etnja kod
koje su svi bridovi razliiti. Staza kod koje su svi vrhovi, osim v1 i vm, meusobno razliiti naziva se
ciklusom.
1
Seminarski rad: Floyd-Warshallov algoritam
Za usmjereni graf D sa n vrhova (v1, v2, ..., vn u nekom poretku) matrica susjedstva, A(G) = [aij] je
kvadratna n n matrica, gdje je aij broj lukova u AD s poetkom u vi i krajem u vj.
Teinski usmjereni graf je ureeni par (D, w) usmjerenog grafa D i teinske funkcije wD: AD R koja
svakom luku a AD pridruuje realan broj wD(a) koji nazivamo teinom luka a. Za striktni teinski
usmjereni graf definiramo i kvadratnu n n teinsku matricu susjedstva, W(G) = [wij], gdje je wij
teina luka s poetkom u vi i krajem u vj, ako taj luk postoji, odnosno wij = 0, a ukoliko ne postoji luk
od vi do vj tada je wij = 0, za i = j (elementi na glavnoj dijagonali), odnosno wij = , za i j.
Ako pretpostavimo da striktni teinski usmjereni graf nema negativnih ciklusa, Floyd-Warshallov
algoritam pronalazi najkrae staze izmeu svakog para vrhova u samo jednom prolasku. Floyd-
Warshallov algoritam je primjer dinamikog programiranja.
Floyd-Warshallov algoritam usporeuje sve mogue staze kroz striktni teinski usmjereni graf D
izmeu svakog para vrhova.
Neka je D striktni teinski usmjereni graf i VD = {v1, v2, ..., vn} skup od n vrhova od D, u nekom
poretku. Definiramo rekurzivnu funkciju ShortestPath(i,j,k):
ShortestPath(i,j,k) =
Minimal(ShortestPath(i,j,k-1),ShortestPath(i,k,k-1)+ShortestPath(k,j,k-1));
ShortestPath(i,j,0) = ArcWeight(i,j);
za koju tvrdimo da, kao rezultat, vraa najkrau moguu stazu s poetkom u vi i krajem u vj, koristei
samo vrhove v1, ..., vk kao prolazne toke du staze.
Polazna osnova algoritma je teinska matrica susjedstva usmjerenog grafa D, tj. W(D) koja nam za sve
parove (vi, vj) daje vrijednost funkcije ArcWeight(i,j). Algoritam pronalaenja najkraih staza
izmeu svakog para vrhova odvija se u n koraka.
Dokaz korektnosti osnove Floyd-Warshallovog algoritma, tj. gore navedene rekurzivne formule
ShortestPath(i,j,k), provodimo matematikom indukcijom, po kardinalnom broju k skupa
vrhova {v1, v2, ..., vk} VD, koje koristimo kao prolazne toke du staze.
Baza indukcije: Za k = 0 skup vrhova koje koristimo kao prolazne toke du staze je prazan skup.
Dakle, najkraa staza s poetkom u vi i krajem u vj, koja ne sadri niti jedan vrh kao prolaznu toku je
ili jednaka teini luka s poetkom u vi i krajem u vj, ako taj luk postoji ili nije definirana (tj. ima
vrijednost ) ako ne postoji luk s poetkom u vi i krajem u vj. Upravo te vrijednosti nalazimo u
teinskoj matrici susjedstva W(D), tj. te vrijednosti vraa funkcija ArcWeight(i,j). Time je
dokazana baza indukcije.
2
Seminarski rad: Floyd-Warshallov
Floyd algoritam
Korak indukcije:: Dokazujemo tvrdnju za k + 1.. Traimo, dakle, najkrau moguu stazu s poetkom u vi
i krajem u vj, koristei samo vrhove iz skupa {v{ 1, v2, ..., vk, vk+1} kao prolazne toke du staze. Postoje
dva kandidata za ovu stazu: ili traena staza koristi samo vrhove iz skupa {v { 1, v2, ..., vk} i ne koristi
vk+1 kao prolaznu toku,, ili postoji kraa staza koja ide od vi do vk+1 i onda od vk+1 do vj. Znamo da je
najkraa mogua staza od vi do vj koja koristi samo vrhove v1, ..., vk definirana funkcijom
ShortestPath(i,j,k). Takoer je oito da ako postoji kraa staza od vi do vj kroz vk+1, tada je
njena duljina suma najkraih staza od vi do vk+1 (koritenjem samo vrhova iz skupa {v1, v2, ..., vk}) i
najkraa staza od vk+1 do vj (takoer koritenjem samo vrhova iz skupa {v1, v2, ..., vk}). Prema tome,
vrijedi:
ShortestPath(i,j,k+1) =
Minimal(ShortestPath(i,j,k)
(i,j,k),ShortestPath(i,k+1,k)+ShortestPath
+ShortestPath(k+1,j,k));
0 3 5
0 7 10
0 5 1
W (D) =
0 6
0 7
8 2 0
Algoritam emo realizirati koritenjem programskog jezik C++. Za podatake o striktnom teinskom
usmjerenom grafu koristit emo razred DiGraph, a za podatke dobivene Floyd-Warshallovim
Floyd
algoritmom koristit emo razred FloydWarshall. Njihove definicije imaju sljedei oblik:
3
Seminarski rad: Floyd-Warshallov algoritam
class DiGraph
{
private:
string SourceFile;
int Dimension;
int **W;
public:
void GetData();
void PrintAdjacencyMatrix();
odnosno
class FloydWarshall
{
private:
string SourceFile;
string WFIFile;
int Dimension;
int ***WFIMatrix;
InterSectionNode ***IsN;
public:
void WFI(DiGraph D);
int ArcWeight(int i, int j);
int ShortestPath(int i, int j, int k);
int Minimal(int i, int j);
void PrintWFIMatrix();
string FindPath(int i, int j);
void PrintInterSectionNodes();
~FloydWarshall();
};
Pri tome koristimo i razred InterSectionNode koji nam slui za definiranje prolaznih toaka
najkraih staza izmeu svakog para vrhova striktnog teinskog usmjerenog grafa D.
class InterSectionNode
{
private:
int NodeNumber;
InterSectionNode *Next;
Dimenzija (tj. broj vrhova) striktnog teinskog usmjerenog grafa D, na slici 1, i teinska matrica
susjedstva pohranjeni su u tekstualnoj datoteci D.gph. Ovdje je potrebno definirati i nain na koji
emo pohraniti vrijednost . Najvei cijeli broj koji C++ moe prepoznati definiran je konstantom
INT_MAX. Meutim, kako mi, u gore navedenoj rekurzivnoj formuli, zbrajamo dvije najkrae staze iz
prethodnog koraka algoritma (ShortestPath(i,k,k-1)+ShortestPath(k,j,k-1)), moramo
paziti da ni taj zbroj ne prijee INT_MAX. Zbog toga je dovoljno za vrijednost uzeti INT_MAX/2 (uz
ogranienje teine luka na 2147483647). Vrijednost INT_MAX/2 definirat emo kao konstantnu
4
Seminarski rad: Floyd-Warshallov algoritam
vrijednost INF. Zbog preglednosti datoteke D.gph, sve nepostojee bridove emo oznaiti sa 0, a
programski emo tu vrijednost interpretirati ili kao 0 (za i = j) ili kao INF (za i j).
Za striktni teinski usmjereni graf D, na slici 1, datoteka D.gph ima sljedei sadraj:
6
0 3 0 0 0 5
0 0 7 0 0 10
0 0 0 5 1 0
0 0 0 0 6 0
0 0 0 0 0 7
0 0 8 2 0 0
void DiGraph::GetData()
{
cout << "Ovaj program izracunava najkrace staze i njihove prolazne _
tocke" << endl;
cout << "izmeu svakog para vrhova tezinskog, usmjerenog grafa, _
koristeci" << endl;
cout << "Floyd-Warshallov algoritam." << endl << endl;
ifstream GraphFile;
cout << "Unesi ime datoteke sa podacima o digrafu: ";
cin >> SourceFile;
GraphFile.open(SourceFile.c_str());
GraphFile >> Dimension;
W = new int*[Dimension];
for(int i = 0; i < Dimension; i++)
W[i] = new int[Dimension];
for(int i = 0; i < Dimension; i++)
for (int j = 0; j < Dimension; j++)
GraphFile >> W[i][j];
GraphFile.close();
}
Ispis teinske matrice susjedstva objekta kojem smo pridruili podatke o grafu realiziramo metodom
PrintAdjacencyMatrix():
void DiGraph::PrintAdjacencyMatrix()
{
cout << endl << "Tezinska matrica susjedstva digrafa:" << endl;
for(int i = 0; i < Dimension; i++)
{
for(int j = 0; j < Dimension; j++)
if((W[i][j] != 0) || (i == j))
cout << W[i][j] << "\t";
else
cout << "-" << "\t";
cout << endl;
}
}
5
Seminarski rad: Floyd-Warshallov algoritam
Sada moemo pristupiti glavnom dijelu programa, tj. izvedbi Floyd-Warshallovog algoritma. Objekt
razreda FloydWarshall sadri podatkovni lan ***WFIMatrix, tj. trodimenzionalnu matricu, iji
k-ti dvodimenzionalni sloj predstavlja tablicu najkraih staza izmeu svakog para vrhova, koritenjem
samo vrhova v1, ..., vk. Ovaj postupak realiziran je metodom WFI():
void FloydWarshall::WFI(DiGraph D)
{
Dimension = D.Dimension;
SourceFile = D.SourceFile;
WFIFile = SourceFile + ".wfi";
6
Seminarski rad: Floyd-Warshallov algoritam
Krajnji rezultat koritenja metode WFI() su vrijednosti najkraih staza je izmeu svakog para vrhova
striktnog teinskog usmjerenog grafa D, smjetene u zadnjem dvodimenzionalnom sloju matrice
WFIMatrix . Ispisujemo ih koritenjem metode PrintWFIMatrix():
7
Seminarski rad: Floyd-Warshallov algoritam
void FloydWarshall::PrintWFIMatrix()
{
cout << endl << "Matrica najkracih staza digrafa:" << endl;
for(int i = 0; i < Dimension; i++)
{
for(int j = 0; j < Dimension; j++)
if((WFIMatrix[i][j][Dimension-1] != INF) || (i == j))
cout << WFIMatrix[i][j][Dimension-1] << "\t";
else
cout << "-" << "\t";
cout << endl;
}
}
Konano, najkrae staze izmeu svakog para vrhova striktnog teinskog usmjerenog grafa D,
ukljuujui i sve prolazne toke tih staza, spremamo u datoteku D.gph.wfi koju kreiramo metodom
PrintInterSectionNodes():
void FloydWarshall::PrintInterSectionNodes()
{
ofstream OutputFile;
OutputFile.open(WFIFile.c_str());
OutputFile << endl << "Shortest Paths:" << endl;
Kako smo, u ranijem postupku, pamtili samo zadnje pronaenu prolaznu toku najkrae staze s
poetkom u vi+1 i krajem u vj+1, za konstruiranje cijele najkrae staze koristimo rekurzivnu metodu
FindPath(i, j):
8
Seminarski rad: Floyd-Warshallov algoritam
if(IsN[i][TempNodeNumber] != NULL)
Path = FindPath(i, TempNodeNumber);
char *NodeString = new char[];
_itoa(TempNodeNumber + 1, NodeString, 10);
Path = Path + " -> " + NodeString;
if(IsN[TempNodeNumber][j] != NULL)
Path = Path + FindPath(TempNodeNumber, j);
return Path;
}
koja u sluaju postojanja prolazne toke vTempNodeNumber+1 najkrae staze s poetkom u vi+1 i krajem u
vj+1, najprije konstruira najkrau stazu s poetkom u vi+1 i krajem u vTempNodeNumber+1, zatim dodaje vrh
vTempNodeNumber+1 i potom konstruira najkrau stazu s poetkom u vTempNodeNumber+1 i krajem u vj+1. Time je
konstruirana cijele najkrae staza s poetkom u vi+1 i krajem u vj+1, odnosno dovrena je izvedba
opisanog Floyd-Warshallovog algoritma.
Konani rezultat cijelog postupka zapisan je, dakle u datoteci D.gph.wfi iji je sadraj:
Shortest Paths:
node 1 to node 1: same node - path length = 0
node 1 to node 2: direct arc - path length = 3
node 1 to node 3: 1 -> 2 -> 3 - path length = 10
node 1 to node 4: 1 -> 6 -> 4 - path length = 7
node 1 to node 5: 1 -> 2 -> 3 -> 5 - path length = 11
node 1 to node 6: direct arc - path length = 5
node 2 to node 1: no path
node 2 to node 2: same node - path length = 0
node 2 to node 3: direct arc - path length = 7
node 2 to node 4: 2 -> 3 -> 4 - path length = 12
node 2 to node 5: 2 -> 3 -> 5 - path length = 8
node 2 to node 6: direct arc - path length = 10
node 3 to node 1: no path
node 3 to node 2: no path
node 3 to node 3: same node - path length = 0
node 3 to node 4: direct arc - path length = 5
node 3 to node 5: direct arc - path length = 1
node 3 to node 6: 3 -> 5 -> 6 - path length = 8
node 4 to node 1: no path
node 4 to node 2: no path
node 4 to node 3: 4 -> 5 -> 6 -> 3 - path length = 21
node 4 to node 4: same node - path length = 0
node 4 to node 5: direct arc - path length = 6
node 4 to node 6: 4 -> 5 -> 6 - path length = 13
node 5 to node 1: no path
node 5 to node 2: no path
node 5 to node 3: 5 -> 6 -> 3 - path length = 15
node 5 to node 4: 5 -> 6 -> 4 - path length = 9
node 5 to node 5: same node - path length = 0
node 5 to node 6: direct arc - path length = 7
node 6 to node 1: no path
node 6 to node 2: no path
node 6 to node 3: direct arc - path length = 8
node 6 to node 4: direct arc - path length = 2
node 6 to node 5: 6 -> 4 -> 5 - path length = 8
node 6 to node 6: same node - path length = 0
9
Seminarski rad: Floyd-Warshallov algoritam
Iako zadatak pronalanja najkraeih staza izmeu svakog para vrhova izgleda sloen, metoda koju je
osmislio S. Warshall, a implementirali T. Floyd i P.Z. Ingerman radi to na iznenaujue jednostavan
nain, za poznatu teinsku matricu susjedstva usmjerenog grafa. Graf moe sadravati i negativne
vrijednosti lukova.
Jednostavnost algoritma se ogleda i u lakoi izraunavanavanja njegove sloenosti. Ako je broj vrhova
u D jednak n, tada je, uz inicijalizaciju poetnog stanja koja se odvija u vremenu (n2), vrijeme
izvedbe Floyd-Warshallovog algoritma odreeno sa trostruko ugnjedenim for petljama koje se
ponavljaju po n puta, tj. algoritam se izvodi u vremenu (n3). Ovo je dobra uinkovitost za gust, skoro
potpun graf, ali u rijetkim grafovima nema potrebe za provjerom svih moguih veza izmeu vrhova.
Za rijetke grafove, moe biti korisnije upotrijebiti metodu pronalaenja najkraih staza od jednog vrha
do svih ostalih i to ponoviti za svaki vrh posebno (npr. Dijkstrin ili Bellman-Fordov algoritam).
ShortestPath(i,j) =
Minimal(ShortestPath(i,j), ShortestPath(i,k) + ShortestPath(k,j));
koja tada zahtjeva samo (n2) memorijskog prostora, uz gubitak prolaznih stanja algoritma.
Osim pronalaenja najkraih staza izmeu svakog para vorova u teinskom grafu ili usmjerenom
grafu (Floydov algoritam) ovaj algoritam, uz odreene izmjene, moe se koristiti i za:
otkrivanje ciklusa u teinskom grafu ili usmjerenom grafu: Dijagonala matrice inicijalizira se na
umjesto na 0. Ako se neka od vrijednosti elemenata na dijagonali promjeni tada graf sadri ciklus.
10
Seminarski rad: Floyd-Warshallov algoritam
6. Literatura
[1] Drozdek A.: Data Structures and Algorithms in C++, 2nd Edition, Brooks/Cole, 2001.
[2] Cormen T.H., Leiserson C.E., Rivest R.L., Stein C.: Introduction to Algorithms, 2nd Edition, The MIT
Press, 2001.
[4] Bijedi N., uretanovi Lj.: Strukture podataka i algoritmi, Univerzitetska knjiga Mostar, 2002.
[5] Wilson R.J.: Introduction to Graph Teory, $th Edition, Longman Group Ltd., 1996.
[9] Preiss B.R.: Data Structures and Algorithms with Object-Oriented Design Patterns in Java,
http://www.brpreiss.com/books/opus5/html/
11