Sunteți pe pagina 1din 33

1

CUPRINS

1. Gsirea drumurilor ntr-un graf orientat


2. Drumuri optime ntr-un graf orientat
3. Algoritmul lui Dijkstra
4. Algoritmul lui Dantzig
5. Algoritmul Bellman-Ford
6. Determinarea drumurilor minime n grafuri
orientate aciclice
7. Algoritmul Floyd-Warhall pentru drumuri minime
8. Algoritmul
Floyd-Warshall
pentru
drumuri
maxime
9. Algoritmul Bellman-Kalaba
10. Drumuri minime ntr-un labirint

11. Gsirea drumurilor ntr-un graf orientat


Dac privim graful ca imagine a unui sistem, nodurile reprezentnd componentele sistemului,
atunci o interpretare imediat a unui arc (xi,xj) este c, componenta xi influeneaz direct
componenta xj. Dac nodurile au semnificaia de stri posibile ale unui sistem atunci un arc (xi,xj)
semnific faptul c sistemul poate trece direct din starea xi n starea xj. n ambele cazuri se vede c
avem de-a face doar cu informaii despre legturi directe; totui, chiar dac o component xi nu
influeneaz direct componenta xj ea o poate influena prin intermediul altor componente, existnd un
ir de componente intermediare: x1 x2 ,..., xk, fiecare influennd-o direct pe urmtoarea i xi
direct pe x1 iar xk direct pe xj. Astfel, dac dintr-o stare xi nu se poate trece direct ntr-o stare xj s-ar
putea totui n mai multe etape, prin alte stri intermediare. Deoarece gsirea acestor influene sau
treceri posibile este de obicei foarte important iar pentru un sistem cu mii sau zeci de mii de
componente acest lucru nu mai poate fi fcut "din ochi", este necesar formalizarea noiunii de
"influene" i "treceri" posibile, nu neaprat directe. Acest lucru a i fost fcut mai sus, deoarece este
evident c "xi influeneaz xj" sau "din starea xi se poate trece n starea xj" este echivalent cu
existena n graf a unui drum de la nodul xi la nodul xj.
n continuare vom da un algoritm prin care putem gsi toate drumurile dintr-un graf orientat cu
un numr finit de noduri.
Pasul 1. Se construiete matricea boolean a adiacenelor directe corespunztoare grafului, notat
cu A. n aceasta se afl, evident, toate drumurile de lungime 1.
Este interesant de vzut ce legtur exist ntre aceast matrice i drumurile de lungime 2. Fie
dou noduri xi i xj oarecare din graf. Existena unui drum de lungime 2 ntre ele presupune existena
unui nod xk, din graf, cu proprietatea c exist att arcul (xi,xk) ct i arcul (xi,xk). Pentru a vedea
dac acesta exist, lum pe rnd fiecare nod al grafului i verificm dac exist sau nu ambele arce
((xi,xk) i (xi,xk)). Aceasta este echivalent cu a verifica dac, n matricea boolean a adiacenelor directe, exist vreun indice k astfel nct elementul k al liniei i i elementul k al coloanei j s fie
ambele egale cu 1. Dac folosim operaiile algebrei booleene de adunare i nmulire:
0
1
0
1

0
0
1
0
0
0
1
1
1
1
0
1
atunci verificrile de mai sus sunt echivalente cu a verifica dac elementul de pe poziia (i,j) din A2
este egal cu 1. Valoarea 1 spune doar c exist cel puin un drum de lungime 2 de la xi la xj. Dac
dorim s vedem i cte sunt, vom folosi regulile de nmulire i adunare obinuit.
De asemenea, se poate observa c existena unui drum de lungime 3 de la xi la xj presupune
existena unui nod xk astfel nct s existe un drum de lungime 2 de la xi la xk i un arc de la xk la xj,
care este echivalent cu a verifica dac exist vreun indice k astfel nct elementul k al liniei i din
matricea A2 i elementul k al coloanei j din A sunt ambele egale cu 1 sau, mai simplu, dac
elementul (i,j) din A3 este 1.
Din cele de mai sus se observ c existena drumurilor de lungime k este dat de valorile
matricei Ak, dac s-au folosit regulile algebrei booleene i numrul lor este dat de Ak, dac s-au folosit
regulile obinuite.
Pasul 2. Vom calcula succesiv puterile lui A pn la puterea An-1
Dac ntre nodurile xi i xj exist un drum de lungime n atunci el va conine un numr de
noduri mai mare sau egal cu n+1 i, cum n graf sunt doar n vrfuri, este clar c cel puin unul, s
zicem xk, va aprea de dou ori. Vom avea n acest caz un drum de la xi pn la prima apariie a lui
xk, i un drum de la ultima apariie a lui xk la xj. Eliminnd toate nodurile dintre prima apariie a lui xk

3
i ultima apariie a sa vom obine un drum de la xi la xj, n care xk apare o singur dat. Aplicnd
acest procedeu pentru toate nodurile care apar de mai multe ori pe drum, vom obine un drum de la
xi la xj, n care fiecare nod apare o singur dat (deci un drum elementar), care are evident cel mult
n-1 arce. n concluzie, dac exist vreun drum de la xi la xj atunci exist i un drum elementar i,
deci, va exista o putere a lui A, ntre A1 i An-1, n care poziia (i,j) este diferit de 0. Pentru
deciderea existenei unui drum ntre oricare dou noduri este suficient, deci, calcularea doar a
primelor n-1 puteri ale lui A.
Se calculeaz matricea D = A + A2 + ... + An-1
Dac ne intereseaz doar existena drumurilor dintre noduri, nu i numrul lor, vom folosi
nmulirea i adunarea boolean i conform observaiei de mai sus:
1, daca exista drum de la xi la xj
0, in caz contrar

dij =

Procedeul de mai sus nu asigur dect aflarea faptului dac exist sau nu drum ntre dou
noduri, eventual ce lungime are i cte sunt de aceast lungime. Totui, n problemele practice cel
mai important este s tim care sunt efectiv aceste drumuri.
Deoarece toate drumurile pot fi descompuse n drumuri elementare i n problemele practice
n general acestea sunt cele care intereseaz, paii urmtori ai algoritmului vor fi dedicai gsirii lor.
Pentru gsirea acestora se folosete reprezentarea grafului prin matricea latin. Matricea
latin este o matrice ptratic nxn n care pe o poziie aij va fi xixj dac exist arcul (xi,xj) i 0 n
caz contrar.
Pasul 3. Construim matricea latin L asociat grafului, unde:
xixj, dac exist arcul (xi,xj)
lij =

0, n caz contrar

i matricea L(1), definit prin:


l

(1)

ij

xj, dac exist arcul (xi,xj)


=

0, n caz contrar

numit matricea latin redus.


Gsirea unui drum de lungime 2 de la xi la xj presupune gsirea unui nod cu proprietatea c
exist arcele (xi,xk) i (xk,xj) i memorarea vectorului (xi, xk, xj). Aceasta este echivalent cu
a gsi un indice k astfel nct elementul de pe poziia k a liniei i, din matricea L, s fie xi,xk i
elementul de pe poziia k al coloanei j, din matricea L(1), s fie xj. Vom nmuli deci matricea L cu
matricea L(1), folosind ns nite reguli de calcul speciale, numite nmulire i adunare latin.
Definiia 1: Se numete alfabet o mulime de semne numite simboluri sau litere {siiI} unde I
este o mulime oarecare de indici, finit sau nu.
Definiia 2: Se numete cuvnt un ir finit de simboluri notat si1si2.....sin.
Definiia 3: Se numete nmulire latin o operaie definit pe mulimea cuvintelor unui alfabet, notat
"xL", astfel:
si1si2.....sin xL sj1sj2.....sjm = si1si2.....sin sj1sj2.....sjm
(produsul a dou cuvinte se obine prin concatenarea lor)
nmulirea latin este asociativ, are ca element neutru cuvntul vid, nu e comutativ i un element

4
este inversabil doar dac este cuvntul vid.
Definiia 3: Se numete adunare latin o funcie definit pe mulimea cuvintelor unui alfabet cu
valori n mulimea parilor mulimi cuvintelor, notat +Lastfel:
si1si2.....sin +L sj1sj2.....sjm = (si1si2.....sin, sj1sj2.....sjm)
(suma a dou cuvinte este mulimea format din cele dou cuvinte)
Pasul 4. Se calculeaz succesiv matricile:
L2 = L xLL(1), L3 = L2xLL(1),

...,Lk+1 = LkxLL(1)

folosind operaiile de nmulire i adunare latin, alfabetul fiind mulimea nodurilor grafului, unde
operaia de nmulire este uor modificat, produsul dintre dou elemente ale matricilor fiind 0, dac
unul dintre ele este 0 sau au un nod comun i este produsul latin al lor, n caz contrar.
Din felul cum a fost construit, matricea Lk va conine toate drumurile elementare de lungime
k. Cum un drum elementar poate avea cel mult n noduri (cte are graful cu totul) rezult c:
primele n-1 puteri ale lui L conin toate drumurile elementare din graf;
puterile lui L mai mari sau egale cu n au toate elementele egale cu 0;
matricea Ln-1 conine toate drumurile hamiltoniene din graf (dac exist).
Observaie: Deoarece obinerea matricii D prin metoda de mai sus presupune un volum foarte mare
de calcule (de exemplu, dac graful are 100 de noduri, ridicarea unei matrici de 100100 la puterea
100) pentru obinerea acesteia se poate aplica i urmtorul algoritm:
Pas 1. Se construiete matricea de adiacen A;
Pas 2. Pentru fiecare linie i se adun boolean la aceasta toate liniile j pentru care aij=1.
Pas 3. Se reia pasul 2 pn cnd, dup o aplicare a acestuia, matricea rmne aceeai (nu
mai apare nici un 1)
Ultima matrice obinut este matricea drumurilor D numit i matricea conexiunilor totale.
Aceast metod, dei mai simpl nu spune ns i care sunt aceste drumuri, pentru gsirea lor
aplicndu-se, de exemplu, nmulirea latin.

Drumuri optime ntr-un graf orientat


n marea majoritate a problemelor care pot fi modelate prin grafuri nu ne intereseaz numai
dac exist sau nu legturi ntre componentele reprezentate prin nodurile grafului ci i intensitatea
acestora. Aceast intensitate are semnificaia unei valori numerice (pozitive sau negative) asociate
arcului corespunztor legturii a crei intensitate o msoar.
n aplicaiile economice aceast valoare poate fi:
lungimea drumului dintre dou localiti;
costul parcurgerii rutei reprezentate prin arcul corespunztor;
durata parcurgerii rutei respective;
cantitatea transportat pe ruta respectiv;
capacitatea maxim a rutei respective;
ctigul realizat prin trecerea de la o stare la alta a sistemului;
consum de energie pentru efectuarea trecerii respective;
punctaj realizat etc.

5
Una din problemele care poate aprea n aceste situaii este gsirea, pentru o anumit
pereche de noduri (sau mai multe perechi), a drumului optim ntre acestea.
Pentru formalizarea problemei vom introduce noiunea de valoare a unui drum, care este
egal cu suma valorilor arcelor care l compun. Vom nota n continuare valoarea unui arc (xi,xj) cu
c(xi,xj) sau cu cij. n aceste condiii putem enuna problema drumului optim astfel:
"Dat un graf G=(X,U) i o funcie care asociaz fiecrui arc o valoare real, s se
gseasc, pentru o pereche dat de noduri, drumul (drumurile) de valoare optim (minim
sau/i maxim) ntre cele dou noduri i valoarea acestuia (acestora)"
Deoarece este vorba de gsirea minimului unei mulimi de numere reale, prima ntrebare care
se pune este dac aceasta admite minim. Dac mulimea nodurilor grafului este infinit atunci pot
exista o infinitate de drumuri elementare distincte ntre cele dou noduri i mulimea valorilor acestora
poate avea orice form (nchis sau nu, mrginit sau nu) devenind foarte greu de caracterizat
cazurile cnd minimul dorit exist. Deoarece totui majoritatea covritoare a problemelor economice
se modeleaz prin grafuri cu numr finit de noduri, ne vom limita n continuare doar la acestea.
Un numr finit de noduri n atrage dup sine existena unui numr finit de arce (cel mult n2) i a
n -1

k!

unui numr finit de drumuri elementare ( cel mult nn! k 1 ). Deoarece oricrui drum d i
corespunde un drum elementar de (obinut prin eliminarea tuturor subcircuitelor lui d) putem calcula
valoarea oricrui drum ca sum ntre valoarea drumului elementar corespunztor i valorile unor
subcircuite ale sale, fiecare nmulit cu numrul de parcurgeri ale circuitului respectiv.
n concluzie, dac exist un circuit de valoare negativ nseamn c exist drumuri de valoare
orict de mic (cele care conin acest circuit), obinut prin parcurgerea acestuia de oricte ori dorim)
i, deci, mulimea valorilor drumurilor este nemrginit inferior, neexistnd drum de valoare minim.
Dac exist un circuit de valoare pozitiv atunci exist drumuri de valoare orict de mare i mulimea
valorilor drumurilor este nemrginit superior, neexistnd drum de valoare maxim.
Dac nu exist circuite de valoare negativ atunci valoarea oricrui drum este mai mare sau
egal cu a drumului elementar corespunztor, deci drumul de valoare minim (dac exist) va fi un
drum elementar. Cum mulimea drumurilor elementare este finit (i deci i mulimea valorilor lor) va
avea minorant i am lmurit problema compatibilitii problemei. Analog, dac nu exist circuite de
valoare pozitiv atunci valoarea oricrui drum este mai mic sau egal cu a drumului elementar
corespunztor, deci drumul de valoare maxim (dac exist) va fi un drum elementar. Cum mulimea
drumurilor elementare este finit (i deci i mulimea valorilor lor), va avea majorant.
Obs. 1. Dac n graf nu exist dect arce de valoare pozitiv atunci exist drum de valoare
minim.
Obs. 1. Dac n graf nu exist dect arce de valoare negativ atunci exist drum de valoare
maxim.
Obs. 1. Dac n graf nu exist circuite atunci exist i drum de valoare minim i drum de
valoare maxim.
Deoarece din cele de mai sus se sesizeaz importana existenei circuitelor ntr-un graf vom
da n continuare un algoritm de depistare a existenei circuitelor ntr-un graf:
Pasul 1. Se construiete mulimea A format din nodurile pentru care toate arcele incidente sunt
incidente spre interior ( noduri n care toate arcele "intr" sau, altfel spus, noduri din care nu
"pleac" nici un arc).
Pasul 2. Se gsesc toate nodurile care nu sunt din A pentru care toate arcele incidente au cealalt
extremitate n A (noduri din care se poate "ajunge" doar in A). Dac nu exist nici un astfel
de arc se trece la pasul 4.
Pasul 3. Se adaug arcele gsite la pasul 2 la mulimea A apoi se reia algoritmul de la pasul 2, pentru
noua mulime A.

6
Pasul 4. Dac A conine mulimea tuturor nodurilor atunci graful nu conine circuite. Dac au rmas
noduri n afara lui A atunci graful conine circuite.
n general, algoritmii existeni pentru determinarea drumurilor optime n grafuri se mpart n
dou mari categorii: algoritmi pentru drumuri minime n grafuri orientate, respectiv algoritmi pentru
drumuri maxime. Deasemeni, exist dou mari categorii de probleme i anume:
- determinarea drumurilor optime de surs unic (surs unic, destinaii multiple)
- determinarea drumurilor optime ntre toate perechile de vrfuri (surse multiple, destinaii
multiple)
Algoritmii prezentai n continuare sunt:

Dijkstra: determin drumurile minime cu surs unic n grafuri cu costuri nenegative


Dantzig: determin drumurile minime cu surs unic n grafuri cu costuri nenegative
Bellman-Ford: drumuri minime cu surs unic n grafuri care admit costuri negative, dar fr
circuite de cost negativ
determinarea drumurilor minime n grafuri orientate aciclice (din CLR)
Floyd-Warhall: drumuri minime ntre oricare dou noduri
Bellman-Kalaba: drumuri maxime cu surs unic i numr fixat de pai
Floyd-Warshall: drumuri maxime ntre oricare dou noduri n grafuri fr circuite

Algoritmul lui Dijkstra


Problem: Fiind dat un graf orientat G=(X,U), o funcie l:U R+ i un nod x0, s se
determine pentru toate vrfurile xi pentru care exist drum de la x0 la xi, lungimea celui mai scurt
drum i unul dintre drumurile minime de la x0 la xi.
Algoritmul utilizeaz metoda Greedy genernd drumurile minime n ordinea cresctoare a
lungimilor.
Exemplu: Pentru graful din figura alturat, considernd nodul de plecare 1, se vor obine n ordine:
D1=(1,2) de lungime 1
D2=(1,2,5) de lungime 2
D3=(1,2,5,3) de lungime 4
D4=(1,2,5,3,4) de lungime 5
De la 1 la 6 nu exist drum.

3
7

1
1
2
1

5
3
4

Se pornete din x0. Evident cel mai scurt drum de la x0 la unul din celelalte vrfuri ale grafului
este dat de arcul (x0,xj) de lungime minim. Urmtorul drum n ordinea lungimilor va fi dat fie de un
alt arc cu extremitatea iniial x0, fie de un drum (x0,xj,xp). Alegem n continuare drumuri n ordinea
cresctoare a lungimilor, pn cnd am determinat drumuri minime de la x0 ctre toate vrfurile
pentru care exist drum pornind din x0. Pentru aceasta se consider S mulimea vrfurilor xjX pentru
care am gsit drum minim de la x0 la xj. Iniial S={x0}. La fiecare pas, adgm n S acel nod xkX-S
cu proprietatea c drumul minim de la x0 la xk are cel mai mic cost dintre toate drumurile de la x0 la xp,
cu xpX-S. Pentru exemplul considerat S va avea pe rnd urmtorul coninut:
S={1}
S={1,2}
S={1,2,5}
S={1,2,5,3}
S={1,2,5,3,4}
Se observ c drumul de la x0 la xk (nodul ce urmeaz s-l adugm n S la un moment dat) trece
numai prin vrfuri din S (cu excepia lui xk). Pentru a alege nodul xkX-S ce urmeaz a fi adgat n S
vom folosi un vector D=(d1,d2,...,dn) astfel nct:
lungimea drumului minim de la x0 la xi, dac xiS
di=

lungimea drumului minim de la x0 la xi ce folosete numai vrfuri din


S, dac xiS

Iniial di=C(x0,i), ()i=1..n, adic este linia x0 din matricea costurilor. La un moment dat,
adgm n S nodul xk cu proprietatea c dk=min{dj | xjX-S}. Dup adgarea lui xk n S trebuie
actualizate valorile lui d pentru elementele care nu sunt n S, deoarece este posibil ca drumul minim
de la x0 la unul dintre aceste noduri (folosind noduri din S) s foloseasc nodul xk pe care tocmai l-am
adgat. Drumul minim de la x0 la xj ce folosete noduri din S (inclusiv xk) va fi de forma (x0,
,xk,xj). Deci pentru xjX-S, dj se modific dup adugarea lui xk la S numai dac dk+c(k,j)<dj,
caz n care dj dk+c(k,j). n final, vectorul d va conine costurile (lungimile) drumurilor minime de
la x0 la celelalte noduri; dac pentru un nod xj nu exist drum de la x0 la xj, atunci dj=.

8
Pentru a reine i drumurile minime (nu numai lungimile lor) vom considera un vector numit T
(tat) care reine indicele precedentului fiecrui nod n drumul minim de la x0 la acel nod.
Iniial:
0 dac i=x0 sau C(x0,i)=
Ti=
x0 dac C(x0,i) i ix0
La fiecare actualizare de forma djDk+c(k,j) vom avea i o actualizare a vectorului T de forma
Tjk. Algoritmul se ncheie cnd S conine toate nodurile xj pentru care exist drum de la x0 la xj,
deci fie cnd S=X (dac exist drumuri de la x0 la toate celelalte noduri), fie cnd mulimea X-S
cuprinde numai noduri pentru care nu exist drumuri pornind din x0 la ele (caz n care min{dj|
xjX-S}=). Pentru reprezentarea mulimii S se poate folosi vectorul caracteristic S cu n
componente definit astfel:
0 dac xiS
Si=
1 dac xiS

Algoritmul lui Dijkstra poate fi descris astfel:


algoritm Dijkstra(G,c,nod)
Initializeaza_Sursa_Unica(G,nod)
S
QX(G)
cat timp Q0 executa
uExtrage_Minim(Q)
SS {u}
pentru fiecare v vecin cu u executa
Relaxeaza(u,v,c)
sfarsit pentru
sfarsit cat timp
unde:
Initializeaza_Sursa_Unica(G,nod)
pentru fiecare v X(G) executa
D[v]
T[v] 0
sfarsit pentru
D[nod]0
Dup iniializare avem T[v]=0 pentru orice nod vU, D[v]=0 pentru v=nod (nodul surs) i D[v]=
pentru vU-nod.
n procesul de relaxare al unui arc (u,v) se verific dac drumul minim la v , determinat pn
n acel moment, poate fi mbuntit pe baza vrfului u, i dac da, atunci se reactualizeaz D[v] i
T[v]. Un pas de relaxare poate determina descreterea valorii estimrii drumului minim D[v] i
reactualizarea cmpului T[v] ce conine predecesorul nodului v pe drumul minim. Pseudocodul
urmtor realizeaz un pas de relaxare pe arcul (u,v).

9
Relaxeaza(u,v,c)
daca D[v]D[u]+c(u,v) atunci
D[v]D[u]+c(u,v)
T[v]u
sfarsit daca
Algoritmul Dijkstra opereaz prin meninerea unei mulimi S de noduri pentru care costurile finale
corespunztoare drumurilor minime de la sursa s au fost deja determinate, respectiv pentru toate
nodurile vS avem D[v] egal cu distana mnim. Algoritmul itereaz selectarea unui nod uX-S
pentru care estimarea drumului minim este minim, introduce u n S i relaxeaz arcele divergente
din u. n algoritmul de mai sus Q este o coad coninnd toate nodurile din X-S indexate prin valorile
D corespunztoare.
Exemplu: Considerm graful anterior i punctul x0=1. Cei trei vectori au valorile iniiale:

1)

2)

3)

4)

D=(0, 1, , , 3, )
T=(0, 1, 0, 0, 1, 0)
S=(1, 0, 0, 0, 0, 0)
determinm min(D[i]| S[i]=0)=> min=1, k=2 => S[2]1
Actualizm distanele la nodurile neselectate nc.
S[3]=0; D[3]=>D[2]+C[2,3]=1+7=8 => D[3]8, T[3]2
S[4]=0; D[4]=, D[2]+C[2,4]=1+ , nu se poate actualiza
S[5]=0; D[5]=3>D[2]+C[2,5]=1+1=2 => D[5]2, T[5]2
S[6]= ; D[6]= , D[2]+C[2,6]=1+ , nu se poate actualiza
Dup primul pas configuraia celor trei vectori este:
D=(0, 1, 8, , 2, )
T=(0, 1, 2, 0, 2, 0)
S=(1, 1, 0, 0, 0, 0)
determinm min(D[i]| S[i]=0) => min=2, k=5 => S[5]1
Actualizm distanele la nodurile neselectate nc.
S[3]=0; D[3]=8>D[5]+C[5,3]=2+2=4 => D[3]4, T[3]5
S[4]=0; D[4]=, D[5]+C[5,4]=2+, nu se poate actualiza
S[6]=0; D[6]=, D[5]+C[5,6]=2+, nu se poate actualiza
Dup al doilea pas configuraia celor trei vectori este:
D=(0, 1, 4, , 2, )
T=(0, 1, 5, 0, 2, 0)
S=(1, 1, 0, 0, 1, 0)
determinm min(D[i]| S[i]=0)=> min=4, k=3 => S[3]1
Actualizm distanele la nodurile neselectate nc.
S[4]=0; D[4]= > D[3]+C[3,4]=4+1=5 => D[4]5, T[4]3
S[6]=0; D[6]= , D[3]+C[3,6]=4+, nu se poate actualiza
Dup al treilea pas configuraia celor trei vectori este:
D=(0, 1, 4, 5, 2, )
T=(0, 1, 5, 3, 2, 0)
S=(1, 1, 1, 0, 1, 0)
determinm min(D[i]| S[i]=0)=> min=5, k=4 => S[4]1
Actualizm distanele la nodurile neselectate nc.
S[6]=0; D[6]=, D[4]+C[4,6]=5+, nu se poate actualiza
Dup al patrulea pas configuraia celor trei vectori este:
D=(0, 1, 4, 5, 2, )
T=(0, 1, 5, 3, 2, 0)

10
S=(1, 1, 1, 1, 1, 0)

5) determinm min(D[i]| S[i]=0)=> min= i algoritmul se ncheie pentru c nu exist


nici-un drum de la nodul 1 la nodul 6
Programul care implementeaz algoritmul lui Dijkstra este urmtorul:
#include<iostream.h>
#include<fstream.h>
#define N 50
#define INF 1<<15
int c[N][N],D[N];
int T[N],S[N],n,xp;
void citire()
{
ifstream f(graf.in);
int i,j,x,y,z;
f>>n>>xp;
//numarul de noduri si nodul de plecare
//initializam matricea costurilor
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) c[i][j]=INF;
for(i=1;i<=n;i++) c[i][i]=0;
while(!feof(f))
{
f>.x>>y>>z; //arcul si costul sau
c[x][y]=z;
}
f.close();
}
void minim(int& q)
{
int m,i;
m=2*INF;
for(i=1;i<=n;i++)
if(!S[i]&&D[i]<m)
{
m=D[i]; q=i;
}
}
void determinare_drumuri()
{
int i,x,j,k,ok;
//initializari
for(i=1;i<=n;i++)
{
D[i]=c[xp][i]; S[i]=0;
if(c[xp][i]<INF) T[i]=xp;
else T[i]=0;
}
S[xp]=1; T[xp]=0; ok=1; x=0;
do{ minim(k);
//determina nodul k aflat la distanta minima
x++;
if(D[k]==INF||x==n) ok=0; //nu mai pot construi drumuri minime
else
{
//actualizam vectorii S,T si D
S[k]=1;
for(j=1;j<=n;j++)
if(!S[j]&&D[j]>D[k]+c[k][j])

11
{
}

D[j]=D[k]+c[k][j]; T[j]=k;

}
}while(ok);
}
void drum(int i)
{
if(i)
{
drum(T[i]); cout<<i<< ; }
}
void afisare_drumuri()
{
int i;
for(i=1;i<=n;i++)
if(i!=xp)
if(D[i]==INF)
cout<<"\nNu exista drum de la :<<xp<<la <<i<endl;
else
{
cout<<"\nDrumul minim de la <<xp<<la <<i<<:
";
drum(i); cout<<"\n";
cout<<"\tLungimea drumului este "<<D[i]<<endl;
}
}
void main()
{
citire(); determinare_drumuri();
afisare_drumuri();}

Algoritmul lui Dantzig


Enun: Se consider un graf orientat G=(X,U) i o funcie cost:U R+.Se desemneaz un vrf de
plecare p. Pentru orice vrf i X se cere determinarea tuturor drumurilor de la p la i care au costul
minim.
Pentru rezolvarea acestei probleme sa va folosi algoritmul lui Dantzig. Acest algoritm obine un
graf parial al lui G=(X,U) n care orice drum care pleac din p este minim, n fapt, pe parcursul
algoritmului se elimin arce ale grafului G, arce care nu particip la construirea nici unui drum de cost
minim cu plecare din p.
Strategia algoritmului se bazeaz pe o parcurgere n lime a grafului G, adic selectarea
nodurilor se face n ordinea apropierii lor de nodul p de plecare. Pe baza costurilor minime
determinate succesiv, la fiecare pas al parcurgerii se identific un nou nod, cel mai apropiat nod fa
de nodul p de plecare. Notm cu k acest nod.
Urmeaz procesul de identificare a arcelor care se vor aduga grafului parial, deoarece acest
proces conduce la obinerea unor drumuri de la p la k cu costul minim determinat. Aceste arce
respect simultan condiiile:
- au extremitatea iniial ntr-un nod i deja selectat
- au extremitatea final n nodul k
- d[i]+cost[i,k]=min (unde d[i] este distana minim de la p la i i cost[i,k] este cosul
arcului de la i la k)
Algoritmul se oprete cnd fie au fost selectate toate nodurile, fie cnd nu mai exist drumuri de la p
ctre vrfurile neselectate.
Considerm ca exemplu graful urmtor:

12
2

4
2
2

2
1

2
1
3

Pasul 1: se selecteaz nodul 2, d[2]=2 i se adaug la graful parial arcul (1,2)

2
6
1

Pasul 2: se selecteaz nodul 3, d[3]=3 i se adaug la graful parial arcul (1,3)

2
6
1

2
3

Pasul 3: se selecteaz nodul 5, d[5]=3, se adaug la graful parial arcele (2,5) i (3,5)

13

2
1
6
1
2
1
3

Pasul 4: se selecteaz nodul 4, d[4]=4, se adaug la graful parial arcele (2,4) i (5,4)

4
2

2
1

1
6

2
1
3

Pasul 5: se selecteaz nodul 6, d[6]=6, se adaug la graful parial arcul (4,6)


2

4
2
2

2
1

1
6

2
1
3

Pentru exemplul considerat, costul minim de la 1 la 6 este 6 i se obine prin drumurile:

14
1 2 4 6
1 2 5 4 6
1 3 5 4 6
Programul urmtor implementeaz algoritmul lui Dantzig. Complexitatea este O(n2).
#include<iostream.h>
#include<fstream.h>
#define N 50
#define INF 1<<15
int a[N][N],b[N][N],d[N],st[N],sos,p;
int sel[N],n,min,k;
void citire()
{
ifstream f(graf.in);
int i,j,x,y,z;
f>>n; //numarul de noduri
//initializam matricea costurilor si matricea grafului partial
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) { a[i][j]=INF; b[i][j]=INF; }
for(i=1;i<=n;i++) { a[i][i]=0; b[i][i]=0; }
while(!feof(f))
{
f>>x>>y>z;//arcul si costul sau
a[x][y]=z;
}
f.close();
}
void minim()
{
int i,j;
min=INF;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(sel[i]&&!sel[j])
if(min>d[i]+a[i][j])
{
min=d[i]+a[i][j]; k=j;
}
}
void dantzig()
{
int i,j;
for(i=1;i<=n-1;i++)
{
minim();
if(min!=INF)
{
sel[k]=1; d[k]=min;
for(j=1;j<=n;j++)
if(sel[j]&&(d[j]+a[j][k]==min)) b[j][k]=a[j][k];
}
}
}
void drum(int k)
{
int i,j;
for(i=1;i<=n;i++)
if(b[st[k-1]][i]<INF && !sel[i])
{

15

if(i!=sos)
{
sel[i]=1; st[k]=i; drum(k+1); sel[i]=0;
}
else
{
for(j=1;j<k;j++) cout<<st[j];
cout<<sos<<" de cost <<d[sos]<<\n";
}

}
void main()
{
int i;
citire();
cout<<"plecare: "; cin>>p;
sel[p]=1; d[p]=0;
dantzig();
for(sos=1;sos<=n;sos++)
if(p!=sos)
{
for(i=1;i<=n;i++) sel[i]=0;
sel[p]=1; st[1]=p; drum(2);
}}

Algoritmul Bellman-Ford
Enun: Se consider un graf orientat G=(X,U) i o funcie de cost c:U R. Mulimea X conine n
vrfuri. Se desemneaz un nod p de plecare. Pentru orice nod j X se cere determinarea drumului
de cost minim de la p la j. Se vor detecta situaiile n care exist circuite de cost negativ care includ
nodul p.
Algoritmul Bellman-Ford determin drumurile de cost minim dintre un nod desemnat ca surs
(plecare) i restul nodurilor accesibile lui chiar dac exist costuri negative pe arce. Aceste rezultate
sunt furnizate numai n situaia n care nodul de plecare nu face parte dintr-un circuit de cost negativ.
Strategia algoritmului este aceea de minimizare succesiv a costului drumului minim de la p la
orice nod j din graf (d[j]) pn la obinerea costului minim.
Aceast operaie se face prin verificarea posibilitii ca fiecare arc (i,j)U s participe la
minimizarea distanei de la p la j. Operaia se face cu o trecere complet prin toate arcele grafului.

d[j]

c[i,j]

d[i]
i

16
Condiia ca distana de la p la j s poat fi minimizat prin arcul (i,j) este ca d[j]d[i]+c[i,j]
Notm cu n numrul de noduri din graf. Algoritmul efectueaz n-1 treceri complete prin
mulimea arcelor grafului (orice drum elementar poate fi format din maxim n-1 arce). n final, existena
unui circuit negativ face ca la o nou trecere prin mulimea arcelor s fie n continuare posibil
minimizarea costului unui drum. n acest caz algoritmul evideniaz prezena circuitului de cost
negativ ce cuprinde nodul surs.
Algoritmul pseudocod poate fi descris astfel:
algoritm Bellman_Ford(G,c,s)
Initializeaza_Sursa_Unica(G,s)
pentru i=1,n-1 executa
Relaxeaza(u,v,c)
sfarsit pentru
pentru fiecare arc (u,v)U(G) executa
daca D[v]D[u]+c(u,v) atunci
returneaza FALS
sfarsit daca
sfarsit pentru
returneaza ADEVARAT
Funciile Initializeaza_Sursa_Unica() i Relaxeaza() sunt cele prezentate la algoritmul
lui Dijkstra. Ca i algoritmul lui Dijkstra, algoritmul Bellman_Ford utilizeaz tehnica de
relaxare, procednd la descreterea estimrii D[v] a drumului minim de la sursa s la fiecare nod vX
pn cnd este obinut costul adevrat corespunztor unui drum minim. Algoritmul returneaz
ADEVARAT dac i numai dac graful nu conine circuite de cost negativ accesibile din sursa s.
n situaia n care graful este memorat n liste de adiacen complexitatea algoritmului este
O(n*m).
n programul urmtor, funcia minimizeaza() efectueaz o trecere complet prin toate arcele
grafului n vederea descreterii costurilor drumurilor cu plecare din nodul surs desemnat prin start.
#include<iostream.h>
#include<fstream.h>
#include<stdlib.h>
#define N 50
#define INF 32000
typedef struct nod{
int inf; //vecinul
int c;
//costul muchiei
nod *leg; //adresa urmatorului vecin
}LST;
LST *lc[N]; //listele de adiacenta (vecini)
int t[N],d[N],n,start;
void citire()
{
ifstream f(graf.in);
LST *x;
int i,j,co;
f>>n;
for(i=1;i<=n;i) //aloca adrese pentru listele de vecini
{
lc[i]=new LST; lc[i]->leg=0;
}

17
while(!feof(f))
{
f>>i>>j>>co;
x=new LST; x->inf=j; x->c=co;
x->leg=lc[i]->leg; lc[i]->leg=x;
//adaug pe j in lista vecinilor lui i
}
f.close();

}
int minimizeaza()
{
int ok=0,j;
LST *p;
for(j=1;j<=n;j)
{
p=lc[j]->leg;
while(p)
{
if(d[p->inf]>d[j]>c)
{
ok=1; d[p->inf]=d[j]>c; t[p->inf]=j;
}
p=p->leg;
}
}
return ok;
}
void bellman_ford()
{
int ok,i;
for(i=1;i<=n;i)
{
t[i]=0; d[i]=INF;
//initializari
}
d[start]=0;
for(i=1;i<=n-1;i) ok=minimizeaza();
ok=minimizeaza();
//a n-a trecere va depista circuite
negativ
if(ok)
{
cout<<"\nCircuit de cost negativ\n";
exit(0);
}
}
void drum(int x)
{
if(x)
{
drum(t[x]); cout<<x;
}
}
void main()
{
int i;
citire();

de

cost

18

cout<<"plecare: "; cin>start;


bellman_ford();
for(i=1;i<=n;i)
if(i!=start)
{
cout<<"cost <<d[i]<< prin ";
drum(i); cout<<"\n";
}

Drumuri minime n grafuri orientate aciclice


Prin relaxarea muchiilor unui graf orientat aciclic ponderat G=(X,U) cu n noduri i m arce,
putem determina drumurile minime de surs unic n timp O(n+m). Drumurile minime sunt totdeauna
bine definite ntr-un astfel de graf datorit faptului c acesta nu poate avea cicluri negativ, chiar dac
graful conine arce de cost negativ.
Algoritmul ncepe prin sortarea topologic a grafului pentru impunerea unei ordini liniare a
nodurilor. Dac exist drum de la nodul u la nodul v atunci u precede v n ordinea topologic. n
continuare, se efectueaz o singur trecere peste nodurile sortate topologic i pe msur ce fiecare
vrf este procesat, sunt relaxate toate muchiile divergente din acel vrf.
n urmtorul algoritm s este nodul surs, graful are n noduri i este reprezentat prin matricea
costurilor cnxn, d este vectorul distanelor minime determinate, T este vectorul predecesorilor.
algoritm GOA_drumuri_minim(G,c,s)
sorteaza in ordine topologica varfurile din G
Initializeaza_Sursa_Unica(G,s)
pentru fiecare nod u in ordinea data de sortarea topologica executa
pentru fiecare nod v vecin cu u executa
Relaxaza(u,v,c)
sfarsit pentru
sfarsit pentru
Sortarea topologic se realizeaz cu ajutorul parcurgerii n adncime DF. n momentul n care
explorarea unui nod i s-a ncheiat, el este introdus la nceputul unei liste. Lista este realizat n
vectorul m care va fi completat de la sfrit spre nceput, n ordinea invers a timpilor de ncheiere a
explorrii unui nod. n continuare, ordinea topologic este dat de valorile din vectorul m.
Funciile Initializeaza_Sursa_Unica() i Relaxaza(u,v,c) au aceeai semnificaie
ca la algoritmul lui Dijkstra.
Programul urmtor implementeaz algoritmul descris mai sus:
#include<iostream.h>
#include<fstream.h>
#define N 50
#define INF 32000
typedef struct nod{
int inf;
nod *leg;
}AD;
AD *L[N]; //listele vecinilor
int c[N][N],viz[N],m[N],T[N],d[N],n,k,s;
void citire()

19
{

int i,j,co; AD *x;


ifstream f(graf.in);
f>>n;
for(i=1;i<=n;i++) //initializare matrice costuri
{
for(j=1;j<=n;j++) c[i][j]=INF;
c[i][i]=0;
}
for(i=1;i<=n;i++) //initializare liste vecini
{
L[i]=new AD; L[i]->leg=0;
}
while(!feof(f))
{
f>>i>>j>>co;
c[i][j]=co; x=new AD; x->inf=j;
x->leg=L[i]->leg; L[i]->leg=x;//adaug j in lista vecinilor lui i
}
f.close();

}
void Init()
{
int i;
for(i=1;i<=n;i++)
{
viz[i]=0; m[i]=0;
}
k=n;
}
void DF(int i)
{
AD *x=L[i]->leg; //lista vecinilor lui i
viz[i]=1;
while(x)
{
if(!viz[x->inf]) DF(x->inf);
x=x->leg;
}
//i a fost complet explorat, il adaug la inceputul listei m
m[k]=i; k--; //m contine nodurile in ordine topologica
}
void Parcurge()
{
int i;
Init();
for(i=1;i<=n;i++)
if(!viz[i]) DF(i);
}
void Initializare(int s) //nodul sursa
{
int i;
for(i=1;i<=n;i++)
//pentru fiecare nod din graf
{
d[i]=INF;

20
//nu s-a determinat nici-un drum de la s la v, cost infinit
T[i]=0;
//nodul tata pe drumul minim de la s la v

}
d[s]=0; //pentru nodul sursa

void Relaxeaza(int u,int v) //relaxeaza arcul (u,v)


{
if(d[v]>d[u]+c[u][v])
{
d[v]=d[u]+c[u][v]; T[v]=u;
}
}
void GOA_drum(int s)
{
int i; AD *x;
Parcurge(); //realizeaza sortarea topologica in vectorul m
Initializare(s);
for(i=1;i<=n;i++)
//pentru fiecare nod in ordinea data de sortarea topologica
{
x=L[m[i]]->leg; //parcurg lista vecinilor lui m[i]
while(x)
{
Relaxeaza(m[i],x->inf);
x=x->leg;
}
}
}
void drum(int i)
{
if(i!=s)
{
drum(T[i]); cout<<"%d ",i);
}
else cout<<"%d ",s);
}
void main()
{
int i;
citire(); cout<<"nodul sursa: "; cin>.s;
GOA_drum(s);
for(i=1;i<=n;i++)
if(m[i]!=s)
if(d[i]<INF)
{
cout<<"de la <<s<<la <<m[i]<< cost <<d[m[i]]<< drum: ;
drum(m[i]); cout<<"\n";
}
else cout<<"nu exista drum de la <<s<< la <<m[i];
}

Algoritmul Floyd-Warshall

21
Enunt: Fiind dat un graf orientat G=(X,U) cu X={x1,x2,.,xn} i o funcie de cost l:U R+
s se determine pentru fiecare pereche de noduri xi,xj (i j) lungimea minim a drumurilor de la
xi la xj precum i aceste drumuri (n caz c exist drumuri de la xi la xj).
Algoritmul Floyd-Warhall determin lungimile minime ale drumurilor ntre oricare dou
noduri ale grafului ntr-o matrice C=(cij)nxn unde :

cij=

lungimea drumului minim de la xi la xj dac exist drum de


la xi la xj
0
dac i=j

dac nu exist drum de la xi la xj

Determinarea matricii C este asemntoare algoritmului Roy-Warshall pentru obinerea matricii


drumurilor. Se pornete de la matricea costurilor ataat grafului. Algoritmul este :
pentru k=1,n
pentru i=1,n
pentru j=1,n
cij=min(cij,cik+ckj)
sf_pentru
sf_pentru
sf_pentru
Simultan cu determinarea lungimilor minime ale drumurilor, pot fi reinute i nodurile care formeaz
drumurile. Vom folosi o matrice D=(dij)nxn ale crei elemente dij sunt mulimi de noduri. Elementul
dij va reprezenta n final mulimea nodurilor ce pot precede pe xj n drumul minim de la xi la xj.
Odat cu iniializarea matricii C cu matricea costurilor, vom iniializa i matricea D astfel:
{xi} dac cij<

i ij
dij=
dac cij= sau i=j

Pe msur ce se actualizeaz matricea C vom actualiza i matricea D dup cum urmeaz:


- dac cij<cik+ckj , atunci dij rmne neschimbat
- dac cij=cik+ckj (nseamn c am gsit noi posibiliti de construire a drumului minim de la
xi la xj folosind nodul k) se adaug la dij nodurile din dkj
- dac cij>cik+ckj se iniializeaz dij cu dkj
n final reconstituirea drumurilor minime ntre oricare dou vrfuri xi,xj se face pornind din xj astfel:
precedentul lui xj l alegem din mulimea dij avnd unul din aceste noduri fixat (s-l numim xq),
precedentul acestuia va fi orice nod din mulimea diq. Procedeul continu pn ajungem la nodul xi.
Observaie: Dac ne intereseaz doar cte un drum pentru fiecare pereche de noduri xi,xj vom
considera n locul matricii D o matrice D tot nxn astfel nct dij s rein un nod ce-l poate precede
pe xj n drumul minim de la xi la xj. n acest caz, algoritmul Floyd-Warshall este urmtorul:
pentru k=1,n
pentru i=1,n
pentru j=1,n
daca cij>cik+ckj
atunci
cij=cik+ckj
dij=k
sf_daca

22
sf_pentru
sf_pentru
sf_pentru
Complexitatea algoritmului este de ordinul O(n3). Programul urmtor implementeaz algoritmul n
varianta de mai sus.
#include<iostream.h>
#include<fstream.h>
#define N 50
#define INF 1<<15
int C[N][N]; //initial matricea costurilor,apoi a costurilor drumurilor
int D[N][N]; //pe linia d[i,j]=nodul care poate precede nodul j
// pe drumul minim de la nodul i la nodul j
int n,m;
void INITC()
//initializeaza matricea costurilor C
{
int i,j,x1,x2,cost;
ifstream f(graf.in);
f>>n>>m;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++) C[i][j]=INF;
C[i][i]=0;
}
for(i=1;i<=m;i++)
{
f>>x1>>x2>>cost;
C[x1][x2]=cost;
}
f.close();
}
void Drum(int i,int j)
//afiseaza un drum de la i la j pornind de la nodul j
{
if(j)
{
Drum(i,D[i][j]);
cout<<j<< ;
}
}
void AFISARE()
//afisarea rezultatelor
{
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(C[i][j]==INF)
cout<<"\nnu exista drum intre <<i<< si <<j<<endl;
else
if(i!=j)
{
cout<<"\ncost drum de la <<i<< la <<j<<este <<C[i][j];

23

cout<<"\tsuccesiunea de varfuri este: ";


cout<<i<< ; Drum(i,j);

}
void main()
{
int i,j,k;
INITC();
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(C[i][k]<INF&&C[k][j]<INF)
if(C[i][j]>C[i][k]+C[k][j])
{
C[i][j]=C[i][k]+C[k][j];
D[i][j]=k;
}
AFISARE();
}

Algoritmul Floyd-Warshall pentru drumuri de cost maxim


Fie G=(X,U) un graf orientat fr circuite cu X=(x1,x2,...,xn) i l:UR+ funcia de cost ataat
grafului. Ne punem problema determinrii drumurilor de lungime maxim n acest graf. Pentru
rezolvarea acestei probleme vom considera graful reprezentat prin matricea costurilor n forma b),
adic prin matricea C=(cij)nxn cu
l(xi,xj)
cij=

dac

(xi,xj)U

dac

i=j

dac

(xi,xj)U

Algoritmul Floyd-Warshall de determinare a drumurilor minime poate fi adaptat cu mici modificri


pentru determinarea drumurilor maxime ntre oricare dou noduri xi,xj (ij). Pentru a reine
nodurile prin care trec aceste drumuri maxime vom folosi matricea D=(dij)nxn n care:

dij=

{xi} dac cij>- i ij

dac cij=- sau i=j

Matricile C i D se modific conform urmtorului algoritm:


pentru k=1,n
pentru i=1, n (ki)
pentru j=1,n (kj)

24
daca cij<cik+ckj
atunci
cijcik+ckj
dijdkj
altfel
daca cij=cik+ckj
atunci dijdijdkj
sf_daca
sf_daca
sf_pentru
sf_pentru
sf_pentru
n matricea C vom avea n final lungimile drumurilor maxime ntre oricare dou noduri, iar n dij vom
avea mulimea nodurilor ce pot precede pe xj ntr-un drum maxim de la xi la xj. Programul pentru
determinarea tuturor drumurilor maxime ntre oricare dou vrfuri ale unui graf G=(X,U) este analog
celui de la problema anterioar; se folosete acelai algoritm ,adaptat noilor cerine.

Algoritmul Bellman-Kalaba
Enun: Se consider un graf orientat G=(X,U) conex, fr circuite i o funcie de cost a:U R.
Desemnndu-se un nod x, se cere determinarea drumurilor de cost maxim de la toate celelalte noduri
la el, drumuri care includ un numr impus de arce (pai).
Pe baza matricii costurilor grafului considerat, algoritmul construiete o nou matrice c n care
pe coloana j (jn) se vor afla costurile maxime ale drumurilor ce ajung n x folosind j arce. Astfel
c[i,j] reprezint costul maxim al unui drum de la i la x i trece prin j arce.
Iniial, matricea c va conine pe prima coloan costul arcelor spre nodul x, deci drumuri de
lungime 1. A doua iteraie va determina costurile maxime ale drumurilor ce ajung n x i conin dou
arce. Ele se vor memora n a doua coloan i se vor determina pe baza valorilor din coloana
anterioar.
Astfel, pentru determinarea valorii c[i,2] vom aduga pe rnd arcele ce pleac din i ctre
drumurile de lungime 1 anterior determinate. Se va identifica valoarea maxim dintre acestea:
c[i,2]=max(c[j,1]+a[i,,j]jX).

25

a[i,j]

c[i,k-1]
x

Generaliznd, pentru a determina costul maxim al drumului de la i la x folosind k arce se


calculeaz: max(c[j,k-1]+a[i,j]jX).
Numerele de pe fiecare linie a matricei c vor forma un ir monoton. Algoritmul se ncheie n
momenul n care valorile situate pe dou coloane consecutive sunt identice, deci cnd nici un drum
nu se poate maximiza. Faptul c nu exist circuite n graf ne asigur c numrul maxim de iteraii ar
putea fi egal cu n-1 (n numrul de noduri). Complexitatea algoritmului este O(n3).
Exemplu: Considerm graful din figur i determinm drumurile maxime ce ajung n nodul x=6.

4
2

2
2
1
1

6
1

5
1

Notm cu c(i) coloana i din matricea c a drumurilor maxime ce ajung n x=6 folosind i arce.
Algoritmul se ncheie la iteraia 5 deoarece c(4)=c(5).
c(1)
-1
-1
-1

c(2)
-1
8
8

c(3)
10
12
8

c(4)
14
12
8

c(5)
14
12
8

26
2
7
0

2
7
0

2
7
0

2
7
0

2
7
0

#include<iostream.h>
#include<fstream.h>
#define N 50
int a[N][N],c[N][N];
int pasi,p1,n,x;
unsigned char t[N][N];
void citire()
{
ifstream f(graf.in);
int i,j,x,y,z;
cin>>n; //numarul de noduri
//initializam matricea costurilor si matricea grafului partial
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) a[i][j]=-1; //pentru arcele lipsa
for(i=1;i<=n;i++) a[i][i]=0;
while(!feof(f))
{
f>>x>>y>z;//arcul si costul sau
a[x][y]=z;
}
f.close();
}
void initializari()
{
int i,j;
for(i=0;i<=n;i++)
for(j=0;j<=n;j++) { c[i][j]=-1; t[i][j]=0; }
for(j=1;j<=n;j++)
{
c[j][1]=a[j][x];
if(c[j][1]!=-1) t[j][1]=j;
}
}
void kalaba()
{
int i,j,ok,k;
k=2;
do{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]!=-1 && c[j][k-1]!=-1)
if(c[i][k]<c[j][k-1]+a[i][j])
{
c[i][k]=c[j][k-1]+a[i][j]; t[i][k]=j; }
ok=1;
for(i=1;i<=n;i++)
if(c[i][k-1]!=c[i][k]) { ok=0; break; }
k++;
}while(!ok);
}
void drum(int x,int y)
{

27
cout<<x<< ;
if(y!=1) drum(t[x][y],y-1);

}
void scrie()
{
if(c[p1][pasi]!=-1)
{
while(c[p1][pasi]==c[p1][pasi-1]) pasi--;
cout<<"drum maxim <<p1<< -> <<x<< prin <<pasi<<arce\n";
cout<<"costul <<c[p1][pasi]<<endl;
drum(p1,pasi); cout<<x<<endl;
}
else cout<<"nu exista\n";
}
void main()
{
citire(); cout<<"plecare: "; cin>.p1; cout<<"sosire: ";
cin>.x; cout<<"numar pasi: "; cin>>pasi;
initializari(); kalaba(); scrie();
}

28

Drumuri minime n labirint


Enun: Se consider un labirint codificat sub forma unei matrici de n*n caractere reprezentnd
camerele labirintului. Caracterul o semnific o camer liber, iar caracterul * o camer ocupat.
Matricea este dat n fiierul lab.in, prima linie a acestuia coninnd dimensiunea n a labirintului.
Dndu-se o camer de plecare (xi,yi) i o camer de sosire (xf,yf), evident neocupate, s se
determine cel mai scurt drum de la camera de plecare pn la camera de sosire tiind c dintr-o
camer liber ne putem deplasa ntr-o alt camer vecin liber aflat la stnga, la dreapta,
deasupra sau dedesubtul camerei curente.
Citirea labirintului din fiier se face prin crearea unei matrici L astfel:
L[i,j]=

0, dac avem camer ocupat, adic *


1, dac avem camer liber, adic o

Vom ataa acestei probleme un graf neorientat cu n*n noduri reprezentnd camerele labiruntului, ele
fiind numerotate n ordine 1,2,..,n*n. Dac dou camere sunt libere i nvecinate, atunci n graf
cele dou noduri vor fi adiacente. Vom memora graful prin matricea costurilor A n care costul unei
muchii este 1.
Pe baza matricii L i a regulilor de vecintate din enun vom construi matricea costurilor A de
dimensiune n*n astfel:
- se iniializeaz matricea A cu o valoare foarte mari (infinit)
- cum avem n*n camere, la generarea matricii costurilor ne vom referi la configuraia
labiruntului astfel: nodul i din graf corespunde camerei (x=(i-1)/n+1,y=(i-1)%n+1) din
labirint (relaii obinute prin liniarizarea matricii L)
- reciproc, nodul reprezentat de (x,y) este elementul p=n*(x-1)+y din matricea L.
n acest fel se verific toate camerele libere vecine i se completeaz matricea costurilor.
Pentru a determina cel mai scurt drum ntre camera de plecare i cea de sosire vom folosi
algoritmul Floyd-Warshall. Pentru a afia efectiv camerele de pe drumul minim determinat de la
nodul sursa nod_i la destinaia nod_f vom folosi strategia Divide et Impera, considernd c
dac avem un nod intermediar k i A[nod_i,nod_f]=A[nod_i,k]+A[k,nod_f], atunci nodul k
se afl pe drumul optim cutat, deci vom genera drumurile (nod_i,k) i (k,nod_f). Complexitatea
acestei metode este dat de complexitatea algoritmului Floyd-Warhall adic este O((n*n)3) ,
inacceptabil pentru valori n chiar relativ mici.
Programul urmtor implementeaz metoda descris mai sus.
#include<iostream.h>
#include<fstream.h>
#define N 15
#define INF 10000
short int L[N][N],A[N*N][N*N],n;
void citire()
{
ifstream f("lab.in";
char s[20]; int i,j;
f>>n; fgetc(f);
for(i=1;i<=n;i++)
{
fgets(s,20,f);
for(j=0;j<n;j++)
if(s[j]=='*') L[i][j+1]=0;
else L[i][j+1]=1;

29
}
f.close();
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++) cout<<L[i][j]<<\t;
cout<<"\n";
}
}
void construieste_graf()
{
int i,j,x,y;
for(i=1;i<=n*n;i++) //initializam matricea costurilor
for(j=1;j<=n*n;j++) A[i][j]=INF;
for(i=0;i<=n+1;i++) //bordam matricea L cu 0
L[0][i]=L[i][0]=L[i][n+1]=L[n+1][i]=0;
for(i=1;i<=n*n;i++)
{
x=(i-1)/n+1; y=(i-1)%n+1;
if(L[x][y]==1)
{
if(L[x][y-1]==1) //la stanga
A[n*(x-1)+y-1][i]=A[i][n*(x-1)+y-1]=1;
if(L[x][y+1]==1) //la dreapta
A[n*(x-1)+y+1][i]=A[i][n*(x-1)+y+1]=1;
if(L[x-1][y]==1) //deasupra
A[i][n*(x-2)+y]=A[n*(x-2)+y][i]=1;
if(L[x+1][y]==1) //dedesubt
A[i][n*x+y]=A[n*x+y][i]=1;
}
A[i][i]=0;
}
}
void Floyd_Warhall()
{
int i,j,k;
for(k=1;k<=n*n;k++)
for(i=1;i<=n*n;i++)
for(j=1;j<=n*n;j++)
if(A[i][j]>A[i][k]+A[k][j]) A[i][j]=A[i][k]+A[k][j];
}
void drum(int x,int y)
{
int k=1,gata=0;
while(k<=n*n && !gata)
{
if(x!=k && y!=k && A[x][y]==A[x][k]+A[k][y])
{
drum(x,k); drum(k,y); gata=1;
}
k++;
}
if(!gata) cout<<y<< ;
}
void afisare_drum(int x,int y)
{

30
if(A[x][y]<INF)
{
cout<<"\nlungime=<,A[x][y];
cout<<"prin celulele: x; drum(x,y);
}
else cout<<"\nNu exista drum\n";

}
void main()
{
int xi,yi,xf,yf,nod_i,nod_f;
citire(); construieste_graf();
cout<<"punctul de plecare (x,y)="; cin>>xi>>yi;
cout<<"punctul de sosire (x,y)="); cin>>xf>>yf;
nod_i=n*(xi-1)+yi; nod_f=n*(xf-1)+yf;
Floyd_Warhall(); afisare_drum(nod_i,nod_f); cout<<"\n";
}
Observaie: Complexitatea algoritmul devine O(n2) dac n loc de algoritmul Floyd-Warshall
folosim o parcurgere BF a grafului reprezentat prin liste de adiacen i atam nodurilor un vector de
marcare (algoritmul lui Lee).
Programul urmtor determin drumul minim ntre camera de plecare nod_i i camera de
sosire nod_f folosind pentru graful asociat listele de adiacen alocate dinamic. Tablourile utilizate de
parcurgerea BF sunt deasemenea alocate dinamic n heap pentru a mri spaiul de memorie
disponibil.
#include<iostream.h>
#include<fstream.h>
#define N 50
typedef struct nod{
short int inf;
nod *leg;
}AD;
AD *LA[N*N];
short int L[N][N],n;
short int *C,*T,*VIZ,*DMIN; //tablouri alocate dinamic in heap
void citire()
{
ifstream f(lab.in");
char s[20]; int i,j;
cin>>n; f.getc(f);
cout<<"\tLabirintul este:\n";
for(i=1;i<=n;i++)
{
f.gets(s,20,f); puts(s);
for(j=0;j<n;j++)
if(s[j]=='*') L[i][j+1]=0;
else L[i][j+1]=1;
}
f.close();
}
void Init() //aloca spatiu pentru tablourile C,T,VIZ,DMIN
{
int i;
C=new short int [n*n+1];

31
T=new short int [n*n+1];
VIZ=new short int [n*n+1];
for(i=1;i<=n*n;i++) VIZ[i]=0;
DMIN=new short int [n*n+1];

//initializam vectorul de vizitare

}
void construieste_graf()
{
int i,x,y;
AD *p;
for(i=1;i<=n*n;i++)
{
LA[i]=new AD; LA[i]->leg=0;
}
for(i=0;i<=n+1;i++) //bordam matricea L cu 0
L[0][i]=L[i][0]=L[i][n+1]=L[n+1][i]=0;
for(i=1;i<=n*n;i++)
{
x=(i-1)/n+1; y=(i-1)%n+1;
if(L[x][y]==1)
{
if(L[x][y-1]==1) //vecin la stanga
{
p=new AD; p->inf=n*(x-1)+y-1; p->leg=LA[i]->leg;
LA[i]->leg=p;
p=new AD; p->inf=i; p->leg=LA[n*(x-1)+y-1]->leg;
LA[n*(x-1)+y-1]->leg=p;
}
if(L[x][y+1]==1) //vecin la dreapta
{
p=new AD; p->inf=n*(x-1)+y+1; p->leg=LA[i]->leg;
LA[i]->leg=p;
p=new AD; p->inf=i; p->leg=LA[n*(x-1)+y+1]->leg;
LA[n*(x-1)+y+1]->leg=p;
}
if(L[x-1][y]==1) //vecin deasupra
{
p=new AD; p->inf=n*(x-2)+y; p->leg=LA[i]->leg;
LA[i]->leg=p;
p=new AD; p->inf=i; p->leg=LA[n*(x-2)+y]->leg;
LA[n*(x-2)+y]->leg=p;
}
if(L[x+1][y]==1) //vecin dedesubt
{
p=new AD; p->inf=n*x+y; p->leg=LA[i]->leg;
LA[i]->leg=p;
p=new AD; p->inf=i; p->leg=LA[n*x+y]->leg;
LA[n*x+y]->leg=p;
}
}
}
}
void BF(int nod,int s)
{
AD *x; int prim,ultim;
VIZ[nod]=1; T[nod]=0; DMIN[nod]=0;

32
prim=ultim=1; C[prim]=nod;
while(prim<=ultim)
{
nod=C[prim];
//extrag nodul din varful cozii
x=LA[nod]->leg; //lista vecinilor lui nod
while(x)
{
if(!VIZ[x->inf])
{
T[x->inf]=nod; VIZ[x->inf]=1;
DMIN[x->inf]=DMIN[nod]+1;
if(x->inf==s) return;
//am ajuns in punctul de sosire, opresc parcurgerea
C[++ultim]=x->inf; //adaug x->inf in coada
}
x=x->leg;
}
prim++; //avansez la urmatorul nod din coada
}
}
void drum(int i,int nod)
{
if(i!=nod) drum(T[i],nod);
cout<<i<< ;
}
void main()
{
int xi,yi,xf,yf,nod_i,nod_f;
citire(); construieste_graf(); Init();
cout<<"punctul de plecare (x,y)="; cin>>xi>>yi;
cout<<"punctul de sosire (x,y)="; cin>>xf>>yf;
nod_i=n*(xi-1)+yi; nod_f=n*(xf-1)+yf;
BF(nod_i,nod_f); //parcurg BF graful din nodul de plecare
if(DMIN[nod_f])
{
cout<<"\nlungime=<< DMIN[nod_f]<<este <<drum(nod_f,nod_i)<<
\ndrum prin nodurile: ";,
cout<<"\n";
}
else
cout<<"\nNu exista drum intre camera <<nod_i<< si camera <<nod_f<<endl;
}

33

Bibliografie

1. Thomas H. Cormen, Charles E. Leiserson, Ronald R. Rivest,


Introducere in algoritmi, Editura Agora, 2000
2. Daniela Oprescu, Liana Bejan Ienulescu, Viorica Patrascu,
Informatica - Manual pentru clasa a XI-a, Editura Niculescu,
2001
3. George Daniel Mateescu, Pavel Florin Moraru, Informatica Manual pentru clasa a XI-a, Editura Niculescu 2003
4. Dana Lica, Doru Popescu Anastasiu, Radu Boriga, Dan Pracsiu,
Fundamentele programarii- Culegere de probleme pentru clasele
IX-XI, Editura L&S Soft 2002
5. Carpen Manuela, Suport de curs si lucrari de laborator,
manuscris

S-ar putea să vă placă și