Documente Academic
Documente Profesional
Documente Cultură
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
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.
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
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
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
12
2 4
2 6 1
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
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); }}
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
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(); }
22
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
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) {
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
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