Sunteți pe pagina 1din 32

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 i ultima apariie a sa vom obine un drum de la xi la xj, n care xk apare o singur dat. Aplicnd

3
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: dij = 1, daca exista drum de la xi la xj 0, in caz contrar

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 = i matricea L(1), definit prin: l(1)ij = 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 {sii I} 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 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: 0, n caz contrar xj, dac exist arcul (xi,xj) 0, n caz contrar

4
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. 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:

5
"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

unui numr finit de drumuri elementare ( cel mult n n! 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. 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)

k!

n -1

6
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.

2 7 1 1 2 1 3 5

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 xj X pentru

care am gsit drum minim de la x0 la xj. Iniial S={x0}. La fiecare pas, adgm n S acel nod xk X-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 xp X-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 xk X-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 xi S di= lungimea drumului minim de la x0 la xi ce folosete numai vrfuri din S, dac xi S

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 | xj X-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 xj X-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= . 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 i x0 La fiecare actualizare de forma dj Dk+c(k,j) vom avea i o actualizare a vectorului T de forma Tj k. 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| xj X-S}= ). Pentru reprezentarea mulimii S se poate folosi vectorul caracteristic S cu n componente definit astfel: 0 dac xi S Si= 1 dac xi S

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 v U, D[v]=0 pentru v=nod (nodul surs) i D[v]= pentru v U-{ 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). 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 v S avem D[v] egal cu distana mnim. Algoritmul itereaz selectarea unui nod u X-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: D=(0, 1, , , 3, ) T=(0, 1, 0, 0, 1, 0) S=(1, 0, 0, 0, 0, 0) 1) 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)

2)

3)

4)

5)

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) S=(1, 1, 1, 1, 1, 0) 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]) { 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();}

10

Algoritmul lui Dantzig

11
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:

2 2

2 2 1 4 1 1 6

2 1 3 5

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

12
2 4

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 5

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

2 1 6 1 2 1 3 5

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

13

2 2

2 1 1 1 6

2 1 3 5

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


2 2 2 2 1 1 1 6 4

2 1 3 5

Pentru exemplul considerat, costul minim de la 1 la 6 este 6 i se obine prin drumurile: 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; }

} 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]) { 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); }}

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();

14

15

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

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

16
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 v X 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; } 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 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(); cout<<"plecare: "; cin>start; bellman_ford(); for(i=1;i<=n;i) if(i!=start) { cout<<"cost <<d[i]<< prin "; drum(i); cout<<"\n"; } }

17

depista

circuite

de

cost

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.

18
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() { 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; //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);

19

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]; }

20

Algoritmul Floyd-Warshall
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

21
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 i j 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 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; }

} 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]; 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(); }

for(i=1;i<=m;i++) { f>>x1>>x2>>cost; C[x1][x2]=cost; } f.close();

22

Algoritmul Floyd-Warshall pentru drumuri de cost maxim

23
Fie G=(X,U) un graf orientat fr circuite cu X=(x1,x2,...,xn) i l:U R+ 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= 0 - dac dac dac (xi,xj) U i=j (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 (i j). Pentru a reine nodurile prin care trec aceste drumuri maxime vom folosi matricea D=(dij)nxn n care: {xi} dac cij>- i i j dac cij=- sau i=j

dij=

Matricile C i D se modific conform urmtorului algoritm: pentru k=1,n pentru i=1, n (k i) pentru j=1,n (k j) daca cij<cik+ckj atunci cij cik+ckj dij dkj altfel daca cij=cik+ckj atunci dij dij dkj 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).

24
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]j X).

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]j X). 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.

25
2 2 2 2 1 1 4 1 6 4

3 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 2 7 0 c(2) -1 8 8 2 7 0 c(3) 10 12 8 2 7 0 c(4) 14 12 8 2 7 0 c(5) 14 12 8 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) { 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(); }

26

27

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; }

} 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) { if(A[x][y]<INF) {

f.close(); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) cout<<L[i][j]<<\t; cout<<"\n"; }

28

} 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]; T=new short int [n*n+1]; VIZ=new short int [n*n+1]; for(i=1;i<=n*n;i++) VIZ[i]=0; //initializam vectorul de vizitare

} else cout<<"\nNu exista drum\n";

cout<<"\nlungime=<,A[x][y]; cout<<"prin celulele: x; drum(x,y);

29

DMIN=new short int [n*n+1]; } 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; prim=ultim=1; C[prim]=nod; while(prim<=ultim) { nod=C[prim]; //extrag nodul din varful cozii

30

} } 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; }

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

31

32

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