Sunteți pe pagina 1din 15

ASD - Grafuri

1
1.1

Algoritmi elementari
Introducere

Def Se numeste graf sau graf neorientat o structura G = (V, E), unde V 6=
este o multime de varfuri si E este o submultime posibil vida a multimii perechilor
neordonate cu componente distincte din V .
Obs:
1. Graful G = (V, E) este graf finit, daca V este o multime finita.
2. Varfurile u, v sunt adiacente in G daca [u, v] E. Intr-un graf neorientat relatia
de adiacenta este simetrica. Se spune si ca muchia [u, v] este incidenta varfurilor u
si v.
3. Intr-un graf neorientat [u, v] si [v, u] sunt considerate a fi aceeasi muchie.
Def Gradul unui varf al unui graf neorientat este nr muchiilor incidente ale acestuia.
Obs: Varful u este izolat daca gradul sau este 0.
Def Un graf orientat sau digraf G este o pereche (V, E) unde V - multimea varfurilor lui G este o multime finita, iar E este o relatie binara pe V . Elementele multimii E se numesc arce. Spunem ca arcul (u, v) este incident din sau pleaca din
varful u si este incident in sau intra in varful v.
Def Un arc care pleaca dintr-un nod u si intra in acelasi nod u se numeste autobucla.

Pentru caracterizarea timpului de rulare a unui algoritm specific grafurilor pe un


G = (V, E) dat, se masoara datele de intrare prin 2 parametri: numar de varfuri |V |
si numar de muchii |E|.
Conventie de notare:
In notatiile asimptotice (notatiile cu O, sau cu ), in mod unic, V denota - card(V)
si E denota card(E). Exemplu: Algoritmul ruleaza in timp O(VE) inseamna ca
ruleaza in timp O(|V ||E|) .

1.2

Reprezentarea grafurilor

Un graf G = (V, E) (orientat sau neorientat) se reprezinta prin:


Liste de adiacenta
Matrice de adiacenta
Listele de adiacenta
In majoritatea algoritmilor, grafurile sunt introduse sub forma de liste de adiacenta.
Sunt indicate in special in reprezentarea grafurilor rare (|E| << |V 2 |). In cazul
grafurilor dense (|E| este aproape de |V 2 |), sau in cazul in care se doreste sa se
cunoasca repede daca exista o muchie care conecteaza doua varfuri date, se prefera
reprezentarea grafurilor prin matrice de adiacenta.
Reprezentarea unui graf prin liste de adiacenta se realizeaza cu cate un vector Adj
asociat fiecarui varf din G. Adj[u] contine toate varfurile v cu proprietatea ca
muchia [u, v] E (toate varfurile adiacente lui u in V ).
Conventie In pseudocod Adj va fi tratat ca un atribut al grafului G si se va nota
de forma G.Adj[u].
Figura 1(b) reprezinta listele de adiacenta asociate grafului neorientat din Figura
1(a). Similar, in Figura 2(b) apar listele de adiacenta asociate grafului orientat (digrafului) din Figura 2(a).
Obs Intr-un graf neorientat suma lungimilor tuturor listelor de adiacenta este cardinalul multimii muchiilor 2|E| iar intr-un graf orientat (digraf) este |E|. In ambele
cazuri reprezentarea listelor de adiacenta se face in timp (V + E).
2

Obs Listele de adiacenta pot fi utilizate cu usurinta in reprezentarea grafurilor


ponderate, adica a grafurilor in care fiecare muchie au asociata o pondere, data in
general printr-o functie ponderata w : E R
Matricea de adiacenta
Se presupune ca varfurile sunt numerotate 1, 2, . . . |V | intr-o maniera arbitrara. Matricea de adiacenta asociata grafului G este A|V ||V | , A = (aij ) unde:
(
1, daca [i, j] E,
aij =
0, altfel.
Figurile 1(c) si 2(c) reprezinta matricele de adiacenta asociate grafurilor din Figurile
1(a), respectiv 2(a).
A = (aij ) se memoreaza in timp (V 2 ) independent de numarul de muchii.
Proprietatile matricei de adiacenta A asociate unui graf neorientat G

1. elementele de pe diagonala principala sunt 0,


2. simetrie fata de diagonala principala (A = AT ),
3. linia corespunzatoare unui nod izolat contine numai 0,
4. suma elementelor de pe fiecare linie i indica gradul nodului i.

Obs Asemeni listelor de adiacenta si matricile de adiacenta pot fi utilizate in


reprezentarea grafurilor ponderate, matricea A modificandu-se astfel:
(
w, daca [i, j] E,
aij =
NIL, altfel.

Figure 1: Reprezentarea unui graf neorientat: a) Graf G cu 6 varfuri si 7 muchii; (b)


Lista de adiacenta a grafului; c) Matricea de adiacenta a grafului

Figure 2: Reprezentarea unui graf orientat: a) Graf G cu 6 varfuri si 7 muchii; (b)


Lista de adiacenta a grafului; c) Matricea de adiacenta a grafului

Parcurgerea in latime

Parcurgerea in latime sta la baza multor algoritmi importanti din teoria grafurilor,
dintre care amintim Algoritmul lui Prim de gasire a arborelui partial de cost minim
al unui graf conex ponderat, sau Algoritmul lui Dijkstra de stabilire a drumului de
cost minim de la un nod de start la oricare altul dintr-un graf.
Fie G = (V, E) si un varf sursa s. Algoritmul de parcurgere in latime (BF) calculeaza distanta (numarul de muchii) dintre varful sursa si fiecare varf la care se
poate ajunge de la s si construieste un arbore de latime (BF) cu radacina in s.
Algoritmul poate fi aplicat atat pe grafuri neorientate cat si pe digrafuri.
Parcurgerea in adancime (BF) gaseste toate varfurile aflate la o distanta k de s inainte de a cauta varfurile de la distanta k + 1.

Pe masura ce se parcurge graful G toate varfurile se coloreaza in alb, gri sau


negru. Initial toate varfurile sunt albe. Daca un varf este gasit pentru prima oara
(nu a mai fost vizitat) se coloreaza. Distinctia se face astfel:
- daca [u, v] E si varful u este negru, atunci varful v poate fi negru sau gri (toate
varfurile adiacente varfurilor negre au fost descoperite);
- nodurile gri reprezinta frontiera intre nodurile vizitate/descoperite si cele nedescoperite
(pot avea noduri albe adiacente).
Contructia unui arbore BF
- radacina este nodul sursa s,
- de fiecare data cand se gaseste un varf alb v cautand in listele de adiacenta asociate
unui nod deja vizitat u, varful v si muchia [u, v] sunt adaugate in arbore (u este
predecesorul lui v).
Fie graful G = (V, E) dat prin listele de adiacenta. Algoritmul de parcurgere
in latime (BFS) ataseaza fiecarui varf u urmatoarele atribute (culoarea - u.color,
predecesorul - u., distanta de la sursa s - u.d). Daca u = s sau u nu a fost inca
descoperit, u. = N IL. Algoritmul foloseste o coada Q pentru gestionarea varfurilor
gri.
BFS (G,s)
1
for each vertex u G.V {s}
2
u.color W HIT E
3
u.d
4
u. N IL
5
s.color GRAY
6
s.d 0
7
s. N IL
8
Q
9
ENQUEUE(Q, s)
10
while Q 6=
11
u DEQUEUE(Q)
12
for each v G.Adj[u]
13
if v.color = W HIT E
14
v.color GRAY
15
v.d u.d + 1
16
v. u
17
ENQUEUE(Q, v)
18
u.color BLACK
5

Figure 3: Parcurgerea in latime (BFS) a unui graf neorientat. Muchiile arborelui sunt
marcate cu rosu pe masura ce se avanseaza.Valoarea lui u.d este calculata pentru
fiecare varf u. Coada Q este afisata la inceputul fiecarei iteratii din ciclul while liniile 10-18. Distanta asociata fiecarui varf este scrisa sub varful introdus in coada.
Procedura BFS este construita astfel:
1. fiecare varf, cu exceptia sursei s, are urmatoarele proprietati: culoare = alb,
distanta = infinit si predecesorul = NIL (liniile 1 - 4);
2. s se coloreaza in gri considerandu-se gasit la inceputul procedurii (linia 5),
atributul distanta devine 0 (linia 6) si predecesorul sursei devine NIL (linia 7);
3. se initializeaza coada Q si se introduce varful sursa (liniile 8 - 9);
4. structura repetitiva while (liniile 10 - 18) se executa atata timp cat exista
varfuri gri (varfuri care sunt descoperite, dar listele lor de adiacenta nu au fost
parcurse in intregime). Invariantul instructiunii repetitive este coada Q care
contine doar varfuri gri (linia 10):
- inaintea primei iteratii Q contine singurul varf gri s;
- se determina u capul cozii si se elimina (linia 11);
- fiecare varf v din lista de adiacenta a nodului u este considerat in structura
repetitiva for (liniile 12 - 17). Daca v este alb (nu a fost inca vizitat) procedura il marcheaza ca gasit (liniile 14 - 17), il coloreaza gri, ii seteaza distanta
ca distanta predecesorului + 1, inregistreaza pe u drept predecesor al lui v si
il introduce pe v in coada.
- u devine negru - toate varfurile adiacente lui au fost vizitate (linia 18).

Analiza complexitatii
Odata lansat in executie algoritmul BFS nu coloreaza niciodata in alb un varf
si deci, testul din linia 13 asigura ca fiecare varf este introdus in coada, si implicit
scos din coada cel mult o data. Operatiile specifice cozii ruleaza in timp O(1), deci
timpul total alocat cozii este O (V).
Deoarece procedura parcurge lista de adiacenta a fiecarui varf doar cand acesta este
scos din coada, parcurgerea listelor se face cel mult o data. Cum suma tuturor
lungimilor listelor de adiacenta este (E), timpul total alocat parcurgerii listelor de
adiacenta este O(E). Initializarea se face in timp O(V) si deci timpul total al rularii
procedurii BFS este O(V+E). Parcurgerea in latime BF ruleaza in timp linear in
cazul unui graf dat prin liste de adiacenta.
Drumul minim
Def Se defineste distanta minima (s, v) de la s la v astfel:
(
numarul minim de muchii de la s la v, daca drum de la s la v
(s, v) =
, altfel.
Lema 1 Fie G = (V, E) un graf neorientat si s V un varf orecare. Atunci, pentru
[u, v] E,
(s, v) (s, u) + 1.
(1)
Demonstratie Daca drum de la s la u, atunci exista drum si de la s la v. In acest
caz, drumul minim de la s la v nu poate fi mai lung decat drumul minim de la s la
u plus muchia [u, v].
Daca @ drum de la u la s, atunci (s, u) = .

Lema 2 Fie G = (V, E) un graf orientat sau neorientat si se apeleaza procedura


BFS pornind de la varful s. Atunci, v V valoarea v.d satisface proprietatea
v.d (s, v).
Demonstratie
Se foloseste inductia pe numarul de adaugari in coada. Ipoteza de inductie este ca
v.d (s, v) v V .
Pas 0/Baza inductiei: adaugarea varfului s in coada (linia 9 in BFS). In acest caz
s.d = 0 = (s, s) iar v.d = (v, s) v V s.
7

Pasul inductiv: Presupunem ca se descopera un varf v in urma parcurgerii listei de


adiacenta asociata unui nod u. Ipoteza de inductie implica u.d (s, u). Folosind
Lema 1 si linia 15 din BFS obtinem:
v.d = u.d + 1
(s, u) + 1
(s, v).
Varful v este adaugat in coada o singura data, pentru ca este colorat gri, iar liniile
14 - 17 se executa doar in cazul varfurilor albe. Deci valoarea v.d nu se mai schimba
iar ipoteza de inductie este mentinuta.
Demonstratia afirmatiei v.d = (s, v) se bazeaza pe modul in care coada este operata in BFS. Lema urmatoare arata ca in orice moment coada tine maxim 2 valori
d distincte.
Lema 3 Presupunem ca in timpul executarii procedurii de parcurgere BFS intr-un
graf G = (V, E) coada Q contine varfurile v1 , v2 , . . . , vr , unde v1 este primul element iar vr este ultimul element din coada. Atunci, vr .d v1 .d + 1 si vi .d vi+1 .d
i = 1, 2, . . . , r 1.
Demonstratie
Se face inductie pe numarul de operatii asurpa cozii.
Pas 0: Initial, cand coada contine doar s lema este triviala.
Pasul inductiv: trebuie demonstrat ca enuntul lemei este valabil si dupa adaugarea
si stergerea unui element. Daca v1 este eliminat, capul cozii devine v2 . Ipoteza de
inductie implica v1 .d v2 .d. Rezulta ca vr .d v1 .d + 1 v2 .d + 1. Deci Lema este
valabila in cazul in care capul cozii este v2 .
In cazul adaugarii unui varf v in coada (linia 17 din BFS), el devine vr+1 . Dar
deja din coada a fost scos nodul u a carei lista de adicaenta este parcursa, iar ipoteza
de inductie implica v1 .d u.d. Rezulta ca vr+1 .d = v.d = u.d + 1 v1 .d + 1.
Tot din ipoteza de inductie avem relatia vr .d u.d + 1 si deci vr .d u.d + 1 = v.d =
vr+1 .d.
Corolarul urmator arata ca valorile distantelor d in momentul introducerii varfurilor in coada, cresc monoton in timp.

Corolar Presupunem ca varfurile vi si vj sunt introduse in coada, in aceasta


ordine, in timpul executiei procedurii BFS. Atunci vi .d vj .d in momentul cand vj
este adaugat.
Demonstratia este imediata folosind rezultatul Lemei 3 si proprietatea ca fiecare
varf primeste o valoare finita d cel mult o data in timpul BFS.
Teorema (Corectitudinea algoritmului de parcurgere in adancime BF)
Fie G = (V, E) un graf neordonat sau ordonat parcurs prin procedura BFS
pornind de la varful sursa s. BFS gaseste toate varfurile v V la care se poate
ajunge pornind de la s, iar v.d = (s, v)v V . In plus, pentru v 6= s la care se
poate ajunge de la s, unul din cele mai scurte drumuri de la s la v este drumul minim
de la s la v. plus muchia [v., v].
Demonstratie:
Folosim metoda reducerii la absurd. Presupunem ca unele varfuri primesc o
valoare pentru d care nu reprezinta lungimea drumului minim. Fie v varful cu (v, s)
minim care primeste o astfel de valoare incorecta pentru parametrul d. Evident v 6= s.
In Lema 2 s-a demonstrat ca v.d (s, v), deci, in cazul actual, v.d (s, v). Fie u
varful care precede pe v in drumul minim de la s la v, astfel incat (s, v) = (s, u)+1.
Datorita proprietatii (s, u) < (s, v) si selectarii modului de a fi ales v obtinem
u.d = (s, u). Punand impreuna toate aceste proprietati, rezulta ca:
v.d > (s, v) = (s, u) + 1 = u.d + 1.

(2)

In momentul in care varful u este scos din coada, varful v este alb, gri sau negru.
In fiecare din aceste cazuri contradictia va fi aratata. Daca v este alb, linia 15 din BFS
implica v.d = u.d + 1 contrazicand inegalitatea 2. Daca este negru, atunci inseamna
ca a fost deja scos din coada si conform Corolarului v.d u.d, iarasi contrazicand
2. Daca v este gri, atunci un varf oarecare w pentru care v.d = w.d + 1 a fost scos
din coada. Corolarul implica w.d u.d si deci se obtine v.d = w.d + 1 u.d + 1
contrazicand 2.
Concluzionand, se poate observa ca daca v. = u, atunci v.d = u.d + 1 si deci,
se poate obtine drumul minim de la s la v luand drumul minim de la s la v. si
adaugand muchia [v., v].

2.1

Arbori de latime (Breadth First Trees)

Procedura BFS construieste un arbore pe masura ce graful G = (V, E) este parcurs. Arborele corespunde atributelor (precedentilor). Mai formal, pentru un graf
G = (V, E) cu varful sursa s, se defineste graful predecesor al lui G astfel:
G = (V , E ), unde V = {v V : v. 6= N IL} {s}
and E = {[v., v] : v V {s}}.
Graful predecesor G este un arbore in latime daca V contine varfurile la care
se poate ajunge pornind de la s si, pentru v V., graful G contine un drum
minim unic de la s la v. Un arbore de latime este un arbore deoarece este conex si
|E.| = |V.| 1.
Lema 6 Graful predecesor G = (V , E ), obtinut prin BFS pornind de la graful
initial, este arbore de latime.
Demonstratie:
v. = u = [u, v] E si (s, v) < (linia 16 dn BFS). V contine varfurile v la care
se poate ajunge pornind de la sursa s. Cum G este arbore, atunci contine un drum
minim unic de la s la fiecare varf din V . Aplicand inductiv Teorema 1 se poate
demonstra ca fiecare asfel de drum este drum minim in G.
Procedura PRINT-PATH afiseaza varfurile celui mai mic drum de la s la v,
presupunand ca BFS a creat deja un arbore de latime.

1
2
3
4
5
6

PRINT-PATH (G,s,v)
if v = s
print s
elseif v. N IL
print no path from s to v exists
else PRINT-PATH (G,s,v.)
print v

Aceasta procedura ruleaza in timp liniar in numarul de varfuri ale drumului


deoarece fiecare apel recursiv se face pentru un varf in minus.

10

Parcurgerea in adancime

Algoritmul de parcurgere in adancime (DFS) exploreaza muchiile incidente (nemarcate) ale celui mai recent varf descoperit v. Daca toate muchiile incidente varfului v
au fost explorate, se face cautarea muchiilor neexplorate ale varfului anterior de la
care v este descoperit in urma parcurgerii DFS. Procesul continua pana cand toate
varfurile la care se poate ajunge de la sursa s, au fost descoperite.
Obs Daca raman varfuri nedescoperite (graful nu este conex), DFS selecteaza
unul dintre ele drept noua sursa si repeta cautarea pornind de la el. Algoritmul
se repeta pana cand toate nodurile au fost descoperite. Ca si in cazul algoritmului de parcurgere in latime (BFS), atributul ia valoarea predecesorului varfului v
(v. = u) cand procedura DFS descopera un varf v in urma parcurgerii listei de
adiacenta a unui nod deja vizitat u.
Obs Spre deosebire de BFS unde subgraful predecesor era un arbore, in cazul
DFS el poate fi format din mai multi arbori deoarece cautarea se poate face pornind
de la mai multe surse. Astfel ca definitia unui graf predecesor difera usor fata de
BF: G = (V, E ) unde E = {[v., v] : v V si v. 6= N IL}.
Subgraful predecesor obtinut printr-un DFS formeaza o padure de adancime (DF)
continand cativa arbori de adancime. Muchiile din E reprezinta muchiile arborelui.
Ca si in cazul BFS, algoritmul DFS coloreaza varfurile pe masura ce sunt vizitate
pentru a indica starea. Fiecare varf este initial alb, devine gri cand este descoperit
in urma parcurgerii si negru cand lista lui de adiacenta a fost complet parcursa.
Aceasta tehnica garanteaza ca fiecare varf apare intr-un arbore de adancime unic si
deci arborii de adancime sunt disjuncti.
Algoritmul DFS eticheteaza temporal fiecare varf v astfel: v.d inregistreaza momentul in care varful este descoperit prima data (si colorat in gri), iar v.f inregistreaza momentul in care lista de adiacenta a lui v a fost complet traversata (varful
devine negru).
Procedura DFS inregistreaza in atributul u.d momentul descoperirii si in atributul
u.f momentul terminarii procesarii lui u. Aceste marcaje sunt numere intregi intre
1 si 2|V | deoarece exista un eveniment unic de descoperire si de terminare u V :
u.d < u.f
11

(3)

Varful u este alb inaintea initierii momentului u.d, gri intre u.d si u.f si negru
dupa.
Pseudocod-ul urmator prezinta algoritmul DFS. Graful poate fi neorientat sau
orientat. Variabila time este folosita pentru etichetare.

1
2
3
4
5
6
7

DFS (G)
for each vertex u G.V
u.color W HIT E
u. N IL
time 0
for each vertex u G.V
if u.color = W HIT E
DFS VISIT(G, u)

1
2
3
4
5
6
7
8
9
10

DFS-VISIT(G,u)
time time + 1
u.d time
u.color GRAY
for each v G.Adj[u]
if v.color = W HIT E
v. u
DFS VISIT(G, v)
u.color BLACK
time time + 1
u.f time

Figura 4 ilustreaza algoritmul de parcurgere in adancime (DFS) pe graful din Fig.


2.

12

Figure 4: Parcurgerea in adancime (DFS) a unui graf orientat. Pe masura ce muchiile


grafului sunt explorate de algoritm, ele fie sunt colorate in rosu (daca fac parte din
arborele de adancime), fie punctate si etichetate B (back), C(cross), sau F(forward).
Fiecare varf retine etichetele temporale: timpul descoperirii si timpul finalizarii.

13

Procedura DFS functioneaza astfel:


1. pentru toate varfurile color = white si = N IL (liniile 1 - 3);
2. resetarea timpului global (linia 4);
3. fiecare varf este vizitat pe rand si daca este alb atunci il viziteaza utilizand
procedura DFS-VIZIT (liniile 5 - 7). De fiecare data cand DFS-VIZIT(G,u)
este apelata in linia 7. Varful u devine radacina unui nou arbore din padurea
de adancime. Iesirea din DFS asigura fiecarui nod u un timp de descoperire
u.d si un timp de finalizare u.f .

Procedura DFS-VIZIT(G,u) functioneaza astfel:


1. initial u este alb,
2. incrementarea timpului global (linia 1),
3. u.d este setat ca noua valoare a variabilei time (linia 2),
4. u devine gri (linia 3),
5. fiecare varf v adiacent cu u este verificat si vizitat in mod recursiv daca este
alb (liniile 4 - 7). Pe masura ce fiecare v Adj[u] este considerat (linia 4),
muchia [u, v] este explorata prin DFS,
6. cand toate muchiile incidente cu u au fost explorate, u devine negru, timpul
este incrementat si timpul final u.f este inregistrat.

Obs Rezultatul parcurgerii in adancime depinde de ordinea in care varfurile sunt


examinate de DFS (linia 5) si de ordinea in care DFS-VISIT exploreaza vecinii unui
varf.

14

Analiza complexitatii
Loop-urile liniilor 1 - 3 si, respectiv, 5 - 7 se realizeaza in timp (V ) independent
de timpul apelurilor procedurii DFS-VIZIT. Procedura DFS-VIZIT este apelata
exact o singura data v V deoarece varful u pe care se aplica procedura trebuie sa
fie alb, iar actiune a procedurii DFS este de a colora varful vizitat in gri. In timpul
unei executii a DFS-VIZIT(G,v) codul din liniile 4 - 7 se executa de |Adj[v]| ori.
Dar:
X
|Adj[v]| = (E),
vV

Costul total al liniilor 4 - 7 este (E).


In concluzie, timpul de rulare al algoritmului de parcurgere in adancime (DFS) este
(V + E).

15