Sunteți pe pagina 1din 8

Algoritmul lui Dijkstra

Este un algoritm utilizat pentru determinarea drumurilor de cost minim de la o surs unic. Este un
algoritm de tip Greedy, pentru determinarea drumului minim de la un nod surs la toate celelalte noduri ale
grafului.
Pentru a reprezenta reeaua, presupunem o funcie valoare astfel nct valoare(i, j) este valoarea arcului de
la nodul i la nodul j. Dac nu exist un arc de la nodul i la nodul j atunci valoare(i, j) este setat la o valoare
arbitrar mare, care indic costul infinit (imposibilitatea) de a merge direct de la nodul i la nodul j.
Dac toate valorile sunt pozitive, urmtorul algoritm atribuit lui Dijkstra, determin cel mai scurt drum de
la nodul s la nodul t al grafului. Un astfel de drum se numete drum special. Pentru a reine costurile drumurilor
speciale vom utiliza un tablou numit distan cu proprietatea c distani conine costul celui mai scurt drum
de la nodul s la nodul i.
Iniial distans = 0 i distani = INFINIT pentru orice nod i diferit de nodul s, unde INFINIT este un
numr foarte mare.

2
1

1
3

3
1

4
6
Figura
Figura2.1.4
3.3.1

Evident, cel mai scurt drum de la nodul s la un nod oarecare al grafului este dat de arcul (s, j) de valoare minim.
Alegem n continuare un drum n ordinea cresctoare a costurilor pn cnd am determinat drumuri de distan
minim de la nodul s la oricare dintre nodurile grafului pentru care exist un drum ncepnd din nodul s.
Reamintesc, matricea costurilor se definete astfel:
mcij=

costul arcului, dac arcul (i,j) exist


0, dac i=j

, dac arcul (i,j) nu exist i este o problem de minim /


(-, dac este o problem de maxim)
Pentru arcele inexistente se reine valoarea

pentru algoritmii de minim respectiv

pentru algoritmii

de maxim. n practic, aceste valori sunt nite valori foarte mari pe care n mod normal nu pot lua valorile
arcelor.
Exemplu: pentru graful din figura 2.1.4 iniial, matricea costurilor este:
0

1
0

3
1

1
0

Datele se citesc, de obicei din fiier. Pentru exemplul de mai sus, fiierul de intrare ar putea fi urmtorul (pe
prima linie este scris numrul de noduri i pe urmtoarele linii sunt scrise cte trei numere reprezentnd capetele
arcelor i costul arcului). Ordinea n care sunt scrise arcele nu este unic.
graf.txt
6
121
237
251
153
532
341
644
611

Implementarea algoritmului Dijkstra folosind reprezentarea cu matrice de costuri:


La citirea datelor din fiier se completeaz matricea costurilor cu valoarea citit, dac exist arcul sau cu o
valoare foarte mare, echivalentul

, dac arcul nu exist.

Se vor folosi trei vectori:


-un vector viz, care iniial are, pentru toate componentele valoarea 0; la alegerea unui nod acesta va deveni
vizitat, valoarea corespunztoare nodului n vectorul viz va deveni 1.
-un vector dr care reine pentru fiecare nod, nodul precedent al su, n drumul de cost minim; dac nu exist un
predecesor al nodului curent, in vectorul dr se reine valoarea -1.
-un vector lung, care reine lungimea drumului minim de la nodul de plecare la toate celelalte noduri ale grafului.
Iniial, vectorul lung primete valorile din matricea de costuri, aceast valoare urmnd a fi mbuntit.
Algoritmul lui Dijkstra:

Pas1. Se creaz matricea costurilor, se citete nodul de plecare i se iniializeaz vectorii viz, dr i lung. Se
viziteaz nodul de plecare, nodul precedent lui se reine a fi nodul 0, n sensul c nu exist un asemenea nod.
Pas 2. Pentru celelalte n-1 noduri ale grafului se determin nodul pentru care costul de la nodul curent este
minim i se reine nodul (k) pentru care se realizeaz valoarea minim. Dac costul drumului la nodul k nu este
infinit, se va vizita nodul k. Se actualizeaz drumurile spre toate nodurile folosind minimul determinat spre
nodul k. Dac exist un nod j cu proprietatea c lung[j]>lung[k]+mc[k][j], atunci nseamn c precedentul lui j
este k dr[j]=k i lung[j]=lung[k]+mc[k][j].
Pas 3. Afiarea drumurilor anterior determinate. Dac lung[i]=max, nseamn c nu exist drum, altfel se
afieaz drumul determinat de la nodul iniial la fiecare din nodurile 1, 2, ..., n.
Observaie: determinarea drumului se realizeaz printr-o funcie recursiv drum care parcurge vectorul dr pn la
ntlnirea valorii 0 din acest vector, valoare care se intlnete pentru nodul iniial.
Exemplu: s considerm graful din figura 2.1.4 i pentru acesta s considerm nodul 1 ca fiind

nodul de plecare. Iniial vectorii dr, lung i viz sunt:

viz

1
1

2
0

3
0

4
0

5
0

6
0

lung

1
0

2
1

3
-1

4
-1

5
3

6
-1

dr

1
0

2
0

3
0

4
0

5
0

6
0

Modificarea vectorilor dr, lung i viz va fi prezentat n tabelul urmtor.


Lungimea minim

Nodul selectat

Evoluia vectorilor viz, dr i lung


viz

1
1

2
1

3
0

4
0

5
0

6
0

lung

1
0

2
1

3
8

4
-1

5
2

6
-1

dr

1
0

2
1

3
2

4
0

5
2

6
0

viz

1
1

2
1

3
0

4
0

5
1

6
0

lung

1
0

2
1

3
4

4
-1

5
2

6
-1

dr

1
0

2
1

3
5

4
0

5
2

6
0

viz

1
1

2
1

3
1

4
0

5
1

6
0

lung

1
0

2
1

3
4

4
5

5
2

6
-1

dr

1
0

2
1

3
5

4
3

5
2

6
0

6, dar nu se poate
forma drum spre
6

viz

1
1

2
1

3
1

4
1

5
1

6
0

lung

1
0

2
1

3
4

4
5

5
2

6
0

dr

1
0

2
1

3
5

4
3

5
2

6
-1

viz

1
1

2
1

3
1

4
1

5
1

6
1

lung

1
0

2
1

3
4

4
5

5
2

6
0

dr

1
0

2
1

3
4

4
5

5
2

6
-1

Programul care realizeaz


#include<fstream.h>
#define max 32000
int mc[20][20],n,viz[20],dr[20],lung[20];
void citire()
{ int i,j,x,y,c;
ifstream f("graf.txt");
f>>n;
for (i=1;i<=n;i++)
for (j=1; j<=n;j++)
if (i!=j) mc[i][j]=max;
else mc[i][j]=0;
while (f>>x>>y>>c)
mc[x][y]=c;
f.close();
}
void drum(int i) //realizeaz afisarea drumului determinat
{ if (i)
{ drum(dr[i]);
cout<<i<<" ";
}
}
void Dijkstra()
{ int x,i,k; //initializare
cout<<"nodul de plecare x=";cin>>x;
for (int i=1;i<=n;i++)
{ viz[i]=0;
lung[i]=mc[x][i];
if (lung[i]<max) dr[i]=x;
else dr[i]=-1;
}
viz[x]=1;
dr[x]=0;
//determin vectorii vizitat, lung, dr
for (int l=1;l<=n-1;l++) //trebuie sa determine n-1 minime
{
int min=max;
for (i=1;i<=n;i++)
if (viz[i]==0 && lung[i]<min)
{ min=lung[i];
k=i; //in k retin nodul spre care costul este minim

}
if (lung[k]<max)
{ viz[k]=1;
for (int j=1;j<=n;j++)
if (viz[j]==0 && lung[j]>lung[k]+mc[k][j])
{ lung[j]=lung[k]+mc[k][j];
dr[j]=k;
//precedentul lui j este k
}
}
}
//afisare drumuri
for (i=1;i<=n;i++)
if (i==x) cout<<"nu exista drum de la "<<x<<" la "<<i<<endl;
else if (lung[i]==max) cout<<"nu exista drum de la "<<x<<" la "<<i<<endl;
else
{ cout<<"drumul minim de la "<<x<<" la "<<i<<" este:";
drum(i);
cout<<" cu lungimea "<<lung[i]<<endl;
}
}
void main()
{

citire();
Dijkstra();

Algoritmul Roy-Floyd
Este utilizat pentru a determina drumurile minime pentru toate perechile de vrfuri. Vom considera, pe
rnd, fiecare nod ca fiind surs i vom determin astfel drumurile de la fiecare astfel de surs la toate celelalte
noduri. n final se vor obine drumurile minime ntre toate perechile de vrfuri.
Algoritmul lui Roy-Floyd:
Fie graful G=(X,U), reprezentat prin matricea costurilor.
Pas 1. iniial n matricea ponderilor se reine numai lungimea drumurilor directe ntre dou noduri, adic nu este
permis ca un drum ntre dou noduri s treac printr-un alt nod.
Pas 2. la nceput ncercm s obinem drumuri mai scurte, ntre oricare dou noduri i, j din X permind ca
acestea s poat trece prin nodul 1. Aceasta nseamn c pentru i, j X , se va face comparaia mc[i]
[j]>mc[i][1]+mc[1][j], adic se compar dac lungimea drumului direct (care nu trece prin alte noduri) este mai
mare dect cea a drumului care trece prin nodul 1. n caz afirmativ, se face atribuirea mc[i][j]=mc[i][1]+mc[1][j].
Dup acest pas, matricea va reine lungimea optim a drumurilor ntre oricare dou noduri, drumuri care pot
trece prin nodul 1.
Pas 3. necrcm s obinem drumuri mai scurte, ntre oricare dou noduri i,j din X permind ca acestea s poat
trece i prin nodul intermediar 2. Aceasta nseamn c pentru i, j X , se va face comparaia mc[i][j]>mc[i]
[2]+mc[2][j], adic se compar dac lungimea drumului care nu trece dect cel mult prin nodul 1 este mai mare
dect cea a drumului care trece prin nodul 2. In caz afirmativ se face atribuirea mc[i][j]=mc[i][1]+mc[1][j]. Dup

acest pas, matricea va reine lungimea optim a drumurilor ntre oricare dou noduri, drumuri care pot trece prin
nodurile intermediare 1 i 2.
Pas 4. Algoritmul continu n acest mod prin eventuale mbuntiri succesive ale lungimii drumurilor,
considernd ca noduri intermediare 3, 4, ..., n, unde n este numrul de noduri al grafului.
Observaii: - problema care apare este dac acest algoritm conduce sau nu la soluia optim. Observm dac
drumul optim ntre dou noduri i i j trece prin nodul k, atunci drumul de la i la k este optim i drumul de la k la j
este optim. Daca, prin absurd, ar exista un drum cu o lungime mai mic ntre i i k sau l i j atunci, n mod
evident, drumul de la i la j n-ar fi optim. De aici se trage concluzia c algoritmul caut drumul optim ntre i i j,
printre noduri k, pentru care se cunoate lungimea optim a drumurilor de la i la k i de la k la j. La pasul k se
cunoate lungimea drumului optim ntre oricare dou noduri i i j drumurile trec prin nodurile 1, 2, ..., k-1. Dup
pasul k se cunoate lungimea drumului optim ntre oricare dou noduri i i j, drumuri care trec numai prin
nodurile intermediare 1, 2, ..., k. Dup pasul n problema este rezolvat.
- la pasul k nu se optimizeaz drumurile de la i la k i de la k la j, deoarece nu se obine nici o
mbuntire din faptul c aceste drumuri pot trece prin nodul k. Din acest motiv se poate utiliza o singur
matrice, pentru care se efectueaz calculele ( mc[i][k] i mc[k][j] rmn nemodificate la acest pas).
Exemplu: pentru graful din figura 2.1.4 se pornete de la matricea costurilor:
0

1
0

3
1

1
0

Conform algoritmului de mai sus, la pasul 1 ncercm s obinem drumuri care trec prin nodul 1:
mc[6][2]=

, mc[6][1]=1, mc[1][2]=1 mc[6][2]>mc[6][1]+mc[1][2]

mc[6][2]=mc[6][1]+mc[1][2]=2
mc[6][5]=

, mc[6][1]=1, mc[1][5]=1 mc[6][5]>mc[6][1]+mc[1][5]

mc[6][5]=mc[6][1]+mc[1][5]=4
Conform algoritmului de mai sus, la pasul 2 ncercm s obinem drumuri care trec prin nodrile 1 si 2:
mc[6][3]=

, mc[6][2]=2, mc[2][3]=7 mc[6][3]>mc[6][2]+mc[2][7]

mc[6][3]=mc[6][2]+mc[2][7]=9
mc[6][5]=4, mc[6][2]=2, mc[2][5]=1 mc[6][5]>mc[6][1]+mc[1][5] =3
mc[6][5]=mc[6][1]+mc[1][5]=3, deci obinem o mbuntire a valorii mc[6][5] determinat la pasul 1
Algoritmul continu prin luarea n considerare a nodurilor 3, 4, 5, 6 ca noduri intermediare n determinarea
drumurilor minime ntre oricare dou noduri din graf. n final se obine matricea drumurilor:

1
0

4
3

5
4

2
1

1
0

2
5

3
4

0
3

Programul care realizeaz determinarea matricei drumurilor i apoi determinarea efectiv a drumurilor este
realizat mai jos.
n plus, algoritmul determin i drumul efectiv, nodurile intermediare ntre oricare dou noduri i i j ntre care se
poate construi un drum. Pentru nodurile ntre care nu se poate construi drum este afiat un mesaj corespunztor.
Determinarea drumului se realizeaz cu un algoritm de tipul Divide et impera: acesta presupune gsirea unui nod
intermediar k ntre i i j astfel nct mc[i][j]=mc[i][k]+mc[k][j]. Dac un astfel de nod este gsit, se continu
procedeul de descompunere a drumului, adic ncercm s scriem drumul dintre i i k precum i dintre k i j.
Procesul de descompunere se ncheie n momentul n care nu msi pot determina ntre dou noduri un nod
intermediar. n acest caz se va afia nodul. Acest lucru se face cel mai simplu folosind o funcie recursiv, drum,
care se apeleaz pentru fiecare pereche de noduri ntre care exist drum. Algoritmul este scris n cele ce urmeaz:
#include<fstream.h>
#define max 32000
int mc[20][20],n;
void citire()
{ int i,j,x,y,c;
f=fopen("in.txt","r");
fscanf(f,"%d",&n);
for (i=1;i<=n;i++)
for (j=1; j<=n;j++)
if (i!=j) mc[i][j]=max;
else mc[i][j]=0;
while (!feof(f))
{ fscanf(f,"%d %d %d",&x,&y,&c);
mc[x][y]=c;
}
fclose(f);
}
void afisare()
{ int i,j;
for (i=1;i<=n;i++)
{ for (j=1;j<=n;j++)
if (mc[i][j]!=max) cout<<mc[i][j]<<"
else cout<<"inf ";
cout<<endl;
}
}

";

void royfloyd()
{ int i,j,k;
for (k=1;k<=n;k++)
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (j!=k && mc[i][j]>(mc[i][k]+mc[k][j]))
mc[i][j]=mc[i][k]+mc[k][j];

}
void drum (int i, int j)
{ int sw=0;
for (int k=1;k<=n&&!sw;k++)
if(i!=k && j!=k && mc[i][j]==mc[i][k]+mc[k][j])
{ drum(i,k);
drum(k,j);
sw=1;
}
if (sw==0) cout<<j<<" ";
}
void main()
{ citire();
cout<<"matricea costurilor:\n";
afisare();
royfloyd();
cout<<"matricea drumurilor:\n";
afisare();
int x;
cout<<"nodul de pecare="; cin>>x;
for (int j=1;j<=n;j++)
if (mc[x][j]<max && x!=j)
{ cout<<"dr. min. de la "<<x<<"->"<<j<<":"<<x<<" ";
drum(x,j);
cout<<" are costul "<<mc[x][j]<<endl;
}
else cout<<"dr. min. de la "<<x<<"->"<<j<<":"<<"nu exista "<<endl;
}

Observaii: algoritmul poate fi adaptat i i pentru calculul drumurilor de lungime maxim; dar pentru a gsi
soluia corect, trebuie ca graful s nu aib circuite. Modificarea apare n testul de comparare a lungimilor
laturilor, se schimb semnul de inegalitate.