Documente Academic
Documente Profesional
Documente Cultură
I. Activități de învățare
Principiul metode este următorul:
- se vizitează mai întâi nodul de plecare, fie acesta i;
- se vizitează apoi toate nodurile adiacente cu nodul i, fie acestea j1, j2, ...., jk, în această
ordine;
- se vizitează toate nodurile adiacente cu nodul j1, apoi cu j2, ...., apoi cu jk;
- .....
- algoritmul continuă în acest mod până când au fost vizitate toate nodurile.
Exemplu: considerăm graful din figura de mai jos pentru care aplicăm parcurgerea BF,
pornind de la noduri diferite:
Parcurgerea BF
De la nodul 1: 1 2 3 4 6 5 7 8
De la nodul 2: 2 1 6 3 4 5 7 8
De la nodul 3: 3 1 5 2 4 7 8 6
De la nodul 4: 4 1 6 2 3 5 7 8
De la nodul 5: 5 3 7 8 1 2 4 6
De la nodul 6: 6 2 4 1 3 5 7 8
De la nodul 7: 7 5 3 8 1 2 4 6
Figura 4.1.1.1 De la nodul 8: 8 5 3 7 1 2 4 6
Descriere algoritm: Strategia parcurgerii BF funcționează respectând mecanismul de tip
FIFO. Ea se bazează pe traversarea tuturor muchiilor disponibile din nodul curent către
nodurile adiacente nedescoperite, care vor fi astfel vizitate. După acest proces, nodul explorat
este scos din coadă, prelucrându-se succesiv toate nodurile ajunse ăn vârful cozii.
În construcția practică a algoritmului, trebuie ales la un moment dat, dintre toți vecinii unui
nod, acela care nu a fost vizitat încă. Pentru a face posibil acest lucru folosim un vector
VIZITAT de dimensiune n, definit astfel: pentru j {1, 2, …, n}
Pas 1: pentru j=1,n execută VIZITAT[j]←0 (inițial nici un nod nu a fost vizitat).
Pas 2: se prelucrează nodul de pornire i:
2.1. C[1] ←i (se adaugă în coadă nodul i);
2.2. VIZITAT[i] ←1 (nodul i se marchează ca vizitat);
Pas 3: cât timp coada nu este vidă (p≤u) execută
3.1. i← C[p] (prelucrăm nodul i aflat la începutul cozii);
3.2. pentru toți vecinii j ai lui i, nevizitați încă, execută
3.2.1. u←u+1; C[u] ←j (se adaugă nodul j în coadă);
3.2.2. VIZITAT[j] ←1 (se marchează nodul ca vizitat);
3.3. p←p+1 (se reia de la pasul 3.1. unde se trece la următorul element ce va fi scos
din coadă);
Pas 4: se afișează coada.
Complexitatea algoritmului: Algoritmul necesită o memorie O(n) pentru tabloul VIZ și tot la
fel pentru coada C. Cazul cel mai nefavorabil este cel în care vârful inițial i este conectat cu
toate celelalte vârfuri ale grafului. În acest caz, în coadă se vor afla n-1 vârfuri.
Se poate verifica corectitudinea algoritmului, în sensul că a fost prelucrat, o singură dată,
fiecare vârf. Primul ciclu for (inițializarea) necesită un timp O(n).
Ciclul while se execută de cel mult n-1 ori ( i este vizitat anterior). În corpul ciclului while
există un nou ciclu for ce contine selecția simplă if care se va executa de câte n ori la fiecare
reluare a lui while. Prin acest for se parcurge linia corespunzătoare vârfului analizat din
matricea de adiacență.
Celelalte instructiuni prezente în algoritm (de asignare, incrementare) nu afectează ordinul de
complexitate al algoritmului .
Asadar, complexitatea algoritmului BF, în cazul reprezentării grafului prin matricea sa de
adiacenta, este O(n(n-1)+n) = O(n2).
Dacă graful G este reprezentat prin liste de adiacență, ciclul initial se executa tot în
O(n) timpi. Lista Lj, adică lista vecinilor vârfului j, va conține dj (valența vârfului j) elemente.
Prin urmare, la fiecare execuție a lui while, ciclul for din corpul său, se va executa într-un
timp cdj, unde c este o constantă, iar j reprezintă vârful care urmează a fi prelucrat și scos din
C. Se stie că 𝑑𝑘 =2m. Deci timpul total este O(n+m).
II. Exerciții de fixare a cunoștințelor teoretice
a. 2 1 3 4 6 7 5
b. 1 2 5 3 7 4
c. 2 1 5 7 3 4 6
d. 1 5 3 2 7 6 4
Figura 4.1.1.2
2) Se consideră graful G=(X,U) în care U={(1,2), (1,3), (1,4), (2,5), (3,5), (5,7), (6,7),
(6,8)}. Care este parcurgerea în lățime dacă se consideră nodul 1 ca nod de plecare?
a. 1 2 3 4 5 6 7 8 c. 1 2 3 4 5 7 6 8
b. 1 2 5 7 6 8 3 4 d. 1 2 3 4 5 7 8 6
(Vezi Anexa 1)
4.1.2. Metoda de parcurgere DF (Depth First – ”în adâncime”).
I. Activități de învățare
Parcurgerea DF
De la nodul 1: 1 2 6 4 3 5 7 8
De la nodul 2: 2 1 3 5 7 8 4 6
De la nodul 3: 3 1 2 6 4 5 7 8
De la nodul 4: 4 1 2 6 3 5 7 8
De la nodul 5: 5 3 1 2 6 4 7 8
De la nodul 6: 6 2 1 3 5 7 8 4
De la nodul 7: 7 5 3 1 2 6 4 8
Figura 4.1.2.1 De la nodul 8: 8 5 3 1 2 6 4 7
Algoritmul în pseudocod: elevii pot lucra pe grupe de câte 2 sau 3 pentru a încerca
descrierea pas cu pas a algoritmului DF, conform prezentărilor teoretice.
Pas 1: pentru j=1,n execută
VIZITAT[j]←0 (inițial nici un nod nu a fost vizitat)
URM[j]←0 (pornind din 0, determinăm prima valoare posibilă pentru
primul nod spre care se poate pleca din nodul j )
Pas 2: se prelucrează nodul de pornire i:
2.1. S[1] ←i (se adaugă în stivă nodul i);
2.2. VIZITAT[i] ←1 (nodul i se marchează ca vizitat);
2.3. p←1 (poinerul de stivă p pointează spre elementul din vârful stivei);
Pas 3: cât timp stiva nu este vidă (p≥1) execută
3.1. j← S[p] (scoate nodul din vârful stivei);
3.2. determină primul dintre vecinii k ai lui j, nevizitați încă: URM[j] ←k
3.3. daca nu există un asemenea k atunci p←p-1
altfel
scrie k;
VIZITAT[k] ←1 (vârful k este vizitat);
p←p+1 (se mărește poinerul de stivă pentru a-l memora în stivă pe k);
S[p] ←k (vârful k devine nodul ce trebuie analizat).
a. 2 1 3 4 5 7 6
b. 1 2 5 7 3 4
c. 2 1 3 4 6 7 5
d. 2 1 3 4 6 5 7
Figura 4.1.2.2
2) Se consideră graful G=(X,U) în care U={(1,2), (1,3), (1,4), (2,5), (3,5), (3,6), (4,6),
(5,7), (6,7), (6,8)}. Care este parcurgerea în adâncime pentru graful dat, dacă se consideră ca
nod de plecare nodul 2?
a. 12345678 c. 12354678
b. 12536478 d. 13254687
3) Se consideră graful G=(X,U) în care U={(1,2), (1,3), (2,3), (3,4), (4,5), (4,6)}. Care
sunt nodurile de plecare pentru care parcurgerile în lățime și în adâncime nu coincid?
a. 1 2 b. 4 2 c. 4 5 6 d. 3 4
b. Sarcină de lucru 2: Fie G=(X,U) un graf neorientat memorat prin matricea de
adiacență. Realizați un program Pascal/C++ care să implementeze algoritmul de parcurgere
în DF.
Activitatea se poate desfășura individual la calculator urmând algoritmul descris în lecția
teoretică.
(Vezi Anexa 2)
4.2. Conexitate. Componente conexe
I. Activități de învățare
Un graf G=(X,U) se numește conex dacă oricare ar fi două noduri x și y din graf, există un
lanț care le leagă.
Se numește componentă conexă a grafului G=(X,U), un subgraf conex G1=(X1,U1) al lui G,
cu proprietatea că nu exisă niciun lanț care să lege un nod din X1 cu un nod din X- X1.
Exemplu: Pentru graful di figura 4.2.1 b) avem trei componente conexe: C1={1, 4},
C2={2, 3, 6}, C3={5}
a) b)
Graf conex Graf neconex
Figura 4.2.1
Observații:
- Dacă numărul componentelor conexe dintr-un graf este mai mare decât 1, atunci graful
nu este conex.
- Un graf conex are o singură componentă conexă care conține toate nodurile grafului.
Sarcină de lucru: Fie G=(X,U) un graf neorientat cu n noduri și m muchii. Să se realizeze un
algoritm care să decidă dacă graful dat este sau nu conex.
Descriere algoritm: Pentru a verifica conexitatea unui graf se pornește de la o observație
evidențiată și anume ” Un graf conex are o singură componentă conexă care conține toate
nodurile grafului”. Altfel spus, dacă în urma unei parcurgeri (BF sau DF) s-au vizitat toate
nodurile, indiferent de nodul de plecare, atunci graful este conex.
Folosind algoritmul de parcurgere BF, utilizăm două structuri de date:
- o coadă C care va memora pe rând nodurile vizitate, în ordinea vizitării lor
- un vector viz care marchează nodurile vizitate cu 1 și pe cele nevizitate cu 0.
După parcurgere, se testează dacă în vectorul viz există vreun element 0, caz în care graful nu
este conex. Dacă toate elementele sunt 1, graful este conex.
II. Exerciții de fixare a cunoștințelor teoretice
Figura 4.2.2
a. Numărul de componente conexe este ................................
b. Numărul minim de muchii care trebuie adăugate pentru ca graful să devină
conex este ........ iar muchiile sunt (precizati o variantă): .................................................
2) Fie un graf neorientat cu n noduri și p componente conexe. Numărul minim de muchii
care trebuie adăugate pentru ca graful să devină conex este ..........
3) Fie un graf neorientat cu n coduri.
a. Numărul minim de componente conexe este ......... iar numărul de muchii
trebuie să fie cel puțin .................
b. Numărul maxim de componente conexe este ..... iar numărul de muchii este .....
Figura 4.2.3
2) Fie un graf neorientat cu n noduri, m muchii și p componente conexe. Care din
următoarele relații este adevărată:
a. m ≤ (n-p)2 c. 2m ≤ (n-p+1) (n-p)
2
b. 2m ≤ (n-p) + (n-p) d. n+p >m
Descriere algoritm:
Elevii pot lucra individual sau pe grupe de câte 2.
(Vezi Anexa 4)
Figura 4.2.4
Componentele conexe ale acestui graf sunt: C1={1, 2, 3, 4}, C2={5, 6, 7}, C3={8}
Memorăm într-un vector L numărul de ordine al componentei conexe din care face parte
fiecare nod al grafului. Astfel, pentru exemplul dat, vectorul L va fi următorul:
i 1 2 3 4 5 6 7 8
L[i] 1 1 1 1 2 2 2 3
Pentru a transforma graful într-un graf conex, trebuie să avem o singură componentă conexă.
Pentru aceasta, vom lua un nod x din componenta C1 și-l vom uni, pe rând, cu câte un nod din
celelalte componente conexe. Practic, unim nodul 1 din C1 cu nodul 5 din C2, respectiv cu
nodul 8 din C3, în final obținându-se graful din figura de mai jos:
Figura 4.2.5
Algoritmul în pseudocod
(Vezi Anexa 5)
Sarcină de lucru 5: Fiind dat un graf neorientat conex G=(X,U) cu n noduri și m muchii citite
de la tastatură, să se determine un nod p care poate fi eliminat astfel încât subgraful generat de
mulțimea X-{p} să rămână conex.
Plecăm dintr-un nod oarecare, fie acesta start. Ne deplasăm pe muchii, trecând prin noduri
nevizitate încă, atâta timp cât este posibil. Notăm cu p nodul în care ne aflăm în fiecare
moment. Când din p nu ne mai putem deplasa folosind noduri nevizitate, înseamnă că nodul p
poate fi eliminat, împreună cu muchiile incidente cu acesta, deoarece el nu afectează
conexitatea grafului.
a) b)
Figura 4.2.6
(Vezi Anexa 6)
4.3. Grafuri hamiltoniene
I. Activități de învățare
În 1857, matematicianul irlandez William Hamilton a inventat Jocul Icosian care consta
în găsirea unui ciclu care să treacă o singură dată prin fiecare din cele 20 de vârfuri ale unui
dodecaedru (făcut din lemn și care avea în fiecare vârf câte un cui cu o floare mare),
deplasarea făcându-se pe muchiile dodecaedrului.
Figura 4.3.1
Într-un graf G=(X,U), un ciclu elementar care conține toate nodurile grafului se
numește ciclu hamiltonian.
Un lanț elementar care conține toate nodurile grafului se numește lanț hamiltonian.
Evemplu: graful din figura 4.3.2. a) este hamiltonian deoarece conține un ciclu hamiltonian
C={1, 2, 3, 5, 4, 1}, pe când graful din figura 4.12. b) nu este hamiltonian.
a) b)
Graf hamiltonian Graful nu este hamiltonian
Figura 4.3.2
O problemă înrudită cu aceea a găsirii într-un graf a unui ciclu hamiltonian este:
Cu alte cuvinte, problema cere să se determine un ciclu hamiltonian de cost minim în graful
Kn ale cărui noduri sunt cele n orașe iar costul unui ciclu este suma costurilor muchiilor sale.
Teoremă: Dacă G=(X,U) este un graf cu n≥3 noduri, astfel încât gradul fiecărui vârf xЄX
satisface condiția d(x) ≥ n/2 atunci garful G este hamiltonian.
a. Sarcină de lucru 1 – elevii se pot organiza în grupe mici sau pot lucra individual.
Figura 4.3.3
1) Secvența de noduri (2, 3, 5, 6, 1, 4, 2) este un ......................................... și are lungimea ....
2) În general, lungimea unui ciclu hamiltonian este egală cu .....................
3) Lanțul hamiltonian (1, 4, 3, 2, 5, 6) este lanț .......................................... și are lungimea .....
4) În general, lungimea unui lanț hamiltonian este egală cu .....................
5) Fie graful parțial G1 obținut prin eliminarea muchiilor (2,3) și (2,5). Secvența (3,5,6,1,4,2)
este lanț hamiltonian? Graful G1 este hamiltonian?
I. Activități de învățare
Fie un graf G=(X,U). Un ciclu care conţine toate muchiile grafului se numeşte ciclu
eulerian. Un graf care conține un ciclu eulerian se numeşte graf eulerian.
Lanțul eulerian este un lanț simplu care conține toate muchiile grafului.
Exemplu: Graful din figura 4.4.1 a) este graf eulerian deoarece conține un ciclu eulerian
C=(1, 3, 2, 5, 3, 4, 5, 1), pe când graful din figura 4.4.1 b) nu este eulerian.
a) b)
Graf eulerian Graful nu este eulerian
Figura 4.4.1
Primul care s-a ocupat de acest tip de grafuri a fost Leonard Euler. El a plecat de la o
problemă practică și anume, ”Problema celor 7 poduri din Koenigsberg” (Poduri peste rîul
Pregel din Koenigsberg – localitate din Prusia sec. XVIII ): Să se găsească dacă este posibil,
o modalitate de traversare a tuturor celor 7 poduri (notate de la “a” la “g”) parcurgîndu-le o
singură dată pe fiecare, cu reîntoarcere în locul de plecare. Notatia “A” – “D” reprezinta
portiuni de uscat
Problema podurilor poate fi “transcrisă” folosind notaţii specifice teoriei grafurilor
prin utilizarea unor segmente (ce marchează calea de urmat) şi cercuri (ce marchează
intersecţia unor căi figurate prin segmente).
Teoremă: Un graf G=(X,U), fără vârfuri izolate, este eulerian dacă şi numai dacă este conex
şi gradele tuturor vârfurilor sunt numere pare.
Figura 4.4.2
1) Secvența de noduri (1, 5, 4, 3, 2, 5, 6, 1) este un ..................................... și are lungimea ....
2) În general, lungimea unui ciclu eulerian este egală cu .....................
3) Lanțul eulerian (3, 4, 5, 1, 6, 5, 2, 3) este lanț ........................................ și are lungimea .....
4) În general, lungimea unui lanț eulerian este egală cu .....................
5) Fie graful parțial G1 obținut prin eliminarea muchiilor (1,2) și (1,5). Secvența (1,6,5,4,3,2)
este lanț eulerian? Graful G1 este eulerian?
Algoritmul în pseudocod:
ciclu_euler(nod)
k=prim_vecin(nod)
cât_timp lista_vecinilor(nod)≠ ∅ execută
elimin(k,nod)
elimin(nod,k)
ciclu_euler(k)
k=următor_vecin(nod)
sfârșit_cât_timp
adaug_coada(nod)
sfârșit_ciclu_euler
Exemplu: Fie graful din figura de mai jos
Figura 4.4.3
Considerăm nodul de pornire în determinarea ciclului eulerian, nod=1.
Pasul 1: se parcurge începând cu nodul 1
Stiva=(1, 2, 3, 1)
Coada=∅
Pasul 2: iese din stivă nodul 1 și se salvează în coadă
Stiva=(1, 2, 3)
Coada=(1)
Pasul 3: se continuă parcurgerea
Stiva=(1, 2, 3, 4, 2, 5, 3)
Coada=(1)
Pasul 4: iese din stivă nodul 3 și se salvează în coadă
Stiva=(1, 2, 3, 4, 2, 5)
Coada=(1, 3)
Pasul 5: se continuă parcurgerea
Stiva=(1, 2, 3, 4, 2, 5, 4, 6, 5)
Coada=(1, 3)
Pasul 6: iese din stivă nodul 5 și se salvează în coadă
Stiva=(1, 2, 3, 4, 2, 5, 4, 6)
Coada=(1, 3, 5)
Pasul 7: toate nodurile sunt extrase din stivă și introduse în coadă
Stiva=∅
Coada=(1, 3, 5, 6, 4, 5, 2, 4, 3, 2, 1)
Fie G=(X,U) un graf neorientat conex. Fiecare muchie (i,j) are asociat un cost cij≥0.
Se cere un arbore parțial al lui G, astfel încât suma costului muchiilor sale să fie minimă.
Un astfel de arbore se numește arbore parțial de cost minim.
Pentru rezolvarea acestei probleme, vom descrie doi algoritmi algoritmul lui Kruskal și
algoritmul lui Prim, ambii algoritmi încadrându-se în tehnica Greedy.
I. Activități de învățare
Prezentare
Notăm cu n numărul de vârfuri din graf. Iniţial considerăm că nici o muchie din
graf nu a fost selectată, deci fiecare vârf din graf este vârf izolat. Cu alte cuvinte, la
momentul iniţial avem o pădure formată din n arbori, fiecare arbore fiind format dintr-un
singur vârf.
La fiecare pas se selectează o muchie de cost minim care nu a mai fost selectată şi care nu
formează cicluri cu muchiile deja selectate.
Exemplu: Fie graful din figura de mai jos:
Figura 4.5.1.1
Pasul 1: Selectăm o muchie de cost minim. (În cazul nostru, de cost 1).
În graful parţial selectat există n - 1 = 4 arbori, pentru că am unificat arborii
corespunzători extremităţilor muchiei selectate. Arborii sunt: { 1, 3 }; { 2 }; { 4 }; { 5 }.
Pasul 2: Selectăm din nou o muchie de cost minim.(Costul minim fiind 1).
În graful parţial selectat există n - 2 = 3 arbori. Arborii sunt: { 1, 3, 4 }; { 2 }; { 5 }.
Pasul 3: La acest pas nu mai putem selecta o muchie de cost 1, deoarece s-ar
obţine un ciclu. Selectăm muchia de cost 2. Arborii sunt: { 1, 2, 3, 4 }; { 5 }.
Pasul 4: Selectând, în final, muchia de cost 3, obţinem un graf fără cicluri cu n-1
muchii, deci un arbore.
Algoritmul în pseudocod
Pas 1. Se ordonează crescător vectorul G, în funcție de costuri
Pas 2. pentru j=1,n execută C[j]=j {inițial, fiecare nod face parte dintr-un
subarbore}
Pas 3. cost=0 {costul total}
k=0 {numără muchiile selectate}
i=1 {prima muchie posibil a fi selectată}
Pas 4. cât timp k<n-1 execută
dacă C[G[i].x]<>C[G[i].y] atunci
k=k+1; scrie G[i] {alege muchia i}
cost=cost+G[i].c {actualizează costul }
nr1=C[G[i].x]
nr2=C[G[i].y]
pentru j=1,n execută
dacă C[j]=nr2 atunci
C[j]=nr1 {se unifică subarborii}
sfârșit_dacă
sfârșit_pentru
sfârșit_dacă
i=i+1 {trec la următoarea muchie}
sfârșit_cât_timp
Pas 5. scrie cost
Complexitatea algoritmului
Sortarea se face în O(m x log(m)). Pentru fiecare muchie, se testează apartenența celor
două noduri cu care este incidentă, la arbori diferiți. Această testare se face în O(log(m)).
Cum avem m muchii testate, testele se efectuează în O(m x log(m)). Deci, eficiența
algoritmului este O(m x log(m)).
II. Exerciții de fixare a cunoștințelor teoretice
1) Pentru graful din figura de mai jos, alcătuiți un APM, folosind algoritmul lui
Kruskal.
Figura 4.5.1.2
2) Pentru graful din figura 4.5.1.3, care este graful parțial obținut după selectarea a
trei muchii prin algoritmul lui Kruskal?
Figura 4.5.1.3
a) b) c)
I. Activități de învățare
Prezentare
Ca şi algoritmul lui Kruskal, algoritmul lui Prim utilizează o strategie Greedy.
Iniţial se pleacă de la un arbore format dintr-un singur vârf. La fiecare pas se selectează o
muchie de cost minim astfel încât mulţimea muchiilor selectate şi mulţimea vârfurilor
unite de acestea să formeze un arbore.
Algoritmul în pseudocod
Pas 1. Se ordonează crescător vectorul U, în funcție de costuri
Pas 2. pentru j=1,n execută VIZ[j]=0 {inițial toate nodurile sunt nevizitate}
Pas 3. VIZ[U[1].x]=1; VIZ[U[1].y]=1 {vizitează extremitățile primei muchii}
scrie U[1] {afișează prima muchie}
cost=U[1].c {costul total}
Pas 4. pentru k=1,n-2 execută
Pas 4.1. caut muchia de cost minim cu o singură extremitate
vizitată; fie aceasta i
Pas 4.2. scrie U[i]
vizitează cealaltă extremitate
cost=cost+U[i].c {actualizează costul}
sfârșit_pentru
Pas 5. scrie cost
Complexitatea algoritmului
Graful va fi indus prim matricea costurilor. Muchia (i,j) de cost minim va fi căutată
pentru toate nodurile cu VIZ[i]=1 și VIZ[j]=0, de unde rezultă că identificarea unei
muchii se face în O(n2). Cum se selectează n-1 muchii, algoritmul va avea complexitatea
O(n3).
Figura 4.5.2.1
4) Algoritmul lui Prim a selectat după primul pas muchiile selectate în figura 4.5.2.2.
Care va fi următoarea muchie selectată?
Figura 4.5.2.2
a) (1,2) b) (4,5) c) (1,5)
5) Pentru graful din figura 4.5.2.3, care este graful parțial obținut după selectarea a trei
muchii prin algoritmul lui Prim?
Figura 4.5.2.3
a) b) c)
I. Activități de învățare
Un graf orientat G=(X,U) este conex, dacă oricare ar fi două vârfuri ale sale, există un
lanț care le leagă .
Exemplu:
Graful din figura 4.6.1. de mai sus este conex. Oricum am lua două noduri putem
ajunge de la unul la celălalt pe un traseu de tip lanț (se face abstracție de orientare).
De exemplu, de la nodul 3 la nodul 2, putem ajunge pe traseul (3, 1, 2), stabilind astfel lanțul
{u1, u3}. Acest lanț nu este unic, alte soluții fiind {u2, u5} și {u4, u3} .
Graful din figura 4.6.1 nu este conex. Luând submulțimea de noduri {2, 3, 4}, putem
spune că între oricare doua noduri din această submulțime există cel puțin un lanț. La fel și în
submulțimea de noduri {5, 1, 6}. Dar nu putem găsi un lanț între un nod din prima
submulțime și un nod din a doua submulțime.
Exemplu: Pentru graful G=(X, U) din figura 4.6.2. de mai sus, cu X={1,2,3,4,5,6} și U={u1,
u2, u3, u4, u5}, nu este conex, el având două componente conexe:
G1=(X1,U1), unde X1={2, 3, 4} și U1={u1, u4, u5};
G2=(X2,U2), unde X2={1, 5, 6} și U2={u2, u3};
Se poate observa că, în cadrul grafurilor orientate, noțiunile de graf conex şi componentă
conexă sunt absolut similare cu cele de la grafuri neorientate. În plus însă, la grafurile
orientate mai întâlnim şi noțiunile de graf tare conex şi componenta tare conexă.
Un graf orientat G=(X,U) este tare conex, dacă pentru oricare două noduri x și y X,
există un drum de la x la y precum şi un drum de la y la x.
Figura 4.6.3
Graf tare conex
Oricum am lua două noduri x,y{1, 2, 3, 4}, căutăm să vedem dacă există drum de la x la y
dar şi un drum de la y la x.
De exemplu, în graful anterior la nodul x=2 la nodul y=1 nu se poate stabili drumul (2, 3, 1),
pentru că, deşi există arcul (2,3), nu există arcul (3,1).
Fiind dat un graf orientat G=(X,U), se numeşte componentă tare conexă a lui G, un
subgraf G1=(X1,U1) , tare conex, şi maximal în raport cu această proprietate (adică pentru
orice nod xX-X1, subgraful indus de X1{x} nu mai este tare conex ).
Exemplu: Pentru graful din figura de mai jos avem 3 componente tare conexe, acestea fiind:
Figura 4.6.4
S[i] mulţimea vârfurilor care sunt extremităţi finale ale drumurilor ce pleacă
din nodul i (adică numărul valorilor de 1 de pe linia i a matricei drumurilor);
P[i] mulţimea vârfurilor care sunt extremități iniţiale ale drumurilor ce intră
în nodul i ( adică numărul valorilor de 1 de pe coloana i a matricei drumurilor).
C[i] reprezintă o componentă tare conexă.
Mai definim o mulţime L, care va conţine la finalul fiecărui pas, nodurile deja incluse în
componentele conexe existente pană în acel moment. Inițial L este mulţimea vidă. Imediat
după ce formăm o componentă tare conexă, pentru a marca acest fapt, introducem în
mulțimea L nodurile componentei.
Număram în variabila nc câte componente tari conexe avem.
Componenta tare conexă din care face parte nodul i, este mulţimea: (S[i] P[i]) {i}.
Algoritmul în pseudocod:
Pas 1 VIZ= ∅ {mulțimea nodurilor incluse deja într-o componentă tare conexă}
nc=0 {numărul de componente tare conexe}
Pas 2. pentru i=1,n execută
Figura 4.6.5
1) Câte componente conexe are graful din figura 4.6.5?
a. 3 c. 2
b. 4 d. 1
2) Câte componente tare conexe are graful din figura 4.6.5?
a. 3 c. 1
b. 6 d. 4
3) Care este numărul maxim de arce care pot fie eliminate astfel încât numărul de
componente conexe să rămână neschimbat?
a. 2 c. 0
b. 1 d. 3
4) Fie graful din figura de mai jos:
Figura 4.6.6
Completați răspunsurile:
I. Activități de învățare
Forma 2
𝒄, 𝒅𝒂𝒄ă ∃ 𝒖𝒏 𝒂𝒓𝒄 𝒅𝒆 𝒄𝒐𝒔𝒕 𝒄 > 0 𝑑𝑒 𝑙𝑎 𝑖 𝑙𝑎 𝑗
𝒂[𝒊, 𝒋] = 𝟎, 𝒅𝒂𝒄ă 𝒊 = 𝒋
−∞, 𝒅𝒂𝒄ă 𝒏𝒖 𝒆𝒙𝒊𝒔𝒕ă 𝒂𝒓𝒄 𝒅𝒆 𝒍𝒂 𝒊 𝒍𝒂 𝒋
4.7.1. Algoritmul lui Roy – Floyd – drumuri minime între oricare vârfuri
Descriere algoritm: Plecăm de la următoarea idee: dacă drumul minim între două vârfuri
oarecare i și j trece printr-un vârf k, atunci drumurile de la i la k și de la k la j sunt la
rândul lor minime. Pentru fiecare pereche de vârfuri (i,j), cu i, j ∈ {1, 2, . . . , n},
procedăm astfel:
Dăm lui k pe rând valorile 1, 2, . . . , n, pentru că vârful k despre care vorbeam mai sus
poate fi, cel puțin teoretic, orice vârf al grafului. Pentru fiecare k:
Dacă ai,j > ai,k+ ak,j atunci ai,j :=ai,k+ ak,j (adică, dacă suma dintre costul drumului
de la i la k si costul drumului de la k la j este mai mică decât costul drumul de la i
la j, atunci drumul inițial de la i la j este înlocuit cu drumul indirect i→k→j);
Altfel, matricea costurilor rămâne neschimbată.
În finalul algoritmului costurile drumurilor minime se găsesc în matricea costurilor, ale
cărei elemente au următoarea semnificație:
Algoritmul în pseudocod
Pasul 1. Inițializăm matricea costurilor C și matricea D după formulele precizate mai sus.
Pasul 2. pentru k=1,n execută
pentru i=1,n execută
pentru j=1,n execută
dacă a[i,k]+a[k,j]<a[i,j] atunci
a[i,j]=a[i,k]+a[k,j]
d[i,j]=d[k,j]
sfârșit_dacă
sfârșit_pentru
sfârșit_pentru
sfârșit_pentru
Exemplu:
Considerăm graful din figura de mai jos:
Figura 4.7.1.1
Pentru fiecare vârf intermediar k=1, 2, ..., n, se parcurg perechile de vârfuri (i,j), cu
proprietatea că i≠k și j≠k; dacă ai,j > ai,k+ ak,j atunci ai,j se înlocuiește cu ai,k+ ak,j și di,j se
înlocuiește cu dk,j .
Se poate observa faptul că la fiecare pas k, elementele care rămân neschimbate sunt cele
de pe linia k (i≠k), coloana k (j≠k) și de pe diagonala principală (ai,j=0, deci valoare
minimă). Dacă elementul ai,j rămâne neschimbat, atuci și elementul corespunzător din
matricea D, di,j rămâne neschimbat.
De asemenea, rămân neschimbate elementele de pe linia i și coloana j pentru care ai,j <
ai,k+ ak,j (nu există drum de la i la j prin intermediarul k, sau există dar costul său este mai
mic sau egal cu costul drumului direct de la i la j).
Prezentăm conținutul matricilor A și D după fiecare iterație a variabilei intermediare k.
0 2 ∞ ∞ ∞ 4 ∅ 1 ∅ ∅ ∅ 1
3 0 ∞ ∞ 5 1 2 ∅ ∅ ∅ 2 2
1 3 0 ∞ ∞ 5 3 1 ∅ ∅ ∅ 1
K=1 A= D=
∞ ∞ ∞ 0 ∞ 3 ∅ ∅ ∅ ∅ ∅ 4
∞ ∞ 3 ∞ 0 ∞ ∅ ∅ 5 ∅ ∅ ∅
∞ ∞ ∞ ∞ 2 0 ∅ ∅ ∅ ∅ 6 ∅
0 2 ∞ ∞ 7 3 ∅ 1 ∅ ∅ 2 2
3 0 ∞ ∞ 5 1 2 ∅ ∅ ∅ 2 2
1 3 0 ∞ 8 4 3 1 ∅ ∅ 2 2
K=2 A= D=
∞ ∞ ∞ 0 ∞ 3 ∅ ∅ ∅ ∅ ∅ 4
∞ ∞ 3 ∞ 0 ∞ ∅ ∅ 5 ∅ ∅ ∅
∞ ∞ ∞ ∞ 2 0 ∅ ∅ ∅ ∅ 6 ∅
0 2 ∞ ∞ 7 3 ∅ 1 ∅ ∅ 2 2
3 0 ∞ ∞ 5 1 2 ∅ ∅ ∅ 2 2
1 3 0 ∞ 8 4 3 1 ∅ ∅ 2 2
K=3 A= D=
∞ ∞ ∞ 0 ∞ 3 ∅ ∅ ∅ ∅ ∅ 4
4 6 3 ∞ 0 7 3 1 5 ∅ ∅ 2
∞ ∞ ∞ ∞ 2 0 ∅ ∅ ∅ ∅ 6 ∅
0 2 ∞ ∞ 7 3 ∅ 1 ∅ ∅ 2 2
3 0 ∞ ∞ 5 1 2 ∅ ∅ ∅ 2 2
1 3 0 ∞ 8 4 3 1 ∅ ∅ 2 2
K=4 A= D=
∞ ∞ ∞ 0 ∞ 3 ∅ ∅ ∅ ∅ ∅ 4
4 6 3 ∞ 0 7 3 1 5 ∅ ∅ 2
∞ ∞ ∞ ∞ 2 0 ∅ ∅ ∅ ∅ 6 ∅
0 2 10 ∞ 7 3 ∅ 1 5 ∅ 2 2
3 0 8 ∞ 5 1 2 ∅ 5 ∅ 2 2
1 3 0 ∞ 8 4 3 1 ∅ ∅ 2 2
K=5 A= D=
∞ ∞ ∞ 0 ∞ 3 ∅ ∅ ∅ ∅ ∅ 4
4 6 3 ∞ 0 7 3 1 5 ∅ ∅ 2
6 8 5 ∞ 2 0 3 1 5 ∅ 6 ∅
0 2 8 ∞ 5 3 ∅ 1 5 ∅ 6 2
3 0 6 ∞ 3 1 2 ∅ 5 ∅ 6 2
1 3 0 ∞ 6 4 3 1 ∅ ∅ 6 2
K=6 A= D=
9 11 8 0 5 3 3 1 5 ∅ 6 4
4 6 3 ∞ 0 7 3 1 5 ∅ ∅ 2
6 8 5 ∞ 2 0 3 1 5 ∅ 6 ∅
Exemplificăm în continuare cum se determină drumul de cost minim dintre două vârfuri,
precum și costul său. Fie aceste vârfuri 1 și 3. Atunci avem:
- din matricea A se poate vedea care este costul drumului minim de la 1 la 3: acesta
este a13=8;
- pentru a determina care este drumul minim de la 1 la 3, plecăm de la d13=5;
conform definiției matricei D rezultă că vârful 5 este vârful anterior lui 3 pe drumul de
cost minim de la 1 la 3 (în acest moment avem drumul 1, 5, 3); în continuare se consideră
d15=6 și rezultă că vârful anterior lui 5 este 6 (drumul este în acest moment 1, 6, 5, 3);
d16=2, deci vârful anterior lui 6 este 2 (drumul este 1, 2, 6, 5, 3); d12=1 adică este chiar
vârful de plecare, ceea ce înseamnă că am determinat drumul de cost minim: 1, 2, 6, 5, 3.
Asemănător se pot obține și celelalte drumuri de cost minim.
Dacă pentru două vârfuri i și j avem aij=∞, atunci nu există drum de la i la j (de exemplu
a54=∞, deci nu există nici drum de la vârful i la vârful j).
În vederea implementării algoritmului, utilizăm următoarele subprograme:
- subprogramul citire – realizează citirea datelor de intrare din fișierul graf.in și
construiește matricea costurilor A; inițial matricea A se inițializează cu ∞, excepție
diagonala principală care este 0; fișierul conține pe prima linie, separate prin spațiu,
numărul de vârfuri n și numărul de arce m, iar pe fiecare din următoarele m linii, trei
valori, separate prin spațiu, ce reptezintă estremitățile arcului și costul arcului; după
citirea fiecărui arc, se completează în matricea A, costul arcului respectiv;
- subprogramul initD – inițializează matricea D prin intermediul căreia vom
reconstitui drumurile de cost minim;
- subprogramul recursiv drum_minim cu doi parametri i și j, care reconstituie
vârfurile de pe drumul de cost minim de la i la j; aceste vârfuri se obțin în ordine inversă,
deci pentru afisarea lor în ordinea dorită (de la i la j), instrucțiunea de afișare va fi plasată
după apelul recursiv;
- subprogramul afisare – realizează afișarea pentru fiecare pereche de vârfuri între
care există drum, drumul de cost minim (deoarece subprogramul drum_minim obține
doar vârfurile anterioare lui j pe drumul minim de la i la j, inclusiv j și exclusiv i, acesta
din urma fiind afișat separat, înainte de apelul subprogramului drum_minim).
1) Se consideră graful din figura 4.7.1.2. Care este costul drumului minim de la
nodul 1 la nodul 4?
Figura 4.7.1.2
2) Se consideră graful din figura 4.7.1.3. Să se indice un drum de cost minim de la
vârful 1 la vârful 4.
Figura 4.7.1.3
3) Se consideră matricea drumurilor de cost minim din figura 4.7.1.4, asociată unui
graf orientat. Care dintre grafurile de mai jos corespunde matricii date?
1 2 3 4
1 0 4 7 6
2 ∞ 0
3 ∞
3 ∞ ∞ 0 ∞
4 ∞ ∞ 2 0
Figura 4.7.1.4
a) b)
I. Activități de învățare
Vectorul VIZ care marchează nodurile grafului pentru care s-a găsit drum de la
start la ele
Vectorul d ale cărui elemente au următoarea semnificație:
Algoritmul în pseudocod
Figura 4.7.2.1
Fie start=1 și căutăm drumurile de cost minim de la 1 la celelalte noduri ale grafului.
Pasul 1. Pasul 2.
prec=(0,1,0,0,0,1)
Pasul 3.
a) b)
3) Se consideră graful orientat din figura 4.7.2.3. Să se indice două drumuri distincte
de cost minim de la vârful de start la vârful 3.
Figura 4.7.2.3
b. Sarcină de lucru 2 - Implementați în limbaj de programare algoritmul care
determină costul drumului minim de la un nod start la toate celelalte noduri din graf.
Activitatea se poate desfășura individual la calculator urmând algoritmul descris în
lecția teoretică sau pe grupe, la laborator.