Sunteți pe pagina 1din 213

Cuprins

1 Introducere n algoritmi 3
1.1 Limbajul pseudocod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.3 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2 Elemente de analiza algoritmilor 23
2.1 Metoda substitut iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.2 Schimbarea de variabila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.3 Metoda iterativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.4 Teorema master . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.5 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3 Grafuri. Grafuri neorientate 34
3.1 Not iuni de baza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2 Operat ii pe grafuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.3 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.4 Parcurgerea grafurilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.4.1 Parcurgerea n lat ime (BF-Breadth-First) . . . . . . . . . . . . . . . . . 46
3.4.2 Parcurgerea D (D - Depth) . . . . . . . . . . . . . . . . . . . . . . . . 50
3.4.3 Parcurgerea n adancime (DFS-Depth First Search) . . . . . . . . . . . 51
3.5 Componente conexe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.6 Muchie critica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.7 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
4 Grafuri euleriene si hamiltoniene 64
4.1 Grafuri Euleriene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
4.1.1 Algoritm pentru determinarea unui ciclu eulerian . . . . . . . . . . . . 65
4.1.2 Algoritmul lui Rosenstiehl . . . . . . . . . . . . . . . . . . . . . . . . . 68
4.1.3 Algoritmul lui Fleury . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4.2 Grafuri Hamiltoniene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
4.2.1 Problema comisvoiajorului . . . . . . . . . . . . . . . . . . . . . . . . 76
5 Arbori. Arbori binari 87
5.1 Arbori binari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5.1.1 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
5.1.2 Metode de parcurgere . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.2 Arbori binari de cautare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5.3 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
1
6 Arbori oarecare 109
6.1 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
6.2 Metode de parcurgere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
6.3 Arbori de acoperire de cost minim . . . . . . . . . . . . . . . . . . . . . . . . . 117
6.3.1 Algoritmul lui Boruvka . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
6.3.2 Algoritmul lui Prim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
6.3.3 Structuri de date pentru mult imi disjuncte . . . . . . . . . . . . . . . . 123
6.3.4 Algoritmul lui Kruskal . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
6.4 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
7 Grafuri orientate 134
7.1 Not iuni de baza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
7.2 Parcurgerea grafurilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
7.3 Sortarea topologica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
7.4 Componente tare conexe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
7.4.1 Algoritmul lui Kosaraju . . . . . . . . . . . . . . . . . . . . . . . . . . 144
7.4.2 Algoritmul lui Tarjan . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
7.4.3 Algoritmul lui Gabow . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
7.5 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
8 Distant e n grafuri 156
8.1 Drumul minim de la un varf la celelalte varfuri . . . . . . . . . . . . . . . . . . 157
8.1.1 Algoritmul lui Moore . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
8.1.2 Algoritmul lui Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
8.2 Drumuri minime ntre toate perechile de varfuri . . . . . . . . . . . . . . . . . 166
8.2.1 Algoritmul lui Roy-Floyd-Warshall . . . . . . . . . . . . . . . . . . . . 166
8.3 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
9 Fluxuri n ret ele de transport 174
9.1 Ret ea de transport. Flux. Taietura . . . . . . . . . . . . . . . . . . . . . . . . 174
9.2 Graf rezidual. Drum de ameliorare. Flux maximtaietura minima . . . . . . . 178
9.3 Metoda Ford-Fulkerson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180
9.3.1 Algoritmul Ford-Fulkerson (varianta) . . . . . . . . . . . . . . . . . . . 182
9.4 Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
A Probleme. Algoritmi. Complexitate 188
A.0.1 Vericare n timp polinomial . . . . . . . . . . . . . . . . . . . . . . . . 190
A.0.2 Reduceri polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
B Metoda Backtracking 193
2
Capitolul 1
Introducere n algoritmi
Denit ia 1.1 Algoritmul constituie o reprezentare nita a unei metode de calcul ce per-
mite rezolvarea unei anumite probleme. Se poate spune ca un algoritm reprezinta o secvent a
nita de operat ii, ordonata si complet denita, care, pornind de la datele de intrare, produce
rezultate.
Termenul de algoritm i este atribuit matematicianului persan Abu Jafar Mohammed
ibn Musa al-Khowarizmi (sec. VIII-IX), care a scris o carte de matematica cunoscuta n
traducere latina sub titlul de Algorithmi de numero indorum, iar apoi ca Liber algorithmi,
unde algorithm provine de la al-Khowarizmi, ceea ce literal nseamna din orasul Khowarizm.
Matematicienii din Evul Mediu nt elegeau prin algoritm o regula (sau o mult ime de reguli)
pe baza careia se efectuau calcule aritmetice: de exemplu n secolul al XVI-lea, algoritmii se
foloseau la nmult iri sau njumatat iri de numere.
Fiecare propozit ie ce face parte din descrierea unui algoritm este de fapt o comanda ce
trebuie executata de cineva, acesta putand o persoana sau o masina de calcul. De altfel,
un algoritm poate descris cu ajutorul oricarui limbaj, de la limbajul natural si pana la
limbajul de asamblare al unui calculator. Denumim limbaj algoritmic un limbaj al carui scop
este acela de a descrie algoritmi.
Algoritmul specica succesiuni posibile de transformari ale datelor. Un tip de date poate
caracterizat printr-o mult ime de valori ce reprezinta domeniul tipului de date si o mult ime
de operat ii denite peste acest domeniu. Tipurile de date pot organizate n urmatoarele
categorii:
1. tipuri de date elementare (de exemplu tipul ntreg, tipul real ) - valorile sunt unitat i
atomice de informat ie;
2. tipuri de date structurate (de exemplu tipul tablou, tipul nregistrare) - valorile sunt
structuri relativ simple rezultate n urma combinat iei unor valori elementare;
3. tipuri de date structurate de nivel nalt (de exemplu stiva) - se pot descrie independent
de limbaj iar valorile au o structura mai complexa.
Un algoritm trebuie sa posede urmatoarele trasaturi caracteristice:
1. claritate - la ecare pas trebuie sa specice operat ia pe care urmeaza sa o efectueze
algoritmul asupra datelor de intrare;
2. corectitudine - rezultatele trebuie sa e corecte;
3
3. generalitate - algoritmul trebuie sa ofere solut ia nu numai pentru o singura problema
ci pentru o ntreaga clasa de probleme;
4. nitudine - algoritmul trebuie sa se termine ntr-un timp nit;
5. ecient a - un algoritm poate utilizat numai n situat ia n care resursele de calcul
necesare acestuia sunt n cantitat i rezonabile, si nu depasesc cu mult posibilitat ile cal-
culatoarelor la un moment dat.
Un program reprezinta implementarea unui algoritm ntr-un limbaj de programare.
Studiul algoritmilor cuprinde mai multe aspecte:
elaborare - activitatea de concepere a unui algoritm are si un caracter creativ, din
aceasta cauza neind posibila deprinderea numai pe cale mecanica. Pentru a facilita
obt inerea unei solut ii la o problema concreta se recomanda folosirea tehnicilor generale
de elaborare a algoritmilor la care se adaugan mod hotarator intuit ia programatorului;
exprimare - implementarea unui algoritm intr-un limbaj de programare se poate face
utilizand mai multe stiluri: programare structurata, programare orientata pe obiecte
etc.;
validare - vericarea corectitudinii algoritmului prin metode formale;
analiza - stabilirea unor criterii pentru evaluarea ecient ei unui algoritm pentru a-i
putea compara si clasica.
Un model de reprezentare al memoriei unei masini de calcul este acela al unei structuri
liniare compusa din celule, ecare celula ind identicata printr-o adresa si putand pastra o
valoare corespunzatoare unui anumit tip de data. Accesul la celule este facilitat de variabile.
O variabila se caracterizeaza prin:
un identicator - un nume ce refera variabila;
o adresa - desemneaza o locat ie de memorie;
un tip de date - descrie tipul valorilor memorate n celula de memorie asociata.
1.1 Limbajul pseudocod
Limbajul natural nu permite o descriere sucient de riguroasa a algoritmilor, de aceea, pentru
reprezentarea acestora se folosesc alte modalitat i de descriere precum:
scheme logice;
limbajul pseudocod.

In continuare vom prezenta pricipalele construct ii din cadrul limbajului pseudocod.


Intrari/iesiri
Citirea datelor de intrare se poate realiza prin intermediul enunt ului Input:
1: Input {lista variabile}
Asarea rezultatelor este reprezentata cu ajutorul instruct iunii Output:
1: Output {lista de valori}
4
Instruct iunea de atribuire
Este instruct iunea cel mai des utilizata ntr-un algoritm si realizeaza ncarcarea unei variabile
(locat ii de memorie) cu o anumita valoare. Are urmatoarea sintaxa:
1: < variabila >< expresie >
unde < expresie > este o expresie aritmetica sau logica.
Se evalueaza expresia < expresie > iar rezultatul se atribuie variabilei < variabila >,
memorandu-se n locat ia de memorie asociata. Aceasta variabila trebuie sa e de acelasi tip
de data cu expresia sau un tip de data care sa includa si tipul expresiei.
O expresie este constituita din operanzi si operatori. Operanzii pot variabile si valori
constante, iar operatorii pot :
operatori aritmetici - + (adunare), (scadere), (nmult ire), / (mpart ire), (ridicare
la putere), div (catul mpart irii ntregi), mod (restul mpart irii ntregi);
operatori relat ionali - = (egal), = (diferit), < (strict mai mic), (mai mic sau egal),
> (strict mai mare), (mai mare sau egal);
operatori logici - OR sau (disjunct ie), AND sau (conjunct ie), NOT sau (negat ie).
Cea mai simpla expresie este formata dintr-o variabila sau o constanta (operand). Ex-
presiile mai complicate se obt in din operat ii efectuate ntre variabile si constante. La scrierea
expresiilor trebuie sa se t ina cont de faptul ca, n momentul evaluarii lor, n primul rand
se vor evalua expresiile din paranteze, iar operat iile se executa n ordinea determinata de
prioritat ile lor.
Enunt uri de ramicare
1: if <expresie-booleana> then
2: <instructiune1>
[
3: else
4: <instructiune2>
]
5: end if
1: if (a mod 2 = 0) then
2: Output {Numarul este par }
3: else
4: Output {Numarul este impar }
5: end if
Enunt ul if...then...else evalueaza mai ntai expresia booleana pentru a determina
unul din cele doua drumuri pe care le poate lua execut ia algoritmului. Ea poate include
opt ional o clauza else.
Daca <expresie-booleana> se evalueaza la valoarea de adevar true, atunci se executa
<instructiune1>si se continua cu urmatoarea instruct iune dupa if. Daca <expresie-booleana>
are valoarea de adevar false, atunci se executa <instructiune2>. <instructiune1>si <instructiune2>
sunt instruct iuni compuse ce pot sa cont ina, la randul lor, o alta instruct iune if.
Exemplul 1.1 Un algoritm simplu este cel ce rezolva ecuat ia de gradul I, ax+b = 0, a, b R
(algoritmul 1). Acesta se bazeaza pe rezolvarea matematica generala a ecuat iei de gradul I:
1. daca a = 0, atunci ecuat ia devine 0 x + b = 0. Pentru cazul n care b = 0 avem
0 x +b = 0, egalitate ce nu poate satisfacuta pentru nicio valoare a lui x R sau C.
Spunemn acest caz ca ecuat ia este incompatibila. Daca b = 0, avem 0x+0 = 0, relat ia
ind adevarata pentru orice valoare a lui x R. Spunem ca ecuat ia este compatibil
nedeterminata.
5
Algoritm 1 Algoritm pentru rezolvarea ecuat iei de gradul I
1: Input {a, b}
2: if (a = 0) then
3: if (b = 0) then
4: Output { Ecuatie compatibil nedeterminata }
5: else
6: Output { Ecuatie incompatibila }
7: end if
8: else
9: x
b
a
10: Output { Solutia este:, x }
11: end if
2. daca a = 0, ecuat ia are o singura solut ie, x
1
=
b
a
R.
Avand acest algoritm drept model sa se realizeze un algoritm pentru rezolvarea ecuat iei de
gradul al II-lea, ax
2
+bx +c = 0, unde a, b, c R.
Enunt uri repetitive
Enunt urile repetitive permit descrierea unor prelucrari ce trebuie efectuate n mod repetat,
n funct ie de pozit ia condit iei de continuare existand doua variante de structuri repetitive:
structura repetitiva condit ionata anterior si structura repetitiva condit ionata posterior.
Structura repetitiva condit ionata anterior while (sau instruct iune de ciclare cu test init ial)
are sintaxa:
1: while <expresie-booleana> do
2: <instructiune>
3: end while
1: sum 0
2: i 1
3: while (i n) do
4: sum sum + i
5: i i + 1
6: end while
Cat timp <expresie-booleana>este adevarata, se executa <instructiune>; daca <expresie-
booleana> este falsa chiar la prima evaluare atunci <instructiune> nu ajunge sa e realizata
niciodata. Acest comportament este exact opus celui corespunzator structurii repetitive
condit ionata posterior repeat, unde <instructiune> este executata cel put in o data. (Daca
o expresie are valoarea de adevar true spunem atunci ca expresia este adevarata; daca o
expresie are valoarea de adevar false spunem atunci ca expresia nu este adevarata este
falsa).
Exemplul 1.2 Vom realiza un algoritm pentru calculul catului si restului mpart irii a doua
numere ntregi, prin scaderi succesive (vezi algoritmul 2).
Mai ntai se init ializeaza catul cu valoarea zero (linia 3) si restul cu valoarea dempart itului
(linia 4). Apoi, atata timp cat restul este mai mare decat valoarea mpart itorului (liniile 5 -
8), vom incrementa catul cu o unitate, si decrementa restul cu valoarea mpart itorului. La
nal, sunt asate valorile catului si restului.
Un caz particular de structura repetitiva condit ionat a anterior este for, utilizata n cazul
n care o instruct iune sau un grup de instruct iuni trebuie sa se repete de 0 sau mai multe
ori - numarul de repetit ii ind cunoscut nainte de nceperea sa. Enunt urile repetitive bazate
6
Algoritm 2 Algoritm pentru calculul mpart irii ntregi
1: Input {a, b}
2: if ((a > 0) (b > 0)) then
3: cat 0
4: rest a
5: while (rest b) do
6: rest rest b
7: cat cat + 1
8: end while
9: Output {cat, rest}
10: else
11: Output {Numerele trebuie sa e strict pozitive!}
12: end if
pe instruct iunile while si repeat sunt mult mai potrivite n cazul n care condit ia de ter-
minare trebuie reevaluata n timpul ciclarii (atunci c and numarul de repetit ii nu este cunoscut
apriori).
Instruct iunea for are urmatoarea sintaxa:
1: for <Var> <Expresie1>, <Expresie2>,
Step < p > do
2: <instructiune>
3: end for
1: sum 0
2: for i 1, n do
3: sum sum + i
4: end for
Comportamentul enunt ului repetitiv for se descrie cel mai bine prin comparat ie cu
enunt ul repetitiv while. Astfel secvent a urmatoare de limbaj pseudocod
1: for v e
1
, e
2
STEP p do
2: < instructiune >
3: end for
este echivalenta cu secvent a ce cont ine enunt ul repetitiv while:
1: v e
1
2: while (v e
2
) do
3: <instructiune>
4: v v + p
5: end while
e
1
reprezinta valoarea init iala, e
2
limita nala, iar p pasul de lucru: la ecare pas, valoarea
variabilei v este incrementata cu valoarea lui p, ce poate atat pozitiva cat si negativa. Daca
p 0 atunci v va lua valori n ordine crescatoare, iar daca p < 0 atunci v va primi valori n
ordine descrescatoare.

In cazul n care pasul de incrementare este 1, atunci el se poate omite din enunt ul repetitiv
for, variabila contor ind incrementata automat la ecare repetit ie cu valoarea 1. Daca pasul
de incrementare p are valoarea 1 atunci avem urmatoarele situat ii posibile pentru construct ia
for:
Expresie1 > Expresie2: <instructiune> nu se executa niciodata;
Expresie1 = Expresie2: <instructiune> se executa exact o data;
Expresie1 < Expresie2: <instructiune> se executa de Expresie2Expresie1+1 ori.
Exemplul 1.3 Un caz destul de frecvent ntalnit n practica este cel n care se cere aarea
elementului maxim, respectiv minim dintr-un sir de elemente. Acest sir de elemente poate
7
pastrat ntr-o structura de date elementara, cunoscuta sub numele de vector. Un vector este
un caz particular de matrice avand o singura linie si n coloane.
Prezentam n continuare algoritmul pentru determinarea elementului de valoare minima
ce face parte dintr-un sir de numere naturale (vezi algoritmul 3).
Algoritm 3 Algoritm pentru calculul elementului de valoare minima dintrun sir
1: Input {N, x
1
, x
2
, ..., x
N
}
2: min x
1
3: for i 2, N do
4: if (min > x
i
) then
5: min x
i
6: end if
7: end for
8: Output { min }

In acest algoritm se observa utilizarea enunt ului repetitiv for, ntalnit, n general, n
situat iile n care se cunoaste apriori numarul de pasi pe care trebuie sa-l realizeze instruct iunea
repetitiva.
Mai ntai se init ializeaza variabila min cu x
1
, presupunand ca elementul de valoare
minima este primul element din cadrul vectorului X (linia 2).

In continuare vom com-
para valoarea variabilei min cu valoarea ecarui element din sir (liniile 37): daca vom gasi
un element a carui valoare este mai mica decat cea a minimului calculat pana la momentul
curent (linia 4), vom ret ine noua valoare n variabila min (linia 5).
Structura repetitiva condit ionata posterior repeat. . .until prezinta urmatoarea sintaxa:
1: repeat
2: <instructiune>
3: until <expresie-booleana>
1: sum 0
2: i 1
3: repeat
4: sum sum + i
5: i i + 1
6: until (i > n)
Atata timp cat <expresie-booleana> este falsa, se executa <instructiune>. Se observa
faptul ca instruct iunile dintre repeat si until se vor executa cel put in o data.
Exemplul 1.4 Algoritmul 4 prezentat n continuare calculeaza suma primelor n numere
naturale, S = 1 + 2 + 3 +. . . +n.
Notam cu S
n
suma primelor n numere naturale (S
n
= 1 + 2 + 3 + . . . + n). Aceasta se
poate calcula ntr-o maniera incrementala astfel:
S
1
= 1
S
2
= 1 + 2 = S
1
+ 2
S
3
= (1 + 2) + 3 = S
2
+ 3
S
4
= (1 + 2 + 3) + 4 = S
3
+ 4
. . .
S
n
= (1 + 2 +. . . +n 1) +n = S
n1
+n
Observat ia 1.5 1. Algoritmul 4 utilizeaza enunt ul repetitiv cu test nal, repeat ...until.
8
Algoritm 4 Algoritm pentru calculul sumei primelor n numere naturale (prima varianta)
1: Input {N}
2: S 0
3: i 1
4: repeat
5: S S + i
6: i i + 1
7: until (i > N)
8: Output {S}
2. Enunt urile S 0 si i 1 au rolul de a atribui valori init iale variabilelor S si i.

Intotdeauna variabilele trebuie init ializate corect din punctul de vedere al algoritmului
de calcul. Variabila ce ret ine rezultatul unui proces de nsumari succesive se va init ializa
ntotdeauna cu 0, valoare ce nu va inuent a rezultatul nal. O variabila ce pastreaza
rezultatul unei sume sau al unui produs se va init ializa cu elementul neutru fat a de
operat ia respectiva.
3. Atribuirile i = i +1 si S = S +i (liniile 5 si 6) sunt lipsite de sens din punct de vedere
algebric.

Insa atunci cand ne referim la un sistem de calcul electronic, aceste operat ii
se refera la valoarea curenta si la cea anterioara a unei variabile. De asemenea, trebuie
sa se faca o distinct ie clara ntre operat ia de atribuire si cea de egalitate: operat ia de
atribuire () face ca valoarea curenta a variabilei din stanga operatorului de atribuire
sa e init ializata cu valoarea expresiei din dreapta acestuia (n expresia k i + 2
variabila k primeste valoarea rezultata n urma evaluarii expresiei i + 2), pe cand
operat ia de egalitate verica daca valoarea elementului din stanga operatorului = (sau
a expresiei aate n partea stanga a operatorului) este egala cu valoarea expresiei din
dreapta acestuia (de exemplu rezultatul evaluarii expresiei k = i + 2) are valoarea de
adevar true daca valoarea variabilei k este egala cu valoarea rezultata n urma evaluarii
expresiei i + 2 si are valoarea de adevar false n caz contrar).
Prin urmare, n cazul expresiei i i +1, valoarea curenta a variabilei i devine valoarea
anterioara a aceleiasi variabile incrementata cu o unitate.
Suma primelor n numere naturale se constituie n suma termenilor unei progresii arit-
metice ce se poate calcula direct cu formula sumei, astfel 1 + 2 + . . . + n =
n(n+1)
2
. Avand
n vedere aceasta identitate, algoritmul de calcul a sumei primelor n numere naturale se
simplica foarte mult (vezi algoritmul 5).
Algoritm 5 Algoritm pentru calculul sumei primelor n numere naturale (a doua varianta)
1: Input {N}
2: S n (n + 1)/2
3: Output {S}
Proceduri si funct ii
Procedurile sunt subrutine ale caror instruct iuni se executa ori de cate ori acestea sunt apelate
prin numele lor.
9
Apelarea procedurilor se face n unitatea de program apelanta prin numele procedurii,
primit la denire, urmat de lista parametrilor actuali. Aceasta trebuie sa corespunda ca
numar si tip cu lista parametrilor formali, n situat ia n care exista o lista de parametri
formali n antetul subrutinei. Denit ia unei proceduri are urmatoarea sintaxa:
1: procedure <nume>(<lista parametri formali>)
2: <instructiune>
3: end procedure
lista parametri formali (opt ionala) simbolizeaza o lista de identicatori (parametri) ce
permite transferul datelor ntre subrutina apelanta si subrutina apelata. Acesti parametri se
specica prin nume (identicator) urmat, eventual, de tipul de data al parametrului. Mai
mult i parametri de acelasi tip pot grupat i, folosindu-se drept separator virgula.
De fapt, lista parametrilor formali poate descrisa mai detaliat astfel:
1: procedure <nume>(<PFI; PFO>)
2: end procedure
unde
PFI = lista parametrilor formali de intrare.
PFO = lista parametrilor formali de iesire.
Enunt ul de apel al unei proceduri are urmatoarea sintaxa:
1: CALL <nume>(PAI; PAO)
PAI - lista parametrilor actuali de intrare, ce corespund parametrilor formali de intrare.
Corespondent a se face de la stanga la dreapta si trebuie sa e de acelasi tip cu parametrii
formali.
PAO - lista parametrilor actuali de iesire.
Exemplul 1.6 Sa se realizeze un algoritm care determina cel mai mare divizor comun a
doua numere naturale.
Reamintim cateva rezultate teoretice ce vor folositoare pentru nt elegerea procesului de
calcul al algoritmului ce va prezentat.
Teorema 1.7 (Teorema mp art irii cu rest) Pentru doua numere ntregi a si b, cu b =
0, doua numere ntregi q si r, unice, astfel ncat:
a = b q +r, 0 r < |b|
unde a se numeste dempart itul, b mpart itorul, q catul iar r restul.
Denit ia 1.2 Cel mai mare divizor comun (notat cmmdc) a doua numere naturale a si b
este un numar natural d cu proprietat ile:
1. d|a, d|b (d este un divizor comun al lui a si b)
2. d

N astfel ncat d

|a, d

|b avem d

|d (oricare alt divizor comun al lui a si b, l divide


si pe d).
Observat ia 1.8 1. cmmdc(a, 0) = a.
2. Daca cmmdc(a, b) = 1 se spune ca numerele a si b sunt prime ntre ele.
3.

Intre cel mai mic multiplu comun si cel mai mare divizor comun exista urmatoarea
relat ie:
cmmmc(a, b) =
a b
cmmdc(a, b)
(1.1)
10
Metoda de calcul pentru a obt ine cel mai mare divizor comun a doua numere a si b prin
mpart iri succesive, cunoscuta sub numele de algoritmul lui Euclid, se poate descrie astfel:
Se mparte a la b si se ret ine restul r. Daca r este nul atunci cel mai mare divizor comun
este b.

In caz contrar, se mparte b la r si se pastreaza noul rest. Calculele se continua,
folosindu-se ca dempart it vechiul mpart itor iar ca mpart itor ultimul rest obt inut, pana
cand restul obt inut devine nul.
Operat iile anterioare pot transpuse prin intermediul urmatoarelor formule matematice:
a = bq
1
+r
1
0 r
1
< b
b = r
1
q
2
+r
2
0 r
2
< r
1
r
1
= r
2
q
3
+r
3
0 r
3
< r
2
. . .
r
k
= r
k+1
q
k+2
+r
k+2
0 r
k+2
< r
k+1
. . .
r
n2
= r
n1
q
n
+r
n
0 r
n
< r
n1
r
n1
= r
n
q
n+1
+r
n+1
0 r
n+1
< r
n
Aceste mpart iri nu se constituie ntr-un proces innit, deoarece secvent a de numere natu-
rale r
1
, r
2
, . . . , r
n+1
, . . . este strict descrescatoare (r
1
> r
2
> . . . > r
n
> . . .) si marginita
inferior de 0. Rezulta ca p N astfel ncat r
p
= 0, si r
p+1
= 0.
Algoritm 6 Algoritmul lui Euclid pentru calculul cmmdc a doua numere
1: procedure cmmdc(x, y; b)
2: a x
3: b y
4: if (b = 0) then
5: b a
6: else
7: r a mod b
8: while (r = 0) do Procesul se ncheie atunci cand r ia valoarea 0
9: a b
10: b r
11: r a mod b
12: end while
13: end if
14: end procedure
Daca analizamntregul proces de calcul, se observa faptul ca dempart itul estempart itorul
de la etapa anterioara, iar mpart itorul este restul de la etapa anterioara. De asemenea, tre-
buie ment ionat ca n acest proces de calcul catul nu participa activ.
Algoritmul 6 este un foarte bun exemplu de utilizare a instruct iunii de ciclare cu test
init ial, while. Din analiza algoritmului reiese faptul ca, mai ntai se efectueaza o evaluare a
restului r (calculul sau, liniile 7 si 11), dupa care se testeaza condit ia egalitat ii acestuia cu 0
(linia 8).
Funct iile au aceeasi sintaxa ca si procedurile:
1: function <nume>(<parametri>)
2: <instructiune>
3: end function
Funct iile pot apelate prin numele lor, ca termen al unei expresii.
11
1.2 Exemple
Exemplul 1.9 Sa se verice printr-un algoritm daca un numar natural este prim sau nu.
Denit ia 1.3 Un numar natural k 2 se numeste prim daca singurii sai divizori naturali
sunt 1 si k.
Pe baza acestei denit ii se poate concluziona ca un numar natural k este prim daca nu are
niciun divizor propriu n intervalul [2, k 1].
Algoritm 7 Algoritm pentru vericarea daca un numar este prim
1: Input {N }
2: if (n < 2) then
3: Output {Numarul nu este prim.}
4: else
5: i 2
6: prim true
7: while ((i n 1) (prim = true)) do
8: if (n mod i = 0) then
9: prim false
10: else
11: i i + 1
12: end if
13: end while
14: if (prim = true) then
15: Output {Numarul este prim.}
16: else
17: Output {Numarul nu este prim.}
18: end if
19: end if
Daca n este numar prim, corpul enunt ului de ciclare while se va executa de n 2 ori
(vezi algoritmul 7).
Condit ia i n 1 poate mbunatat ita cu i n/2, deoarece ntre jumatatea numarului
si n nu mai exista niciun alt divizor, pentru orice valoare a lui n.
Daca 2 este un divizor al numarului n atunci si n/2 este un divizor al lui n. Daca 2 nu
este divizor al lui n atunci nici n/2 nu este divizor al lui n. Un enunt asemanator este valabil
si pentru numerele 3, 4, 5, . . .. Astfel se formeaza doua siruri:
2
corespunde

n
2
3
corespunde

n
3
4
corespunde

n
4
.
.
.
.
.
.
k
..
corespunde

n
k
..
Sir
1
Sir
2
Se observa faptul ca primul sir (Sir
1
) este compus din elemente cu valori consecutive,
iar al doilea sir (Sir
2
) nu respecta aceasta proprietate. Numerele dintro pereche (p,
n
p
) sunt
12
legate ntre ele astfel: n momentul n care am vericat faptul ca numarul p nu este divizor
al lui n, implicit am dedus ca nici n/p nu este un divizor al lui n. Prin urmare nu mai este
nevoie sa vericam si valoarea n/p. Primul sir este strict crescator iar cel de-al doilea este
strict descrescator. Elementele din primul sir devin mai mari decat cele din al doilea atunci
cand k n/k k
2
n k

n. Astfel rezulta condit ia pentru limita superioara a


ciclarii: i

n (vezi algoritmul 8).


Algoritm 8 Algoritm pentru vericarea daca un numar este prim (varianta optimizata)
1: Input {N }
2: if (n < 2) then
3: Output {Numarul nu este prim.}
4: else
5: i 2
6: prim true
7: while ((i

n) (prim = true)) do
8: if (n mod i = 0) then
9: prim false
10: else
11: i i + 1
12: end if
13: end while
14: if (prim = true) then
15: Output {Numarul este prim.}
16: else
17: Output {Numarul nu este prim.}
18: end if
19: end if
Exemplul 1.10 Sa se aproximeze, cu o precizie data, limita sirului de numere reale a
n
,
n 0:
a
n
=
n

k=0
1
k!
. (1.2)
Analizand structura termenului general al sirului a
n
,
a
n
=
1
0!
+
1
1!
+
1
2!
+. . . +
1
(n 1)!
+
1
n!
(1.3)
se observa ca avem relat ia:
a
n+1
a
n
=
1
(n + 1)!
.
Se noteaza t
n
=
1
n!
. Vom calcula termenul a
n
pana cand diferent a dintre doi termeni consecu-
tivi ai sirului este mai mica decat :
|a
n
a
n1
| <
1
n!
< t
n
< . (1.4)
Pe de alta parte avem urmatoarea relat ie ntre doi termeni consecutivi ai sirului t
n
t
n+1
=
t
n
n + 1
, (1.5)
pe care o vom folosi pentru a reduce numarul de calcule efectuate de algoritmul 9.
13
Algoritm 9 Algoritm pentru calculul limitei unui sir de numere cu aproximare
1: Input {}
2: a 1, t 1, k 1
3: while (t ) do
4: a a + t
5: t
t
k+1
6: k k + 1
7: end while
8: a a + t
9: Output {a, k}
Exemplul 1.11 Se spune ca un vector este simetric daca primul element este egal cu ultimul,
al doilea cu penultimul etc. Algoritmul urmator verica daca un vector de numere ntregi este
simetric.
Vom utiliza doua variabile de indici, ce pornesc, una din stanga, si cealalta din dreapta.
Atata timp cat variabila din stanga este mai mica decat variabila din dreapta iar elementele
din vector corespunzatoare variabilelor de indiciere sunt egale, se incrementeaza variabila din
stanga si se decrementeaza variabila din dreapta. Dupa parasirea instruct iunii de ciclare, se
face o vericare pentru determinarea condit iei care nu a mai fost ndeplinita si a condus la
iesirea din bucla. Daca i j atunci condit ia (i < j) nu a mai fost ndeplinita. Acest lucru
conduce la concluzia ca cealalta condit ie, (x
i
= x
j
) a fost ndeplinita tot timpul (i < j, i, j =
1, n). Deci sirul este simetric n aceasta situat ie.
Algoritm 10 Algoritm pentru vericarea simetriei unui vector
1: Input {N, x
1
, x
2
, ..., x
N
}
2: i 1, j N
3: while ((i < j) (x
i
= x
j
)) do
4: i i + 1
5: j j 1
6: end while
7: if (i j) then
8: Output {Vectorul este simetric.}
9: else
10: Output {Vectorul nu este simetric.}
11: end if
Exemplul 1.12 Se da urmatorul sir de numere naturale: 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, . . .. Pentru
un numar natural n dat, sa se determine cel de-al n-lea element al sirului. De exemplu, cel
de-al 5-lea element al sirului prezentat este 2.
Dupa cum se observa din construct ia sirului, acesta este format din concatenarea mai
multor secvent e de numere naturale consecutive, ecare secvent a ncepand cu valoarea 1.
Lungimea ecarei subsecvent e este cu o unitate mai mare decat lungimea subsecvent ei ante-
rioare: astfel prima subsecvent a are lungimea 1, a doua subsecvent a are lungimea 2, a treia
subsecvent a are lungimea 3, etc.

In cadrul algoritmului 11 se va ncerca decrementarea vari-
abilei index cu lungimea cate unui sir n ntregime (index index k), atata timp cat este
posibil acest lucru. Valoarea cu care ramane variabila index reprezinta cel de-al n-lea element
al sirului.
Se poate optimiza algoritmul 11 astfel ncat sa renunt am la enunt ul de ciclare cu test
init ial while, procesul de calcul efectuand astfel mai put ine calcule (exercit iu).
14
Algoritm 11 Algoritm pentru determinarea celui deal nlea element
1: Input {N}
2: k 1
3: index N
4: while (k < index) do
5: index index k
6: k k + 1
7: end while
8: Output {Cel de-al n-lea element este, index}
Exemplul 1.13 Se dau doua siruri de numere naturale, a
1
, a
2
, . . . , a
n
si b
1
, b
2
, . . . , b
n
(a
i
, b
i

N). Sa se determine doua numere naturale d si e (d, e N) astfel ncat:
(a
2
1
+b
2
1
) (a
2
2
+b
2
2
) . . . (a
2
n
+b
2
n
) = d
2
+e
2
Vom demonstra prin induct ie matematica faptul ca
a
i
, b
i
N, i = 1, n, d, e N astfel ncat (a
2
1
+b
2
1
) (a
2
2
+b
2
2
) . . . (a
2
n
+b
2
n
) = d
2
+e
2
(1.6)
Fie n = 2. Ar trebui sa determinam valorile necunoscutelor d si e astfel ncat sa avem
(a
2
1
+b
2
1
) (a
2
2
+b
2
2
) = d
2
+e
2
.
Daca vom considera
_
d = a
1
a
2
+b
1
b
2
e = a
1
b
2
b
1
a
2
atunci, dupa efectuarea calculelor obt inem
d
2
+e
2
= (a
1
a
2
+b
1
b
2
)
2
+(a
1
b
2
b
1
a
2
)
2
= a
2
1
a
2
2
+b
2
1
b
2
2
+2a
1
a
2
b
1
b
2
+a
2
1
b
2
2
+b
2
1
a
2
2
2a
1
a
2
b
1
b
2
=
a
2
1
a
2
2
+b
2
1
b
2
2
+a
2
1
b
2
2
+b
2
1
a
2
2
= (a
2
1
+b
2
1
) (a
2
2
+b
2
2
),
si relat ia anterioara devine adevarata.
Presupunem ca relat ia (1.6) este adevarata k n.
Vom arata ca ea este adevarata si pentru n + 1:
a
i
, b
i
N, i = 1, n + 1, d, e N astfel ncat (a
2
1
+b
2
1
) (a
2
2
+b
2
2
) . . . (a
2
n+1
+b
2
n+1
) = d
2
+e
2
(1.7)
Aplicand de doua ori ipoteza de induct ie avem:
(a
2
1
+b
2
1
) (a
2
2
+b
2
2
) . . . (a
2
n
+b
2
n
)
. .
u
2
+v
2
(a
2
n+1
+b
2
n+1
) = (u
2
+v
2
) (a
2
n+1
+b
2
n+1
) = d
2
+e
2
(1.8)
unde e = ua
n+1
+vb
n+1
si e = ub
n+1
va
n+1
.
Algoritmul 12 se bazeaza pe modelul de construct ie pentru d si e, prezentat n demonstrat ia
anterioara.
Exemplul 1.14 Se da un numar de 9 monede de acelasi tip. Printre ele s-a strecurat o
moneda falsa: ea este mai grea sau mai usoara decat celelalte. Avem la dispozit ie o balant a
fara greutat i. Se cere un algoritm care sa determine moneda falsa, stiind ca putem folosi
cantarul doar pentru 3 operat ii de cantarire.
Fie a
1
, a
2
, . . . , a
9
cele 9 monede. Vommpart i monedele n trei grupe egale: A = {a
1
, a
2
, a
3
},
B = {a
4
, a
5
, a
6
} si C = {a
7
, a
8
, a
9
}. Pentru a determina moneda falsa avem nevoie de doua
informat ii:
15
Algoritm 12 Algoritm pentru calculul elementelor unei expresii
1: Input {N, a
1
, . . . , a
N
, b
1
, . . . , b
N
}
2: d a
1
3: e b
1
4: for i 2, N do
5: u = d a
i
+ e b
i
6: v = d b
i
e a
i
7: d u
8: e v
9: end for
10: Output {d, e}
1. n ce grupa se aa moneda falsa;
2. cum este moneda falsa (mai grea sau mai usoara fat a de restul).
Notam cu g() greutatea unei monede sau a unei mult imi de monede. Vom compara grupurile
A si B cu ajutorul balant ei. Avem urmatoarele cazuri:
1. g(A) = g(B).

In aceasta situat ie moneda falsa se aa n cea dea treia grupa, C = {a


7
, a
8
, a
9
}.
Comparam monedele a
7
si a
8
, rezultand una din situat iile urmatoare:
(a) g(a
7
) = g(a
8
) a
9
este moneda falsa.
(b) g(a
7
) < g(a
8
).
Mai departe comparam monedele a
7
cu a
9
si avem:
i. g(a
7
) = g(a
9
) a
8
este moneda falsa si este mai grea decat restul monedelor.
ii. g(a
7
) > g(a
9
) a
8
> a
7
> a
9
(imposibil deoarece doua monede trebuie sa e
egale).
iii. g(a
7
) < g(a
9
) a
7
este moneda falsa si este mai usoara decat restul monede-
lor.
(c) g(a
7
) > g(a
8
).
Se trateaza n mod analog cu situat ia de la punctul b).
2. g(A) < g(B).

In continuare comparam grupa A cu grupa C si vom obt ine una din situat iile urmatoare:
(a) g(A) = g(C) moneda falsa se aa n grupa B si este mai grea.
Mai departe comparam moneda a
4
cu moneda a
5
:
i. g(a
4
) = g(a
5
) a
6
este moneda falsa.
ii. g(a
4
) < g(a
5
) a
5
este moneda falsa (deoarece este mai grea).
iii. g(a
4
) > g(a
5
) a
4
este moneda falsa.
(b) g(A) < g(C)
g(A)<g(B)
g(B) = g(C) moneda falsa se aa n grupa A si este mai
usoara.

In acest caz, comparam moneda a


1
cu moneda a
2
:
i. g(a
1
) = g(a
2
) a
3
este moneda falsa.
ii. g(a
1
) < g(a
2
) a
1
este moneda falsa (deoarece este mai usoara).
16
iii. g(a
1
) > g(a
2
) a
2
este moneda falsa.
(c) g(A) > g(C) - Acest caz nu poate sa apara deoarece am avea g(B) > g(A) > g(C),
imposibil, deoarece doua grupe trebuie sa e egale n greutate.
3. g(A) > g(B).
Rat ionamentul este analog cu cel de la punctul 2).
Exemplul 1.15 Se dau n numere naturale a
1
, a
2
, . . . , a
n
(a
i
N). Se cere sa se determine
numarul de cifre de 0 n care se termina produsul a
1
a
2
. . . a
n
.
La o prima evaluare a cerint ei, se poate schit a urmatoarea solut ie: se calculeaza produsul
celor n numere si apoi se mparte rezultatul succesiv la 10 atata timp cat restul este nul.
Se poate nsa ca produsul celor n numere sa e un numar mare ce depaseste valoarea
maxima ce poate pastrata ntro variabila dintrunul din tipurile elementare.

Intr-o astfel
de situat ie este necesar sa se implementeze operat ii cu numere mari.
Se pune ntrebarea daca se poate raspunde la cerint a problemei fara a se face calculul
efectiv al produsului celor n numere.
Fie exp2 valoarea exponentului numarului 2 din descompunerea n factori primi a ter-
menului produs a
1
a
2
. . .a
n
, si exp5 valoarea exponentului numarului 5 din descompunerea n
factori primi a aceluiasi termen. Numarul de zerouri n care se termina produsul a
1
a
2
. . .a
n
este min (exp2, exp5) (vezi algoritmul 13).
Algoritm 13 Algoritm pentru calculul numarului de zerouri ale unui produs de numere
1: Input {N, a
1
, . . . , a
N
}
2: exp2 0
3: exp5 0
4: for i 1, N do
5: while ((a
i
= 0) (a
i
mod 2 = 0)) do
6: exp2 exp2 + 1
7: a
i
a
i
/2
8: end while
9: while ((a
i
= 0) (a
i
mod 5 = 0)) do
10: exp5 exp5 + 1
11: a
i
a
i
/5
12: end while
13: end for
14: if (exp2 < exp5) then
15: min exp2
16: else
17: min exp5
18: end if
19: Output {min}
Exemplul 1.16 Se da un numar format din n cifre. Vom prezenta un algoritm n care se
determina cel mai mare numar obt inut prin eliminarea a k cifre (k < n) dintre cele n (vezi
algoritmul 14).
Compararea a doua numere naturale ce prezinta acelasi numar de cifre se face ncepand
de la stanga spre dreapta (de la cifrele mai semnicative c atre cele mai put in semnicative).
17
Fie A = a
1
a
2
. . . a
n
numarul nostru.Vom nota prin m numarul de cifre ce vor ramane din
numarul init ial dupa eliminarea celor k cifre (m = nk). Problema se reduce la determinarea
celui mai mare numar format cu m cifre dintre cele n cifre init iale.
La nceput numarul cont ine n cifre, pastrate n ordine, n vectorul A: a
1
, a
2
, . . . , a
n
.
Solut ia se construieste n mod iterativ, la pasul i aleganduse o valoare corespunzatoare: se
determina prima cifra de valoare maxima si pozit ia acesteia n cadrul subsecvent ei de limite
l si n m +i, a
l
, . . . , a
nm+i
.
Algoritm 14 Algoritm pentru determinarea numarului maxim obt inut dupa eliminarea a k
cifre
1: Input {n, a
1
, . . . , a
n
, k}
2: m n k
3: l 0
4: for i 1, m do
5: l l + 1
6: j l
7: max 0
8: while (j n m + i) do
9: if (max < a
j
) then
10: max a
j
11: l j
12: end if
13: j j + 1
14: end while
15: Output {max}
16: end for


In instruct iunea for (linia 4) pentru ecare pozit ie libera din numarul rezultat, se va
alege cifra maxima dintre cele disponibile;
linia 5 - se trece la pozit ia urmatoare: l reprezinta indexul din sirul A al cifrei aleasa
la pasul anterior (i 1) si cont ine pozit ia pe care a fost gasita cifra maxim a. Cifra
maxima pentru pasul curent va cautata n intervalul l . . . n m+ i, unde n m+ i
reprezinta limita superioara a indexului pana la care se poate alege un element la pasul
curent;
a
1
. . . a
l
. . . a
nm+i
. .
subsecvent a pentru care se determin a cifra maxim a
. . . a
n
liniile 6, 7 - se init ializeaza variabila de ciclare j cu l si valoarea maxima cu 0; Deoarece
a
i
0, i = 1, n, se poate init ializa variabila max (unde se va pastra valoarea maxima)
cu 0;
linia 8 - se cauta cifra maxima pana la limita din dreapta nm+i (daca se merge mai
la dreapta dincolo de aceasta limita nu se mai pot alege restul de mi cifre);
linia 10 - se actualizeaza valoarea maxima;
linia 11 - se actualizeaza pozit ia valorii maxime.
18
Exemplul 1.17 Vom prezenta doi algoritmi ce determina toate tripletele de numere naturale
(a, b, c) ce verica relat ia a
2
+b
2
= c
2
unde c 100.
Prima varianta de lucru prezinta generarea tuturor tripletelor (i, j, k) unde 2 i < j <
k n. Dintre acestea se vor alege doar acelea ce verica relat ia k k = i i +j j. Daca vom
considera doar instruct iunea de ciclare 4, atunci condit ia 5 se va verica de n(j +1) +1 =
n j ori. Deoarece j = i + 1, n 1, vom obt ine faptul ca instruct iunea 5 se va executa de:
(n i 1) + (n i 2) +. . . + (n n + 1) =
ni1

j=1
j =
(n i) (n i 1)
2
ori.
Din i = 2, n 2 rezulta ca
n2

i=2
ni1

j=1
j =
n2

i=2
(n i) (n i 1)
2
=
1
2
n2

i=2
(i
2
+ (1 2n)i +n
2
n)
=
1
2
[
n2

i=2
i
2
+ (1 2n)
n2

i=2
i + (n
2
n) (n 3)]
1: Input {n}
2: for i 2, n 2 do
3: for j i + 1, n 1 do
4: for k j + 1, n do
5: if (k k = i i + j j) then
6: Output {i, j, k}
7: end if
8: end for
9: end for
10: end for
11: return
1: Input {n}
2: for i 2, n 1 do
3: for j i + 1, n do
4: s i i + j j
5: k

s
6: if ((k k = s) (k n)) then
7: Output {i, j, k}
8: end if
9: end for
10: end for
11: return
Pentru cea de-a doua varianta, cea din dreapta, se genereaza perechile de numere (i, j) cu
proprietatea ca 2 i < j n, se calculeaza s i i + j j si se verica daca numarul
obt inut este patrat perfect (linia 6: (

s)
2
= s). Condit ia de la linia 6 se va executa de
n (i + 1) + 1 = n i ori.
Deoarece linia 2 se va executa de n 1 2 + 1 = n 2 ori, valoarea totala reprezentand
numarul de vericari (linia 6) va :
n1

i=2
(n i) =
n1

i=1
(n i) (n 1) =
n1

i=1
i (n 1) =
n(n 1)
2
n + 1
1.3 Exercit ii
1. (a) Sa se determine daca un numar natural este simetric sau nu.
(b) Sa se determine toate cifrele distincte dintr-un numar natural.
(c) Sa se determine reprezentarea n baza 2 a unui numar natural.
19
(d) Sa se determine forma corespunzatoare n baza 10 a unui numar reprezentat n
baza 2.
(e) Sa se elimine dintrun numar natural toate cifrele de forma 3k +1 si sa se aseze
numarul rezultat.
(f) Pentru un numar natural dat sa se construiasca din cifrele acestuia cel mai mare
numar prin amplasarea mai ntai a cifrelor impare si apoi a cifrelor pare.
2. (a) Sa se determine tot i divizorii unui numar natural.
(b) Sa se verice daca doua numere naturale sunt prime ntre ele.
(c) Sa se determine tot i divizorii comuni a doua numere naturale.
(d) Sa se calculeze toate numerele prime mai mici decat o valoare specicata.
(e) Sa se descompuna n factori primi un numar natural.
(f) Sa se determine cel mai mare divizor comun a doua numere naturale folosinduse
descompunerea n factori primi.
3. Pentru un numar natural b (1 < b < 10) sa se determine toate numerele naturale mai
mici decat o valoare specicata n, (1 n 10
5
) care scrise n baza b, cont in numai
cifrele 0 si 1.
Intrare
7 5000
Iesire
0 1 7 8 49 50 56 57 343 344 350 351 392 393 399 400 2401
4. (a) Pentru un numar natural n dat (n < 32000), sa se determine ultima cifra nenula
a lui n!.
(b) Pentru un numar natural n dat (n < 1000), sa se determine numarul de cifre ale
lui n!.
5. Se da un numar natural n (0 n 10
6
). Se aplica asupra numarului n una dintre
urmatoarele transformari:
(a) Se calculeaza suma factorialelor cifrelor numarului n si se obt ine un nou numar.
(b) Se calculeaza suma cuburilor cifrelor numarului n.
Dupa aceasta, procedeul se repeta aplicandu-se de ecare data numai una din cele doua
operat ii (a) sau (b) (cea cu care s-a nceput).
Sa se aseze sirul de numere astfel obt inut pana cand elementele lui ncep sa se repete.
Se cere lungimea listei pana la prima repetit ie si pozit ia elementului care se repeta
primul.
6. O secvent a Farey[44] de ordinul n este un sir de numere rat ionale
a
b
unde 0 a b
n, (a, b) = 1. De exemplu, secvent ele Farey de ordinul 1, 2 si 3 sunt:
F
1
= {
0
1
,
1
1
}
F
2
= {
0
1
,
1
2
,
1
1
}
F
3
= {
0
1
,
1
3
,
1
2
,
2
3
,
1
1
}
20
Pentru un numar natural n (n < 2
16
) sa se determine elementele secvent ei Farey de
ordinul n.
Intrare
7
Iesire
(0,1),(1,7),(1,6),(1,5),(1,4),(2,7),(1,3),(2,5),(3,7),(1,2),(4,7),(3,5),
(2,3),(5,7),(3,4),(5,6),(6,7),(1,1)
Indicat ie Fie
a
1
b
1
,
a
2
b
2
,
a
3
b
3
trei elemente consecutive ale unei secvent e Farey de ordinul n.
Atunci avem relat iile ([68]):
b
1
a
2
a
1
b
2
= 1 (1.9)
a
2
b
2
=
a
1
+a
3
b
1
+b
3
(1.10)
Daca
a
1
b
1
si
a
3
b
3
sunt doua elemente consecutive ale unei secvent e Farey de ordinul n,
atunci
a
1
+a
3
b
1
+b
3
este un element al secvent ei Farey de ordinul n + 1.
Fie
a
1
b
1
si
a
2
b
2
doua elemente consecutive ale unei secvent e Farey de ordinul n. Elementul
urmator ce apart ine secvent ei,
a
3
b
3
, se poate determina astfel:
a
2
b
2
=
a
1
+a
3
b
1
+b
3
. k N

astfel
ncat ka
2
= a
1
+ a
3
si kb
2
= b
1
+ b
3
a
3
= ka
2
a
1
si b
3
= kb
2
b
1
. Valoarea lui k
trebuie aleasa astfel ncat fract ia
a
3
b
3
sa e cat mai apropiata de
a
2
b
2
. Astfel k trebuie sa
e cat mai mare, nsa respectand restrict ia k
n+b
1
b
2
.
7. Fiind date doua numere ntregi X si Y , sa se determine cea mai mica baza pentru Y
astfel ncat X si Y sa reprezinte aceeasi valoare.
De exemplu numerele 12 si 5 nu sunt egale n baza 10 (12
10
= 5
10
), nsa ele sunt egale
daca le consideram ca ind reprezentate n bazele 3 si respectiv 6: 12
3
= 5
10
, 5
6
= 5
10
.
Bazele n care se vor considera reprezentate numerele au valoarea maxima 36.
Intrare Iesire
12 5 12
3
= 5
6
10 A 10
10
= A
11
12 34 12
17
= 34
5
123 456 no solution
10 2 10
2
= 2
3
(ACM, 1995)
8. Sa se calculeze 2
n
pentru 30 < n < 100.
9. Fie D o dreapta avand ecuat ia ax + by + c = 0 si un cerc C(O, r) unde O(x
0
, y
0
) este
centrul cercului iar r este raza acestuia.
Sa se realizeze un algoritm care sa stabileasca pozit ia dreptei fat a de cercul C n funct ie
de valorile parametrilor reali a, b, c, x
0
, y
0
, r.
10. Sa se determine toate numerele naturale n (1 n 10
6
) cu proprietatea ca atat n cat
si oglinditul sau sunt numere prime.
21
11. Sa se scrie un algoritm ce calculeaza coecient ii polinomului urmator, ind date nu-
merele a, b si n:
P(X) = (aX +b)
n
, a, b Z, n N. (1.11)
12. Sa se determine toate radacinile rat ionale ale unei ecuat ii cu coecient i ntregi.
Fie ecuat ia:
a
n
x
n
+a
n1
x
n1
+. . . +a
1
x +a
0
= 0. (1.12)
O radacina rat ionala a ecuat iei 1.12 va avea forma
p
q
unde p|a
0
si q|a
n
.
13. Pentru o secvent a de numere naturale de lungime n, sa se realizeze un algoritm care sa
determine cea mai lunga subsecvent a de elemente consecutive avand aceeasi valoare.
14. Sa se realizeze un algoritm care sa determine primele n numere prime, pentru un numar
natural n dat.
15. Sa se realizeze un algoritm pentru calcularea tuturor solut iilor ecuat iei:
3x +y + 4xz = 100, x, y, z N. (1.13)
Indicat ie Pentru o valoare z 25 si x = 0 (x > 0) avem:
3x +y + 4xz 3x + 4xz 3 + 4z > 100.
Astfel pentru z obt inem ca 0 z 24.
Ecuat ia 1.13 se poate scrie astfel:
3x +y + 4xz = 100 x(3 + 4z) = 100 y x =
100 y
3 + 4z
(1.14)
Daca x = 0 si y 0 x =
100y
3+4z

_
100y
3+4z

x [1,
_
100y
3+4z

].
Astfel, pentru ecare pereche de numere (z, x) vom calcula pe y astfel: y = 100 3x
4xz.
De asemenea, n 1.14 daca luam x = 0 obt inem mult imea de solut ii (0, 100, z), z N.
16. Un moment de timp este specicat n formatul ora:min:sec:sutimi.
Sa se elaboreze o subrutina ce calculeaza timpul (n sutimi de secunda) trecut de
la momentul 00 : 00 : 00 : 00 al ecarei zile si pana la momentul curent;
Sa se calculeze timpul scurs ntre doua momente de timp hh
1
: mm
1
: ss
1
: tt
1
si
hh
2
: mm
2
: ss
2
: tt
2
;
Fiind dat un numar natural n, ce reprezinta numarul de secunde trecute de la
momentul 00 : 00 : 00 : 00, sa se realizeze o subrutina ce transforma acest numar
n formatul ora:min:sec:sutimi.
Ora ia valori n intervalul 0 . . . 23, minutul si secundele iau valori n intervalul 0 . . . 59,
iar sutimile de secunda au valori n intervalul 0 . . . 99.
22
Capitolul 2
Elemente de analiza algoritmilor
Gradul de dicultate al unei probleme P poate pus in evident a prin timpul de execut ie al
algoritmului corespunzator si/sau prin spat iul de memorie necesar. Timpul de execut ie n
cazul cel mai defavorabil ne da durata maxima de execut ie a algoritmului. Timpul mediu
de execut ie se obt ine prin nsumarea timpilor de execut ie pentru toate mult imile de date de
intrare urmata de raportarea la numarul acestora.
Denit ia 2.1 Timpul de execut ie n cazul cel mai defavorabil al unui algoritm A este o
funct ie T
A
: N N unde T
A
(n) reprezinta numarul maxim de instruct iuni executate de
catre A n cazul unor date de intrare de dimensiune n.
Denit ia 2.2 Timpul mediu de execut ie al unui algoritm A este o funct ie T
med
A
: N N
unde T
med
A
(n) reprezinta numarul mediu de instruct iuni executate de catre A n cazul unor
date de intrare de dimensiune n.
Fiind data o problema P, o funct ie T(n) se spune ca este o margine superioara daca exista
un algoritm A ce rezolva problema P iar timpul de execut ie n cazul cel mai defavorabil al
algoritmului A este cel mult T(n).
Fiind data o problema P, o funct ie T(n) se spune ca este o margine pentru cazul mediu
daca exista un algoritm A ce rezolva problema P iar timpul mediu de execut ie al algoritmului
A este cel mult T(n).
Fiind data o problema P, o funct ie T(n) se spune ca este o margine inferioara daca orice
algoritm A ce rezolva problema P va avea cel put in un timp T(n) pentru unele date de intrare
de dimensiune n, atunci cand n tinde la innit (n ).
Denit ia 2.3 Fiind data o funct ie g : N R vom nota cu O(g(n)) mult imea: O(g(n)) =
{f(n)| c > 0, n
0
0 a.. 0 f(n) c g(n), n n
0
}.
Vom spune despre f ca nu creste n mod sigur mai repede decat funct ia g. Pentru a indica
faptul ca o funct ie f(n) este un membru al mult imii O(g(n)), vom scrie f(n) = O(g(n)), n
loc de f(n) O(g(n)).
Observat ia 2.1 Vom prezenta cateva proprietat i ale lui O():
O(f(n) +g(n)) = O(max(f(n), g(n))).
De exemplu pentru funct ia f(n) = 7 n
5
n
2
+3 log n aplicand regula valorii maxime
vom avea: O(f(n)) = O(max(7 n
5
, n
2
, 3 log n)) adica O(f(n)) = O(n
5
).
O(log
a
n) = O(log
b
n);
23
f(n) = O(f(n)) (reexivitate);
f(n) = O(g(n)) si g(n) = O(h(n)) atunci f(n) = O(h(n)) (tranzitivitate).
Denit ia 2.4 Fiind data o funct ie g : N R vom nota cu (g(n)) mult imea: (g(n)) =
{f(n)| c
1
, c
2
> 0, n
0
0 a.. 0 c
1
g(n) f(n) c
2
g(n), n n
0
}
Spunem ca g(n) este o margine asimptotic tare pentru f(n).
Denit ia 2.5 Fiind data o funct ie g : N R vom nota cu (g(n)) mult imea: (g(n)) =
{f(n)| c > 0, n
0
0 a.. 0 c g(n) f(n), n n
0
}
La fel cum O furnizeaza o delimitare asimptotica superioara pentru o funct ie, furnizeaza
o delimitare asimptotica inferioara pentru aceasta.
Teorema 2.2 Pentru orice doua funct ii f(n) si g(n), avem f(n) = (g(n)) f(n) =
O(g(n)) si f(n) = (g(n)).
Denit ia 2.6 Fiind data o funct ie g : N R vom nota cu o(g(n)) mult imea: o(g(n)) =
{f(n)| c > 0, n
0
> 0 a.. 0 f(n) < c g(n), n n
0
}
Observat ia 2.3 f(n) = o(g(n)) lim
n
f(n)
g(n)
= 0.
Denit ia 2.7 f(n) (g(n)) g(n) o(f(n))
(g(n)) este o mult ime ce se deneste astfel:
(g(n)) = {f(n)| c > 0, n
0
> 0 a.. 0 c g(n) < f(n), n n
0
}
Observat ia 2.4 1. f(n) = (g(n)), g(n) = (h(n)) = f(n) = (h(n)) (tranzitivitate);
2. f(n) = (f(n)) (reexivitate);
3. f(n) = (g(n)) g(n) = (f(n)) (simetrie).
Denit ia 2.8 O funct ie f are o crestere exponent iala daca c > 1 a.i. f(x) = (c
x
) si
d a.. f(x) = O(d
x
). O funct ie f este polinomiala de gradul d daca f(n) = (n
d
) si
f(n) = O(n
d

), d

d.
Teorema 2.5
lim
n
g(n)
f(n)
=
_

_
c g(n) (f(n)), c > 0
0 g(n) o(f(n))
f(n) o(g(n))
(2.1)
Exemplul 2.6 pentru x R

+
avem x
n
o(n!).
Deoarece
x
n
n!
<
x
n
x
4
. . . x
4
. .
n/2ori

x
n
(x
4
)
n/2
=
x
n
x
2n
= (
1
x
)
n
(2.2)
rezulta ca
lim
n
x
n
n!
= 0 (2.3)
24
log n o(n).
lim
x
log x
x
= lim
x
(log x)

(x)

= lim
x
1
xln 2
1
= 0
pentru a, b > 1, a, b R

avem log
a
n (log
b
n).
Calcularea cu exactitate a timpului de execut ie al unui program oarecare se poate dovedi
o activitate dicila. De aceea, n practica se utilizeaza estimari ncercandu-se eliminarea
constantelor si simplicarea formulelor ce intervin n cadrul evaluarii.
Daca doua part i ale unui program, P
1
si P
2
, au timpii de execut ie corespunzatori T
1
(n) si
T
2
(n), unde T
1
(n) = O(f(n)) si T
2
(n) = O(g(n)), atunci programul P
1
P
2
va avea timpul
de execut ie T
1
(n) +T
2
(n) = O(max(f(n), g(n))) (regula sumei ), unde reprezinta operat ia
de concatenare.
Prin aplicarea acestei reguli rezulta faptul ca timpul necesar execut iei unui numar nit
de operat ii este, neluand n considerare constantele, caracterizat n principal de catre timpul
de execut ie al operat iei cele mai costisitoare.
Cea dea doua regula, regula produsului, spune ca ind date doua funt ii f(n) si g(n) astfel
ncat T
1
(n) = O(f(n)) si T
2
(n) = O(g(n)), atunci avem T
1
(n) T
2
(n) = O(f(n) g(n)).
Pe baza regulilor produsului si sumei putem face urmatoarele reduceri:
O(1) O(log n) O(n) O(nlog n) O(n
2
) O(n
3
) O(2
n
)
Prezentamn continuare cateva reguli generale pentru evaluarea complexitat ii unui algoritm:
timpul de execut ie al unei instruct iuni de atribuire, citire sau asare a unei variabile
este O(1).
timpul de execut ie al unei secvent e de instruct iuni este proport ional cu timpul instruct iunii
care dureaza cel mai mult.
timpul de execut ie al unei instruct iuni de decizie (if ) este timpul executarii instruct iu-
nilor de pe ramura aleasa plus timpul necesar evaluarii condit iei.
timpul de execut ie pentru o instruct iune de ciclare este suma, dupa numarul de pasi
pe care i realizeaza instruct iunea de ciclare, dintre timpul necesar executarii corpului
instruct iunii plus timpul necesar evaluarii condit iei.
1: for i 1, n do
2: A(i)
3: end for
Daca instruct iunii compuse A(i) i corespunde un timp de execut ie constant t, ce nu
depinde de i, atunci timpul corespunzator ntregii instruct iuni de ciclare for anterioare
este:
n

i=1
t = t
n

i=1
1 = t n = O(n) (2.4)

In cazul general, timpul de execut ie al instruct iunii compuse A(i) depinde de pasul i,
notat cu t
i
. Astfel timpul total corespunzator instruct iunii for este

n
i=1
t
i
.
Instruct iunile de ciclare al caror numar de pasi depinde de ndeplinirea unei condit ii
(while) sau de nendeplinirea acesteia (repeat ... until), sunt mult mai dicil
de analizat deoarece nu exista o metoda generala de a aa cu exactitate numarul de
repetari al corpului instruct iunii. De exemplu, pentru fragmentul urmator
25
1: i l
2: while (a
i
< x) do
3: . . . calcule ce pot modica, direct sau indirect, valoarea lui a
i
4: i i + 1
5: end while
nu se poate preciza de cate ori se va ajunge la realizarea instruct iunii de incrementare
din interiorul instruct iunii while.

In marea majoritate a cazurilor se utilizeaza teoria
probabilitat ilor n vederea obt inerii unei estimari a acestui numar.
Exemplul 2.7 De exemplu
1: for i 1, n do
2: instructiune1
3: end for
are timpul de execut ie O(n).
1: for i 1, n do
2: for j 1, m do
3: instructiune2
4: end for
5: end for
Timpul de execut ie pentru secvent a de cod ce cont ine dou a instruct iuni de ciclare imbricate
este O(n m).
Exemplul 2.8 Sa consideram un alt exemplu: se da un sir A de n numere reale, si se doreste
calcularea elementelor unui sir B astfel ncat b
i
=
1
i

i
j=1
a
j
, pentru i = 1, n.
1: for i 1, n do
2: s 0
3: for j 1, i do
4: s s + a
j
5: end for
6: b
i

s
i
7: end for
8: return
Daca notam cu o constanta c
x
timpul necesar pentru efectuarea unei operat ii atomice,
vom obt ine: costul efectuarii liniei 1 este c
1
n, al liniei 2 este c
2
n, al liniei 3 este c
3
i, al
liniei 4 este c
4
i, al liniei 6 este c
5
n iar al liniei 8 este c
6
.
T(n) = c
1
n +c
2
n +
n

i=1
c
3
i +
n

i=1
c
4
i +c
5
n +c
6
= c
1
n +c
2
n +c
3
n

i=1
i +c
4
n

i=1
i +c
5
n +c
6
=
n(n + 1)
2
(c
3
+c
4
) +n(c
1
+c
2
+ c
5
) +c
6
=
1
2
(c
3
+c
4
)n
2
+
1
2
(c
3
+c4)n +n(c
1
+c
2
+c
5
) +c
6
=
1
2
(c
3
+c
4
)n
2
+ [
1
2
(c
3
+c
4
) +c
1
+c
2
+c
5
]n +c
6
= n
2
p +n q +c
6
De obicei nu se efectueaza o analiza asa de detaliata a algoritmului, dar se ncearca o eval-
uare a blocurilor principale cum ar instruct iunile de ciclare, atribuindule direct valori
corespunzatoare complexitat ii timp, atunci cand este posibil:
T(n) = O(n
2
) +O(n) +O(1) = O(n
2
) (2.5)
26
Vom modica algoritmul anterior astfel ncat sa reducem numarul de calcule efectuate:
1: s 0
2: for i 1, n do
3: s s + a
i
4: b
i

s
i
5: end for
6: return
Pentru aceasta varianta de lucru, complexitatea timp este urmatoarea:
T(n) = O(1)(linia 1) +O(n)(liniile 24) +O(1)(linia 6) = O(n) (2.6)

In urma analizei de complexitate, putem concluziona ca cea de-a doua varianta a algoritmului
ruleaza ntrun timp liniar.
2.1 Metoda substitut iei
Metoda substitut iei presupune mai ntai ghicirea (estimarea) formei solut iei pentru relat ia
de recurent a si apoi demonstrarea prin induct ie matematica a corectitudinii solut iei alese.
Metoda poate aplicata n cazul unor ecuat ii pentru care forma solut iei poate estimata.
Sa consideram urmatoarea relat ie de recurent a:
T(n) =
_
1 , daca n = 1
2T(
n
2
) +n , n rest
(2.7)
Vom presupune ca solut ia acestei relat ii de recurent a este T(n) = O(nlog n) (notam
log
2
n = log n). Folosind metoda induct iei matematice, vom ncerca sa demonstram inegali-
tatea:
T(n) cnlog n. (2.8)
Presupunem mai ntai ca inecuat ia (2.8) are loc pentru k < n, inclusiv pentru
n
2
, adica
T(
n
2
) c
n
2
log (
n
2
).
Vom demonstra ca inecuat ia (2.8) este ndeplinita si pentru n: T(n) = 2T(
n
2
) +n.
T(n) 2(c
n
2
log
n
2
) +n = cnlog
n
2
+n
= cnlog n cnlog 2 +n = cnlog n cn +n
cnlog n
(2.9)
Metoda induct iei matematice presupune sa aratam ca solut ia respecta si cazurile particulare
(T(1) = 1). Pentru n = 1 vom avea T(1) = c 1 log 1 = 0 ceea ce contrazice relat ia T(1) = 1.
Aceasta situat ie poate rezolvata daca consideram c a T(n) = cnlog n, n n
0
(n
0
este
o constanta).
Din T(2) = 4 si T(3) = 5 vom alege valoarea parametrului c astfel ncat sa e ndeplinite
inegalitat ile T(2) 2c log 2 si T(3) 3c log 3. Se observa ca orice valoare a lui c 2 satisface
inegalitat ile anterioare.
2.2 Schimbarea de variabila
Aceasta metoda presupune realizarea unei schimbari de variabila n vederea simplicarii
formulei sau pentru regasirea unei formule deja cunoscut a.
27
Sa consideram ecuat ia T(n) = 2T(

n) + log n. Daca nlocuim pe n cu 2


m
obt inem:
T(2
m
) = 2T(2
m
2
) + log 2
m
= 2T(2
m
2
) +m (2.10)
Notam cu S(m) = T(2
m
) si nlocuind n (2.10) obt inem o noua relat ie de recurent a:
S(m) = 2S(
m
2
) +m (2.11)
Se observa ca aceasta relat ie are o forma similara cu cea din formula (2.7).
Solut ia relat iei (2.11) este:
S(m) = O(mlog m) T(n) = T(2
m
) = S(m) = O(mlog m) = O(log nlog log n) (2.12)

In concluzie avem T(n) = O(log nlog log n).


2.3 Metoda iterativa
Metoda iterativa este mult mai ecienta deoarece nu presupune ghicirea solut iei, varianta
ce conduce deseori la rezultate gresite si timp pierdut. De exemplu, sa consideram formula
de recurent a:
T(n) =
_
1 , daca n = 1
T(
n
2
) + 1 , n rest
(2.13)
Pentru rezolvarea acestei recurent e vom substitui succesiv pe n cu
n
2
:
T(n) = T(
n
2
) + 1
= T(
n
4
) + 2
= T(
n
8
) + 3
. . .
= T(
n
2
k
) +k
(2.14)
Prin urmare atunci cand 1 =
n
2
k
k = log n, vom avea
T(n) = 1 +k = 1 + log n T(n) = O(log n).
Fie o alta formula de recurent a:
T(n) =
_
1 , daca n = 1
2T(
n
2
) +n , n rest
(2.15)

Inlocuind succesiv pe n cu
n
2
vom obt ine urmatoarea serie de identitat i:
T(n) = 2T(
n
2
) +n
= 2(2T(
n
2
) +
n
2
) +n = 4T(
n
4
) + 2n
= 4(2T(
n
8
) +
n
4
) + 2n = 8T(
n
8
) + 3n
. . .
= 2
k
T(
n
2
k
) +kn
(2.16)
Deoarece substitut ia se opreste atunci cand
n
2
k
= 1 adica pentru k = log n, vom avea:
T(n) = 2
k
+kn = n +nlog n = O(nlog n) (2.17)
28
2.4 Teorema master
Metoda master pune la dispozit ie o varianta de rezolvare a unor recurent e de forma
T(n) = aT(
n
b
) +f(n) (2.18)
unde a 1, b > 1 sunt constante, iar f(n) este o funct ie asimptotic pozitiva. Formula de
recurent a (2.18) descrie timpul de execut ie al unui algoritm ce presupune descompunerea unei
probleme de dimensiune n n a subprobleme, ecare avand dimensiunea datelor de intrare
n
b
.
f(n) reprezinta costul asociat mpart irii datelor de intrare cat si costul combinarii rezultatelor
celor a subprobleme.
Teorema 2.9 (Teorema master) [30] Fie a 1 si b > 1 doua constante, f(n) o funct ie
asimptotic pozitiva, si T(n) denita de relat ia de recurent a T(n) = aT(
n
b
) +f(n), unde
n
b
va

n
b
sau
n
b
.
Atunci T(n) este marginita asimptotic dupa cum urmeaza:
1. daca f(n) = O(n
log
b
a
) pentru o constanta > 0, atunci T(n) = (n
log
b
a
);
2. daca f(n) = (n
log
b
a
log
k
n), atunci T(n) = (n
log
b
a
log
k+1
n) (de obicei k = 0);
3. daca f(n) = (n
log
b
a+
) pentru o constanta > 0, si daca af(
n
b
) cf(n) pentru o
constanta c < 1 si oricare numar n sucient de mare, atunci T(n) = (f(n)).
Corolarul 2.10 Pentru o funct ie f de tip polinomial unde f(n) = cn
k
avem:
1. daca a > b
k
atunci T(n) = O(n
log
b
a
);
2. daca a = b
k
atunci T(n) = O(n
k
log n);
3. daca a < b
k
atunci T(n) = O(n
k
).
Exemplul 2.11 Fie T(n) = 2T(
n
2
)+n. Avem a = 2, b = 2, k = 1, f(n) = n
k
. Aplicand
corolarul pentru cazul a = b
k
, solut ia este T(n) = O(n
k
log n) = O(nlog n).
Fie T(n) = 9T(
n
3
) + n. Avem a = 9, b = 3, k = 1. Aplicand corolarul pentru cazul
a > b
k
, se obt ine solut ia T(n) = O(n
log
3
9
) = O(n
2
).
Fie T(n) = 4T(
n
2
) + n
3
. Avem a = 4, b = 2, k = 3, f(n) = n
3
. Aplicand corolarul
pentru cazul a < b
k
, se obt ine solut ia T(n) = O(n
3
).
Fie T(n) = 2
n
T(
n
2
) + n
n
. Nu se poate aplica Teorema master deoarece a = 2
n
nu este
constant.
Fie T(n) = 2T(
n
2
) + nlog n. Atunci avem a = 2, b = 2, k = 1, f(n) = (n
log
2
2
log
k
n),
si aplicand Teorema master, cazul al doilea, obt inem: T(n) = (nlog
2
n).
Fie T(n) =
1
2
T(
n
2
) +
1
n
. Nu se poate aplica Teorema master deoarece a =
1
2
< 1.
Fie T(n) =

2T(
n
2
) + log n. Aplicand Teorema master pentru a =

2, b = 2, f(n) =
O(n
1
2

) obt inem: T(n) = (

n).
Fie T(n) = 3T(
n
4
) + nlog n. Aplicand Teorema master pentru a = 3, b = 4, f(n) =
(n
log
4
3+
) obt inem: T(n) = (nlog n).
29
Fie T(n) = 16T(
n
4
) nlog n. Nu se poate aplica Teorema master deoarece f(n) =
nlog n nu este o funct ie asimptotic pozitiva.
Exemplul 2.12 Analiza act iunilor
Deschiderea unei act iuni la o anumita data calendaristica se calculeaza drept numarul
maxim de zile consecutive (pana la acea data) n care pret ul act iunii a fost mai mic sau egal
cu pret ul din ziua respectiva. Fie p
k
pret ul unei act iuni n ziua k iar d
k
deschiderea calculata
n aceeasi zi.

In continuare se prezinta un exemplu de calcul al deschiderii unei act iuni pentru un numar
de 7 zile:
p
0
p
1
p
2
p
3
p
4
p
5
p
6
9 6 3 4 2 5 7
d
0
d
1
d
2
d
3
d
4
d
5
d
6
1 1 1 2 1 4 6
Algoritm 15 Algoritm de calcul al deschiderii unei act iuni (prima varianta)
1: procedure ComputeSpan1(p, n; d)
2: for k 0, n 1 do
3: j 1
4: while (j < k) (p
kj
p
k
) do
5: j j + 1
6: end while
7: d
k
j
8: end for
9: return
10: end procedure
Algoritmul 15 calculeaza deschiderea unei act iuni pentru un interval mai lung de timp pe
baza evolut iei pret urilor acesteia. Timpul de execut ie al acestui algoritm este O(n
2
).
Vom prezenta un alt mod de calcul al deschiderii unei act iuni folosind o stiva (vezi algo-
ritmul 16).
Stiva este o structura de date de tip container deoarece ea depoziteaza elemente de un
anumit tip. Pentru a putea sa operam asupra unei colect ii de elemente pastrate ntro stiva
se denesc urmatoarele operat ii, n afara de operat iile fundamentale push si pop:
push(x:object) adauga obiectul x n varful stivei.
pop():object elimina si ntoarce obiectul din varful stivei; daca stiva este goala
avem o situat ie ce genereaza o except ie.
peek():object ntoarce valoarea obiectului din varful stivei fara al extrage.
size():integer ntoarce numarul de obiecte din stiva.
isEmpty():boolean ntoarce true daca stiva nu cont ine nici un obiect.
isFull(): boolean ntoarce true daca stiva este plina.
init(capacitate:integer) init ializeaza stiva.
Timpul de execut ie al noului algoritm este O(n).
30
Algoritm 16 Algoritm de calcul al deschiderii unei act iuni (a doua varianta)
1: procedure ComputeSpan2(p, n; d)
2: call init(S)
3: for k 0, n 1 do
4: ind 1
5: while (isEmpty(S) = false) (ind = 1) do
6: if (p
k
p
peek(S)
) then
7: call pop(S)
8: else
9: ind 0
10: end if
11: end while
12: if (ind = 1) then
13: h 1
14: else
15: h peek(S)
16: end if
17: d
k
k h
18: call push(S, k)
19: end for
20: return
21: end procedure
2.5 Exercit ii
1. Sa se evalueze complexitatea algoritmului 17, ce realizeaza descompunerea n factori
primi a unui numar natural.
Algoritm 17 Algoritm pentru descompunerea n factori primi a unui num ar natural
1: Input {n}
2: j 2
3: while (j n) do
4: if (n mod j = 0) then
5: k 0
6: while (n mod j = 0) do
7: k k + 1
8: n n div j
9: end while
10: Output {j
k
}
11: end if
12: j j + 1
13: end while
2. Pentru ecare dintre urmatoarele relat ii de recurent a calculat i complexitatea timp:
(a) T(n) = 2T(
n
2
) +
n
log n
;
(b) T(n) = 16T(
n
4
) +n!;
(c) T(n) = 3T(
n
3
) +

n;
31
(d) T(n) = 3T(
n
3
) +
n
2
.
3. Sa se calculeze timpul mediu de lucru T(n) al algoritmului 18.
Algoritm 18 Algoritm Calcul5
1: for i 1, n do
2: j n
3: while (j 1) do
4: . . .
5: j
j
2

6: end while
7: end for
4. Sa se calculeze timpul mediu de lucru T(n) al algoritmului 19.
Algoritm 19 Algoritm Calcul6
1: i n
2: while (i 1) do
3: j i
4: while (j n) do
5: . . .
6: j j 2
7: end while
8: i
i
2

9: end while
5.

Intr-o secvent a de n numere naturale (a
1
, a
2
, . . . , a
n
, a
i
N, 1 a
i
65535, 1 n
10
7
) se spune ca un numar este majoritar daca numarul de aparit ii este cel put in
n
2
+1.
Sa se realizeze un algoritm ce determina daca avem vreun numar majoritar n secvent a
de n elemente, si n caz armativ sa se aseze aceasta valoare.
6. Sa se rezolve urmatoarele ecuat ii recurente:
T(n) = 2 T(
n
2
) + nlg n, n = 2
k
;
T(n) = 3 T(
n
2
) + c n, n = 2
k
> 1.
7. Sa se rezolve ecuat ia recurenta T(n) = n T
2
(
n
2
), n = 2
k
, T(1) = 6.
8. Sa se arate ca e
x
= 1 +x + (x
2
) unde x .
9. Sa se determine primele n elemente ale sirurilor a
k
si b
k
date prin urmatoarele relat ii
de recurent a:
a
k+1
=
5a
k
+ 3
a
k
+ 3
, b
k
=
a
k
+ 3
a
k
+ 1
, k 0, a
0
= 1. (2.19)
10. Fie [P
1
P
2
. . . P
n
] un poligon convex dat prin coordonatele carteziene ale varfurilor sale,
n ordine trigonometrica. Sa se calculeze aria poligonului.
11. Sa se verice daca urmatoarele armat ii sunt adevarate:
(a) n
2
O(n
3
);
32
(b) n
3
O(n
2
);
(c) 2
n+1
O(2
n
);
(d) (n + 1)! O(n!);
(e) f : N R

, f O(n) f
2
O(n
2
);
(f) f : N R

, f O(n) 2
f
O(2
n
).
12. Sa se realizeze un algoritm ce verica daca un text dat T constituie o permutare circu-
lara a unui alt text T
0
.
13. Se da o secvent a de numere ntregi n care pot sa existe si numere duplicate. Sa se
realizeze un algoritm care sa determine o pereche de numere apart inand secvent ei, a
caror suma sa e egala cu o valoare specicata k.
14. Sa se realizeze o subrutina ce verica daca un sir de caractere S reprezinta o anagrama
a altui sir de caractere S
0
.
15. O secvent a S cont ine n 1 numere naturale distincte ale caror valori apart in mult imii
de valori {1, 2, . . . , n}. Sa se realizeze un algoritm ce determina ce numar din intervalul
[1, n] lipseste din secvent a.
16. Sa se elaboreze un algoritm pentru stergerea dintrun vector a unui element aat pe
pozit ia k.
33
Capitolul 3
Grafuri. Grafuri neorientate
3.1 Not iuni de baza
Fie V o mult ime nita si nevida avand n elemente (V = {x
1
, x
2
, . . . , x
n
}). Fie E o mult ime
nita astfel ncat E V V (unde V V este produsul cartezian al mult imii V cu ea nsasi)
si E = {(x, y)|x, y V } (E este mult imea perechilor (x, y) cu proprietatea ca x si y apart in
mult imii V ).
Denit ia 3.1 Se numeste graf o pereche ordonata G = (V, E).
Elementele x
i
V se numesc noduri sau v arfuri. Elementele mult imii E sunt arce
sau muchii. O muchie (x
k
, x
l
) E se mai noteaza si cu [x
k
, x
l
].
|V | se numeste ordinul grafului G si reprezinta numarul varfurilor acestuia, iar |E| se
numeste dimensiunea grafului G si reprezinta numarul muchiilor/ arcelor grafului G.
Graful = (, ) se numeste graful vid.
Daca ntr-o pereche [x
k
, x
l
] nu t inem cont de ordine atunci graful este neorientat iar
perechea reprezinta o muchie ([x
k
, x
l
] = [x
l
, x
k
]). Daca se introduce un sens ecarei muchii
atunci aceasta devine arc iar graful se numeste orientat ([x
k
, x
l
] = [x
l
, x
k
]). Muchiile ce au
aceleasi varfuri se spune ca sunt paralele. O muchie de forma [u, u] se numeste bucla.
Un graf G se numeste simplu daca oricare doua varfuri ale sale sunt extremitat i pentru
cel mult o muchie. Un graf este nit daca mult imile V si E sunt nite.

In continuare vom considera un graf neorientat, simplu si nit. Daca [x, y] E vom
spune ca x si y sunt adiacente, iar muchia [x, y] este incidenta cu varfurile x si y. x si y se
Fig. 3.1: a) Un exemplu de graf neorientat cu 6 varfuri b) Graful complet K
5
34
mai numesc capetele muchiei. Doua muchii sunt adiacente daca au un varf comun. Un graf
este trivial daca are un singur varf. Daca E = atunci graful G = (V, E) se numeste graf
nul.
Observat ia 3.1 Un graf neorientat, simplu, nit poate utilizat drept model de reprezentare
al unei relat ii simetrice peste o mult ime.
Denit ia 3.2 Se numeste graf complet de ordinul n, si se noteaza cu K
n
, un graf cu pro-
prietatea ca oricare doua varfuri distincte ale sale sunt adiacente (x V, y V, x = y
[x, y] E).
Exemplul 3.2 Sa consideram grafurile din gura 3.1.
a) G = (V, E), V = {1, 2, 3, 4, 5, 6}, E = {[1, 2], [1, 5], [2, 3], [2, 6], [3, 4], [4, 5], [5, 6]} (vezi
gura 3.1 a));
b) K
5
este graful complet cu 5 varfuri. Varfurile 3 si 5 sunt adiacente (vezi gura 3.1 b)).
Fig. 3.2: a) Un exemplu de graf neorientat cu 5 varfuri. b) Subgraf al grafului din gura 3.1 b). c) Graf
part ial al grafului din gura 3.1 b).
Denit ia 3.3 Un graf part ial al unui graf dat G = (V, E) este un graf G
1
= (V, E
1
) unde
E
1
E.
Denit ia 3.4 Un subgraf al unui graf G = (V, E) este un graf H = (V
1
, E
1
) unde V
1
V
iar muchiile din E
1
sunt toate muchiile din E care au ambele extremitat i n mult imea V
1
(E
1
= E|
V
1
V
1
= {[x, y]|[x, y] E, x, y V
1
}).
Se spune ca graful H este indus sau generat de submult imea de varfuri V
1
si se noteaza
H = G|
V
1
sau H = [V
1
]
G
.
Iata alte cateva notat ii des ntalnite:
- GV
1
= subgraful ce se obt ine din G prin eliminarea submult imii de varfuri V
1
(V
1

V );
- Gx = subgraful G{x};
- < E
1
>
G
= graful part ial al lui G generat de E
1
;
35
- GE
1
=< E \ E
1
>
G
;
- Ge = G{e}, graful part ial obt inut prin eliminarea unei muchii e.
Exemplul 3.3 Graful part ial din gura 3.2 c) se obt ine din graful 3.1 b) prin stergerea
muchiilor [2, 4], [2, 5], [3, 5], [4, 5]. Subgraful din gura 3.2 b) este indus de mult imea V
1
=
{1, 3, 4, 5} din graful complet K
5
(H = K
5
|V
1
).
Denit ia 3.5 Gradul unui varf este egal cu numarul muchiilor incidente cu varful x si se
noteaza cu d(x) (d(x) = |{[x, u]|[x, u] E, u V }|). Un varf cu gradul 0 (d(x) = 0) se
numeste v arf izolat.
Notam (G) = min{d
G
(u)|u G} si (G) = max{d
G
(u)|u G}.
Fig. 3.3: Graful lui Petersen
Exemplul 3.4 Graful lui Petersen din gura 3.3 este un exemplu de graf trivalent sau cubic
(toate varfurile grafului au acelasi grad, 3).
Propozit ia 3.5 Pentru un graf G = (V, E), V = {x
1
, x
2
, . . . , x
n
}, |E| = m, avem urmatoarea
relat ie:
n

k=1
d(x
k
) = 2m. (3.1)
Astfel n orice graf G exista un numar par de varfuri al caror grad este un numar impar.
Denit ia 3.6 Se numeste secvent a grac a un sir de numere naturale d
1
, d
2
, . . . , d
n
cu
proprietatea ca ele reprezinta gradele varfurilor unui graf neorientat.
Corolarul 3.6 Pentru ca o secvent a de numere naturale d
1
, d
2
, . . . , d
n
sa e secvent a graca,
este necesar ca:
1. k = 1, n, d
k
n 1;
2.

n
k=1
d
k
este un numar par.
Denit ia 3.7 Un lant L = [v
0
, v
1
, . . . , v
m
] este o succesiune de varfuri cu proprietatea ca
oricare doua varfuri vecine sunt adiacente ([v
i
, v
i+1
] E, i = 0, m1). Varfurile v
0
si v
m
se numesc extremit at ile lant ului, iar m reprezinta lungimea lant ului.
36
Daca varfurile v
0
, v
1
, . . . , v
m
sunt distincte doua cate doua, lant ul se numeste elementar
(v
i
= v
j
, i, j = 0, m).
Denit ia 3.8 Un lant L pentru care v
0
= v
m
se numeste ciclu.
Denit ia 3.9 Se numeste ciclu hamiltonian un ciclu elementar ce trece prin toate varfurile
grafului. Un graf ce admite un ciclu hamiltonian se numeste graf Hamilton sau graf
hamiltonian.
Denit ia 3.10 Un lant L ce cont ine ecare muchie exact o singura data se numeste lant
eulerian. Daca v
0
= v
m
si lant ul este eulerian atunci ciclul se numeste ciclu eulerian.
Un graf ce cont ine un ciclu eulerian se numeste graf eulerian.
Exemplul 3.7 [1, 2, 3, 1, 4] este un exemplu de lant n graful din gura 3.2 c). Varfurile 1
si 4 sunt extremitat ile lant ului. Lant ul nu este elementar deoarece varful 1 se ntalneste de
doua ori, n schimb [1, 2, 3, 4, 1] este un ciclu elementar.
[3, 4, 5, 1, 2, 3] este un ciclu hamiltonian n graful din gura 3.2 a). [4, 5, 1, 2, 4, 3] este un
lant eulerian, precum si [2, 4, 3, 2, 1, 5, 4].

In acest graf nu exista nici un ciclu eulerian.
Fig. 3.4: Componente conexe
Denit ia 3.11 Un graf se numeste conex daca pentru orice pereche de varfuri x si y exista
un lant de la x la y (x, y V, x y).
Se numeste component a conex a un subgraf conex maximal, adica un subgraf conex n
care nici un varf din subgraf nu este adiacent cu unul din afara lui prin intermediul unei
muchii apart inand grafului init ial.
Denit ia 3.12 O muchie e E se numeste muchie critic a daca prin eliminarea acesteia
o componenta conexa se mparte n doua sau mai multe componente conexe.
Exemplul 3.8 Graful din gura 3.4 are doua componente conexe: {1, 2, 3, 4, 5, 6} si {7, 8, 9}.
Muchia [2, 5] este muchie critica.
Denit ia 3.13 Un graf planar este un graf ce poate reprezentat n plan astfel ncat
muchiile sale sa nu se intersecteze doua cate doua.
Denit ia 3.14 Un graf G = (V, E) se numeste graf bipartit daca exista o partit ie a
mult imii nodurilor {V
1
, V
2
} (V = V
1
V
2
, V
1
V
2
= , V
1
, V
2
= ) astfel ncat orice muchie din
E va avea o extremitate n mult imea V
1
si cealalta extremitate n mult imea V
2
([x, y] E
avem x V
1
si y V
2
).
37
Propozit ia 3.9 Un graf este bipartit daca si numai daca nu cont ine cicluri de lungime
impara.
Denit ia 3.15 Un graf bipartit este complet daca x V
1
, y V
2
, [x, y] E (G =
(V, E), V = V
1
V
2
, V
1
V
2
= ). Daca |V
1
| = p, |V
2
| = q atunci graful bipartit complet se
noteaza K
p,q
.
Fig. 3.5: Un exemplu de graf bipartit si graf bipartit complet.
Exemplul 3.10

In gura 3.5 a) este ilustrat un graf bipartit (V
1
= {1, 2, 3}, V
2
= {4, 5}),
iar n cazul b) avem un graf bipartit complet, K
2,3
.
Denit ia 3.16 Se numeste izomorsm de la graful G la graful G

o funct ie bijectiva :
V (G) V (G

) astfel ncat [u, v] E(G) ([u, v]) E(G

).
Daca exista un izomorsm de la graful G la graful G

atunci se spune ca G este izomorf


cu G

si notam acest lucru astfel: G G

.
Denit ia 3.17 Un graf etichetat este un graf n care ecare muchie si varf poate avea
asociata o eticheta.
Vom prezenta n continuare cateva operat ii dintre cele mai ntalnite ce se pot efectua
asupra unui graf oarecare:
ind dat un nod se cere lista vecinilor sai. Aceasta operat ie este cea mai utilizata pentru
o serie ntreaga de algoritmi pe grafuri;
ind data o pereche de noduri {u, v} se cere sa se determine daca aceasta constituie o
muchie sau un arc al grafului;
adaugarea sau stergerea unui nod sau a unei muchii/arc;
translatarea dintrun mod de reprezentare n altul. De foarte multe ori modul de
reprezentare sub forma caruia au fost introduse datele, difera de modul de reprezentare
optim recomandat pentru un anumit algoritm.

In aceasta situat ie este indicata trans-
formarea primului mod de reprezentare n modul de reprezentare optim;
ind data o muchie sau un nod se cere o informat ie asociata acestui element: de exemplu
lungimea muchiei sau distant a de la sursa la nodul specicat.
38
3.2 Operat ii pe grafuri
1. Complementarul grafului G = (V, E) se deneste astfel: este graful G
c
= (V
c
, E
c
), unde
V
c
= V si E
c
= {[x, y]|x, y V, [x, y] / E}. Altfel spus E
c
= (V V ) \ E.
Fig. 3.6: Un exemplu de graf complementar altui graf.

In gura 3.6 b) este reprezentat graful complementar G


c
al grafului G = (V, E), din
gura 3.6 a) (V = {1, 2, 3, 4, 5}, E = {[1, 2], [1, 5], [2, 3], [3, 4], [4, 5]}). Conform denit iei
G
c
= (V
c
, E
c
) unde V
c
= V si E
c
= {[1, 3], [1, 4], [2, 4], [2, 5], [3, 5]}.
2. Graful obt inut din G = (V, E) prin insert ia unui varf v / V pe o muchie [x, y] E
este graful G
i
= (V
i
, E
i
) unde V
i
= V {v}, E
i
= (E \ {[x, y]}) {[x, v], [v, y]}.
Considerand graful din gura 3.6 a), prin insert ia varfului 6 pe muchia [1, 5] se obt ine
graful din gura 3.7 a).
3. Graful obt inut din G = (V, E) prin contract ia unei muchii u = [x, y] la un varf t este
graful G
ct
= (V
ct
, E
ct
), unde V
ct
= (V \ {x, y}) {t}.
Fig. 3.7: a) Graful obt inut prin inserarea varfului 6 n graful din gura 3.6 a). b) Graful obt inut prin
contract ia muchiei [3, 4] n graful din gura 3.6 a).

In gura 3.7 b) este reprezentat graful obt inut prin contract ia muchiei [3, 4] din graful
G = (V, E) (vezi gura 3.6 a)).
4. Se numeste graf reprezentativ al muchiilor unui graf G = (V, E), graful G
R
= (V
R
, E
R
)
n care |V
R
| = |E| si E
R
= {[e, f]|e, f E adiacente} (vezi gura 3.8).
5. Denim graful total al unui graf G = (V, E) ca ind graful G
T
= (V
T
, E
T
) unde V
T
=
V E si E
T
= {[u, v]|u, v V E iar u si v sunt adiacente sau incidente n G}.
39
Fig. 3.8: Figura b) prezinta graful reprezentativ al muchiilor grafului din gura a).
Fig. 3.9: a) Un exemplu de graf neorientat. b) Graful total al grafului din gura a).
Graful total G
T
= (V
T
, E
T
), unde V
T
= {1, 2, 3, 4, v
1
, v
2
, v
3
, v
4
}, si E = {[1, 2], [1, 4],
[2, 3], [3, 4], [v
1
, v
2
], [v
1
, v
4
], [v
2
, v
3
], [v
3
, v
4
], [v
1
, 1], [v
1
, 2], [v
2
, 2], [v
2
, 3], [v
3
, 3], [v
3
, 4], [v
4
, 4], [v
4
, 1]},
corespunde grafului G = (V, E), V = {1, 2, 3, 4}, E = {[1, 2], [1, 4], [2, 3], [3, 4]} (vezi
gura 3.9).
6. Reuniunea si intersect ia a doua grafuri se denesc astfel:
daca V
1
= V
2
atunci: G
1
G
2
= (V
1
, E
1
E
2
), G
1
G
2
= (V
1
, E
1
E
2
);
daca V
1
V
2
= atunci: G
1
G
2
= (V
1
V
2
, E
1
E
2
), G
1
G
2
= (V
1
V
2
, E
1
E
2
);
daca V
1
V
2
= atunci G
1
G
2
se numeste reuniune disjuncta a grafurilor G
1
si
G
2
, iar G
1
G
2
este graful vid.
7. Denim suma grafurilor G
1
si G
2
ca ind graful complementar al reuniunii comple-
mentarelor celor doua grafuri: G
1
G
2
= (G
c
1
G
c
2
)
c
.
Pentru grafurile complete K
p
si K
q
avem: K
p
K
q
= (K
c
p
K
c
q
)
c
= K
p+q
. Un alt
exemplu de suma a doua grafuri poate urmarit n gura 3.10.
8. Se numeste produsul cartezian al grafurilor G
1
= (V
1
, E
1
) si G
2
= (V
2
, E
2
), graful
G
1
G
2
= (V

, E

), unde V

= V
1
V
2
si E

= {[(u
1
, u
2
), (v
1
, v
2
)]|u
1
, v
1
V
1
, u
2
, v
2

V
2
; u
1
= v
1
si [u
2
, v
2
] E
2
sau u
2
= v
2
si [u
1
, v
1
] E
1
}.
40
Fig. 3.10: a) Doua grafuri neorientate, G
1
si G
2
. b) Grafurile complementare G
c
1
si G
c
2
. c) Reuniunea
grafurilor G
c
1
si G
c
2
. d) Graful complementar al grafului reuniune (G
c
1
G
c
2
)
c
.
Fig. 3.11: Graful produs cartezian a doua grafuri
Fie G
1
= (V
1
, E
1
) unde V
1
= {u
1
, v
1
} si E
1
= {[u
1
, v
1
]}, si G
2
= (V
2
, E
2
), unde V
2
=
{u
2
, v
2
, w
2
} si E
2
= {[u
2
, v
2
], [v
2
, w
2
]}, doua grafuri neorientate. Atunci graful produs
cartezian al grafurilor G
1
si G
2
este G
1
G
2
= (V

, E

) unde:
V

= {(u
1
, u
2
), (u
1
, v
2
), (u
1
, w
2
), (v
1
, u
2
), (v
1
, v
2
), (v
1
, w
2
)}, si
E

= {[(u
1
, u
2
), (v
1
, u
2
)], [(u
1
, u
2
), (u
1
, v
2
)], [(u
1
, v
2
), (v
1
, v
2
)], [(u
1
, v
2
), (u
1
, w
2
)],
[(u
1
, w
2
), (v
1
, w
2
)], [(v
1
, u
2
), (v
1
, v
2
)], [(v
1
, v
2
), (v
1
, w
2
)]} (vezi gura 3.11).
9. Se numeste radacina patrata a grafului G, un graf neorientat H cu proprietatea ca
H
2
= G (H
2
= H H).
10. Operat ia de compunere a doua grafuri neorientate G
1
= (V
1
, E
1
) si G
2
= (V
2
, E
2
),
notata cu G
1
[G
2
], se realizeaza astfel: varful (x
1
, y
1
) este adiacent cu varful (x
2
, y
2
) n
graful rezultat daca varful x
1
este adiacent cu varful x
2
n graful G
1
sau (x
1
= x
2
si
varful y
1
este adiacent cu varful y
2
n graful G
2
) (vezi gura 3.12).
41
Fig. 3.12: Graful rezultat n urma compunerii grafurilor G
1
si G
2
din gura 3.11
3.3 Moduri de reprezentare
Fig. 3.13: Un exemplu de graf neorientat
Pentru o mult ime de noduri V vom presupune un mod de ordonare a nodurilor grafului
(primul nod, al doilea nod, etc.), deoarece reprezentarea unui graf depinde de aceasta or-
donare. Astfel, numerotam n mod arbitrar varfurile grafului cu 1, 2, . . . , |V |.
1. Matricea de adiacent a - este o matrice A M
nn
Z unde n = |V |, iar a
i,j
= 1 daca
exista o muchie ntre nodurile numerotate i si j (ntre x
i
si x
j
), sau a
i,j
= 0 daca nu
exista o muchie ntre acestea.
a
i,j
=
_
1 , daca [x
i
, x
j
] E
0 , daca [x
i
, x
j
] / E
Pentru un graf neorientat aceasta matrice este simetrica (a
i,j
= a
j,i
).
Exemplul 3.11 Matricea de adiacent a corespunz atoare grafului din gura 3.13 este:
A =
_
_
_
_
_
_
_
_
_
_
_
_
0 1 1 1 0 0 0 0
1 0 0 0 1 0 0 0
1 0 0 0 1 0 0 0
1 0 0 0 0 1 0 0
0 1 1 0 0 0 1 0
0 0 0 1 0 0 1 1
0 0 0 0 1 1 0 0
0 0 0 0 0 1 0 0
_
_
_
_
_
_
_
_
_
_
_
_
42
Fig. 3.14: Un exemplu de graf neorientat ponderat
Matricea de adiacent a are un numar de n
2
elemente, iar elementele neredundante sunt
n numar de
n(n1)
2
. Prin urmare complexitateaspat iu a matricii de adiacent a este
O(n
2
).
2. Matricea costurilor - reprezinta o varianta a matricei de adiacent a ce se obt ine n mod
natural luanduse n considerare graful ponderat: ecarei muchii i se ataseaza un cost
d, iar valorile matricii A se denesc astfel:
a
i,j
=
_

_
0 , daca x
i
= x
j
+ , daca [x
i
, x
j
] / E
d > 0 , daca [x
i
, x
j
] E
(3.2)
sau
a
i,j
=
_

_
0 , daca x
i
= x
j
, daca [x
i
, x
j
] / E
d > 0 , daca [x
i
, x
j
] E.
(3.3)
Exemplul 3.12 Matricea costurilor corespunz atoare grafului din gura 3.14 are urm atoarele
valori:
A =
_
_
_
_
_
_
_
_
_
_
_
_
0 35 7 20
35 0 50
7 0 22
20 0 15
50 22 0 44
15 0 10 27
44 10 0
27 0
_
_
_
_
_
_
_
_
_
_
_
_
Notat ia (3.2) este folosita n aplicat ii n care se cere un drum de lungime minima iar
(3.3) este folosita n aplicat ii n care se cere un drum de lungime maxima ntre doua
noduri.
Matricea costurilor va ocupa un spat iu de memorie mai mare decat cel ocupat de
matricea de adiacent a: pentru reprezentarea unui element al matricii de adiacent a este
sucient un bit, pe cand pentru reprezentarea unui element al matricii costurilor se
foloseste un byte, un ntreg (lung) sau un numar real.
43
Prin urmare pentru reprezentarea unei matrici de adiacent a de dimensiuni n n sunt
necesari n
n
8
octet i, pe cand pentru reprezentarea unei matrici de costuri cu elemente
numere ntregi sunt necesari 2 n
2
octet i (daca presupunem ca un numar ntreg fara
semn este pastrat pe 2 octet i).
3. Liste de adiacent a - pentru ecare nod se ret ine lista nodurilor adiacente. Astfel unui
nod x
k
i se va atasa lista tuturor vecinilor sai.
Aceasta reprezentare se preteaza mai bine pentru grafuri cu un numar mare de noduri
si un numar mic de muchii (graf rar).

In cazul unui graf neorientat numarul elementelor
din listele de adiacent a este 2 |E|, deoarece o muchie [u, v] va prezenta de doua ori,
atat n lista de adiacent a a nodului u cat si n lista de adiacent a a nodului v.
Exemplul 3.13 Listele de adiacent a pentru graful din gura 3.13 sunt:
1: (2, 3, 4) 5: (2, 3, 7)
2: (1, 5) 6: (4, 7, 8)
3: (1, 5) 7: (5, 6)
4: (1, 6) 8: (6)
Aceste liste de adiacent a (sau liste de vecini) pot reprezentate prin intermediul
tablourilor sau prin intermediul listelor simplu sau dublu nlant uite.
Pentru reprezentarea ce utilizeaza tablouri, se vor deni doua tablouri Cap si List
(Cap R
1n
, List R
2m
, m = |E|) unde:
Cap
k
=
_

_
0 , nodul respectiv nu are vecini
j , indica numarul coloanei din matricea List unde se aa primul vecin
al varfului x
k
.
List
1,j
- indicele varfului ce se aa n lista de vecini a varfului x
k
.
List
2,j
=
_

_
0 , daca varful respectiv este ultimul (aceasta valoare are aceeasi
semnicat ie ca si valoarea NIL sau NULL utilizata n lucrul cu pointeri)
i , indica numarul coloanei unde se aa urmatorul vecin din lista
de vecini a nodului x
k
.
Exemplul 3.14 Pentru exemplul din gura 3.13 avem urmatoarea congurat ie pentru
cei doi vectori considerat i:
Nod 1 2 3 4 5 6 7 8
Cap 1 4 6 8 10 13 16 18
List =
_
2 3 4 1 5 1 5 1 6 2 3 7 4 7 8 5 6 6
2 3 0 5 0 7 0 9 0 11 12 0 14 15 0 17 0 0
_

In limbajul C denim urmatoarele structuri de date avand rolul de a ne ajuta la


ment inerean memorie a listelor de adiacent a ale unui graf oarecare folosind liste liniare
simplu nlant uite (vezi si gura 3.15):
44
1
2
3
4
5
6
7
8
2 3 4
1 5
2 3 7
4 7 8
5 6
6
1 5
1 6
NULL
NULL
NULL
NULL
NULL
NULL
NULL
NULL
Fig. 3.15: Liste de adiacent a
typedef struct nod{
int nodeIndex;
struct nod *next;
}NOD;
#define MAX 100
NOD* vecini[MAX];
NOD* vecini[MAX] este un array de pointeri ce cont ine n vecini[i] capul listei de vecini
ai nodului de indice i. struct nod *next reprezinta un pointer catre urmatoarea
nregistrare de tip NOD ce pastreaza informat ii cu privire la urmatorul vecin.
Cantitatea de memorie necesara pentru pastrarea listelor de adiacent a este:
reprezentarea folosind matricile Cap si List - putem presupune ca n, m 65535
adica sunt sucient i 2 octet i pentru reprezentarea acestor numere n memorie
(2
16
1 = 65535).

In aceasta situat ie cantitatea de memorie necesara pentru
matricea Cap este 2n, iar pentru matricea List este 8m. Astfel complexitatea
spat iu este O(n +m).
reprezentarea folosind pointeri - presupunem ca avem 2 octet i pentru informat ia
utila si 2 octet i pentru informat ia de legatura. Num arul de octet i folosit i pentru
reprezentarea unui pointer n limbajul C poate depinde de modelul de memorie
ales (small, huge, etc.) sau de dimensiunea instrut iunilor (pe 16, 32 sau 64 de
bit i).
Astfel se utilizeaza 2n octet i pentru vectorul ce cont ine adresele primului element
(capul) al ecarei liste de vecini, si 8m octet i pentrunregistrarile listelor de vecini.
Din aceasta cantitate de memorie, 4m reprezinta informat ie utila (indicii vecinilor)
iar 2n + 4m informat ie auxiliara (pointeri).
4. Lista de muchii - ntr-o structura de date se pastreaza lista tuturor muchiilor grafului.
Aceasta constituie cea mai simpla modalitate de reprezentare a unui graf. Operat ia de
adaugare a unui nod sau a unei muchii se face ntrun timp constant, pe cand, alte
operat ii sunt mai costisitoare: de exemplu, determinarea listei de vecini a unui nod
necesita un timp (m).
Exemplul 3.15 Pentru pastrarea n memorie se poate folosi o matrice M cu doua linii
si |E| coloane (M M
2|E|
), unde:
45
M
1,i
- indicele varfului ce se aa n prima extremitate a muchiei i;
M
2,i
- indicele varfului ce se aa n cea dea doua extremitate a muchiei i.
M =
_
1 1 1 2 3 4 5 6 6
2 3 4 5 5 6 7 7 8
_
Vom sintetiza complexitatea timp pentru diverse operat ii folosind ecare dintre modurile
de reprezentare prezentate:
Matricea de adiacent a Liste de vecini Lista de muchii
Gradul unui nod x
i
O(n) O(d(x
i
)) O(m)
(x
i
, x
j
) E? O(1) O(d(x
i
)) O(m)
Urmatorul vecin al lui x
i
O(n) O(d(x
i
)) O(m)
3.4 Parcurgerea grafurilor
Pentru un graf dat este important sa se determine o modalitate sistematica de vizitare a
tuturor varfurilor grafului, vizitare ce se realizeaza n scopul prelucrarii informat iei cont inute
de acestea.
3.4.1 Parcurgerea n lat ime (BF-Breadth-First)
Metoda de parcurgere n lat ime viziteaza nodurile grafului n felul urmator (vezi algoritmul
20):
se viziteaza mai ntai varful de pornire k;
urmeaza n ordine tot i vecinii nca nevizitat i ai acestuia;
se continua cu vecinii nca nevizitat i ai acestora, s.a.m.d.
Fig. 3.16: Arbore de acoperire n lat ime
Pentru graful considerat n gura 3.13 ordinea de parcurgere este urmatoarea: 1, 2, 3, 4,
5, 6, 7, 8. Daca consideram muchiile folosite n timpul parcurgerilor (muchiile prin intermediul
carora sa naintat n graf) se obt ine un arbore/padure de parcurgere/vizitare/acoperire.

In gura 3.16 este reprezentat arborele de acoperire n lat ime rezultat n urma parcurgerii
grafului din exemplu.
46
Algoritmul de parcurgere utilizeaza o structura de date de tip coada n care vor intro-
duse nodurile vizitate, dar care nu au fost nca prelucrate (nu au fost cercetat i vecinii lor).
Reamintim ca numarul de noduri din mult imea V este n. Vectorul vizitat pastreaza situat ia
vizitarii nodurilor grafului G:
vizitat
k
=
_
1 , daca nodul k a fost vizitat
0 , daca nodul k nu a fost vizitat.
Algoritm 20 Algoritm de vizitare n lat ime
1: procedure BFS(k, n, V ecin)
Input:
_

_
k - nodul de la care se porneste vizitarea
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: for i 1, n do
3: vizitat
i
0
4: end for
5: vizitat
k
1 marcarea nodului curent ca ind vizitat
6: Q k inserarea nodului curent k n coada
7: call V izitare(k) vizitarea nodului curent
8: while (Q = ) do
9: Q k extragere nod curent din coada
10: for i 1, n do
11: if (vizitat
i
= 0) (vecin
k,i
= 1) then
12: vizitat
i
1 marcarea nodului i ca ind vizitat
13: Q i inserarea nodului i n coada
14: call V izitare(i) vizitarea nodului i
15: end if
16: end for
17: end while
18: end procedure
Implementarea n limbajul C a algoritmului 20 este urmatoarea:
#include <stdio.h>
#include <mem.h>
#define MAX 100
#define TRUE 1
#define FALSE 0
// Numarul de noduri din graf
int n;
// Matricea de adiacenta
char vecin[MAX][MAX];
// coada
int coada[MAX];
// Indicele primului element din coada
int first;
// Indicele ultimului element din coada
int last;
// Pastreaza starea cozii
47
int vida;
/**
* Initializarea cozii circulare.
*/
void initQueue(void) {
vida = TRUE;
first = 0;
last = MAX;
}
/**
* Intoarce pentru pozitia i, urmatoarea pozitie din coada.
*/
int next(int i) {
return (i + 1) % MAX;
}
/**
* Insereaza elementul a carui valoare este pastrata in variabila k in coada.
*/
void enQueue(int k) {
last = next(last);
coada[last] = k;
if (vida)
vida = FALSE;
}
/**
* Extrage un element din coada.
*/
int deQueue(void) {
int k = coada[first];
first = next(first);
if (first == next(last))
vida = TRUE;
return k;
}
/**
* Parcurge in latime graful pornind de la nodul de inceput k.
*/
void bfs(int k) {
int i;
char vizitat[MAX];
memset(vizitat, 0, sizeof(vizitat));
vizitat[k] = 1;
enQueue(k);
printf("%d ", k);
while (!vida) {
k = deQueue();
48
for (i = 0; i < n; i++)
if ((vizitat[i] == 0) && (vecin[k][i] == 1)) {
vizitat[i] = 1;
enQueue(i);
printf("%d ", i);
}
}
}
/**
* Se citesc numarul de noduri precum si matricea de adiacenta.
*/
void readInput(void) {
int i, j;
printf("n = "); scanf("%d",&n);
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++) {
printf("a[%d,%d] = ", i, j);
scanf("%d", &vecin[i][j]);
vecin[j][i] = vecin[i][j];
}
}
void main(void) {
readInput();
initQueue();
bfs(0);
}


In exemplul anterior funct ia de citire readInput() este foarte simpla: se citeste mai
ntai numarul de noduri al grafului, si apoi se citeste matricea de adiacent a a grafului.
Variabilele n si vecin sunt declarate drept variabile globale. Deoarece matricea vecin
este simetrica si pentru a reduce numarul de citiri, se vor solicita numai valorile aate
deasupra diagonalei principale:
void readInput(void) {
int i, j;
printf("n = "); scanf("%d",&n);
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++) {
printf("a[%d,%d] = ", i, j);
scanf("%d", &vecin[i][j]);
vecin[j][i] = vecin[i][j];
}
}
Funct ia memset() este o funct ie de biblioteca a carei declarat ie poate gasitan header-
ele mem.h si string.h la Borland C sau memory.h si string.h la Visual C++ 2010
1
.
Funct ia are urmatoarea semnatura
2
1
http://msdn.microsoft.com/en-us/library/1fdeehz6.aspx
2
http://en.wikibooks.org/wiki/C_Programming/Strings#The_memset_function
49
void *memset(void *dest, int c, size t count);
si are rolul de a init ializa cu valoarea c primii count octet i din zona de memorie ce
ncepe de la adresa identicata de pointerul dest.
vida este o variabila globala ce ia valoarea true atunci cand coada nu cont ine nici un
element si valoarea false n caz contrar.
Coada este implementata static sub forma unei cozi circulare.
Vizitarea ncepe de la nodul 0 (bfs(0)).
Algoritmul BF este utilizat de catre metoda Branch-and-Bound ca metoda de explorare
a spat iului solut iilor, cat si n cadrul problemelor de determinare a distant ei minime de la
un varf la toate celelalte varfuri n cazul n care lungimea unui drum dintre doua noduri se
considera ca ind numarul de noduri intermediare ale acestuia.
3.4.2 Parcurgerea D (D - Depth)
Metoda de parcurgere D este asemanatoare cu metoda de parcurgere n lat ime (BF):
la nceput se viziteaza varful de pornire k;
urmeaza n ordine tot i vecinii nca nevizitat i ai acestuia;
la pasul urmator se considera ultimul nod vizitat v si se ncearca vizitarea vecinilor nca
nevizitat i ai acestuia. Daca nodul v nu mai are vecini nevizitat i, se continua procesul
de parcurgere cu nodul ce a fost vizitat exact naintea nodului v, etc.
Metoda de parcurgere D este o combinat ie ntre metoda de parcurgere n lat ime (vezi
sect iunea 3.4.1) si metoda de parcurgere n adancime (vezi sect iunea 3.4.3). Pentru un nod
se viziteaza tot i vecinii nca nevizitat i ai acestuia, nsa spre deosebire de metoda de parcurgere
n lat ime unde ordinean care au fost vizitate nodurile se pastreaza si la parcurgere, la metoda
de parcurgere D se prelucreaza mereu ultimul nod vizitat.
Pentru aceasta n algoritmul D se nlocuieste structura de date de tip coada utilizata n
algoritmul BF, cu o structura de date de tip stiva (vezi algoritmul 21).
Fig. 3.17: Arbore de acoperire pentru parcurgerea D

In gura 3.17 poate urmarit arborele de acoperire pentru parcurgerea D a grafului G


din gura 3.13.
50
Algoritm 21 Algoritm de vizitare D
1: procedure D(k, n, V ecin)
Input:
_

_
k - nodul de la care se porneste vizitarea
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: for i 1, n do
3: vizitat
i
0
4: end for
5: vizitat
k
1 marcarea nodului curent ca ind vizitat
6: S k inserarea nodului curent k n stiva
7: call V izitare(k) vizitarea nodului curent
8: while (S = ) do
9: S k extragerea nodului curent din stiva
10: for i 1, n do
11: if (vizitat
i
= 0) (vecin
k,i
= 1) then
12: vizitat
i
1 marcarea nodului i ca ind vizitat
13: S i inserarea nodului i in stiva
14: call V izitare(i) vizitarea nodului i
15: end if
16: end for
17: end while
18: end procedure
3.4.3 Parcurgerea n adancime (DFS-Depth First Search)

In cadrul acestei metode se va merge n adancime ori de cate ori este posibil: prelucrarea
unui varf consta n prelucrarea primului dintre vecinii sai nca nevizitat i.
se viziteaza varful de pornire k;
urmeaza, n ordine, primul vecin nca nevizitat al acestuia;
se cauta primul vecin nca nevizitat al primului vecin nevizitat al nodului de start,
s.a.m.d.;
se merge n adancime pana cand se ajunge la un varf ce nu are vecini, sau pentru care
tot i vecinii sai au fost vizitat i.

In acest caz, se revine n nodul sau parinte (nodul din
care a fost vizitat nodul curent), si se continua algoritmul.
Pentru graful considerat (vezi gura 3.13), n urma parcurgerii n adancime, vom obt ine
nodurile n ordinea urmatoare: 1, 2, 5, 3, 7, 6, 4, 8 (vezi gura 3.18). Daca ne propunem sa
vizitam exact o singura data toate nodurile unui graf, aplicand algoritmul DFS de cate ori
este nevoie, si selectam numai muchiile utilizate n timpul explorarii, rezulta o padure de
arbori. Fiecare dintre acesti arbori constituie un arbore de acoperire n adancime.

In urma parcurgerii n adancime muchiile unui graf pot clasicate n urmatoarele cate-
gorii:
1. muchie a arborelui de acoperire - muchia [u, v] este o muchie a arborelui de acoperire
daca dfs(u) apeleaza direct dfs(v) sau invers;
2. muchie de ntoarcere - muchia [u, v] este o muchie de ntoarcere daca dfs(u) apeleaza
indirect dfs(v) (x V a.i. dfs(u) dfs(x) dfs(v)) sau invers.
51
Fig. 3.18: Arbore de acoperire n adancime
Exemplul 3.16 Pentru graful din gura 3.13 avem:
muchiile [1, 2], [2, 5], [3, 5], [4, 6], [5, 7], [6, 7], [6, 8] sunt muchii ale arborelui de acoperire;
muchiile [1, 3], [1, 4] sunt muchii de ntoarcere;
Algoritm 22 Algoritm de vizitare n adancime (varianta recursiva)
1: procedure DFS(k, n, V ecin)
Input:
_

_
k - nodul vizitat
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: vizitat
k
1 marcarea nodului curent ca ind vizitat
3: call V izitare(k) vizitarea nodului curent
4: for i 1, n do
5: if (vizitat
i
= 0) (vecin
k,i
= 1) then
6: call DFS(i, n, vecin) apelul recursiv al subrutinei DFS pentru nodul i
7: end if
8: end for
9: end procedure
Implementarea algoritmului se poate realiza e n varianta recursiva (vezi algoritmul 22),
e n varianta nerecursiva (vezi algoritmul 23). Ca si la algoritmul de parcurgere n lat ime,
vectorul vizitat pastreaza situat ia vizitarii nodurilor grafului G:
vizitat
k
=
_
1 , daca nodul k a fost vizitat
0 , n caz contrar.
Subrutina DFS (algoritmul 22)ncepe cu marcarea nodului curent ca ind vizitat (vizitat
k

1) si apelul procedurii V izitare (call V izitare(k)). Apoi se cauta primul vecin nevizitat i
al varfului curent k ((vizitat
i
= 0) (vecin
k,i
= 1)) si se reia secvent a de operat ii pentru
acesta, printrun apel recursiv (call DFS(i)). Enunt ul repetitiv for i 1, n poate opti-
mizat astfel ncat sa nu se mai verice toate varfurile grafului, ci numai nodurile adiacente
cu nodul curent: n aceasta situat ie reprezentarea cu liste de adiacent a este optima din punct
52
de vedere al numarului de operat ii efectuate, ind preferata reprezentarii prin matricea de
adiacent a.
Algoritm 23 Algoritm de vizitare n adancime (varianta nerecursiva)
1: procedure DFS Nerecursiv(k, n, V ecin)
Input:
_

_
k - nodul de la care se porneste vizitarea
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: for i 1, n do
3: vizitat
i
0
4: end for
5: vizitat
k
1 marcarea nodului curent ca ind vizitat
6: call V izitare(k) vizitarea nodului curent
7: S k inserarea nodului curent k n stiva
8: found false
9: while (S = ) do cat timp stiva nu este vida
10: if ((found)) then
11: S k extragerea nodului curent din stiva
12: end if
13: i 1
14: found false
15: while (i n) (found = false) do
16: if (vizitat
i
= 0) (vecin
k,i
= 1) then
17: vizitat
i
1 marcarea nodului i ca ind vizitat
18: S k inserarea nodului curent k n stiva
19: call V izitare(i) vizitarea nodului i
20: k i
21: found true
22: else
23: i i + 1
24: end if
25: end while
26: end while
27: end procedure
Algoritmul 23 utilizeaza o stiva S pentru a pastra tot timpul nodul grafului din care s-a
ajuns la nodul curent (tatal nodului curent din arborele de acoperire n adancime). Secvent a
de instruct iuni 23.1323.25 nu este optima deoarece, de ecare data cand se revine la un nod
parinte, se verica ntreaga mult ime V pentru a identica un vecin nevizitat al acestuia.

In
vederea reducerii numarului de vericari, se va utiliza reprezentarea prin liste de adiacent a,
si se salveaza pe stiva, pe langa valoarea nodului curent k, valoarea vecinului nevizitat gasit,
astfel ncat, la revenire, sa se continue cautarea urm atorului vecin nevizitat al nodului curent
k pornind de la acest nod. Daca nu mai exista nici un vecin nevizitat al varfului k (linia
10), atunci se revine la parintele nodului curent aat pe stiva. Algoritmul se opreste n
cazul n care stiva este vida (atunci cand nodul curent este radacina arborelui de vizitare n
adancime).
Am ales aici varianta recursiva pentru usurint a de programare si elegant a ei. Prezentam
n continuare implementarea n limbajul C a algoritmului 22:
#include <stdio.h>
53
#include <mem.h>
#define MAX 100
// Matricea de adiacenta
char vecin[MAX][MAX];
// Vector ce pastreaza starea unui nod: vizitat sau nevizitat
char vizitat[MAX];
// Numarul de varfuri din graf
int n;
// Nodul din care se porneste vizitarea
int nodi;
/**
* Se citesc numarul de noduri precum si matricea de adiacenta.
*/
void readInput(void) {
int i, j;
printf("n = "); scanf("%d",&n);
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++) {
printf("a[%d,%d] = ", i, j);
scanf("%d", &vecin[i][j]);
vecin[j][i] = vecin[i][j];
}
printf(Nodul initial = ); scanf(%d,&nodi);
memset(vizitat, 0, sizeof(vizitat));
}
/**
* Parcurgerea in adancime pornind din nodul k.
*/
void dfs(int k) {
int i;
vizitat[k] = 1;
printf("%d ",k);
for (i = 0; i < n; i++)
if (vizitat[i] == 0 && vecin[k][i] == 1)
dfs(i);
}
void main(void) {
readInput();
dfs(nodi);
}
Complexitatea algoritmilor de parcurgere
Complexitatea algoritmilor prezentat i este O(n
2
) deoarece se utilizeaza matricea de adiacen-
t a drept modalitate de reprezentare a grafului. Daca se utilizeaza reprezentarea prin liste de
54
vecini, atunci complexitatea algoritmilor devine O(n +m), unde m = |E|.
Matricea de adiacent a Liste de vecini Lista de muchii
BFS O(n
2
) O(n + m) O(n + m
2
)
D O(n
2
) O(n + m) O(n + m
2
)
DFS O(n
2
) O(n + m) O(n + m
2
)
3.5 Componente conexe
Se poate deni pe mult imea varfurilor unui graf neorientat G o relat ie astfel: xy daca
x = y sau exista n G un lant de la x la y.
Se demonstreaza foarte usor ca relat ia este o relat ie de echivalent a. Se cunoaste faptul ca
o relat ie de echivalent a determina pe mult imea pe care este denita o partit ie. Componentele
conexe vor elementele acestei partit ii formate din varfurile ce sunt echivalente ntre ele
(conform relat iei de echivalent a).
Cu alte cuvinte, exista o partit ie a mult imii varfurilor V
V =
m
_
i=1
V
i
, V
i
V
j
= , i, j = 1, m, i = j
si o partit ie a mult imii muchiilor E
E =
m
_
i=1
E
i
, E
i
E
j
= , i, j = 1, m, i = j
astfel ncat ecare graf G
i
= (V
i
, E
i
), i = 1, m, este conex.
Algoritm 24 Algoritm pentru determinarea componentelor conexe
Input:
_
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
1: for i 1, n do
2: vizitat
i
0
3: end for
4: cmp conex nr 0
5: for i 1, n do
6: if (vizitat
i
= 0) then
7: cmp conex nr cmp conex nr + 1
8: call DFS(i, n, V ecin) determinarea componentei conexe ce cont ine nodul i
9: end if
10: end for
Pentru determinarea componentelor conexe vom utiliza metoda de vizitare n adancime a
unui graf. Pasii algoritmului descrisi n limbaj natural sunt urmatorii (algoritmul 24 prezinta
descrierea formalizata n pseudocod):
Pas 1. Se cauta un nod nca nevizitat.
Pas 2.

Incepand cu acesta se parcurg toate nodurile accesibile si nevizitate, avand grija sa
marcam vizitarea acestora. Toate aceste noduri formeaza o componenta conexa.
Pas 3. Daca mai exista noduri nevizitate mergi la pasul Pas 1, altfel algoritmul se termina.
55
3.6 Muchie critica
Reamintim faptul ca ntrun graf neorientat G = (V, E), o muchie critica este acea muchie
care prin eliminarea ei conduce la cresterea numarului de componente conexe ale grafului.
Se cere sa se determine toate muchiile critice ale unui graf dat.

In continuare sunt prezen-
tate doua variante de rezolvare.
Solut ia I
Pentru simplitate, vom trata situat ia n care graful considerat este conex (daca graful nu
este conex se determina numarul de componente conexe si se aplica algoritmul pentru ecare
componenta conexa n parte). Se elimina, pe rand, ecare muchie a grafului si apoi se verica
daca graful rezultat mai este conex (vezi algoritmul 25).
Algoritm 25 Algoritm de determinare a muchiei critice (prima varianta)
1: procedure MuchieCriticaI(n, m, V ecin)
Input:
_

_
n - numarul de noduri din graf
m - numarul de muchii din graf
V ecin - matricea de adiacent a
2: for k 1, m do
3: elimina muchia k
4: if (conex(n, vecin) = false) then
5: Output {Muchia k este critica}
6: end if
7: adauga muchia k reface graful init ial
8: end for
9: end procedure
10: function Conex(n, V ecin)
11: for i 1, n do
12: vizitat
i
0
13: end for
14: call DFS(1, n, V ecin) vizitarea n adancime a grafului
15: for i 1, n do
16: if (vizitat
i
= 0) then
17: return false
18: end if
19: end for
20: return true
21: end function
Subrutina Conex verica daca graful identicat prin matricea de adiacent a V ecin este
conex. Subrutina ntoarce valoarea 1 n cazul n care graful considerat este conex si 0 n
caz contrar. Pentru aceasta, la nceput se marcheaza toate nodurile ca ind nevizitate, si se
ncearca parcurgerea nodurilor grafului, prin intermediul unui apel al subrutinei de vizitare.
Implementarea n limbajul C:
#include <stdio.h>
#include <mem.h>
#define MAX 100
56
#define TRUE 1
#define FALSE 0
char vecin[MAX][MAX];
char vizitat[MAX];
int n;
/**
* Se citesc numarul de noduri precum si matricea de adiacenta.
*/
void readInput(void) {
int i, j;
printf("n = "); scanf("%d", &n);
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++) {
printf("a[%d,%d] = ", i, j);
scanf("%d", &vecin[i][j]);
vecin[j][i] = vecin[i][j];
}
}
/**
* Parcurgerea in adancime a grafului pornind din nodul de start k.
*/
void dfs(int k) {
int i;
vizitat[k] = TRUE;
printf("%d ", k);
for (i = 0; i < n; i++)
if ((vizitat[i] == FALSE) && (vecin[k][i] == 1))
dfs(i);
}
/**
* Functia verifica daca graful este conex.
*/
int conex(void) {
int i;
memset(vizitat, 0, sizeof(vizitat));
dfs(0);
for (i = 0; i < n; i++)
if (vizitat[i] == FALSE) {
return FALSE;
}
return TRUE;
}
void main(void) {
int i, j;
57
readInput();
for (i = 1; i < n; i++)
for (j = 0; j < i; j++)
if (vecin[i][j] == 1) {
vecin[i][j] = 0;
vecin[j][i] = 0;
if (conex() == FALSE) {
printf("Muchia (%d,%d) este critica! \n",i,j);
}
vecin[i][j] = 1;
vecin[j][i] = 1;
}
}
Observat ia 3.17 Am presupus ca numerotarea nodurilor se face de la 0 si ca exista un nod
cu eticheta 0.
Complexitateatimp a acestui algoritm (presupunem ca avem o singura componenta
conexa), este O(m(n + m)): se ia ecare muchie (O(m)), se elimina din graf, si se verica
daca graful ramas este conex (O(n +m)).
Solut ia a IIa
Cea dea doua varianta de abordare pentru identicarea unei solut ii foloseste urmatoarea
proprietate:
Observat ia 3.18 O muchie nu este critica daca ea face parte din cel put in un ciclu elemen-
tar al grafului respectiv.

In urma vizitarii DFS, toate muchiile unui graf se mpart n muchii ale arborelui de
acoperire si muchii de ntoarcere.
Vom numerota toate nodurile grafului n preordine - n momentul n care un nod este
marcat ca ind vizitat - toate valorile ind pastrate ntr-un vector prenum. Fie low
u
valoarea
unui nod u, calculata dupa formula:
low
u
= min
_

_
prenum
u
, si
prenum
x
, daca [u, x] este muchie de ntoarcere, si
low
y
, y descendent direct al lui u.
Daca prenum
u
low
v
, v descendent direct al lui u, atunci nseamna ca v sau un
descendent al lui v are o muchie dentoarcere la u sau la un stramos al acestuia. Astfel muchia
[u, v] apart ine unui ciclu elementar, si prin urmare nu este muchie critica (vezi algoritmul
26). Prin negat ie, daca exista cel put in un varf v, descendent direct al lui u, cu proprietatea
ca prenum
u
< low
v
atunci [u, v] este muchie critica. Dupa ecare apel recursiv al subrutinei
DFS (linia 16) se verica gradul de adevar al expresiei (prenum
k
< low
i
) (linia 18).
Variabila counter este globala pentru cele doua subrutine, MuchieCriticaII() si DFS critic().
La numerotarea n preordine se folosesc atribuirile: counter counter + 1, si prenum
k

counter. Cand un nod i este vecin cu nodul curent k, si nu a fost nca vizitat, valoarea lui
low
k
se calculeaza astfel: low
k
min {low
k
, low
i
}. Pentru un nod i vecin cu nodul curent
k, deja vizitat, avem o muchie de ntoarcere (nodului k i sa atribuit deja un numar n
preordine): astfel valoarea lui low
k
se calculeaza dupa formula low
k
min {low
k
, prenum
i
}.
Implementarea n limbajul C a algoritmului 26 este:
58
Algoritm 26 Algoritm de determinare a muchiei critice (a doua varianta)
1: procedure MuchieCriticaII(n, V ecin)
Input:
_
n - numarul de noduri din graf
V ecin - matricea de adiacent a
2: for i 1, n do
3: vizitat
i
0
4: end for
5: counter 0
6: call DFS critic(1, n, V ecin) vizitarea n adancime a grafului
7: end procedure
8: procedure DFS critic(k, n, V ecin)
9: vizitat
k
1
10: counter counter + 1
11: prenum
k
counter, low
k
counter
12: for i 1, n do
13: if (vecin
k,i
= 1) then
14: if (vizitat
i
= 0) then
15: tata
i
k
16: call DFS critic(i, n, V ecin)
17: low
k
Min(low
k
, low
i
)
18: if (prenum
k
< low
i
) then
19: Output {Muchia (k,i) este critica}
20: end if
21: else
22: if (tata
k
= i) then
23: low
k
Min(low
k
, prenum
i
)
24: end if
25: end if
26: end if
27: end for
28: end procedure
#include <stdio.h>
#include <mem.h>
#define MAX 100
/**
* Numarul de noduri din graf
*/
int n;
/**
* Matricea de adiacenta
*/
char vecin[MAX][MAX];
/**
* Vector ce pastreaza starea unui nod: vizitat sau nevizitat.
*/
char vizitat[MAX];
/**
59
* Pastreaza tatal fiecarui nod in arborele de acoperire
* in adincime generat de metoda DFS.
*/
int tata[MAX];
/**
* prenum[i] - numerotarea in preordine
*/
int prenum[MAX];
int low[MAX];
/**
* contor global ce numara momentul cand este vizitat un nod.
*/
int counter;
void readInput(void) {
int i, j;
printf("n = "); scanf("%d",&n);
for (i = 0; i < n - 1; i++)
for (j = i + 1; j < n; j++) {
printf("a[%d,%d] = ", i, j);
scanf("%d", &vecin[i][j]);
vecin[j][i] = vecin[i][j];
}
}
int min(int x, int y) {
return (x < y) ? x : y;
}
void dfs(int k) {
int i;
vizitat[k] = 1;
counter++;
prenum[k] = counter; low[k] = counter;
for (i = 0; i < n; i++)
if (vecin[k][i] == 1)
if (vizitat[i] == 0) {
tata[i] = k;
dfs(i);
low[k] = min(low[k], low[i]);
if (prenum[k] < low[i])
printf("%d -> %d \n", k, i);
}
else
if (tata[k] != i)
low[k] = min(low[k], prenum[i]);
/*printf("prenum[%d] = %d low[%d] = %d\n",k,prenum[k],k,low[k]);*/
}
void critic(void) {
60
memset(vizitat, 0, sizeof(vizitat));
counter = 0;
dfs(0);
}
void main(void) {
printf("\n");
readInput();
critic();
}
Fig. 3.19: Algoritmul 26 aplicat pentru graful din gura 3.13
Exemplul 3.19 Pentru graful din gura 3.13, valorile prenum si low sunt cele din gura
3.19 (valoarea din partea dreapta a unui varf reprezinta valoarea sa la numerotarea n preor-
dine, prenum, iar numarul din stanga reprezinta valoarea calculata low). Condit ia prenum
u
<
low
v
, unde [u, v] este o muchie a grafului, este ndeplinita doar pentru u = 6 si v = 8. Prin
urmare [6, 8] este muchie critica n graful considerat.
Deoarece acest algoritm este constituit din algoritmul modicat de vizitare n adancime
a unui graf, complexitateatimp este O(n +m) atunci cand graful este reprezentat prin liste
de adiacent a si O(n
2
) n situat ia n care graful este reprezentat prin matricea de adiacent a.
3.7 Exercit ii
1. Un graf neorientat cu n noduri, G = (V, E) se numeste graf scorpion daca poseda trei
noduri speciale:
(a) acul - d
G
(u) = 1 si este legat de coada;
(b) coada - d
G
(u) = 2 si este legata de ac si corp;
(c) corpul - d
G
(u) = n 2 ind legat de toate nodurile din graf cu except ia acului.
61
Fig. 3.20: Un exemplu de graf neorientat cu 8 varfuri
Nu exista alte restrict ii cu privire la nodurile grafului.
Sa se realizeze un algoritm care determina daca un graf este graf scorpion folosind O(n)
ntrebari de forma Exista o muchie ntre nodurile u si v?.
2. Se considera n bazine dispuse circular si lipite unul de altul n ordinea numerelor de
ordine. Se da lista celor m perechi de bazine ce trebuie unite prin canale. Un numar
de bazine poate sa apara n mai multe perechi. Canalele pot realizate n interiorul
sau n exteriorul cercului, cu condit ia ca ele sa nu se intersecteze.
Daca problema are solut ie, vor asate doua liste: cea a perechilor de bazine unite
prin canale interioare si cea a perechilor de bazine unite prin canale exterioare. Daca
problema nu are solut ie, atunci se va raporta acest lucru.

In cazul n care problema are solut ie sa se determine toate posibilitat ile de unire prin
canale exterioare sau interioare.
(ONI, 1993)
3. Sa se parcurga n lat ime si n adancime graful din gura 3.20, sa se construiasca arborii
de parcurgere si sa se puna n evident a muchiile de ntoarcere.
4. Compania TLC (Telephone Line Company) a stabilit o noua ret ea de cablu telefonic.
Ea leaga mai multe locuri numerotate cu numere ntregi de la 1 la N. Nu exista doua
locuri numerotate cu acelasi numar. Liniile sunt bidirect ionale si leaga doua locuri;
ecare loc are un post telefonic. Din orice loc poate apelat oricare alt loc, prin
legatura directa sau conexiuni intermediare. Uneori ret eaua cade n unele locuri si
conexiunea aferenta nu mai este posibila. Tehnicienii de la TLC au realizat ca n acest
caz, nu numai ca locul respectiv nu mai poate apelat, dar el rupe legatura si ntre
alte locuri pentru care asigura conexiunea.

In aceasta situat ie spunem ca locul (unde
a aparut caderea) este critic.
Se cere sa de dezvolte un algoritm care sa calculeze numarul tuturor acestor puncte
critice.
(ACM Europa Centrala, 1996)
5. Fiind dat un graf G = (V, E), sa se verice daca este aciclic.
6. Fiind dat un graf G = (V, E), sa se verice daca este bipartit.
62
7.

Intrun oras intersect iile sunt numerotate de la 1 la n (se considera intersect ie nu
numai locul unde se intersecteaza mai multe strazi ci si punctele terminale capetele
de strazi). Edilii orasului doresc sa numeroteze si strazile orasului, dar ntrun mod
care sa t ina seama de numerotarea intersect iilor, si anume: doua strazi diferite vor avea
numere diferite si n ecare intersect ie trebuie sa soseasca o strada care sa aiba numarul
intersect iei.
Se cere sa se realizeze un algoritm care sa determine o astfel de numerotare, daca exista.
Datele de intrare constau dintrun numar n reprezentand numarul de puncte de inter-
sect ie; ecare punct este identicat prin numarul cu care este numerotat, ntre 1 si n,
urmat de lista punctelor cu care acesta comunica direct printro strada. Prin strada se
nt elege o port iune de drum aata ntre doua puncte de intersect ie, neglijand faptul ca
n practica strazile cuprind mai multe intersect ii.
8. Se considera o tabla de sah de dimensiune n n (n 100) pe care sunt dispuse
obstacole. Se cere sa se determine numarul minim de mutari necesare unui nebun
pentru a se deplasa, respectand regulile jocului de sah si ocolind obstacolele, dintro
pozit ie init iala data ntro pozit ie nala data.
Se considera ca obstacolele nu coincid cu pozit ia init iala si nici cu cea nala a nebunului.
(Concurs student esc, 1993)
9. Pe o tarla agricola sunt mai multe parcele ce trebuie cosite. Parcelele de diferite culturi
(lucerna, trifoi, iarba, furaje) vor cosite de muncitori diferit i ce lucreaza numai la un
anumit fel de cultura (de exemplu este specializat numai pe cositul lucernei).
Terenul agricol se modeleaza printro matrice n m. Fiecare element al matricii core-
spunde unei mult imi de un anumit tip. Doua elemente ale matricii sunt vecine daca
au o latura comuna. O parcela este o mult ime maximala de elemente astfel ncat un
muncitor se poate deplasa ntre oricare doua elemente dea lungul a doua elemente
vecine.
Se cere sa se determine numarul de muncitori care pot sa coseasca o cultura data.
63
Capitolul 4
Grafuri euleriene si hamiltoniene
4.1 Grafuri Euleriene

In anul 1736, matematicianul Leonhard Euler publica o lucrare asupra problemei podurilor
din Konigsberg
1
(gura 4.1) n care se prezinta un studiu teoretic asupra lant urilor si ciclurilor
Euleriene.
Fig. 4.1: Podurile din Konigsberg
Sa consideram un graf neorientat G = (V, E).
Denit ia 4.1 Un lant L ce cont ine ecare muchie a unui graf G o singura data se numeste
lant Euler sau lant eulerian. Daca extremitat ile lant ului sunt identice si lant ul este
eulerian atunci ciclul se numeste ciclu Euler sau ciclu eulerian. Un graf ce cont ine un
ciclu eulerian se numeste graf eulerian.
O problema mai cunoscuta legata de not iunile de ciclu si lant eulerian este aceea de a
desena cu o singura linie nentrerupta o anumita gura (vezi gura 4.2).
Teorema 4.1 (Euler) Un graf G conex (|V | 3) este eulerian daca si numai daca gradul
ecarui varf este par.
1
http://en.wikipedia.org/wiki/Seven Bridges of Konigsberg
64
Fig. 4.2: Doua guri geometrice ce pot desenate folosind o singura linie
Demonstrat ie: Fie G un graf conex eulerian un ciclu eulerian C. Acesta
trece o singura data prin toate muchiile grafului. Gradul ecarui varf u este par deoarece
pentru ecare muchie incidenta cu u prin intermediul careia se ajunge n varful u, exista o
alta muchie prin intermediul careia se paraseste varful u.
Presupunem ca u V , d
G
(u) este par. Fie L un lant de lungime maxima n G si
e u si v extremitat ile lant ului.
Presupunem ca u = v. Deoarece d
G
(v) este par, [v, w] E astfel ncat [v, w] / L. Lant ul
L {[v, w]} are lungimea mai mare decat L, contradict ie. Prin urmare u = v. Rezulta ca
L = C este un ciclu de lungime maxima.
Presupunem ca ciclul C nu este ciclu eulerian. Atunci x, y V, [x, y] E, [x, y] / C si
x C (exista o muchie a grafului G ce nu apart ine ciclului C cu proprietatea ca cel put in o
extremitate apart ine ciclului).
Fie L
1
= [x, . . . , u, v, . . . , x] un lant n G ce cont ine exact muchiile lui C.
Atunci L
2
= [x, . . . , u, v, . . . , x, y] este un lant n G ce are lungimea mai mare decat L,
contradict ie. Rezulta atunci ca ciclul C este eulerian G este un graf eulerian.
Teorema 4.2 (Euler) Un graf G conex are un lant eulerian daca si numai daca exista exact
doua varfuri n G al caror grad sa e impar.
Demonstrat ie: Se demonstreaza la fel ca la teorema 4.1.
Fie G = (V, E) un graf conex ce are exact doua varfuri de grad impar, u si
v. Sa considera un nod w / V mpreuna cu muchiile [u, w] si [v, w]. Fie G

= (V

, E

),
V

= V {w}, E

= E {[u, w], [v, w]}, graful obt inut din G prin adaugarea nodului w si a
muchiilor [u, w], [v, w]. Atunci d
G
(u) este par, u V

exista un ciclu eulerian C n G

.
Daca eliminam muchiile [u, w] si [v, w] obt inem un lant eulerian n G.
Corolarul 4.3 Un graf G conex (|V | 3) este eulerian daca si numai daca mult imea muchi-
ilor sale poate descompusa n cicluri disjuncte.
Teorema 4.4 Pentru un graf conex cu 2k varfuri de grad impar, k 1, exista k lant uri
n G ale caror mult imi de muchii formeaza o partit ie a lui E, si din care cel mult unul are
lungime impara.
4.1.1 Algoritm pentru determinarea unui ciclu eulerian
Pornind de la Teorema 4.1 construim un ciclu eulerian. Se considera drept punct de plecare
un varf oarecare al grafului. La ecare pas se alege pentru varful curent u, un varf adiacent
65
Fig. 4.3: Exemplu de graf eulerian
v, diferit de varful din care sa ajuns n u. Parcurgerea se continua pana n momentul n
care ajungem ntrun varf ce a fost deja vizitat si se nchide ciclul C. Daca ciclul C nu
este eulerian, atunci se elimina din graful G toate muchiile ciclului C, rezultand mai multe
componente conexe G
1
1
, G
1
2
, . . . , G
1
k
.
Pentru ecare astfel de componenta G
1
i
, ce are cel put in doua varfuri, aplicam recursiv
algoritmul. Conform teoremei 4.1, ecare componenta G
1
i
este euleriana. Fie C
1
i
ciclul
eulerian corespunzator componentei G
1
i
.
Ciclul C are cel put in cate un varf comun cu ecare ciclu C
1
i
. Fie acest varf u
i
. Denim
un ciclu C
0
astfel: pentru ecare i, i = 1, k, adaugam la ciclul C, n varful u
i
, ciclul C
1
i
.
Ciclul C
0
cont ine toate muchiile grafului G, prin urmare este eulerian.
Funt ia IsEulerian() verica daca un graf este eulerian conform teoremei 4.1 (vezi algo-
ritmul 27).
Algoritm 27 Algoritm de vericare daca un graf conex este eulerian
1: function IsEulerian(G = (V, E))
2: if (|V | < 3) then
3: return false
4: end if
5: for i 1, n do
6: s 0
7: for j 1, n do
8: s s + vecin
i,j
9: end for
10: if (s mod 2 = 1) then
11: return false
12: end if
13: end for
14: return true
15: end function
Dupa cum se poate vedea din funct ia IsEulerian numai componentele conexe ce au
ordinul mai mare sau egal cu 3 vor luate n considerare.

In algoritmul 28 este prezentata funct ia EulerRec pentru determinarea unui ciclu eulerian.
66
Procedura FindCycle(G) (vezi algoritmul 28) construieste un ciclu: se alege un v arf u
0
si
se cauta prima muchie [u
0
, u
1
].

In varful u
1
se cauta o muchie [u
1
, u
2
] astfel ncat varful u
2
sa
e distinct de varful din care sa ajuns n u
1
(u
2
= u
0
) si sa nu mai fost vizitat. Daca u
2
a
fost vizitat atunci funct ia se termina. Se continua procedeul de cautare pana cand se ajunge
la un varf ce a fost vizitat anterior si se returneaza ciclul cuprins ntre cele doua aparit ii ale
aceluiasi varf.
Procedura FindComponents(G

; k, G
1
1
, G
1
2
, . . . , G
1
k
) determina componentele conexe ale
grafului G

= G E(C), obt inut prin eliminarea din graful G a muchiilor ciclului C, unde
G
1
1
, G
1
2
, . . . , G
1
k
sunt cele k componente conexe returnate de aceasta.
Procedura MergeCycles(C, C
1
1
, . . . , C
1
k
; C
0
) construieste un ciclul C
0
obt inut prin adaugarea
la ciclul C, succesiv, a ciclurilor C
1
1
, . . . , C
1
k
.
Algoritm 28 Algoritm de determinare a unui ciclu eulerian ntrun graf conex
1: function EulerRec(G = (V, E))
2: if (IsEulerian(G) = false) then
3: return
4: end if
5: call FindCycle(G; C)
6: if (E(G) \ E(C) = ) then
7: return C
8: end if
9: G

GE(C)
10: call FindComponents(G

; k, G
1
1
, G
1
2
, . . . , G
1
k
)
11: for i 1, k do
12: C
1
i
EulerRec(G
1
i
)
13: end for
14: call MergeCycles(C, C
1
1
, . . . , C
1
k
; C
0
)
15: return C
0
16: end function
Fig. 4.4: Grafurile part iale obt inute n urma primelor doua etape ale algoritmului 28
Exemplul 4.5 Sa aplicam algoritmul 28 pentru graful din gura 4.3. Presupunem ca primul
element (elementul de start) este varful u
0
= 1. Procedura FindCycle construieste lant ul
67
Fig. 4.5: Grafurile part iale obt inute n urma etapelor 3 si 4 ale algoritmului 28
L = [1, 2, 3, 4, 5, 3]. Se observa prezent a ciclului C
1
= [3, 4, 5, 3].

In urma eliminarii acestuia
ramane graful din gura 4.4 a) care este un graf conex.
Continuam procesul de construire a unui ciclu eulerian, prin apelul procedurii FindCycle
pentru noul graf. Aceasta returneaza ciclul C
2
= [1, 2, 3, 9, 1]. Prin eliminarea muchiilor
acestuia, E(C
2
), se obt ine graful din gura 4.4 b).

In continuare se construieste lant ul
L = [2, 8, 7, 5, 6, 4, 10, 2], ce cont ine ciclul C
3
= [2, 8, 7, 5, 6, 4, 10, 2]. Graful obt inut prin
eliminarea muchiilor ciclului este cel din gura 4.5 a). Apelul procedurii FindCycle conduce
la determinarea lant ului L = [6, 7, 9, 8, 10, 6] si a ciclului C
4
= [6, 7, 9, 8, 10, 6].
Ciclul eulerian se formeaza prin reuniunea ciclurilor intermediare determinate: C =
(((C
4
C
3
) C
2
) C
1
) adica C = [1, 2, 8, 7, 5, 6, 7, 9, 8, 10, 6, 4, 10, 2, 3, 4, 5, 3, 9, 1] (C
4
C
3
=
[2, 8, 7, 5, 6, 7, 9, 8, 10, 6, 4, 10, 2]).
4.1.2 Algoritmul lui Rosenstiehl
Algoritmul lui Rosenstiehl [51] construieste un lant L care la nal va deveni un ciclu eulerian,
folosind pentru aceasta o stiva drept structura de date auxiliara.
Se porneste de la un nod oarecare. Se nainteaza atata timp cat este posibil: pentru nodul
curent u se cauta o muchie incidenta cu el, si care sa nu mai fost parcursa la unul din pasii
anteriori. Daca exista o astfel de muchie (e = [u, v]), atunci se salveaza pe stiva nodul u,
iar nodul v devine nodul curent.

In momentul n care nodul curent u nu mai are muchii
nevizitate, se adauga lant ului L, si se extrage de pe stiva nodul anterior (din care sa ajuns
n u) (vezi algoritmul 29). Vectorul vizit are drept scop sa pastreze situat ia muchiilor:
vizit
e
=
_
1 , daca e E a fost parcursa
0 , daca e E nu a fost nca parcursa.
Exemplul 4.6 Sa aplicam algoritmul 29 pentru graful din gura 4.3. Sa presupunem ca
varful u de la care porneste algoritmul este varful 1. La sfarsitul primului pas al enunt ului
repetitiv while (liniile 6 14) avem valorile:
S = [1, 2, 3, 4, 5, 3, 9], L = [1], u = 1.
La pasul urmator, se extrage valoarea 9 de pe stiva si astfel u devine 9. La sfarsitul acestuia
avem:
S = [1, 2, 3, 4, 5, 3, 9, 7, 5, 6, 4, 10, 2, 8, 7, 6, 10, 8], L = [1, 9], u = 9.
68
Algoritm 29 Algoritm lui Rosenstiehl de determinare a unui ciclu eulerian ntrun graf
conex
1: function Rosenstiehl(u, G)
2: for e E do
3: vizit
e
0
4: end for
5: S u Se insereaza pe stiva nodul u
6: while (S = ) do
7: S u Se extrage din stiva nodul curent
8: while (e = [u, v] E) (vizit
e
= 0)) do
9: vizit
e
1 Se marcheaza muchia e ca ind utilizata
10: S u Se salveaza pe stiva nodul curent u
11: u v Nodul curent devine nodul v
12: end while
13: L u Se adauga la lista L nodul curent
14: end while
15: return L
16: end function

In continuare, deoarece nu mai exista muchii nevizitate, se vor extrage elementele aate pe
stiva S cate unul la ecare pas, formand secvent a (8, 10, 6, 7, 8, 2, 10, 4, 6, 5, 7, 9, 3, 5, 4, 3, 2, 1),
si se vor introduce n lista L:
Pas 20 : S = [], L = [1, 9, 8, 10, 6, 7, 8, 2, 10, 4, 6, 5, 7, 9, 3, 5, 4, 3, 2, 1], u = 1.
Ciclul eulerian obt inut se aa n lista L.

In continuare se prezinta implementarea n limbajul C ++ a algoritmului lui Rosenstiehl :


#include <vector>
#include <stack>
#include <list>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <conio.h>
using namespace std;
#define INPUT_FILE "graf1.txt"
typedef vector<int> Linie;
typedef vector<Linie> Matrice;
int readInput(Matrice& ma) {
int n, i, j, value;
ifstream fin(INPUT_FILE);
fin >> n;
ma = Matrice(n, Linie(n, 0));
for (i = 0; i < n; i++)
69
for (j = 0; j < n; j++) {
fin >> ma[i][j];
}
fin.close();
return n;
}
void print(list<int>& l) {
list<int>::iterator it;
cout << "Ciclu eulerian: [";
for (it = l.begin(); it != l.end(); it++)
cout << *it << ", ";
cout << "]\n";
}
void rosenstiehl(int n, Matrice& ma, int u, list<int>& l) {
stack<int> s;
int v;
s.push(u);
while (!s.empty()) {
u = s.top();
s.pop();
v = 0;
while (v < n) {
if (ma[u][v] == 1) {
ma[u][v] = 0;
ma[v][u] = 0;
s.push(u);
u = v;
v = 0;
}
else
v++;
}
l.push_back(u);
}
}
void main(void) {
Matrice ma;
list<int> l = list<int>();
int n = readInput(ma);
rosenstiehl(n, ma, 0, l);
print(l);
}
Datele de intrare vor preluate dintr-un sier. Cont inutul sierului de intrare graf1.txt
corespunzator grafului din gura 4.6 este urmatorul:
70
6
0 1 1 1 1 0
1 0 1 1 1 0
1 1 0 1 0 1
1 1 1 0 0 1
1 1 0 0 0 0
0 0 1 1 0 0
Pe prima linie avem numarul de varfuri al grafului (cardinalul mult imii V ), si ncepand
cu cea de-a doua linie avem valorile matricei de adiacent a, separate prin spat ii, cate un rand
al acesteia pe ecare pe linie.
Fig. 4.6: Un alt exemplu de graf eulerian
Pentru a reduce timpul de implementare, am utilizat cateva structuri de date deja exis-
tente n limbajul C++, mai exact structuri de date implementate cu ajutorul template-urilor
din cadrul librariei Standard Template Library - STL
2 3
:
stiva - stack
4
. Am folosit o stiva de numere ntregi: stack<int> s;.
lista - list
5
. Pentru a pastra elementele ciclului eulerian am folosit o lista liniara,
informat ia utila din cadrul nodurilor ind constituita din valori ntregi: list<int> l
= list<int>();.
vector - vector
6
. Matricea de adiacent a am implementat-o sub forma unui vector de
vectori cu elemente numere ntregi:
typedef vector<int> Linie;
typedef vector<Linie> Matrice;
...
Matrice ma;
ma = Matrice(n, Linie(n, 0));
Dupa cum se poate observa din programul anterior, pentru reprezentarea interna a
grafului s-a folosit matricea de adiacent a.
2
http://en.wikipedia.org/wiki/Standard_Template_Library,
3
http://www.sgi.com/tech/stl/
4
http://www.sgi.com/tech/stl/stack.html
5
http://www.sgi.com/tech/stl/List.html
6
http://www.sgi.com/tech/stl/Vector.html
71
Parcurgerea elementelor listei se realizeaza cu ajutorul unui iterator - iterator
7
. Declararea
unui obiect de tip list<int>::iterator se poate face astfel: list<int>::iterator
it;.
void print(list<int>& l) {
list<int>::iterator it;
cout << "Ciclu eulerian: [";
for (it = l.begin(); it != l.end(); it++)
cout << *it << ", ";
cout << "]\n";
}
Deoarece muchiile sunt parcurse o singura data n cadrul acestui algoritm, si pentru a
nu mai pastra o structura auxiliara care sa marcheze faptul ca o muchie a fost vizitata, vom
marca parcurgerea unei muchii prin stergerea acesteia din matricea de adiacent a astfel:
ma[u][v] = 0;
ma[v][u] = 0;
Ciclul eulerian obt inut pentru graful din gura 4.6 este: L = [1, 5, 2, 4, 6, 3, 4,
1, 3, 2, 1].
4.1.3 Algoritmul lui Fleury
Un alt algoritm pentru determinarea unui ciclu eulerian este algoritmul lui Fleury.
Fig. 4.7: Exemplu de graf eulerian pentru algoritmul lui Fleury
Se porneste cu un varf oarecare al grafului G (G = (V, E), |V | = n, |E| = m). Ideea consta
n a construi un lant prin alegerea la ecare pas a unei muchii nealeasa la pasii anteriori, si
care, de preferat, sa nu e muchie critica n graful part ial obt inut prin eliminarea muchiilor
deja alese.
Sa consideram ca, la un moment dat, avem construit un lant L
k
= [v
0
, [v
0
, v
1
], v
1
, . . . ,
[v
k1
, v
k
], v
k
]. Cautam o muchie e
k+1
= [v
k
, v
k+1
] astfel ncat e
k+1
/ L
k
si care nu este muchie
7
http://www.sgi.com/tech/stl/Iterators.html
72
critica n graful part ial G
k
= G {e
1
, e
2
, . . . , e
k
} (graful obt inut prin eliminarea tuturor
muchiilor lant ului L
k
). Daca nu exista decat muchii critice n graful part ial G
k
incidente cu
v
k
atunci alegem una dintre ele.
Daca exista o muchie e
k+1
cu aceste proprietat i atunci construim lant ul L
k+1
= [L
k
, e
k+1
, v
k+1
]
(L
k+1
= [v
0
, [v
0
, v
1
], v
1
, . . . , [v
k1
, v
k
], v
k
, [v
k
, v
k+1
], v
k+1
]).

In momentul n care E(L
k
) = E(G)
algoritmul lui Fleury se opreste (vezi algoritmul 30).
Algoritm 30 Algoritm lui Fleury de determinare a unui ciclu eulerian ntrun graf conex
1: function Fleury(u
0
, G = (V, E))
2: k 0
3: L
0
[u
0
]
4: while (k m) do
5: caut e
k+1
= [v
k
, v
k+1
] a.i. e
k+1
/ L
k
si e
k+1
, de preferat, nu este muchie critica n graful
G
k
= G{e
1
, e
2
, . . . , e
k
}
6: L
k+1
[L
k
, e
k+1
, v
k+1
]
7: k k + 1
8: end while
9: return L
k
10: end function
Exemplul 4.7 Sa aplicam algoritmul 30 pentru graful din gura 4.7. La nceput L
0
= [u
1
].
Apoi se intra n ciclul while (liniile 4 8): tabelul urmator indica muchia ce a fost aleasa
la ecare pas k, precum si congurat ia lant ului L
k
.
Pasul k Muchia aleas a L
k
1 [u
1
u
4
] L
1
= [u
1
, [u
1
u
4
], u
4
]
2 [u
4
u
10
] L
2
= [u
1
, [u
1
u
4
], u
4
, [u
4
u
10
], u
10
]
3 [u
10
u
3
] L
3
= [u
1
, [u
1
u
4
], u
4
, [u
4
u
10
], u
10
, [u
10
u
3
], u
3
]
4 [u
3
u
2
] L
4
= [. . . , [u
10
u
3
], u
3
, [u
3
, u
2
], u
2
]
5 [u
2
u
6
] L
5
= [. . . , u
2
, [u
2
u
6
], u
6
]
6 [u
6
u
1
] L
6
= [. . . , u
6
, [u
6
u
1
], u
1
]
7 [u
1
u
5
] L
7
= [. . . , u
1
, [u
1
u
5
], u
5
]
8 [u
5
u
6
] L
8
= [. . . , u
5
, [u
5
u
6
], u
6
]
9 [u
6
u
7
] L
9
= [. . . , u
6
, [u
6
u
7
], u
7
]
10 [u
7
u
2
] L
10
= [. . . , u
7
, [u
7
u
2
], u
2
]
11 [u
2
u
8
] L
11
= [. . . , u
2
, [u
2
u
8
], u
8
]
12 [u
8
u
3
] L
12
= [. . . , u
8
, [u
8
u
3
], u
3
]
13 [u
3
u
9
] L
13
= [. . . , u
3
, [u
3
u
9
], u
9
]
14 [u
9
u
8
] L
14
= [. . . , u
9
, [u
9
u
8
], u
8
]
15 [u
8
u
7
] L
15
= [. . . , u
8
, [u
8
u
7
], u
7
]
16 [u
7
u
13
] L
16
= [. . . , u
7
, [u
7
u
13
], u
13
]
17 [u
13
u
5
] L
17
= [. . . , u
13
, [u
13
u
5
], u
5
]
18 [u
5
u
12
] L
18
= [. . . , u
5
, [u
5
u
12
], u
12
]
19 [u
12
u
4
] L
19
= [. . . , u
12
, [u
12
u
4
], u
4
]
73
Pasul k Muchia aleas a L
k
20 [u
4
u
11
] L
20
= [. . . , u
4
, [u
4
u
11
], u
11
]
21 [u
11
u
10
] L
21
= [. . . , u
11
, [u
11
u
10
], u
10
]
22 [u
10
u
9
] L
22
= [. . . , u
10
, [u
10
u
9
], u
9
]
23 [u
9
u
13
] L
23
= [. . . , u
9
, [u
9
u
13
], u
13
]
24 [u
13
u
11
] L
24
= [. . . , u
13
, [u
13
u
11
], u
11
]
25 [u
11
u
12
] L
25
= [. . . , u
11
, [u
11
u
12
], u
12
]
26 [u
12
u
1
] L
26
= [. . . , u
12
, [u
12
u
1
], u
1
]
La nal, lant ul are urmatoarea component a: L
2
= [u
1
, u
4
, u
10
, u
3
, u
2
, u
6
, u
1
, u
5
, u
6
, u
7
, u
2
,
u
8
, u
3
, u
9
, u
8
, u
7
, u
13
, u
5
, u
12
, u
4
, u
11
, u
10
, u
9
, u
13
, u
11
, u
12
, u
1
] (s-au omis din aceasta enumerare
muchiile grafului).
4.2 Grafuri Hamiltoniene
Denit ia 4.2 Se numeste lant Hamilton sau lant hamiltonian un lant L ce trece o
singura data prin toate varfurile unui graf.
Denit ia 4.3 Se numeste ciclu hamiltonian un ciclu elementar ce trece prin toate varfurile
grafului. Un graf ce admite un ciclu hamiltonian se numeste graf hamiltonian.
Problema determinarii daca un graf oarecare G este hamiltonian este o problema dicila,
atent ia cercetatorilor ndreptanduse catre enunt area unor condit ii suciente de existent a a
unui ciclu hamiltonian.
Lema 4.8 Fie G = (V, E) un graf neorientat si e u si v doua varfuri neadiacente ale grafului
(u, v V , u = v, [u, v] / E), astfel ncat d
G
(u) + d
G
(v) n. Atunci G este hamiltonian
G+ [u, v] este hamiltonian.
Demonstrat ie: Daca G este hamiltonian, atunci cu atat mai mult, graful G+[u, v]
este hamiltonian.
Presupunem ca G + [u, v] este un graf hamiltonian. Atunci exista un ciclu hamil-
tonian n graful G+ [u, v] pe care l notam cu C.
1. daca [u, v] / C atunci C este un ciclu hamiltonian si n graful G G este un graf
hamiltonian.
2. daca [u, v] C atunci C = [u, v, x
3
, x
4
, . . . , x
n1
, x
n
, u]. Pentru ecare muchie [u, x
k
]
E putem avea urmatoarele situat ii:
(a) [v, x
k+1
] E. Atunci ciclul C
1
= [u, x
k
, x
k1
, . . . , x
3
, v, x
k+1
, . . . , x
n
, u] este hamil-
tonian n graful G graful G este hamiltonian.
(b) [v, x
k+1
] / E. Notam d
G+[u,v]
(u) = k. Atunci d
G+[u,v]
(v) n k 1. si De aici,
rezulta ca d
G
(u) +d
G
(v) < d
G+[u,v]
(u) +d
G+[u,v]
(v) n k +k 1 = n 1 < n.
Contradict ie cu d
G
(u) +d
G
(v) n, u, v V, u = v, [u, v] / E.
Prin urmare lema este demonstrata.
Teorema 4.9 (Dirac, 1952) Un graf G = (V, E) (|V | 3) este hamiltonian daca u V
avem d
G
(u)
n
2
(orice varf al grafului are gradul mai mare decat jumatate din numarul de
varfuri din graf ).
74
Teorema 4.10 (Ore, 1961) Un graf G = (V, E) (|V | 3) este hamiltonian daca u, v V
avem d
G
(u) + d
G
(v) n unde u = v, [u, v] / E (pentru oricare doua varfuri distincte,
neadiacente, ale grafului suma gradelor lor este mai mare decat numarul de varfuri din graf ).
Teorema 4.11 (Chvatal, 1972) Fie un graf G = (V, E) (|V | 3) si d
1
, d
2
, . . . , d
n
o
secvent a graca. Daca este satisfacuta relat ia
k a.i. d
k
k
n
2
d
nk
n k
atunci graful este hamiltonian.
Denit ia 4.4 Pentru un graf G construim un sir de grafuri G = G
1
, G
2
, . . . astfel: graful
G
k+1
se obt ine din graful G
k
prin adaugarea muchiei [u
k
, v
k
], unde varfurile u
k
, v
k
V nu
sunt adiacente n G
k
si d
G
(u
k
) + d
G
(v
k
) n. Procesul se ncheie n momentul n care nu
mai exista doua varfuri neadiacente distincte astfel ncat d
G
(u
p
) +d
G
(v
p
) n. Graful G
p
se
numeste nchiderea lui G si se noteaza cu cl(G).
Lema 4.12 Orice graf prezinta o singura nchidere.
Corolarul 4.13 Un graf G = (V, E) (|V | 3) este hamiltonian daca cl(G) K
n
(daca
nchiderea lui G este izomorfa cu graful complet de ordinul n).
Denim (G) = min{d
G
(u)|u V } si (G) = max{d
G
(u)|u V }.
Corolarul 4.14 Un graf G = (V, E) (|V | 3) este hamiltonian daca (G)
n
2
.
Denit ia 4.5 O mult ime de varfuri A a unui graf G se spune ca este independenta daca
oricare doua elemente distincte din A sunt independente. Numarul de independent a al lui G,
notat cu (G), reprezinta numarul maxim de varfuri dintro mult ime independenta.
(G) = 1 daca si numai daca graful G este complet.
Denit ia 4.6 Pentru un graf G se numeste conectivitatea lui G, si notam cu (G),
numarul minim de varfuri ale unei taieturi. O taietura este o submult ime U a lui V astfel
ncat graful GU sa e neconex.
Teorema 4.15 Un graf G = (V, E) avand ordinul n 3, este hamiltonian daca (G)
(G).
Observat ia 4.16 Pentru un graf bipartit G = (V
1
, V
2
, E) condit ia necesara pentru a hamil-
tonian este |V
1
| = |V
2
|.
Problema comisvoiajorului include problema determinarii existent ei unui ciclu hamilto-
nian ntrun graf.
Cautarea optimului printre toate variantele de cicluri nu este o solut ie fezabila deoarece
pentru un graf G numarul de cicluri poate foarte mare. De exemplu pentru graful complet
K
n
avem
(n1)!
2
cicluri hamiltoniene distincte.
Exemplul 4.17 Graful din gura 3.20 nu este hamiltonian (nu admite un ciclu hamilto-
nian).
75
Graful din gura 4.6 are mai multe cicluri hamiltoniene: de exemplu ciclurile C
1
= [1, 5,
2, 3, 6, 4, 1] si C
2
= [1, 3, 6, 4, 2, 5, 1].
Nod 1 2 3 4 5 6
d
G
4 4 4 4 2 2
Teorema lui Dirac (1952) nu se poate aplica deoarece nu este ndeplinita condit ia orice varf
al grafului are gradul mai mare decat jumatate din numarul de varfuri din graf:
d
G
(5) = 2 <
n
2
=
6
2
= 3.
De asemenea, pentru teorema lui Ore (1961) nu este ndeplinita condit ia pentru oricare doua
varfuri dinstincte, neadiacente, ale grafului suma gradelor lor este mai mare decat numarul
de varfuri din graf: e varfurile 5 si 6, neadiacente, pentru care avem
d
G
(5) +d
G
(6) = 2 + 2 = 4 < 6.
Pentru graful din gura 4.8 avem:
Nod 1 2 3 4 5 6 7 8
d
G
3 4 3 4 4 5 3 4
condit ia teoremei lui Dirac (1952), nu este ndeplinita: d
G
(1) = 3 < 4 =
n
2
;
condit ia teoremei lui Ore (1961), nu este ndeplinita: d
G
(2) +d
G
(7) = 4 + 3 = 7 < 8;
observam ca nici condit iile teoremei lui Chvatal (1972) nu sunt ndeplinite: e d
1
, d
2
, . . . , d
n
o secvent a graca.
Nod 1 3 7 2 4 5 8 6
d
G
3 3 3 4 4 4 4 5
Relat ia urmatoare nu este satisfacuta:
k a.i. d
k
k
n
2
d
nk
n k.
4.2.1 Problema comisvoiajorului
Un comis-voiajor trebuie sa viziteze n orase etichetate cu numerele de la 1 la n. Pentru a
simplica problema, acesta va pleca ntotdeauna din orasul numarul 1 si se va ntoarce tot n
1, trecand prin ecare oras o singura data (cu except ia orasului 1 care va vizitat de doua
ori). Cunoscand distant ele ntre orase, sa se determine o parcurgere (ciclu hamiltonian) de
cost minim.
Pentru a reprezenta drumurile directe dintre orase (existent a unei legaturi directe ntre
acestea) utilizam matricea costurilor A = (a
ij
), i, j = 1, n:
a
i,j
=
_

_
0 , daca x
i
= x
j
+ , daca [x
i
, x
j
] / E
d > 0 , daca [x
i
, x
j
] E
. (4.1)
Vectorul solut iilor rezultat va X = (x
1
, x
2
, . . . , x
n+1
) V . . . V unde x
1
= x
n+1
= 1:
la pasul i, i = 2, n + 1, se viziteaza orasul x
i
V . Primul oras, orasul din care se pleaca,
este xat la 1 (vezi algoritmul 31).
76
La pasul k (2 k n + 1) se ncearca vizitarea orasului x
k
+ 1 daca nu a fost vizitat
la un pas anterior, si daca costul part ial al lant ului este mai mic decat costul celui mai bun
ciclu hamiltonian obt inut pana n acel moment n graf:
1 x
k
< n si vizitat
x
k
+1
= 0 si cost +a
x
k1
,x
k
+1
cost
optim
(4.2)
(pentru k = n + 1 trebuie vericata si condit ia x
k
= 1).
La nceput costul celui mai scurt ciclu hamiltonian poate determinat cu un algoritm
de tip Greedy sau i se poate atribui valoarea + (o valoare sucient de mare, de exemplu
n max{a
i,j
|i, j = 1, n, i = j, a
i,j
= }).
Daca condit iile anterioare sunt ndeplinite, atunci x
k
x
k
+1. Se marcheaza orasul ales
la pasul k ca ind vizitat (vizitat
k
1), se actualizeaza costul drumului pana n momentul
curent (cost cost +a
x
k1
,x
k
), si se trece la pasul k + 1.

In caz contrar, nu exista nici o alegere convenabila pentru orasul de pe pozit ia k si va


trebui sa nentoarcem pentru o alta alegere pentru orasul vizitat la pasul k1. Pentru aceasta
se marcheaza orasul ales la pasul anterior ca neind vizitat (vizitat
x
k
0), si se scade din
costul drumului pana n momentul curent, costul muchiei [x
k1
, x
k
] (cost cost a
x
k1
,x
k
).
Fig. 4.8: Exemplu de graf pentru problema comis-voiajorului
Exemplul 4.18 Matricea costurilor corespunzatoare grafului din gura 4.8 are urmatoarele
valori:
A =
_
_
_
_
_
_
_
_
_
_
_
_
0 14 6 5
14 0 12 16 20
6 0 12 12
12 0 21 24 10
5 16 21 0 16
20 12 16 0 14 6
24 14 0 10
12 10 6 10 0
_
_
_
_
_
_
_
_
_
_
_
_
Graful respectiv are mai multe cicluri hamiltoniene:
C
1
= [1, 2, 4, 5, 6, 7, 8, 3, 1].
C
2
= [1, 2, 5, 4, 8, 7, 6, 3, 1].
C
3
= [1, 5, 6, 2, 4, 7, 8, 3, 1].
77
Algoritm 31 Algoritm pentru problema comis-voiajorului
Input:
_
A - matricea de costuri ce cont ine distant ele dintre orase
n - numarul de orase
1: function CanContinue(A, X, k, cost)
2: if (vizitat
x
k
= 1) (cost + a
x
k1
,x
k
> cost
optim
) ((k = n + 1) (x
k
= x
1
))) then
3: return false
4: else
5: return true
6: end if
7: end function
8: procedure Evaluare Solutie(X, cost)
9: X
optim
X
10: cost
optim
cost
11: end procedure
12: procedure ComisVoiajorBacktracking(A, n)
13: x
1
1, cost 0, cost
optim

14: k 2, x
k
1
15: while (k > 1) do
16: gasit false
17: while ((x
k
+ 1 n) (gasit = false)) do
18: x
k
x
k
+ 1
19: gasit CanContinue(A, X, k, cost)
20: end while
21: if (gasit = true) then
22: if (k = n + 1) then
23: call Evaluare Solutie(X, cost + a
x
k1
,x
k
)
24: else
25: vizitat
x
k
1
26: cost cost + a
x
k1
,x
k
27: k k + 1
28: x
k
0
29: end if
30: else
31: k k 1
32: vizitat
x
k
0
33: if (k > 1) then
34: cost cost a
x
k1
,x
k
35: end if
36: end if
37: end while
38: Output {Solutia optima: , x
optim
1
, . . . , x
optim
n+1
, cost
optim
}
39: end procedure
C
4
= [1, 3, 6, 7, 8, 4, 2, 5, 1].
Programul corespunzator scris n limbajul C este urmatorul:
#include <stdio.h>
#include <memory.h>
78
Fig. 4.9: Rezultatul rularii programului pentru determinarea ciclului hamiltonian optim
#define NMAX 100 //numarul maxim de noduri din graf
#define LIMIT 100000 //lungimea maxima a unei muchii echivalenta cu infinit
typedef int Matrice[NMAX][NMAX];
typedef int Vector[NMAX];
long cost_optim; //costul circuitului hamiltonian optim
Vector x_optim; //elementele circuitului hamiltonian optim
/**
* Functia citeste valorile datelor de intrare.
*/
int readInput(Matrice a) {
int n;
int i, j, max = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
if (max < a[i][j])
max = a[i][j];
if (a[i][j] < 0)
a[i][j] = LIMIT;
}
cost_optim = n * max;
return n;
}
/**
* Functia verifica daca a + b > c.
*/
int mai_mare(long a, long b, long c) {
if (a + b > c)
79
return 1;
else
return 0;
}
/**
* Functia afiseaza solutia calculata a problemei.
*/
void AfisareSolutie(int n) {
int i;
printf("Costul ciclului optim: %ld \n", cost_optim);
printf("Ciclu hamiltonian: [");
for (i = 1; i < n+1; i++)
printf("%d, ", x_optim[i]);
printf("%d]\n", x_optim[n+1]);
}
/**
* Functia de continuare: aici se verifica daca elementul de pe pozitia k
* nu se mai afla in sirul A.
*/
int CanContinue(int n, Matrice a, int k, long cost, Vector vizitat, Vector x) {
if ((vizitat[x[k]] == 1) || (mai_mare(cost, a[x[k-1]][x[k]], cost_optim))
|| ((k != n+1) && (x[k] == 1)))
return 0;
else
return 1;
}
/**
* Functia salveaza solutia optima (circuitul hamiltonian de cost minim)
* determinata/gasita pana in momentul curent.
*/
void EvaluareSolutie(int n, long cost, Vector x) {
int i;
cost_optim = cost;
for (i = 1; i <= n+1; i++)
x_optim[i] = x[i];
AfisareSolutie(n);
}
/**
* Metoda backtracking implementata.
*/
void ComisVoiajorBacktracking(int n, Matrice a) {
Vector x;
Vector vizitat;
int k, gasit;
long cost;
80
memset(vizitat, 0, sizeof(vizitat));
x[1] = 1;
cost = 0;
k = 2; x[k] = 1;
while (k > 1) {
gasit = 0;
while ((x[k] + 1 <= n) && (gasit == 0)) {
x[k] = x[k] + 1;
gasit = CanContinue(n, a, k, cost, vizitat, x);
}
if (gasit == 1) {
if (k == n+1)
EvaluareSolutie(n, cost + a[x[k-1]][x[k]], x);
else {
vizitat[x[k]] = 1;
cost = cost + a[x[k-1]][x[k]];
k = k + 1;
x[k] = 0;
}
}
else {
k = k - 1;
vizitat[x[k]] = 0;
if (k > 1)
cost = cost - a[x[k-1]][x[k]];
}
}
}
void main(void) {
Matrice a;
int n = readInput(a);
ComisVoiajorBacktracking(n, a);
}
Cont inutul sierului graf1.txt este:
8
0 14 6 -1 5 -1 -1 -1
14 0 -1 12 16 20 -1 -1
6 -1 0 -1 -1 12 -1 12
-1 12 -1 0 21 -1 24 10
5 16 -1 21 0 16 -1 -1
-1 20 12 -1 16 0 14 6
-1 -1 -1 24 -1 14 0 10
-1 -1 12 10 -1 6 10 0
Corespunzator valorii am utilizat n sierul de test valoarea negativa 1.

In timpul
citirii datelor aceasta a fost nlocuita cu o constanta sucient de mare:
...
scanf("%d", &a[i][j]);
if (max < a[i][j])
81
max = a[i][j];
if (a[i][j] < 0)
a[i][j] = LIMIT;

In timpul citirii se determina valoarea maxima, max{a


i,j
|i, j = 1, n, i = j, a
i,j
= },
pentru a se init ializa mai apoi costul optim cu valoarea n max.
Funct ia n care se verica condit iile de continuare este urmatoarea:
int CanContinue(int n, Matrice a, int k, long cost, Vector vizitat, Vector x) {
if ((vizitat[x[k]] == 1) || (mai_mare(cost, a[x[k-1]][x[k]], cost_optim))
|| ((k != n+1) && (x[k] == 1)))
return 0;
else
return 1;
}
Folosim o funct ie (mai mare()) cu scopul de a realiza vericarea inegalitat ii cost +
a
x
k1
,x
k
+1
> cost
optim
:
int mai_mare(long a, long b, long c) {
if (a + b > c)
return 1;
else
return 0;
}
si a preveni eventualele depasiri (overow)
8
n timpul calculelor.
Nu am asat numai solut ia optima, ci am ales sa asam toate ciclurile hamiltoniene care
mbunatat eau solut ia anterioara:
void EvaluareSolutie(int n, long cost, Vector x) {
int i;
cost_optim = cost;
for (i = 1; i <= n+1; i++)
x_optim[i] = x[i];
AfisareSolutie(n);
}
Partea principala a programului, motorul, este constituita din funct ia:
void ComisVoiajorBacktracking(int n, Matrice a) {
Vector x;
Vector vizitat;
int k, gasit;
long cost;
memset(vizitat, 0, sizeof(vizitat));
x[1] = 1;
cost = 0;
k = 2; x[k] = 1;
while (k > 1) {
gasit = 0;
8
http://en.wikipedia.org/wiki/Arithmetic_overflow
82
while ((x[k] + 1 <= n) && (gasit == 0)) {
x[k] = x[k] + 1;
gasit = CanContinue(n, a, k, cost, vizitat, x);
}
if (gasit == 1) {
if (k == n+1)
EvaluareSolutie(n, cost + a[x[k-1]][x[k]], x);
else {
vizitat[x[k]] = 1;
cost = cost + a[x[k-1]][x[k]];
k = k + 1;
x[k] = 0;
}
}
else {
k = k - 1;
vizitat[x[k]] = 0;
if (k > 1)
cost = cost - a[x[k-1]][x[k]];
}
}
}
Pentru n = 8, mult imea A
i
va alcatuita din elementele {1, 2, . . . , 8}. La nceput, x
1
va
primi valoarea 1, iar pentru k = 2, x
2
va primi tot valoarea 1:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 1
Pentru k = 2, se verica condit iile de continuare pentru x
2
= x
2
+ 1 = 1 + 1 = 2, si
deoarece acestea sunt respectate, se trece la pasul urmator (orasul urmator) (la init ializare
avem k = k + 1 = 3, x
3
= 0):
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 0
Se verica mai multe valori (1, 2 si 3) pentru x
3
, pentru care condit iile de continuare nu
sunt ndeplinite. Pentru x
3
= 4 condit iile de continuare sunt ndeplinite, si se trece la pasul
urmator, k = k + 1 = 4:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 0
Pentru k = 4, prima valoare ce verica condit iile de continuare este 5:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 0

In mod asemanator se aleg valorile pentru pasii k = 5, 6, 7, 8:


x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 3 8 7 0
La pasul k = 9, nici una dintre valorile 1, 2, . . . , 8 nu verica condit iile de continuare (ind
la ultimul oras, acesta ar trebui sa e 1, adica orasul de unde s-a pornit). Astfel, se trece la
pasul anterior:
k = k - 1;
vizitat[x[k]] = 0;
83
if (k > 1)
cost = cost - a[x[k-1]][x[k]];
adica la pasul k = k 1 = 9 1 = 8.
Valoarea 8, urmatoarea valoare din domeniul de valori nevericata si singura ce mai
ramasese de atribuit pentru x
8
, nu verica condit iile de continuare, si deoarece nu mai sunt
valori de testat la pasul k = 8, se trece la nivelul anterior: k = k 1 = 8 1 = 7.
La pasul k = 7, deoarece nu au mai ramas valori netestate din mult imea A
7
= {1, 2, . . . , 8},
se trece la pasul k = 6:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 3
Aici continuam cu vericarea valorilor 4, 5, 6 si 7. Pentru x
6
= 7 sunt vericate condit iile
de continuare si se poate trece la pasul urmator, k = 7:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 7 0
Doar pentru valoarea 8 sunt ndeplinite condit iile de continuare:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 7 8 0
La pasul k = 8, x
k
= 3 ndeplineste cont iile de continuare si se poate trece la nivelul
urmator, k = 9:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 7 8 3 0
Aici solut ia optima gasita este urmatoarea:
x
1
x
2
x
3
x
4
x
5
x
6
x
7
x
8
x
9
1 2 4 5 6 7 8 3 1
avand un cost al ciclului hamiltonian de 105.
Se pastreaza solut ia optima identicata pana n acest moment, se aseaza, si se continua
efectuarea calculelor metodei pana la epuizarea spat iului solut iilor posibile.
84
Fig. 4.10: Pasii efectuati de algoritm pentru determinarea ciclului hamiltonian asociat grafului din gura 4.8
85
Fig. 4.11: Pasii efectuati de algoritm pentru determinarea ciclului hamiltonian asociat grafului din gura 4.8
(continuare)
86
Capitolul 5
Arbori. Arbori binari
Denit ia 5.1 Fiind data o mult ime M de elemente denumite noduri, vom numi arbore o
submult ime nita de noduri astfel ncat:
1. exista un nod cu destinat ie speciala, numit radacina arborelui;
2. celelalte noduri sunt repartizate n n mult imi distincte, disjuncte doua cate doua, A
1
, A
2
, . . . , A
n
,
ecare mult ime A
i
constituind la randul ei un arbore.
Aceasta denit ie este una recursiva, construct ia unui arbore depinzand de alt i arbori.
Descendent ii direct i ai radacinii arborelui sunt radacinile subarborilor A
1
, A
2
, . . . , A
n
, n 1.
Orice nod al unui arbore cu radacina constituie radacina unui subarbore compus din nodul
respectiv si tot i descendent ii sai.
Se observa ca un arbore impune o structura de organizare ierarhica asupra elementelor
unei mult imi.
Denit ia 5.2 Se numeste arbore liber (free tree) un graf G = (V, E) neorientat, conex
si aciclic.
Teorema 5.1 (Proprietat ile arborilor liberi) Fie G = (V, E) un graf neorientat. Urmatoarele
armat ii sunt adevarate:
1. G este un arbore liber.
2. Oricare doua varfuri din G sunt conectate printr-un drum elementar unic.
3. G este conex, dar, daca eliminam o muchie oarecare din E, graful obt inut nu mai este conex.
4. G este conex, si |E| = |V | 1.
5. G este aciclic, si |E| = |V | 1.
6. G este aciclic, dar daca adaugam o muchie oarecare n E, graful obt inut cont ine un ciclu.
Daca se alege un varf sau nod drept radacina arborelui, atunci un arbore liber devine
arbore cu radacina.

In general vom folosi termenul de arbore n loc de termenul corect arbore
cu radacina.
Un varf terminal (frunza) este un varf fara descendent i. Varfurile care nu sunt terminale
sunt neterminale (sau noduri interioare). De obicei, se considera ca exista o ordonare a
descendent ilor aceluiasi parinte.
87
1
2
5
11
10
4
9
8
3
7
15
14
6
13
12
Fig. 5.1: Exemplu de arbore binar plin cu 2
4
1 varfuri
Denit ia 5.3 Adancimea unui varf este data de lungimea drumului de la radacina la acel
varf.

Inalt imea unui varf se determina ca ind lungimea celui mai lung drum dintre acel varf
si un varf terminal.

Inalt imea radacinii determina nalt imea arborelui. Nivelul unui varf se
calculeaza ca diferent a dintre nalt imea arborelui si adancimea acestui varf.
Toate varfurile unui arbore ce au aceeasi adancime se spune ca sunt pe acelasi nivel. Un
arbore oarecare cu radacina este n-ar daca ecare varf are pana la n descendent i direct i.
O mult ime de arbori disjunct i formeaza o padure.
Din punct de vedere grac, un arbore se poate reprezenta descriind nodurile cu ajutorul
unor cercuri sau patrate n care se aa informat ia aferenta, iar relat ia de descendent a prin
legaturile ce unesc nodurile cu i lor.
5.1 Arbori binari
Denit ia 5.4 Un arbore binar este un arbore oarecare cu radacina, ecare varf al sau
avand cel mult doi descendent i, indicandu-se cine este descendentul stang al radacinii si cine
este cel drept.
Trebuie ment ionat ca un arbore binar nu este un caz particular de arbore oarecare,
deoarece n cazul unui arbore oarecare este sucient sa spunem ca ca un varf are un singur
decendent spre deosebire de cazul arborelui binar cand trebuie precizat daca descendentul
este drept sau stang. Arborele binar ce nu cont ine nici un nod se numeste arbore vid sau
arbore nul.
Denit ia 5.5 Se numeste arbore binar plin un arbore binar cu 2
k
1 varfuri asezate pe
k nivele astfel ncat pe ecare nivel i avem 2
i1
varfuri.
Se observa ca ecare varf al arborelui are doi descendent i, descendentul stang si descen-
dentul drept, cu except ia nodurilor terminale.

In gura 5.1 este prezentat un arbore binar plin n care varfurile sunt asezate pe 4 niveluri
(k = 4). De regula varfurile unui arbore binar plin se numeroteaza n ordinea nivelurilor, iar
n cadrul unui nivel, de la stanga la dreapta.
Denit ia 5.6 Se numeste arbore binar complet cu n varfuri un arbore binar plin avand
k nivele, unde 2
k1
n < 2
k
, din care se elimina varfurile numerotate n+1, n+2, . . . , 2
k
1.
88
1
2
5
11
10
4
9
3
7
6
12
8
Fig. 5.2: Exemplu de arbore binar complet cu 12 varfuri

In gura 5.2 este ilustrat un exemplu de arbore binar complet.


Un arbore binar poate transformat ntrun arbore binar plin n modul urmator: com-
pletam arborele cu noi varfuri astfel ncat ecare varf sa aiba doi descendent i sau nici unul,
renumerotam varfurile iar varfurilor nou introduse li se asociaza o valoare ce va indica faptul
ca ele sunt ctive.
5.1.1 Moduri de reprezentare
Cele mai cunoscute modalitat i de reprezentare a arborilor binari sunt:
1. expresii cu paranteze;
2. forma standard;
3. reprezentarea tip tata.
1
2 8
5
7
6
9
3
4
Fig. 5.3: Exemplu de arbore binar
1. expresii cu paranteze expresia ncepe cu radacina si dupa ecare varf k urmeaza expre-
siile subarborilor ce au ca radacini descendent ii varfului respectiv, separate prin virgula
si incluse ntre paranteze. Daca un descendent al unui v arf nu exista atunci expresia
respectiva este nlocuita cu 0 sau NULL. Un arbore cu un singur varf (radacina),
etichetat cu a
1
, se reprezinta astfel: a
1
(0, 0). Un arbore format din radacina a
1
si doi
descendent i, a
2
si a
3
, se reprezinta astfel: a
1
(a
2
(0, 0), a
3
(0, 0)).
Pentru arborele din gura 5.3 avem:
1(2(3(0, 4(0, 0)), 5(6(0, 0), 7(0, 0))), 8(0, 9(0, 0)))
89
2. forma standard se indica radacina arborelui, iar pentru ecare varf k se precizeaza
descendentul sau stang si/sau drept.
Stang
k
=
_
i , daca nodul i este descendentul stang al nodului k
0 , daca nu exista descendentul stang
Drept
k
=
_
i , daca nodul i este descendentul drept al nodului k
0 , daca nu exista descendentul drept.
Pentru arborele din gura 5.3 avem urmatoarea reprezentare (Rad = 1):
Nod 1 2 3 4 5 6 7 8 9
Stang 2 3 0 0 6 0 0 0 0
Drept 8 5 4 0 7 0 0 9 0
Fig. 5.4: Exemplu de arbore binar cu 8 noduri
Dupa modelul listei liniare dublunlat uita, putem folosi o structura de date asemanatoare
pentru reprezentarea unui arbore binar. Un nod al arborelui are urmatoarea congurat ie:
typedef struct nod {
TipOarecare data;
struct nod* stang;
struct nod* drept;
}Nod;
Nod rad; rad este o variabila de tip pointer la Nod (variabila pastreaza adresa
unei zone de memorie ce cont ine date numerice de tip Nod). rad desemneaza adresa
radacinii arborelui.

In gura 5.5 avem reprezentarea arborelui din gura 5.4.


3. reprezentarea tip tata ecarui varf k i se indica tatal nodului respectiv.
tata
k
=
_
i , daca nodul i este parintele nodului k
0 , nu exista
Nod 1 2 3 4 5 6 7 8 9
Tata 0 1 2 3 2 5 5 1 8
Observat ia 5.2 Urmatoarea numerotare este utilizata pentru anumite tipuri de arbori
binari, si are drept caracteristica faptul ca structura arborelui se poate deduce printr-o
numerotare adecvata a varfurilor:
90
Fig. 5.5: Exemplu de arbore binar cu 8 noduri
Tata
i
=
_

i
2
, i 2
nu exista , i = 1
Stang
i
=
_
2 i , 2 i n
nu exista , 2 i > n
Drept
i
=
_
2 i + 1 , 2 i + 1 n
nu exista , 2 i + 1 > n
5.1.2 Metode de parcurgere
Exista mai multe moduri de parcurgere a unui arbore binar. Indiferent de metoda de parcurg-
ere aleasa se parcurge mai ntai subarborele stang si apoi subarborele drept. Dupa momentul
n care un nod k este vizitat fat a de subarborii sai stang si drept, avem:
parcurgere n preordine (radacina, subarbore stang, subarbore drept).

In urma parcurgerii n preordine a arborelui din gura 5.3 rezulta urmatoarea ordine
pentru noduri: 1, 2, 3, 4, 5, 6, 7, 8, 9.

In gura 5.6 este prezentata parcurgerea n preordine a unui arbore binar, descrisa n
mai mult i pasi, conform descrierii recursive a acestei metode.
Vom da exemplu de o procedura nerecursiva de vizitare n preordine (vezi algoritmul
32). Se pleaca de la radacina si se merge spre stanga atata timp cat este posibil (liniile
58). Daca nu se mai poate merge spre stanga se ncearca continuarea algorimului
din descendentul drept, daca este posibil. Daca nu se poate face un pas spre dreapta
(descendentul drept nu exista linia 10), se va urca n arbore cate un nivel (liniile
1222), pana cand se ajunge n situat ia de a se veni din descendentul stang (linia 19)
si se reia algoritmul trecand n descendentul drept, daca exista (linia 25).

In momentul
n care sa ajuns n nodul radacina venind din dreapta, algoritmul se ncheie. Datorita
faptului ca atunci cand se urca n arbore trebuie sa stim din ce descendent venim, vom
utiliza si vectorul tata.
Aceasta procedura poate utilizata si pentru celelalte moduri de parcurgere, modicarile
necesare referinduse la momentul cand trebuie vizitat nodul curent (prin apelul pro-
cedurii V izit - instruct iunea call V izit(k)).
91
Fig. 5.6: Parcurgerea n preordine a unui arbore binar a) arborele init ial; b) arborele vizitat n preordine,
primul nivel; c) arborele vizitat n preordine, al doilea nivel; d) arborele vizitat n preordine, al treilea nivel.
Implementarea n limbajul C a algoritmului de parcurgere n preordine este:
#include <stdio.h>
#define MAX 100
/** stang[k] - descendentul stang al nodului k; 0 daca nu exista */
char stang[MAX];
/** drept[k] - descendentul drept al nodului k */
char drept[MAX];
/** tata[k] - parintele nodului k */
char tata[MAX];
/** numarul de noduri din arbore */
int n;
/** nodul radacina */
int rad;
void vizit(int nod) {
printf("%2d ", nod);
}
void readInput(void) {
int k;
printf("n = "); scanf("%d", &n);
printf("rad = "); scanf("%d", &rad);
for (k = 1; k <= n; k++) {
printf("stang[%d] = ", k); scanf("%d", &stang[k]);
}
92
Algoritm 32 Algoritm de parcurgere n preordine
1: procedure Preordine(Rad, Stang, Drept, Tata)
2: k rad
3: q 0
4: while (q = 0) do
5: while (stang
k
= 0) do
6: call V izit(k) prelucrarea informat iei din nodul vizitat
7: k stang
k
8: end while
9: call V izit(k)
10: while (q = 0) (drept
k
= 0) do
11: found 0
12: while (q = 0) (found = 0) do
13: j k
14: k tata
k
15: if (k = 0) then
16: q 1
17: else
18: if (j = stang
k
) then
19: found 1
20: end if
21: end if
22: end while
23: end while
24: if (q = 0) then
25: k drept
k
26: end if
27: end while
28: return
29: end procedure
for (k = 1; k <= n; k++) {
printf("drept[%d] = ", k); scanf("%d", &drept[k]);
}
for (k = 1; k <= n; k++) {
printf("tata[%d] = ", k); scanf("%d", &tata[k]);
}
}
void preord(int rad) {
int i, j;
int q, found;
i = rad; q = 0;
while (q == 0) {
while (stang[i] != 0) {
vizit(i);
i = stang[i];
93
}
vizit(i);
while ((q == 0) && (drept[i] == 0)) {
found = 0;
while ((q == 0) && (found == 0)) {
j = i;
i = tata[i];
if (i == 0)
q = 1;
else
if (j == stang[i])
found = 1;
}
}
if (q == 0)
i = drept[i];
}
}
void main(void){
readInput();
preord(rad);
}
parcurgere n inordine (arbore stang, radacina, arbore drept): 3, 4, 2, 6, 5, 7, 1, 8, 9.
Metoda de parcurgere n inordine este ilustrata de algoritmul 33 [93], [123]. Vom utiliza
o stiva S unde se vor introduce nodurile din care se coboara spre stanga (liniile 69).
Atunci cand nu se mai poate merge spre stanga se ncearca continuarea algoritmului din
descendentul drept al nodului curent. Daca acesta nu exista, se reface drumul napoi
spre radacina, compus numai din descendent ii stangi (liniile 1118). Parcurgerea se
termina n momentul n care stiva este vida (vezi algoritmul 33).
Implementarea n limbajul C a algoritmului 33 este:
#include <stdio.h>
#define MAX 100
/** stang[k] - descendentul stang al nodului k; 0 daca nu exista */
char stang[MAX];
/** drept[k] - descendentul drept al nodului k */
char drept[MAX];
/** Numarul de noduri din arbore */
int n;
/** Nodul radacina */
int rad;
void vizit(int nod) {
printf("%2d ", nod);
}
void readInput(void) {
94
Algoritm 33 Algoritm de parcurgere n inordine
1: procedure Inordine(Rad, Stang, Drept)
2: k rad
3: q 0
4: S init ializare stiva vida
5: while (q = 0) do
6: while (stang
k
= 0) do
7: S k S.push(k)
8: k stang
k
9: end while
10: call V izit(k)
11: while (q = 0) (drept
k
= 0) do
12: if (S = ) then vericare daca stiva este vida
13: q 1
14: else
15: S k S.pop(k)
16: call V izit(k)
17: end if
18: end while
19: if (q = 0) then
20: k drept
k
21: end if
22: end while
23: return
24: end procedure
int k;
printf("n = "); scanf("%d", &n);
printf("rad = "); scanf("%d", &rad);
for (k = 1; k <= n; k++) {
printf("stang[%d] = ", k); scanf("%d", &stang[k]);
}
for (k = 1; k <= n; k++) {
printf("drept[%d] = ", k); scanf("%d", &drept[k]);
}
}
void inord(int rad) {
int i, cap;
int q;
int stack[MAX];
i = rad; q = 0;
cap = -1;
while (q == 0) {
while (stang[i] > 0) {
95
cap++;
stack[cap] = i;
i = stang[i];
}
vizit(i);
while ((q == 0) && (drept[i] == 0)) {
if (cap < 0)
q = 1;
else {
i = stack[cap];
cap--;
vizit(i);
}
}
if (q == 0)
i = drept[i];
}
}
void main(void) {
readInput();
inord(rad);
}
parcurgere n postordine (subarbore stang, subarbore drept, radacina): 4, 3, 6, 7, 5, 2, 9, 8, 1
(vezi algoritmul 34).
Algoritm 34 Algoritm de parcurgere n postordine
1: procedure Postordine(K, Stang, Drept)
2: if (k = 0) then
3: call Postordine(stang
k
, stang, drept)
4: call Postordine(drept
k
, stang, drept)
5: call V izit(k)
6: end if
7: return
8: end procedure
Modalitatea de vizitare recursiva a arborilor binari este exemplicata la arborii binari de
sortare.
Daca presupunem realizarea unei act iuni de vizitare pe exteriorul frontierei arborelui,
deplasarea efectuandu-se n sens trigonometric si avand drept punct de plecare radacina
acestuia, vom ajunge sa vizitam cel put in o data toate nodurile arborelui (vezi gura 5.7).
T inand cont de momentul vizitarii se poate obt ine oricare dintre metodele de parcurgere
(preordine, inordine, postordine): pentru preordine vom marca un nod n momentul n care
l vizitam pentru prima data, n cazul metodei de vizitare n inordine vom marca un nod
n momentul n care l vizitam pentru prima data daca este frunza, respectiv a doua oara
daca este un nod interior, iar la postordine vom marca un nod n momentul n care l vizitam
pentru ultima oara.
96
1
2 8
5
7
6
9 3
4
Fig. 5.7: Vizitarea unui arbore pe frontiera
Fig. 5.8: Arbore asociat expresiei aritmetice 2 ((a + b) (c + b))
Arborele asociat unei expresii aritmetice
Oricarei expresii aritmetice i se poate asocia un arbore binar astfel:
ecarui operator i corespunde un nod neterminal avand drept subarbori stang si drept
cei doi operanzi corespunzatori.
ecare nod terminal este etichetat cu o variabila sau o constanta.
Arborele din gura 5.8 corespunde expresiei matematice: 2 ((a +b) (c +b)).

In urma
vizitarii n postordine a acestui arbore se obt ine forma poloneza postxata asociata expresiei
anterioare: 2ab + cb + . Pentru a obt ine valoarea expresiei respective, arborele poate
parcurs n postordine.
5.2 Arbori binari de cautare
Denit ia 5.7 [93] Se numeste arbore binar de c autare un arbore binar ce verica urmatoarea
proprietate:
97
pentru orice varf i apart inand arborelui, avem
_
Inf
i
Inf
j
, pentru toate varfurile j ce apart in descendentului stang al varfului i
Inf
i
Inf
j
, pentru toate varfurile j ce apart in descendentului drept al varfului i
unde Inf
i
este informat ia asociata varfului i. Aceasta informat ie este de un tip de date peste
care avem o relat ie de ordine (de obicei un tip numeric sau tipul sir de caractere).
Un arbore binar de cautare mai este cunoscut si sub numele de arbore binar de sortare
deoarece parcurgerea n inordine a unui arbore binar de cautare ne conduce la obt inerea
elementelor vectorului Inf n ordine crescatoare.

In principal aceasta structura de date este
utilizata pentru regasirea ecienta a unor informat ii.
Operat iile de creare a arborelui, stergere a unui nod, modicare a informat iei asociate
unui nod sau inserare a unui nod se pot realiza ntr-un mod optim astfel ncat s a nu se
distruga proprietatea de arbore de cautare.
Daca dorim ca arborele sa nu cont ina chei duplicate, vom modica denit ia de mai sus
astfel:
pentru orice varf i apart inand arborelui, avem
_
Inf
i
< Inf
j
, pentru toate varfurile j ce apart in descendentului stang al varfului i
Inf
i
> Inf
j
, pentru toate varfurile j ce apart in descendentului drept al varfului i.

In continuare vom utiliza aceasta denit ie pentru descrierea algoritmilor ce urmeaza.


Crearea unui arbore de cautare
Crearea (construirea) unui arbore de cautare se face aplicand n mod repetat operat ia de
inserare.
Cautarea unei informatii ntr-un arbore de cautare
Informat ia asociata unui nod mai poarta numele de cheie.
Sa presupunem ca dorim sa cautam o cheie x ntr-un arbore de cautare. Vom compara
mai ntai cheia x cu informat ia asociata radacinii arborelui (vezi algoritmul 35):
1. daca cheia x este mai mica decat cheia radacinii, atunci se va continua cautarea n
subarborele stang;
2. daca cheia x este mai mare decat cheia radacinii, atunci se va continua cautarea n
subarborele drept;
3. daca cheia x este egala cu cheia radacinii, atunci cautarea se ncheie cu succes.
Inserarea unui nod ntr-un arbore de cautare
Aceasta operat ie prezinta urmatoarele particularitat i (vezi algoritmul 36):
se verica prin intermediul operat iei de cautare daca cheia x a nodului care se doreste
sa e inserat mai exista n arbore;
n cazul n care cautarea se ncheie cu succes, inserarea nu va mai avea loc;
n cazul n care operat ia de cautare se termina fara succes, atunci se va crea un nod
nou n locul subarborelui vid unde s-a terminat cautarea.

In gura 5.9 este ilustrata inserarea unui nod ntrun arbore binar.
98
Algoritm 35 Algoritm de cautare a unei valori ntr-un arbore binar de cautare
1: function SearchNode(p, Key)
2: if (p = NULL) then
3: if (p.info > key) then
4: return SearchNode(p.left, key)
5: else
6: if (p.info < key) then
7: return SearchNode(p.right, key)
8: else
9: return p
10: end if
11: end if
12: else
13: return NULL
14: end if
15: end function
Algoritm 36 Algoritm de inserare ntr-un arbore binar de cautare
1: function InsertNode(p, Key)
2: if (p = NULL) then
3: call CreateNode(p, key)
4: else
5: if (p.info > key) then
6: p.left InsertNode(p.left, key)
7: else
8: if (p.info < key) then
9: p.right InsertNode(p.right, key)
10: end if
11: end if
12: end if
13: return p
14: end function
Stergerea unui nod dintr-un arbore de cautare
Mai ntai se va cauta nodul ce se doreste sa e eliminat.
Sa presupunem ca am gasit nodul ce urmeaza a sters. Avem urmatoarele situat ii (vezi
algoritmul 38):
1. nodul ce urmeaza sa e sters este un nod terminal - se face stergerea normal avand
grija sa se nlocuiasca legatura din nodul parinte c atre el cu null;
2. nodul ce urmeaza sa e sters are un singur descendent - nodul respectiv se sterge iar
parintele va cont ine acum noua legatura catre descendentul fostului u;
3. nodul ce urmeaza a sters (notat A) are doi descendent i:
se determina cel mai din stanga nod (notat B) din subarborele drept al nodului
ce trebuie sters (vezi algoritmul 37); acesta va sters n mod zic, dar la un pas
ulterior;
99
Fig. 5.9: Arbore binar de cautare. Inserarea unui nod.
toate informat iile legate de datele cont inute n nodul B vor copiate n nodul A;
subarborele drept al nodului B se va lega e ca descendent drept al nodului A
(daca nodul B este descendent direct al nodului A), e ca descendent stang al
tatalui nodului B;
se va sterge zic nodul B.
Exemplul 5.3 Fie un arbore binar, eticheta ecarui nod ind un sir de caractere (un cuvant).
Se cere sa se realizeze un program care sa creeze un arbore binar de sortare, sa-l parcurga n
inordine si sa permita inserarea si stergerea unui nod specicat.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
typedef struct nod {
100
Fig. 5.10: Arbore binar de cautare. Stergerea unui nod. a) Nod fara descendent i b) Nod cu un singur
descendent c) Nod cu doi descendent i.
101
Algoritm 37 Algoritm pentru determinarea celui mai din stanga nod
1: function LeftmostNode(Parent, Curent)
2: while (curent.left = NULL) do
3: parent curent
4: curent curent.left
5: end while
6: if (parent.right = curent) then
7: parent.right curent.right
8: else
9: parent.left curent.right
10: end if
11: return curent
12: end function
char *cuvint;
struct nod *left,*right;
} NOD;
NOD *rad;
NOD* Search(NOD *p, char *sir) {
int ind;
if (p != NULL) {
ind = strcmp(p->cuvint, sir);
if (ind < 0)
return Search(p->right, sir);
else
if (ind > 0)
return Search(p->left, sir);
else
return p;
}
else
return NULL;
}
NOD* CreareNod(char *sir) {
NOD *p;
p = (NOD*)malloc(sizeof(NOD));
p->left = p->right = NULL;
p->cuvint = (char*)malloc(sizeof(char) * (strlen(sir) + 1));
strcpy(p->cuvint, sir);
return p;
}
NOD* Insert(NOD *p, char *sir) {
int ind;
102
Algoritm 38 Algoritm de stergere a unui nod ntr-un arbore binar de cautare
1: function DeleteNode(p, Key)
2: if (p = NULL) then
3: if (p.info > key) then
4: p.left DeleteNode(p.left, key)
5: else
6: if (p.info < key) then
7: p.right DeleteNode(p.right, key)
8: else
9: if (p.left = NULL) (p.right = NULL) then
10: if (p.left = NULL) then
11: tmp p.left
12: else
13: tmp p.right
14: end if
15: call DisposeNode(p)
16: p tmp
17: else
18: tmp p.right
19: tmp LeftmostNode(p, tmp)
20: tmp.left p.left
21: tmp.right p.right
22: call DisposeNode(p)
23: p tmp
24: end if
25: end if
26: end if
27: end if
28: return p
29: end function
if (p == NULL)
p = CreareNod(sir);
else {
ind = strcmp(p->cuvint, sir);
if (ind < 0)
p->right = Insert(p->right, sir);
else
if (ind > 0)
p->left = Insert(p->left, sir);
}
return p;
}
void VisitInord(NOD *p) {
if (p != NULL) {
VisitInord(p->left);
printf("[%s] ", p->cuvint);
103
VisitInord(p->right);
}
}
NOD* LeftmostNod(NOD* parent, NOD* curent) {
while (curent->left != NULL) {
parent = curent;
curent = curent->left;
}
if (parent->right == curent)
parent->right = curent->right;
else
parent ->left = curent->right;
return curent;
}
NOD* ElibNod(NOD *p) {
free(p->cuvint);
free(p);
return NULL;
}
NOD* DeleteNod(NOD* p, char *sir) {
NOD *tmp;
int ind;
if (p != NULL){
ind = strcmp(p->cuvint, sir);
if (ind < 0)
p->right = DeleteNod(p->right, sir);
else
if (ind > 0)
p->left = DeleteNod(p->left, sir);
else
if (p->left == NULL || p->right == NULL) {
if (p->left != NULL)
tmp = p->left;
else
tmp = p->right;
ElibNod(p);
p = tmp;
}
else{
tmp = p->right;
tmp = LeftmostNod(p, tmp);
tmp->left = p->left;
tmp->right = p->right;
ElibNod(p);
p = tmp;
}
104
}
return p;
}
void main(void) {
char cuvint[100];
char ch;
NOD *p;
rad = NULL;
while (1) {
printf("***********************************\n");
printf("1. Inserare \n");
printf("2. Cautare\n");
printf("3. Stergere\n");
printf("4. Afisare arbore\n");
printf("0. Exit \n");
ch = getch();
if (ch != 0 && ch != 4) {
printf("Cuvint: "); scanf("%s", cuvint);
}
switch (ch) {
case 1: rad = Insert(rad, cuvint); break;
case 2: p = Search(rad, cuvint);
if (!p)
printf("Cuvintul %s nu a fost gasit! \n", cuvint);
else
printf("Cuvintul %s exista in arbore! \n", cuvint);
break;
case 3: rad = DeleteNod(rad, cuvint); break;
case 4: VisitInord(rad); break;
case 0: exit(1);
}
}
}
5.3 Exercit ii
1. (a) Sa se realizeze o subrutina ce determina cea mai mare valoare pastrata ntrun
arbore binar de cautare;
(b) Aceeasi cerint a pentru cea mai mica valoare.
2. Sa se realizeze o subrutina ce determina toate nodurile unui arbore binar de cautare cu
proprietatea ca informat ia k asociata unui nod verica relat ia a k b, unde a si b
sunt date.
3. (a) Sa se realizeze un algoritm care determina numarul arborilor binari distinct i cu
n noduri, unde n este un numar natural dat.
105
Fig. 5.11: Exemplu de arbore binar complet cu 7 varfuri
(b) Aceeasi problema pentru arbori binari de cautare.
4. Sa consideram o secvent a de intrare compusa din termeni denit i recursiv astfel:
(a) X este un termen;
(b) daca A si B sunt termeni, atunci (A B) este un termen;
(c) orice termen se construieste cu ajutorul regulilor (i) si (ii).
Un termen este transformat cu ajutorul urmatoarei reguli de rescriere: sablonul
(((X A) B) C) unde A, B si C sunt termeni, este nlocuit cu ((A C)(B C)).
Reducerea unui termen nseamna aplicarea acestei reguli. Un termen se numeste redus
daca nu cont ine nici un subtermen care sa poata redus. Un termen poate considerat
ca subtermen pentru el nsusi.
Sa se realizeze un algoritm care determina pentru un termen de intrare, termenul redus
corespunzator. Un termen cont ine doar simbolurile X, ( si ), fara spat ii ntre ele.
Lungimea unui termen de intrare este 100.
Observat ia 5.4 O expresie va avea maxim 9 nivele de parantezare. Numarul de redu-
ceri ce pot efectuate este nit. Liniile de iesire cont in maxim 80 caractere. Caracterele
posibile din termenii de iesire sunt tot X, ( si ).
Intrare Iesire
(((XX)X)X) ((XX)(XX))
(((XX)(XX)X) ((XX)((XX)X))
(XX) (XX)
(ACM, Bucuresti, 1996)
5. Prin arbore binar completnt elegem un arbore binarn care un nod are e doi descendent i,
e nu are nici unul.
Un arbore binar complet poate reprezentat prin codicarea drumurilor de la radacina
la ecare frunza utilizand numai valorile 0 si 1: atunci cand coboram n arbore spre
stanga se adauga valoarea 0 iar atunci cand coboram spre dreapta se adauga valoarea
1.
106
Pentru arborele din gura 5.11 drumurile de la radacina la ecare frunza se codica
astfel:
ABC : 00
ABDE : 010
ABDF : 011
AG : 1
Concatenand toate drumurile de la radacina catre frunze, arborele anterior poate
reprezentat prin secvent a ce poate interpretata ca reprezentarea n baza 2 a unui
numar (000100111).
Fiind date m si n doua numere naturale, se cere sa se determine daca exist a un arbore
binar complet a carui reprezentare va cont ine exact m cifre 0 si n cifre 1 (0 < m, n
100).
(Timisoara-pregatire, 1996)
6. Scriet i o subrutina nerecursiva care numara nodurile frunza ale unui arbore binar.
7. Realizat i o subrutina care sa determine nivelul cu cele mai multe noduri frunze dintrun
arbore binar.
8. Determinat i nat imea unui arbore binar printro funct ie nerecursiva.
9. Se considera un dict ionar ce este implementat sub forma unei structuri de arbore.
Pentru ecare cuvant se cunoaste traducerea acestuia precum si probabilitatea lui de
aparit ie n texte.
Se cere sa se realizeze un algoritm care sa conduca la o cautare optima a cuvintelor
n dict ionar. Se ment ioneaza faptul ca probabilitatea de a cauta un cuvant care nu se
gaseste n dict ionar este zero.
Datele de iesire constau din asarea arborelui optimal de cautare compus din cuvintele
introduse.
Spre exemplu, un set de date de intrare poate :
5
1 abroad in_strainatate
4 baker brutar
2 calf gamba
1 dice zaruri
2 ear ureche
10. O casa de comenzi este interesata de crearea unui program pe calculator care sa t ina
evident a comenzilor n ordinea datelor la care au fost onorate, iar n cadrul ecarei date
de livrare, n ordine lexicograca dupa numele produsului. Sa se scrie un program care
foloseste structuri de date de tip arbore.
Intrarea este formata din mai multe linii. Pe ecare linie avem cate o comanda data
sub forma: [nume
p
rodus] [zi] [luna] [an]. Intrarea se termina cu o linie pe care avem
doar &.
Iesirea este formata prin asarea comenzilor n ordinea datei la care au fost onorate,
iar n cadrul unei date, n ordine lexicograca n funct ie de numele comenzii.
Indicat ie: Se va crea un arbore de cautare dupa data de livrare si n ecare nod va
un arbore de cautare dupa numele comenzii.
107
11. Se considera o expresie logica formata din n variabile logice reprezentate printro sin-
gura litera si operatorii & (AND), | (OR), ! (NOT) (nu avem paranteze). Expresia este
reprezentata sub forma unui arbore binar.
Se cere sa se realizeze un algoritm care pentru o expresie logica data cerceteaza existent a
unei combinat ii de valori logice (true/false), pentru care expresia data ia valoarea logica
true.
De exemplu pentru expresia a|!b|c&d solut ia este a = false, b = false, c = false,
d = false, iar pentru expresia !a&a nu avem solut ie.
12. Se considera o expresie matematica reprezentata printr-un arbore binar. Operatorii
corespund operat iilor matematice uzuale +, , , /, si ? (pentru ridicare la putere).
Nu avem paranteze si tot i operatorii sunt operatori binari. Operanzii sunt identicat i
printro singura litera.
Se cere sa se realizeze un algoritm ce creaza structura de date corespunzatoare unei
expresii date si sa evalueaze expresia pentru o mult ime de valori ale operanzilor.
Pentru expresia a + b c unde a = 2, b = 3 si c = 1 avem valoarea 1, iar n urma
evaluarii expresiei a b/c?a cu a = 2, b = 9 si c = 3 obt inem valoarea 1.
108
Capitolul 6
Arbori oarecare
Reamintim denit ia unui arbore oarecare:
Denit ia 6.1 Fiind data o mult ime M de elemente denumite noduri, vom numi arbore o
submult ime nita de noduri astfel ncat:
1. exista un nod cu destinat ie speciala, numit radacina arborelui;
2. celelalte noduri sunt repartizate n n mult imi disjuncte doua cate doua, A
1
, A
2
, , A
n
, ecare
mult ime A
i
constituind la randul ei un arbore.
6.1 Moduri de reprezentare
Pentru reprezentarea arborilor oarecare pot utilizate urmatoarele metode:
legaturi u-frate: fiu
k
- este primul descendent al varfului k, frate
k
- urmatorul descen-
dent al tatalui nodului k, ce urmeaza dupa k.

Intre descendent ii unui varf se presupune
ca denim o relat ie de ordine.
Radacina arborelui din gura 6.1 este Rad = 1.
1
2 4
5 9 6 7 8
3
10
Fig. 6.1: Exemplu de arbore oarecare
Table 6.1: Reprezentarea cu legaturi ufrate a arborelui din gura 6.1.
Nod 1 2 3 4 5 6 7 8 9 10
Fiu 2 0 5 7 0 0 0 0 0 0
Frate 0 3 4 0 6 0 8 9 10 0
109
Daca identicam Fiu cu Stang si Frate cu Drept, unui arbore oarecare i se poate
asocia un arbore binar.
Pentru reprezentarea unui arbore oarecare, modelul de reprezentare u-frate n varianta
de alocare statica poate usor extins la o varianta de alocare dinamica, folosind pointeri
pentru legaturile catre primul descendent respectiv pentru urmatorul frate. Astfel un
nod al arborelui poate avea urmatoarea congurat ie:
typedef struct nod {
TipOarecare data;
struct nod* fiu;
struct nod* frate;
}Nod;
Asemanator cu modelul construit la arbori binari, rad (Nod rad;) este o variabila de
tip pointer la Nod (variabila pastreaza adresa unei zone de memorie). rad desemneaza
adresa radacinii arborelui.
Fig. 6.2: Exemplu de arbore oarecare cu 10 noduri reprezentat prin legaturi u-frate

In gura 6.2 este reprezentat arborele din gura 6.1 prin legaturi u-frate.
lista descendent ilor.

In cadrul acestui mod de reprezentare ecare varf este descris prin
lista descendent ilor sai. Pentru memorare se va utiliza un vector cu n componente:
C
k
=
_
0 , varful respectiv nu are descendent i
j , j indica adresa (coloana) unde ncepe lista descendent ilor varfului k.
Listele de descendent i se pastreaza prin intermediul unei matrice L cu 2 linii si N 1
coloane:
L
1,k
- un descendent al varfului a carui lista cont ine coloana k a matricei date.
L
2,k
=
_
0 , daca descendentul respectiv este ultimul
j , j indica coloana unde se aa urmatorul descendent
110
Table 6.2: Reprezentarea arborelui din gura 6.1 folosind liste cu descendent i.
Nod 1 2 3 4 5 6 7 8 9 10
C 1 0 4 6 0 0 0 0 0 0
L =
_
2 3 4 5 6 7 8 9 10
2 3 0 5 0 7 8 9 0
_
Exploatand mai departe aceasta idee, ntr-un nod al arborelui oarecare se poate pastra o
lista cu adresele descendent ilor sai, lista ind reprezentata sub forma unui tablou alocat
static sau dinamic. Oricum modelul se recomanda atunci cand numarul descendent ilor
unui nod este limitat superior, sau cand acesta este cunoscut/stabilit n momentul n
care se construieste arborele. Modicarile efectuate asupra arborelui, cum ar inserari
de descendent i noi, atunci cand intrarile alocate pentru acesti descendent i sunt deja
alocate nu poate conduce decat la realocarea spat iului de memorie cu un cost reectat
n complexitatea algoritmului. Astfel daca numarul de descendent i este limitat superior
putem deni
#define NMAX 100
typedef struct nod {
TipOarecare data;
struct nod* children[NMAX];
}Nod;
sau
typedef struct nod {
TipOarecare data;
int no_of_children;
struct nod** children;
}Nod;
atunci cand numarul maxim de descendent i nu poate cunoscut decat n momentul
construirii arborelui. Astfel, n acel moment, se aloca spat iu pentru un tablou de
pointeri catre structura de tip Nod denita (children = malloc(sizeof(Nod*) *
no of children)).

In gura 6.3 este reprezentat arborele din gura 6.1 folosind liste cu descendent i.
Tata - ecarui nod k se indica nodul parinte.
Table 6.3: Reprezentarea arborelui din gura 6.1 folosind vectorul tata.
Nod 1 2 3 4 5 6 7 8 9 10
Tata 0 1 1 1 3 3 4 4 4 4
Acest mod de reprezentare are dezavantajul ca nu pastreaza n mod explicit ordinea
descendent ilor unui nod. Aceasta ordine poate dedusa printro numerotare adecvata a
nodurilor. De obicei reprezentarea cu vectorul tata nu este folosita singura ci mpreuna
cu alte moduri de reprezentare, ca o completare.
111
3 1
0 2 2 3 4 4
0 5 0 6
rad
0 7 0 8 0 9 0 10
Fig. 6.3: Exemplu de arbore oarecare cu 10 noduri reprezentat prin liste cu descendent i
De exemplu, reprezentarea unui nod propusa la primul punct, poate modifcata astfel
ncat sa incorporeze si informat ii despre nodul parinte:
typedef struct nod {
TipOarecare data;
struct nod* fiu;
struct nod* tata;
struct nod* frate;
}Nod;
1
2 3 4
5
rad
NULL
NULL
6
NULL
NULL 7
10
NULL
NULL
8 9
NULL NULL NULL
NULL
NULL
NULL
NULL
Fig. 6.4: Exemplu de arbore oarecare cu 10 noduri reprezentat prin legaturi u-frate-tata

In gura 6.4, reprezentarea din gura 6.2 este mbunatat ita prin legatura tata.
6.2 Metode de parcurgere
Pentru parcurgerea unui arbore oarecare se pot folosi metodele generale pentru parcurg-
erea arborelui binar asociat. Arborele binar asociat unui arbore oarecare se obt ine n urma
realizarii corespondent ei Fiu Stang si Frate Drept.
112

In plus fat a de acestea, avem si doua metode de parcurgere pe care putem sa le numim
specice unui arbore oarecare. Acestea se pot clasica dup a momentul n care se realizeaza
vizitarea nodului parinte astfel:
Apreordine: se viziteaza mai ntai radacina, si apoi, n ordine, subarborii sai [93],
[123]. Metoda este identica cu metoda de parcurgere n preordine a arborelui binar
atasat: 1, 2, 3, 5, 6, 4, 7, 8, 9, 10 (vezi algoritmul 39). Parcurgerea n Apreordine este
exemplicata pe arborele oarecare din gura 6.1.
Algoritm 39 Algoritm de parcurgere n A-preordine
1: procedure APreordine(Rad, Fiu, Frate)
2: k rad
3: q 0
4: S init ializare stiva vida
5: while (q = 0) do
6: if (k = 0) then
7: call V izit(k)
8: S k S.push(k)
9: k fiu
k
10: else
11: if (S = ) then vericare daca stiva este vida
12: q 1
13: else
14: S k S.pop(k)
15: k frate
k
16: end if
17: end if
18: end while
19: return
20: end procedure
Apostordine: se viziteaza mai ntai tot i subarborii ce au drept radacini, descendent ii
radacinii arborelui si apoi radacina arborelui [93], [123].

In urma parcurgerii n A
postordine a arborelui din gura 6.1 se obt ine 2, 5, 6, 3, 7, 8, 9, 10, 4, 1.
Exemplul 6.1 [31]

In continuare se prezinta implementarea n limbajul de programare C
a variantelor recursive pentru ecare dintre cele doua metode de vizitare ale unui arbore
oarecare.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
/**
* Definitii de tipuri necesare cozii
*/
typedef struct nod {
int id;
float info;
struct nod *down, *next;
113
}NOD;
typedef NOD* TINFO;
/**
* Definitii de tipuri pentru reprezentarea arborelui
*/
typedef struct cnod {
TINFO info; //informatia memorata in nod
struct cnod *next; //adresa urmatorului element
}CNOD;
CNOD *prim = NULL, *ultim = NULL;
NOD* citListaDescendenti(NOD *up);
/**
* Functie ce testeaza daca coada e vida
* @return 1 daca coada e vida
* 0 altfel
*/
int isEmpty(void) {
if (prim == NULL)
return 1;
else
return 0;
}
/**
* Functia adauga un element la sfarsitul unei cozi
* unde n reprezinta elementul ce se adauga.
*/
void add(TINFO n) {
CNOD *curent;
curent = (CNOD *) malloc(sizeof(CNOD));
curent->info = n;
curent->next = NULL;
if (!prim) {
prim = ultim = curent;
} else {
ultim->next = curent;
ultim = curent;
}
}
/**
* Functia extrage un element din coada. Returneaza elementul scos.
*/
TINFO get(void) {
CNOD *curent;
TINFO n;
114
if (prim == ultim) {
n = prim->info;
free(ultim);
prim = ultim = NULL;
} else {
curent = prim;
n = prim->info;
prim = prim->next;
free(curent);
}
return n;
}
/**
* Functia realizeaza crearea unui arbore oarecare. Se introduce initial radacina,
* apoi descendentii ei, dupa care se introduc descendentii nodurilor de pe
* nivelul 1, dupa care se introduc descendentii nodurilor de pe nivelul 2 s.a.m.d.
*/
NOD* creare(void) {
NOD *p, *c;
p = (NOD *)malloc(sizeof(NOD));
p->next = NULL;
printf("Dati id:"); scanf("%d", &p->id);
add(p);
while (!isEmpty()) {
c = get();
c->down = citListaDescendenti(c);
}
return p;
}
/**
* Functia citeste informatia asociata unui nod.
* @return 1 daca citirea s-a facut corect
* 0 altfel
*/
int citInfo(NOD *pn) {
printf("Id:");
pn->next = NULL;
pn->down = NULL;
return scanf("%d",&pn->id) == 1;
}
/**
* Functia realizeaza citirea listei de descendenti ai nodului up si
* returneaza adresa primului descendent din lista.
*/
NOD* citListaDescendenti(NOD *up) {
NOD *prim, *ultim, *p;
NOD n;
115
printf("\nLista de descendenti pt %d (CTRL+Z) daca nu are\n", up->id);
prim = ultim = NULL;
while (citInfo(&n)) {
p = (NOD *)malloc(sizeof(NOD));
*p = n;
if (prim == NULL)
prim = ultim = p;
else {
ultim->next = p;
ultim = p;
}
add(p);
}
return prim;
}
/**
* Parcurgerea in A-preordine a arborelui cu radacina p.
*/
void aPreordine(NOD *p) {
NOD *desc;
printf("%d ", p->id);
desc = p->down;
while (desc != NULL) {
aPreordine(desc);
desc = desc->next;
}
}
/**
* Parcurgerea in A-postordine a arborelui cu radacina p.
*/
void aPostordine(NOD *p) {
NOD *desc;
desc = p->down;
while (desc != NULL) {
aPostordine(desc);
desc = desc->next;
}
printf("%d ",p->id);
}
void main(void) {
NOD *rad;
rad = creare();
printf("\n Parcurgerea in A-Preordine este:\n");
aPreordine(rad);
printf("\n Parcurgerea in A-Postordine este:\n");
116
aPostordine(rad);
}
6.3 Arbori de acoperire de cost minim
Fie G = (V, E) un graf neorientat si e c : E R o funct ie de cost ce asocieaza o valoare
reala ecarei muchii. Notam cu T
G
mult imea arborilor part iali ai grafului G (un arbore
part ial este un graf part ial conex si fara cicluri al grafului init ial).
Cerint a problemei este aceea de a determina un arbore T

T
G
avand costul cel mai mic
dintre tot i arborii ce apart in mult imii T
G
:
c(T

) = min{c(T)|T T
G
}
unde costul unui arbore T se denet te ca c(T) =

eE
T
c(e). Arborele T

ce poseda aceasta
proprietate se numeste arbore de acoperire de cost minim (eng. minimum spanning tree -
MST). Se mai ntalneste si sub denumirea de arbore part ial de cost minim sau arbore part ial
minim.
Altfel spus, se cere sa se determine un graf part ial conex G
1
= (V, E
1
) (E
1
E) cu
proprietatea ca suma costurilor tuturor muchiilor este minima, graful part ial de cost minim
ind chiar un arbore.
Determinarea arborelui de acoperire de cost minim are multe aplicat ii practice: de exem-
plu, daca se dau n orase precum si costul legaturilor ntre acestea, se cere sa se determine o
conectare a tuturor oraselor astfel ncat oricare doua orase sa e conectate direct sau indirect
iar costul conectarii sa e minim.
Lema 6.2 (Proprietatea taieturii) Fie S o submult ime de noduri a lui V si e muchia ce are
costul minim dintre toate muchiile ce au o singura extremitate n S. Atunci arborele part ial
de cost minim va cont ine muchia e.
Demonstrat ie: Fie T

un arbore part ial de cost minim. Presupunem prin reducere la


absurd ca e / E
T
. Daca adaugam muchia e la T

se obt ine un ciclu C.



In acest ciclu exista
o alta muchie f ce are exact o extremitate n mult imea S.

Inlocuind muchia f cu muchia e n arborele T

, obt inem un alt arbore de acoperire T

=
T

{e} \ {f}.
Deoarece c(e) < c(f) vom avea ca c(T

) = c(T

) +c(e) c(f)
. .
<0
c(T

) < c(T

) adica am
obt inut un arbore de acoperire T

ce are costul mai mic decat T

, contradict ie cu faptul ca
T

este un arbore de acoperire de cost minim.


Denit ia 6.2 Se numeste t aietur a a grafului G o partit ie de doua submult imi a mult imii
nodurilor V , notata astfel: < S, T > (unde S T = V si S T = ).
Lema 6.3 (Proprietatea ciclului) Fie C un ciclu si f muchia ce are costul maxim dintre
toate muchiile ce apart in lui C. Atunci arborele part ial de cost minim T

nu cont ine muchia


f.
Demonstrat ie: Fie T

un arbore part ial de cost minim. Presupunem prin reducere la


absurd ca f E
T
. Daca stergem muchia f din arborele T

, se obt ine o taietura < S, V \S >.


Avem ca f C si o extremitate a lui f apart ine lui S. Exista atunci o alta muchie e cu
proprietatea ca e C si e are o extremitate ce apart ine lui S.
117

Inlocuind muchia f cu muchia e n arborele T

, obt inem un alt arbore de acoperire T

=
T

{e} \ {f}.
Deoarece c(e) < c(f) c(T

) < c(T

) adica am obt inut un arbore de acoperire T

ce are
costul mai mic decat T

, contradict ie.
Majoritatea algoritmilor ce calculeaza arborele de acoperire de cost minim prezinta aceeasi
tehnica generala de calcul. Lanceput se porneste cu o padure de arbori, T
0
= {T
0
1
, T
0
2
, . . . , T
0
n
}
unde T
0
i
= {x
i
}, i = 1, n este un arbore format dintrun singur nod. La pasul k vom avea
mult imea T
k
compusa din n k arbori: T
k
= {T
k
1
, T
k
2
, . . . , T
k
nk
}.
La ecare pas, se alege un arbore T
k
i
si o muchie (u

, v

) avand costul minim dintre toate


muchiile (u, v) cu proprietatea ca o extremitate apart ine mult imii de noduri a arborelui T
k
i
(u

T
k
i
) si cealalta extremitate apart ine mult imii V \ V
T
k
i
(v

V \ V
T
k
i
).
Prin urmare, mult imea T
k+1
se obt ine din mult imea T
k
prin reuniunea arborilor T
k
i
si
T
k
j
(i = j), unde u

T
k
i
si v

T
k
j
(T
k+1
= T
k
\ {T
k
i
, T
k
j
} {T
k
i
T
k
j
}).

In nal, la pasul n 1, mult imea T


n1
= {T
n1
1
} va compusa dintrun singur element,
acesta ind arborele de acoperire de cost minim.
Algoritmii cei mai cunoscut i pentru determinarea arborilor de acoperire de cost minim
sunt:
1. Algoritmul lui Boruvka (vezi algoritmul 40)
Algoritm 40 Algoritmul lui Boruvka (varianta schematica)
1: procedure Boruvka1(G, C, n; L)
2: init ializeaza padurea de arbori P compusa din n arbori, ecare arbore ind compus dintrun
singur nod
3: L
4: while (|P| > 1) do
5: for T P do
6: alege e muchia de cost minim de la T la G\ T
7: L e adauga muchia e la lista de muchii alese ce vor forma arborele de acoperire
de cost minim
8: end for
9: adauga toate muchiile selectate n cadrul for-ului anterior la P
10: end while
11: end procedure
2. Algoritmul lui Prim (vezi algoritmul 41)
3. Algoritmul lui Kruskal (vezi algoritmul 42)
Algoritmul lui Prim implementat simplu are o complexitate O(n
2
)[30] si atinge o com-
plexitate de O(mlog n) daca se folosesc heapuri Fibonacci [54], sau pairing heaps [115].

In tabelul 6.4 sunt prezentat i mai mult i algoritmi dezvoltat i dea lungul timpului pentru
determinarea arborelui de acoperire minimal si complexitat ile lor. Karger, Klein si Tarjan [79]
pornind de la algoritmul lui Boruvka au realizat un algoritm randomizat pentru determinarea
arborelui de acoperire minimal, avand o complexitate liniara, iar Chazelle [26] a dezvoltat
un algoritm avand complexitatea O(n(m, n)) ((m, n) este inversa funct iei lui Ackerman).
Pe de alta parte, Pettie si Ramachandran [105] au propus un algoritm demonstrat ca ind
optimal, avand complexitatea cuprinsa ntre O(n +m) si O(n(m, n)).
118
Algoritm 41 Algoritmul lui Prim (varianta schematica)
1: procedure Prim1(n, C, u; L)
2: S {u}, L
3: for i 1, n do
4: d
i
c
u,i
5: end for
6: for i 1, n 1 do
7: k min{d
k
|k V \ S}
8: L (tata
k
, k)
9: S S {k}
10: for each j V \ S do
11: d
j
min{d
j
, c
k,j
}
12: end for
13: end for
14: end procedure
Algoritm 42 Algoritmul lui Kruskal (varianta schematica)
1: procedure Kruskal1(G, C, n; L)
2: ordoneaza muchiile n ordine crescatoare dupa cost
3: L
4: for each u V do
5: creaza o mult ime compusa din {u}
6: end for
7: count 0
8: while count < n 1 do
9: alege muchia (u, v)
10: if (u si v sunt n mult imi diferite) then
11: L (u, v)
12: reuneste mult imile ce cont in pe u si v
13: count count + 1
14: end if
15: end while
16: end procedure
Fie G(V, E) un graf neorientat unde V = {1, 2, ..., n} este mult imea nodurilor si E este
mult imea muchiilor (E V V ). Pentru reprezentarea grafului se utilizeaza matricea
costurilor C:
c
i,j
=
_

_
0 , daca i = j
, daca (i, j) / E
d > 0 , daca (i, j) E
6.3.1 Algoritmul lui Boruvka
Algoritmul lui Boruvka [77] a fost descoperit de catre matematicianul ceh Otakar Boruvka
n 1926 [21], si redescoperit apoi de catre alt i cercet atori. Dintre acestia, Sollin (1961) este
cel care a mai dat numele algoritmului, acesta ind cunoscut n literatura de specialitate si
sub numele de algoritmul lui Sollin. Pentru ca acest algoritm sa poata aplicat, trebuie ca
muchiile grafului sa aiba costuri distincte (vezi algoritmul 43).
119
Table 6.4: Algoritmi pentru determinarea arborelui de acoperire minim
Anul Complexitate Autori
1975 E log log V Yao
1976 E log log V Cheriton-Tarjan
1984 E log

V, E +V log V Friedman-Tarjan
1986 E log log

V Gabow-Galil-Spencer-Tarjan
1997 E(V ) log (V ) Chazelle
2000 E(V ) Chazelle [26]
2002 optimal Pettie-Ramachandran [105]
Algoritm 43 Algoritmul lui Boruvka
1: procedure Boruvka2(G, C, n; L)
2: for i 1, n do
3: V
i
{i}
4: end for
5: L , M {V
1
, . . . , V
n
}
6: while (|T| < n 1) do
7: for U M do
8: e (u, v) muchia pentru care se obt ine valoarea minima min{c(u

, v

)|(u

, v

) E, u

U, v

/ V \ U}
9: determina componenta U

ce cont ine pe v
10: L (u, v)
11: end for
12: for U M do
13: reuneste mult imile ce cont in pe u si v, U si U

14: end for


15: end while
16: end procedure
Exemplul 6.4 Sa consideram graful din gura 6.5:
G = (V, E), V = {1, 2, 3, 4, 5, 6, 7, 8}
Aplicand algoritmul lui Boruvka, la pasul ntai vor selectate muchiile (1, 2), (3, 6), (4, 5),
(4, 7) si (7, 8).

In urma operat iilor de reuniune a componentelor conexe pe baza muchiilor
selectate, vor mai ramane trei componente conexe n mult imea M.
La pasul al doilea sunt alese muchiile (2, 5) si (1, 3) ce conduc, n urma operat iilor de
reuniune, la o singura componenta conexa.
6.3.2 Algoritmul lui Prim
Algoritmul a fost descoperit mai ntai de V. Jarnik (1930) [76], si apoi independent de Prim
(1957) [106] si Djikstra (1959) [38].
Se porneste cu o mult ime S formata dintr-un singur nod (S = {v
0
}). La ecare pas se
alege muchia de cost minim ce are numai o extremitate n mult imea S. Procesul se ncheie
dupa n 1 pasi, rezultand un graf part ial aciclic. Din teorema 5.1 rezulta faptul ca acest
graf part ial aciclic cu n 1 muchii este un arbore (de acoperire).
120
Fig. 6.5: Exemplu de graf ponderat - aplicat ie algoritmul lui Boruvka
Conform Proprietat ii taieturii, toate muchiile alese apart in arborelui part ial de cost minim
de unde rezulta ca acest arbore de acoperire este un arbore part ial minim.
Vom utiliza trei vectori de dimensiune n, unde n reprezinta numarul de varfuri al grafului
(vezi algoritmul 44):
vizitat - vector caracteristic
vizitat
k
=
_
1 , daca nodul k S
0 , daca nodul k V \ S
d - pentru un nod k / S, d
k
va cont ine distant a minima de la k la un nod j S. La
nceput, d
j
= c
v
0
,j
. Pentru un nod k ales la un moment dat, d
j
(j S) se modica
numai daca c
k,j
< d
j
astfel d
j
= c
k,j
.
tata - cont ine pentru ecare nod k / S nodul j S astfel ncat c
k,j
= min{c
k,i
|i S}.
La nceput,
tata
k
=
_
0 , daca nodul k = v
0
v
0
, daca nodul k = v
0

In momentul n care se modica d


j
, se va modica si valoarea lui tata
j
= k.
Exemplul 6.5 Fie graful din gura 6.6:
G = (V, E), V = {1, 2, 3, 4, 5, 6, 7, 8}
Vom lua nodul init ial v
0
= 1. La nceput, dupa etapa de init ializare avem:
1 2 3 4 5 6 7 8
d 14 6 5
tata 0 1 1 1 1 1 1 1
vizitat 1 0 0 0 0 0 0 0
Dupa primul pas al ciclului, selectam muchia (1, 5).
1 2 3 4 5 6 7 8
d 14 6 21 5 16
tata 0 1 1 5 1 5 1 1
vizitat 1 0 0 0 1 0 0 0
121
Algoritm 44 Algoritmul Prim (varianta detaliata)
1: function DistantaMinima(n, vizitat, d)
2: min
3: for j 1, n do
4: if (vizitat
j
= 1) (d
j
< min) then
5: min d
j
6: j
0
j
7: end if
8: end for
9: if (min = ) then
10: return 1
11: else
12: return j
0
13: end if
14: end function
15: procedure Prim2(n, C, v
0
; d, tata)
16: vizitat
v
0
1
17: tata
v
0
0
18: for i 1, n do
19: if (i = v
0
) then
20: vizitat
i
0
21: d
i
c
v
0
,i
22: tata
i
v
0
23: end if
24: end for
25: for i 1, n 1 do
26: k DistantaMinima(n, vizitat, d)
27: if (k < 0) then
28: Output Graful nu este conex!
29: return
30: end if
31: vizitat
k
1 (k, tata
k
) este o muchie ce apart ine arborelui part ial minim
32: for j 1, n do
33: if (vizitat
j
= 1) (d
j
> c
k,j
) then
34: tata
j
k
35: d
j
c
k,j
36: end if
37: end for
38: end for
39: end procedure
La pasul al doilea se alege nodul 3 si muchia (1, 3):
1 2 3 4 5 6 7 8
d 14 6 21 5 12 12
tata 0 1 1 5 1 3 1 3
vizitat 1 0 1 0 1 0 0 0
La pasul al treilea avem doua noduri ale caror distant e la noduri din mult imea S sunt
egale: 6 si 8. Alegem primul nod - 6 si muchia (3, 6):
122
Fig. 6.6: Exemplu de graf ponderat - aplicat ie algoritmul lui Prim
1 2 3 4 5 6 7 8
d 14 6 21 5 12 14 6
tata 0 1 1 5 1 3 6 6
vizitat 1 0 1 0 1 1 0 0
Al patrulea nod ales este 8:
1 2 3 4 5 6 7 8
d 14 6 10 5 12 10 6
tata 0 1 1 8 1 3 8 6
vizitat 1 0 1 0 1 1 0 1
La pasul cinci, nodul aat la distant a minima este 7:
1 2 3 4 5 6 7 8
d 14 6 10 5 12 10 6
tata 0 1 1 8 1 3 8 6
vizitat 1 0 1 0 1 1 1 1
La pasul sase este ales nodul 4:
1 2 3 4 5 6 7 8
d 12 6 10 5 12 10 6
tata 0 4 1 8 1 3 8 6
vizitat 1 0 1 1 1 1 1 1
La nal, ultimul nod ales este 2 mpreuna cu muchia (4, 2).
Trebuie sa remarcam faptul ca algoritmul lui Prim (vezi algoritmul 44) este aproape
identic cu algoritmul lui Dijkstra (vezi algoritmul 59).
Dupa cum am subliniat, implementarea optima se realizeaza folosind niste structuri de
date avansate - heapuri Fibonacci sau pairing heaps (vezi algoritmul 45).
6.3.3 Structuri de date pentru mult imi disjuncte
O partit ie a unei mult imi A este o secvent a nita de mult imi (submult imi) A
1
, . . . , A
m
disjuncte doua cate doua, cu proprietatea ca reuniunea acestora este chiar mult imea A
(A =

m
i=1
A
i
si A
i
A
j
= , i, j = 1, m, i = j).
123
Algoritm 45 Algoritmul lui Prim folosind structuri de date avansate
1: procedure Prim3(n, C, u)
2: for ecare v V do
3: d
v

4: end for
5: Q init ializeaza coada cu prioritate Q cu mult imea vida
6: for ecare v V do
7: Q v
8: end for
9: S init ializeaza mult imea S cu mult imea vida
10: while Q = do
11: u deleteMin(Q) extrage nodul de prioritate minima din Q
12: S S {u}
13: for ecare muchie e = (u, v) E do
14: if (v / S) (c(e) < d
v
) then
15: actualizeaza prioritatea lui v: d
v
c(e)
16: end if
17: end for
18: end while
19: end procedure
Exista mai multe probleme ai caror algoritmi de rezolvare depind de urmatoarele operat ii
efectuate asupra elementelor partit iei: vericarea dac a doua elemente fac parte din aceeasi
submult ime precum si operat ia de reuniune a doua submult imi.
O structura de date pentru mult imi disjuncte memoreaza o colect ie de mult imi disjuncte
dinamice. Fiecare mult ime este identicata printrun reprezentant [30]. Operat iile de baza
ale acestei structuri de date sunt [2]:
init(x, B) - procedura creaza o mult ime B formata dintrun singur element x;
find(x) - ntoarce reprezentantul mult imii careia i apart ine x;
merge(A, B) - reuneste mult imile distincte A si B (x A, y B) ntro noua mult ime
ce cont ine elementele celor doua mult imi.
O astfel de structura de date pentru mult imi disjuncte se mai numeste si structura de date
unionnd (eng. unionnd data structure).
Reprezentarea folosind vectori
Vom folosi un vector C de dimensiune n, unde n reprezinta numarul de elemente, iar c
k
= u
indica faptul ca elementul k apart ine mult imii u.
Init consta din init ializarea lui c
x
cu identicatorul mult imii, u. Find ntoarce valoarea
lui c
x
(valoarea identicatorului mult imii).

In funct ia Merge se cauta toate elementele ce
fac parte din mult imea de identicator c
y
si se trec n mult imea al carui identicator este c
x
(vezi algoritmul 46).
Exemplul 6.6 Pentru o putea opera cu modul de reprezentare ales, cel cu vectori, trebuie
ca elementele mult imii sa ia valori naturale n intervalul [1,. . . ,n]. Daca acest lucru nu
este posibil atunci folosim un vector auxiliar A ce pastreaza valorile elementelor, n cadrul
reprezentarii utilizanduse indicele acestora. Sa presupunem ca avem mult imea de elemente
124
Algoritm 46 Algoritmi pentru operat iile init, nd, merge (varianta ntai)
1: procedure Init(x, u)
2: c
x
u
3: end procedure
4: function Find(x)
5: return c
x
6: end function
7: function Merge(x, y)
8: setx c
x
9: sety c
y
10: for k 1, n do
11: if (c
k
= sety) then
12: c
k
setx
13: end if
14: end for
15: return setx
16: end function
A = {a, b, e, x, y, z, u, v} si partit ia {a, x, y}, {b, z, v}, {e, u}. Atunci conform modului de
reprezentare descris avem:
1 2 3 4 5 6 7 8
A a b e x y z u v
C 1 2 3 1 1 2 2 3
a
2
=

are semnicat ia urmatoare: elementul de pe pozit ia 2 are valoarea



b

. c
2
= 2 -
elementul de pe pozit ia 2 face parte din mult imea de identicator 2. Sau a
4
=

- elementul
de pe pozit ia 4 are valoarea

x

, si c
4
= 1 - elementul de pe pozit ia 4 face parte din mult imea
de identicator 1.
Reprezentarea folosind liste nlant uite

In cadrul acestei metode ecare mult ime este reprezentat a printro lista simplu nlant uita,
elementul reprezentant ind elementul aat n capul listei. Un nod al listei va avea un camp
ce pastreaza informat ia cu privire la un element al unei mult imi, si un camp ce cont ine
legatura catre urmatorul nod al listei.
Vom folosi un vector de adrese (List), ce cont ine adresa primului element din ecare lista
(List
i
).
Procedura Init aloca un nod si init ializeaza campurile acestuia. Adresa nodului alocat
este pastrata n List
k
(vezi algoritmul 47).
Funct ia Find cauta un element printre elementele pastrate de ecare lista n parte. Se
parcurge vectorul List si se obt ine reprezentantul ecarei submult imi pastrate. Se parcurge
lista (cautare liniara) si se cauta un element cu valoarea x. Daca elementul este gasit atunci
se ntoarce capul listei n care a fost gasit. Daca pan a la sfarsit nu a fost identicat elementul
x, atunci funct ia returneaza valoarea NULL.
Funct ia Merge reuneste doua liste: practic se adauga o lista la sfarsitul celeilalte. Pentru
a realiza aceasta operat ie pe langa adresa primului element avem nevoie de adresa ultimului
element. Acest lucru se poate obt ine indirect prin parcurgerea listei de la primul la ultimul
element, e direct daca n momentul crearii pastram pentru ecare lista nca o variabila ce
cont ine adresa ultimului element (last).
125
Algoritm 47 Algoritmi pentru operat iile init, nd, merge (varianta a II-a)
1: procedure Init(x, k)
2: List
k
new node aloca spat iu pentru un nod al listei
3: List
k
.data x
4: List
k
.next NULL
5: end procedure
6: function Find(x)
7: for i 1, m do
8: p List
i
, reprezentant p
9: while (p = NULL) (p.data = x) do
10: p p.next
11: end while
12: if (p = NULL) then
13: return reprezentant
14: end if
15: end for
16: return NULL
17: end function
18: function Merge(x, y)
19: cap
x
Find(x)
20: cap
y
Find(y)
21: curent cap
x
22: while (curent.next = NULL) do
23: curent curent.next
24: end while
25: curent.next cap
y
26: return cap
x
27: end function
Reprezentarea folosind o padure de arbori

In cadrul acestei modalitat i de reprezentare ecare mult ime este pastrata sub forma unui
arbore. Pentru ecare nod pastram informat ia despre parintele sau: tata
k
reprezinta indicele
nodului parinte al nodului k.
Se poate observa foarte usor (vezi algoritmul 48) faptul c a arborele obt inut n urma unor
operat ii repetate Merge poate deveni degenerat (o lista liniara). Pentru a putea sa evitam o
astfel de situat ie, reuniunea se poate realiza t inand cont de una din urmatoarele caracteristici:
1. numarul de elemente din ecare arbore - radacina arborelui ce are mai put ine elemente
(notam arborele cu T
B
) va deveni descendentul direct al radacinii arborelui ce poseda
mai multe elemente (notat cu T
A
). Astfel toate nodurile din arborele T
A
vor ramane cu
aceeasi adancime, pe cand nodurile din arborele T
B
vor avea adancimea incrementata
cu 1. De asemenea, arborele rezultat n urma reuniunii va avea cel put in de doua ori
mai multe noduri decat arborele T
B
.
126
Algoritm 48 Algoritmi pentru operat iile init, nd, merge (varianta a III-a)
1: procedure Init(x)
2: tata
x
x
3: end procedure
4: function Find(x)
5: while (x = tata
x
) do
6: x tata
x
7: end while
8: return x
9: end function
10: function Merge(x, y)
11: radx Find(x)
12: rady Find(y)
13: tata
rady
radx
14: return radx
15: end function
1: procedure Init(x)
2: tata
x
1
3: end procedure
4: function Find(x)
5: while (tata
x
> 0) do
6: x tata
x
7: end while
8: return x
9: end function
1: function Merge(x, y)
2: radx Find(x)
3: rady Find(y)
4: size |tata
radx
| +|tata
rady
|
5: if (|tata
radx
| > |tata
rady
|) then
6: tata
rady
radx
7: tata
radx
size
8: return radx
9: else
10: tata
radx
rady
11: tata
rady
size
12: return rady
13: end if
14: end function
Prin aceasta euristica simpla se urmareste o echilibrare a arborelui rezultat pentru a se
evita cazurile degenerate. Complexitatea timp a procedurii Find este O(log n).
2. nalt imea ecarui arbore - radacina arborelui ce are nalt imea mai mica (notam arborele
cu T
B
) va deveni descendentul direct al radacinii arborelui cunalt imea mai mare (notat
cu T
A
). Daca nalt imile lui T
A
si T
B
sunt egale si T
A
devine subarbore al lui T
B
atunci
nalt imea lui T
B
creste cu o unitate.

Inalt imea ecarui subarbore de radacina u se pastreazantro variabila noua h


u
. Pentru
a economisi cantitatea de memorie utilizata, se poate pastra nalt imea unui arbore n
vectorul tata: tata
x
= valoarea nalt imii arborelui, atunci cand x reprezinta nodul
radacina al unui arbore.
127
1: procedure Init(x)
2: tata
x
x
3: h
x
0
4: end procedure
5: function Find(x)
6: while (tata
x
= x) do
7: x tata
x
8: end while
9: return x
10: end function
1: function Merge(x, y)
2: radx Find(x)
3: rady Find(y)
4: if (h
radx
> h
rady
) then
5: tata
rady
radx
6: return radx
7: else
8: tata
radx
rady
9: if (h
radx
= h
rady
) then
10: h
rady
h
rady
+ 1
11: end if
12: return rady
13: end if
14: end function
Cea dea doua tehnica utilizata pentru a reduce complexitatea timp a operat iilor Find si
Merge este reprezentata de comprimarea drumului. Aceasta consta n a apropia ecare nod
de radacina arborelui caruia i apart ine. Astfel n timpul operat iei Find(x) se determina mai
ntai radacina arborelui caruia i apart ine (rad) si apoi se mai parcurge o data drumul de la
nodul x la radacina, astfel tata
y
rad, y lant ul de la x la rad.
1: function Find(x)
2: y x
3: while (tata
y
= y) do
4: y tata
y
5: end while
6: rad y
7: y x
8: while (tata
y
= y) do
9: y tata
y
10: tata
x
rad
11: x y
12: end while
13: return rad
14: end function
6.3.4 Algoritmul lui Kruskal
Algoritmul lui Kruskal [88] este o ilustrare foarte buna a metodei generale Greedy (vezi
algoritmul 49). La nceput se pleaca cu o padure de arbori, ecare arbore ind alcatuit
dintrun singur nod. La ecare pas se alege o muchie: daca cele doua extremitat i (noduri)
fac parte din acelasi arbore atunci nu se va adauga muchia curenta la arborele part ial respectiv
deoarece ar conduce la un ciclu, ceea ce ar strica proprietatea de graf aciclic. Altfel, daca cele
doua noduri fac parte din arbori part iali distinct i, se adauga muchia curenta la mult imea de
muchii alese anterior, iar cei doi arbori part iali devin unul singur. La ecare pas, numarul
de arbori part iali scade cu 1. Dupa n 1 alegeri padurea init iala compusa din n arbori sa
transformat ntrun singur arbore.
Pentru a pastra muchiile grafului vom utiliza o matrice A cu m coloane si 3 linii: primele
doua linii cont in extremitat ile muchiilor, iar linia a 3-a costul muchiei respective. Pentru a se
aplica o strategie Greedy, datele de intrare muchiile se vor ordona crescator n funct ie de
costul asociat. Deoarece graful part ial respectiv este un arbore cu n noduri el va avea n 1
muchii.
128
O vericare ecienta cu privire la apartenent a la acelasi arbore a celor doua extremitat i
ale unei muchii se poate face daca vom utiliza o structura de date pentru mult imi disjuncte.
Ca implementare, am ales reprezentarea cu padure de arbori. Vom folosi un vector tata
care, pentru ecare nod, va pastra tatal acestuia n arborele part ial caruia i apart ine.
Cand sunt preluate ca date de intrare, muchiile vor prezentate n ordinea crescatoare a
extremitat ilor lor, de forma i j cost, cu i < j.
Algoritm 49 Algoritmul lui Kruskal
1: procedure Kruskal2(n, m, A; L, cost)
2: for i 1, n do
3: call Init(i)
4: end for
5: cost 0
6: j 1, L
7: for i 1, n 1 do
8: q 0
9: while (q = 0) do
10: r
1
Find(A
1,j
)
11: r
2
Find(A
2,j
)
12: if (r
1
= r
2
) then
13: cost cost + A
3,j
14: call Merge(r
1
, r
2
)
15: L L {(A
1,j
, A
2,j
)}
16: q 1
17: end if
18: j j + 1
19: end while
20: end for
21: end procedure
Exemplul 6.7 Sa consideram graful din gura 6.6. Muchiile grafului si costurile lor sunt
(am ales sa reprezentam matricea A sub forma unei matrice cu m coloane si 3 linii din motive
de spat iu):
A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
linia 1 1 1 1 2 2 2 3 3 4 4 4 5 6 6 7
linia 2 2 3 5 4 5 6 6 8 5 7 8 6 7 8 8
linia 3 14 6 5 12 16 20 12 12 21 24 10 16 14 6 10
Dupa asezarea n ordine crescatoare a muchiilor dupa cost avem:
A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
linia 1 1 1 6 4 7 2 3 3 1 6 2 5 2 4 4
linia 2 5 3 8 8 8 4 6 8 2 7 5 6 6 5 7
linia 3 5 6 6 10 10 12 12 12 14 14 16 16 20 21 24

In gura 6.7, sunt ilustrat i pasii algoritmului lui Kruskal aplicat pe graful considerat.
La nceput se init ializeaza padurea de arbori, ecare arbore ind alcatuit dintrun singur
nod, acesta ind si radacina arborelui. Apoi la ecare pas se alege o muchie si se verica
daca extremitat ile acesteia fac parte din arbori diferit i. Daca raspunsul este armativ atunci
muchia respectiva este selectata, altfel se trece la muchia urmatoare.
129
Fig. 6.7: Algoritmului lui Kruskal exemplicat pe graful din gura 6.6
La pasul ntai evaluam muchia (1, 5), si deoarece cele doua extremitat i fac parte din arbori
distinct i, vom selecta aceasta muchie (L = {(1, 5)}). Reunim arborii din care fac parte cele
doua extremitat i, (vezi gura 6.7 (1)).
La pasul al doilea, se ia n considerare muchia (1, 3) si mult imea muchilor selectate devine
L = {(1, 5), (1, 3)} (vezi gura 6.7 (2)).
La pasul al patrulea, ajungem la muchia (4, 8) ce are costul 10. Nodul 4 face parte din
arborele de radacina 4 iar nodul 8 face parte din arborele de radacina 6. Deoarece extremitat ile
muchiei sunt amplasate n arbori distinct i selectam muchia curenta pentru arborele part ial
de cost minim, L = {(1, 5), (1, 3), (6, 8), (4, 8)}.

In urma reuniunii arborilor corespunzatori
celor doua noduri se obt ine congurat ia din gura 6.7 (4).
130
Subliniem faptul ca arborii reprezentat i n gura 6.7 sunt diferit i de arborii ce con-
duc la obt inerea solut iei problemei: arborii din gura constituie suportul necesar pentru
reprezentarea structurii de date pentru mult imi disjuncte, ce este utilizata pentru efectuarea
ecienta a operat iilor Find si Merge. Acest lucru justica faptul ca desi la pasul al patrulea
selectam muchia (4, 8) pentru arborele part ial de cost minim, ea nu se regaseste n congurat ia
(4) (nodul 4 este unit direct cu nodul 6, vezi gura 6.7). Singura legatura dintre un arbore
suport pentru reprezentarea unei mult imi si un arbore folosit pentru obt inerea arborelui part ial
de cost minim, este mult imea de noduri ce este comuna.
La pasii urmatori, cinci si sase, sunt alese muchiile (7, 8) si respectiv (2, 4): L = {(1, 5), (1, 3),
(6, 8), (4, 8), (7, 8), (2, 4)}.
La pasul al saptelea se evalueaza muchia (3, 6). Nodurile 3 si 6 fac parte din arbori diferit i,
astfel ncat muchia curenta poate selectata pentru solut ia problemei, L = {(1, 5), (1, 3), (6, 8),
(4, 8), (7, 8), (2, 4), (3, 6)}.
6.4 Exercit ii
1. Sa se realizeze o subrutina ce ntoarce numarul de noduri dintrun arbore oarecare.
2. Se da o secvent a formata din n numere naturale d
1
, d
2
, . . . , d
n
. Sa se realizeze un
algoritm prin care sa se verice daca exista un arbore cu n noduri ale caror grade sunt
d
1
, d
2
, . . . , d
n
.
Daca exista un astfel de arbore, acesta va reprezentat prin liste ale nodurilor. O lista
a unui nod cont ine numarul nodului urmat de i sai.
Intrare Iesire
1 1 2 3 1 1 3 DA
1 2 3 4
2 5 6
3 7
4
5
6
7
(Timisoara-pregatire, 1996)
3. Fie un graf G cu n varfuri si m muchii de cost pozitiv. Alegand un nod, numit nod
central, sa se determine un subarbore al lui G astfel ncat drumurile de la nodul central
la toate celelalte noduri sa aiba lungimea minima.
4. Fiind date n puncten spat iul R
3
determinate prin coordonatele (x, y, z), sa se elaboreze
un algoritm ce determina sfera de raza minima cu centrul ntrunul din punctele date
si care cont ine n interiorul ei toate cele n puncte.
5. Se considera procesul de proiectare a unei placi electronice cu N componente (1 N
100). Pentru ecare componenta electronica C se cunoaste numarul de interconexiuni.
Se considera graful determinat de mult imea pinilor si mult imea interconectarilor posi-
bile ale tuturor componentelor, precum si lungimile lor. Dintre toate modalitat ile de
interconectare posibile se cere cea corespunzatoare arborelui de acoperire minim (inter-
conectarea pentru care suma tuturor circuitelor imprimate are lungimea minima).
131
Datele de intrare sunt alcatuite din descrierile mai multor placi electronice. Descrierea
ecarei placi cont ine numarul N de componente si numarul M de interconexiuni. O
conexiune se caracterizeaza prin trei valori: doua varfuri, u si v, precum si lungimea
acesteia l.
Datele de iesire constau dintr-un raspuns pentru ecare mult ime de date de test, compus
din numarul testului (se ncepe numerotarea cu 1), precum si costul interconectarii de
lungime minima.
Exemplul 6.8 Pentru datele de intrare
5 7
1 2 40 2 3 35 1 5 27 1 4 37 4 5 30 2 4 58 3 4 60
0 0
vom obt ine rezultatul
Cazul 1: [1 5] [4 5] [2 3] [1 2]
Interconectarea de cost minim are valoarea 132.

In gura 6.8 este reprezentat graful corespunzator datelor de intrare.


Fig. 6.8: Descrierea conexiunilor posibile dintre componentele unei placi electronice
6. Realizat i o subrutina nerecursiva care sa determine cheia minima dintrun arbore oare-
care.
7. Determinat i nalt imea unui arbore oarecare printro funct ie nerecursiva.
8. Pentru asigurarea securitat ii activitat ilor dintrun combinat chimic sa apelat la o com-
panie de pompieri. Desfasurarea activitat ilor companiei presupune stabilirea locurilor
de instalare a comandamentului precum si a posturilor de supraveghere. Pentru aceasta
sunt disponibile n cadrul combinatului n puncte de control. Pentru ecare pereche de
puncte de control se cunoaste daca exista o legatura directantre ele si, n caz armativ,
distant a dintre ele. Se cunoaste, de asemenea, faptul ca ntre oricare doua puncte de
control exista un drum direct sau indirect.
Odata stabilite amplasamentele comandamentului si ale punctelor de supraveghere n
cate unul dintre cele n puncte de control este posibil sa se ajunga de la comandament
132
la ecare punct de supraveghere parcurgand un anumit drum. Evident este de dorit ca
lungimea acestui drum sa e minima si valoarea maxima dintre lungimile drumurilor
minime pentru ecare punct de supraveghere n parte sa e cat mai mica posibila.
Se cere sa se determine punctul de control n care trebuie instalat comandamentul cat
si drumurile ce vor parcurse de la comandament la ecare punct de supraveghere,
astfel ncat aceste drumuri sa aiba valoarea lungimii minima si cel mai lung dintre ele
sa e cat mai scurt posibil.
133
Capitolul 7
Grafuri orientate
7.1 Not iuni de baza
Fie o mult ime nita V = {x
1
, x
2
, . . . , x
n
}. Fie E V V (unde V V este produsul
cartezian al mult imii V cu ea nsasi).

In cazul unui graf orientat, not iunea de muchie este nlocuita cu not iunea de arc (o
pereche de noduri (x, y) devine ordonata, adica (x, y) = (y, x)). Pentru un arc (x, y) E,
varful x reprezinta extremitatea init iala a arcului, iar varful y reprezinta extremitatea nala.
Vom spune ca varfurile x si y sunt adiacente.
Denit ia 7.1 Un graf orientat este o pereche ordonata G = (V, E), unde V este o
mult ime de varfuri sau noduri, iar E este o mult ime de arce.
Exemplul 7.1 Fie graful orientat G = (V, E), V = {1, 2, 3, 4, 5, 6, 7, 8},
E = {(1, 2), (1, 3), (1, 4), (2, 1), (3, 5), (4, 6), (5, 2), (5, 7), (6, 4), (6, 8), (7, 5), (7, 6)}. Acest graf
se poate reprezenta ca n gura 7.1.
Denit ia 7.2 Un graf part ial al unui graf orientat G = (V, E) este un graf orientat
G
1
= (V, E
1
) unde E
1
E.
Exemplul 7.2 Pentru graful G din exemplul anterior (G = (V, E)), consideram graful
part ial G
1
= (V, E
1
), cu E
1
= {(1, 3), (2, 1), (3, 5), (4, 6), (5, 2), (5, 7), (6, 4), (6, 8)}, si V =
{1, 2, 3, 4, 5, 6, 7, 8}.
Denit ia 7.3 Un subgraf al unui graf orientat G = (V, E) este un graf orientat H =
(V
1
, E
1
) unde V
1
V iar arcele din E
1
sunt toate arcele din E ce au ambele extremitat i n
mult imea V
1
(E
1
= E|
V
1
V
1
).
Exemplul 7.3 Fie subgrafurile H
1
si H
2
ale grafului G din exemplul anterior: H
1
= (V
1
, E
1
),
unde V
1
= {1, 2, 3, 5}, iar E
1
= {(1, 2), (1, 3), (2, 1), (3, 5), (5, 2)}, si H
2
= (V
2
, E
2
), unde
V = {4, 6, 7, 8} si E
2
= {(4, 6), (6, 4), (6, 8), (7, 6)}.
Denit ia 7.4 Gradul exterior al unui varf d
+
(x) este egal cu numarul arcelor ce au ca
extremitate init iala pe x. Gradul interior al unui varf d

(x) este egal cu numarul arcelor ce


au ca extremitate nala pe x (d
+
(x) = |{(x, u)|(x, u) E, u V }|, d

(x) = |{(u, x)|(u, x)


E, u V }|).
134
Fig. 7.1: Un exemplu de graf orientat
Denit ia 7.5 Se numeste lant o secvent a de arce L = {l
1
, . . . , l
p
} cu proprietatea ca oricare
doua arce consecutive ale secvent ei au o extremitate comuna. (L = [v
0
, v
1
, . . . , v
p
] unde
(v
i
, v
i+1
) E sau (v
i+1
, v
i
) E, i = 0, p 1).
Denit ia 7.6 Un drum D = [v
0
, v
1
, . . . , v
p
] este o succesiune de varfuri cu proprietatea ca
oricare doua varfuri vecine sunt adiacente. ((v
i
, v
i+1
) E, i = 0, p 1).
Daca varfurile v
0
, v
1
, . . . , v
p
sunt distincte doua cate doua, drumul se numeste elementar.
Exemplul 7.4 L
1
= {(6, 8), (7, 6), (7, 5), (3, 5), (1, 3)} si L
2
= {(6, 8), (6, 4), (1, 4)} sunt lant uri
de la varful 8 la varful 1, iar D
1
= {(1, 3), (3, 5), (5, 7), (7, 6), (6, 8)} si
D
2
= {(1, 4), (4, 6), (6, 8)} sunt drumuri elementare de la varful 1 la varful 8.
Denit ia 7.7 Un drum D pentru care v
0
= v
p
se numeste circuit.
Denit ia 7.8 Se numeste circuit hamiltonian un circuit elementar ce trece prin toate
varfurile grafului. Un graf ce admite un circuit hamiltonian se numeste graf hamiltonian
orientat.
Denit ia 7.9 Un drum D ce cont ine ecare arc exact o singura data se numeste drum eu-
lerian. Daca v
0
= v
p
si drumul este eulerian atunci circuitul se numeste circuit eulerian.
Un graf ce cont ine un circuit eulerian se numeste graf eulerian orientat.
Denit ia 7.10 Un graf se numeste conex daca pentru orice pereche de varfuri x si y exista
un lant L
xy
de la x la y.
Denit ia 7.11 Un graf orientat este complet daca oricare doua varfuri sunt adiacente.
Metodele utilizate pentru reprezentarea unui graf neorientat se pot adapta n mod natural
pentru reprezentarea unui graf orientat, nlocuind not iunea de muchie cu cea de arc.
135
Fig. 7.2: Arbore de acoperire n lat ime pentru graful orientat din gura 7.1
7.2 Parcurgerea grafurilor

In urma vizitarii unui graf neorientat de obicei nu rezult a numai un arbore de acoperire ci o
padure de arbori de acoperire.

In urma unei parcurgeri n lat ime a unui graf orientat, se ntalnesc urmatoarele tipuri de
arce:
arc al arborelui de acoperire - arcul (u, v) este un arc al arborelui de acoperire n lat ime.
arc de ntoarcere - arcul (u, v) se numeste arc de ntoarcere daca are sensul contrar unui
drum de la v la u n arborele de acoperire (v u) (se spune ca u este un descendent
al lui v si v este un stramos al lui u).
arc de traversare - arcul (u, v) este un arc de traversare daca v nu este nici descendent
direct, nici stramos al lui u.

In gura 7.2 este prezentat arborele de acoperire n lat ime corespunzator grafului din
gura 7.1 avand radacina 1: arcele (2, 1), (7, 5), (6, 4) sunt arce de ntoarcere, (5, 2), (7, 6)
sunt arce de traversare, iar celelalte sunt arce ale arborelui de acoperire (de exemplu (1, 3),
(6, 8)).
Vom prezenta schit a unui algoritm mai general pentru parcurgerea unui graf (vezi al-
goritmul 50). Pentru aceasta se utilizeaza doua mult imi de noduri, V izitat si Neexplorat,
unde V izitat reprezinta mult imea nodurilor vizitate iar Neexplorat (Neexplorat V izitat)
reprezinta mult imea nodurilor vizitate dar neexplorate (noduri ce prezinta vecini nca nevizitat i).

In urma unei parcurgeri n adancime a unui graf orientat, ecare arc din mult imea arcelor
poate ncadrat ntrunul dintre tipurile urmatoare:
arc al arborelui de acoperire - arcul (u, v) este un arc al arborelui de acoperire daca
dfs(u) apeleaza dfs(v) (dfs(u)
call
dfs(v)).
arc de naintare - arcul (u, v) este un arc de naintare daca este paralel cu un drum de
la u la v din arborele de acoperire (u v) (nu face parte din arborele de acoperire).
136
Algoritm 50 Algoritm de vizitare a unui graf (model general)
1: procedure ParcurgereGraf(u, G)
Input:
_
u - varful de unde se porneste vizitarea
G - graful
2: V izitat {u}
3: Neexplorat V izitat
4: while (Neexplorat = ) do
5: extrage un nod x din Neexplorat
6: determina y, urmatorul vecin al lui x ce nu a fost vizitat
7: if (y = NULL) then
8: elimina x din Neexplorat
9: else
10: if (y / V izitat) then
11: V izitat V izitat {y}
12: Neexplorat Neexplorat {y}
13: end if
14: end if
15: end while
16: end procedure
arc de ntoarcere - arcul (u, v) se numeste arc de ntoarcere daca are sensul contrar unui
drum de la v la u din arborele de acoperire (v u).
arc de traversare - arcul (u, v) este un arc de traversare daca dfs(v) a fost apelat si sa
terminat nainte de apelul lui dfs(u).
Fig. 7.3: Arbore de acoperire n adancime pentru graful orientat din gura 7.1
Pentru ecare nod v al unui graf vom introduce doua numere, prenum
v
si postnum
v
,
numere ce depind de ordinea n care sunt ntalnite nodurile acestuia n timpul vizitarii n
adancime: prenum
v
marcheaza momentul cand este ntalnit nodul v pentru prima oara
137
iar postnum
v
momentul n care prelucrarea nodului v sa ncheiat. Variabila counter este
init ializata cu valoarea 1:
1: procedure Prenum(v)
2: prenum
v
counter
3: counter counter + 1
4: end procedure
si
1: procedure Postnum(v)
2: postnum
v
counter
3: counter counter + 1
4: end procedure
Un arc (u, v) va avea urmatoarele proprietat i, n funct ie de una din cele patru categorii
de arce introduse anterior n care se ncadreaza:
1. arc al arborelui de acoperire: prenum
u
< prenum
v
si postnum
u
> postnum
v
;
2. arc de naintare: prenum
u
< prenum
v
si postnum
u
> postnum
v
;
3. arc de ntoarcere: prenum
u
> prenum
v
si postnum
u
< postnum
v
;
4. arc de traversare: prenum
u
> prenum
v
si postnum
u
> postnum
v
.
Arborele de acoperire n adancime corespunzator grafului din gura 7.1 ilustreaza aceste
tipuri de arce: arc de naintare (1, 4), arce de ntoarcere (2, 1), (7, 5), (4, 6) arc de
traversare (5, 2), arce ale arborelui de acoperire (1, 2), (1, 3), (3, 5), (5, 7), (7, 6), (6, 8),
(6, 4). (vezi gura 7.3).
Algoritm 51 Algoritm de vizitare n adancime pentru un graf orientat
1: procedure DFSNum(k, n, V ecin)
Input:
_

_
k - nodul curent vizitat
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: vizitat
k
1 marcarea nodului curent ca ind vizitat
3: call Prenum(k)
4: call V izitare(k) vizitarea nodului curent
5: for i 1, n do
6: if (vizitat
i
= 0) (vecin
k,i
= 1) then
7: call DFSNum(i, n, V ecin) apelul recursiv al subrutinei DFSNum pentru nodul
i
8: end if
9: end for
10: call Postnum(k)
11: end procedure
Lema 7.5 Fiind dat un graf orientat G si doua noduri oarecare u, v G ce apart in aceluiasi
arbore de acoperire n adancime rezultat n urma parcurgerii cu metoda DFS a grafului G
avem:
1. daca (u, v) este un arc al arborelui de acoperire sau un arc de naintare sau un arc de traver-
sare postnum
u
> postnum
v
;
138
2. daca (u, v) este un arc de ntoarcere postnum
u
< postnum
v
.
Lema 7.6 Fiind dat un graf orientat G pentru oricare doua noduri u, v G avem:
1. v este un descendent al lui u n padurea de arbori de acoperire rezultat i n urma vizitarii n
adancime a grafului G intervalul [prenum
v
, postnum
v
] este inclus n intervalul [prenum
u
,
postnum
u
];
2. nu exista nici o legatura ntre u si v n padurea de arbori de acoperire rezultat i n urma
vizitarii n adancime a grafului G intervalele [prenum
u
, postnum
u
] si [prenum
v
, postnum
v
]
sunt disjuncte;
3. situat ii prenum
u
< prenum
v
< postnum
u
< postnum
v
sau prenum
v
< prenum
u
< postnum
v
< postnum
u
nu sunt posibile.
Lema 7.7 Fiind dat un graf neorientat G, daca pentru doua noduri oarecare u, v G avem
relat ia prenum
u
< prenum
v
< postnum
u
atunci:
prenum
u
< prenum
v
< postnum
v
< postnum
u
.
exista un drum de la u la v n G.
Exemplul 7.8

In urma apelarii procedurii DFSNum(1, 8, V ecin) (vezi algoritmul 51), sec-
vent a de apeluri recursive ale procedurii DFSNum este ilustrata prin arborele de acoperire
n adancime din gura 7.3.
Numerotarea nodurilor n preordine si postordine rezultata n urma vizitarii este urmatoarea:
1 2 3 4 5 6 7 8
prenum 1 2 4 8 5 6 7 10
postnum 16 3 15 9 14 13 12 11
Pentru arcul (1, 4) avem prenum
1
= 1, postnum
1
= 16, prenum
4
= 8 si postnum
4
= 9.
Deoarece relat ia prenum
u
< prenum
v
< postnum
u
este adevarata conform lemei 7.7 ar
trebui sa avem prenum
u
< prenum
v
< postnum
v
< postnum
u
si sa existe un drum de la u
la v, lucruri care sunt adevarate (prenum
1
< prenum
4
< postnum
4
< postnum
1
si exista un
drum de la 1 la 4 n arborele de acoperire n adancime).
7.3 Sortarea topologica
Fig. 7.4: Un graf orientat aciclic
139
Denit ia 7.12 Un graf orientat si care nu poseda circuite se numeste graf orientat aciclic
(directed acyclic graph - DAG).
Lema 7.9

Intrun graf orientat aciclic, daca prenum
u
< prenum
v
si exista un drum de la
u la v n G, atunci prenum
u
< prenum
v
< postnum
v
< postnum
u
.

In practica, exista mai multe situat ii n care o mult ime de activitat i sau sarcini, trebuie
organizate ntro anumita ordine, ntre acestea exist and, de obicei, o mult ime de restrict ii
sau dependent e.

In activitatea de construire a unei cladiri, anumite activitat i nu pot
ncepute decat dupa nalizarea altor activitat i: spre exemplu, nu se poate ncepe ridicarea
peret ilor decat dupa turnarea fundat iei si nalizarea structurii de rezistent a, nu se poate rea-
liza instalat ia electrica daca nu au fost ridicate zidurile, s.a.m.d. Sau daca un student doreste
sa si alcatuiasca un plan de studiu individual ce va cont ine pe langa cursurile obligatorii, si
o serie de cursuri opt ionale, va trebui sa t ina cont de anul de studiu n care se preda ecare
materie, precum si de cerint ele obligatorii ale acestora: un curs nu poate inclus n planul de
studiu individual al unui student decat daca acesta a parcurs si a obt inut creditele la toate
materiile anterioare cerute explicit n programa cursului.
Algoritm 52 Algoritm de sortare topologica a unui graf orientat (prima varianta)
1: procedure SortTop1(n, V ecin)
Input:
_
n - numarul de noduri din graf
V ecin - vector ce cont ine listele cu vecini ai ecarui nod
2: for k 1, n do
3: dminus
k
0
4: end for
5: for (u, v) E do
6: dminus
v
= dminus
v
+ 1
7: end for
8: Q se init ializeaza coada
9: for k 1, n do
10: if (dminus
k
= 0) then
11: Q k se insereaza ntro coada nodurile cu gradul interior 0
12: end if
13: end for
14: while (Q = ) do
15: Q k se extrage din coada un nod
16: L k se insereaza nodul ntr-o lista
17: w V ecin
k
v ia valoarea capului listei de vecini a nodului k
18: while (w = NULL) do
19: dminus
w.nodeIndex
dminus
w.nodeIndex
1
20: if (dminus
w.nodeIndex
= 0) then
21: Q w.nodeIndex se insereaza n coada nodul w.nodeIndex
22: end if
23: w w.next se trece la urmatorul vecin
24: end while
25: end while
26: end procedure
Dependent a dintre doua activitat i Asi B o putem modela prin introducerea a doua noduri
n graf x
i
si x
j
, asociate celor doua activitat i. Daca activitatea A trebuie realizata naintea
activitat ii B, atunci se adauga arcul (x
i
, x
j
).
140
Denit ia 7.13 Se numeste sortare topologic a pentru un graf orientat G = (V, E) o or-
donare {x
1
, x
2
, . . . , x
n
} a nodurilor grafului astfel ncat pentru orice arc (x
i
, x
j
) sa avem
i < j.
Prin urmare o sortare topologica presupune aranjarea liniara a varfurilor unui graf astfel
ncat toate arcele sale sa e orientate de la stanga la dreapta.
Lema 7.10 Daca un graf orientat G admite o sortare topologica atunci G este aciclic.
Lema 7.11 Daca un graf orientat G este aciclic atunci el admite o sortare topologica.
Observat ia 7.12

Intrun graf orientat aciclic exista cel put in un nod al c arui grad interior
este 0 (graful nu poseda arce care sa aiba nodul v drept extremitate nala).
Pornind de la aceasta observat ie se schit eaza urmatorul algoritm [78]: ntrun graf G se
determina un nod v astfel ncat gradul sau interior sa e zero (d

(v) = 0); se adauga acest


nod la o lista ce va cont ine ordonarea topologica, se sterge nodul din graf mpreuna cu toate
arcele ce l au ca extremitate init iala, si se reia algoritmul pentru graful G

= (V

, E

), unde
V

= V \ {v}, E

= E|
V

V
.
Algoritmul 52 se termina n cel mult n pasi (|V | = n). Daca se termina mai devreme,
atunci graful G nu este aciclic (la un moment dat nu mai exista nici un nod v astfel ncat
d

(v) = 0).
Fig. 7.5: Sortare topologica cu algoritmul 52 pentru graful orientat din gura 7.4
Exemplul 7.13 Fie graful orientat din gura 7.5. Varful 3 are d

(v) = 0. Se adauga acest


nod la lista nala ce va cont ine nodurile ordonate, se sterge nodul mpreuna cu arcele care l
au drept extremitate init iala.

In graful rezultat, varful 1 are proprietatea ca d

(v) = 0. Se
adauga la lista de rezultate, si se elimina din graf mpreuna cu arcele ce pleaca din el. Se
continua procedeul pana cand graful devine vid (ntregul proces poate urmarit n gura 7.5).
141
Algoritm 53 Algoritm de sortare topologica a unui graf orientat (a doua varianta)
1: procedure SortTop2(n, V ecin)
Input:
_
n - numarul de noduri din graf
V ecin - matricea de adiacent a a grafului
2: for k 1, n do
3: prenum
k
0, postnum
k
0
4: vizitat
k
0
5: end for
6: for k 1, n do
7: if (vizitat
k
= 0) then
8: call DFSNum(k, n, V ecin)
9: end if
10: end for
11: se ordoneaza descrescator nodurile dupa postnum
k
12: end procedure
Lema 7.14 Un graf orientat G este aciclic daca si numai daca n urma unei vizitari n
adancime a acestuia nu este ntalnit nici un arc de ntoarcere.
Ideea algoritmului 53 o reprezinta lema 7.14[118].
Exemplul 7.15 Sa consideram ca date de intrare pentru algoritmul 53 graful orientat din
gura 7.4. Dupa etapa de init ializare (liniile 2 - 5) avem:
1 2 3 4 5 6 7
prenum 0 0 0 0 0 0 0
postnum 0 0 0 0 0 0 0
vizitat 0 0 0 0 0 0 0
Se apeleaza mai ntai DFSNum(1, 7, V ecin). Secvent a rezultata de apeluri recursive este
urmatoarea: DFSNum(1, 7, V ecin) DFSNum(2, 7, V ecin) DFSNum(4, 7, V ecin)
DFSNum(5, 7, V ecin) DFSNum(7, 7, V ecin) DFSNum(6, 7, V ecin).

In urma acestei secvent e valorile vectorilor prenum si postnum sunt urmatoarele:


1 2 3 4 5 6 7
prenum 1 2 0 3 4 6 5
postnum 12 11 0 10 9 7 8
vizitat 1 1 0 1 1 1 1
Mai ramane nevizitat un singur nod, 3, drept pentru care vom mai avea un apel
DFSNum(3, 7, V ecin) din procedura principala SortTop2:
1 2 3 4 5 6 7
prenum 1 2 13 3 4 6 5
postnum 12 11 14 10 9 7 8
vizitat 1 1 1 1 1 1 1
Ordonarea descrescatoare a nodurilor mult imii V dupa valorile vectorului postnum con-
duce la urmatoarea asezare:
142
postnum 14 12 11 10 9 8 7
3 1 2 4 5 7 6
Astfel sortarea topologica a nodurilor grafului obt inuta n urma aplicarii algoritmului 53
este: 3, 1, 2, 4, 5, 7, 6.
Observat ia 7.16 O optimizare a algoritmului 53 se refera la adaugarea nodului v ntr-o
stiva atunci cand se termina vizitarea acestui nod v si se calculeaza postnum
v
. Aceasta stiva
la sfarsit va cont ine nodurile grafului n ordinea descrescatoare a valorilor postnum
v
.
Prin urmare nu mai este nevoie sa ordonam descrescator valorile vectorului postnum
pentru a obt ine o sortare topologica a nodurilor grafului G, iar complexitatea algoritmului 53
devine O(|V | +|E|).
7.4 Componente tare conexe
Fig. 7.6: Graf orientat. Componente tare conexe.
Fie G = (V, E) un graf orientat unde V = {1, 2, ..., n} este mult imea nodurilor si E este
mult imea arcelor (E V V ).
Denit ia 7.14 O component a tare conex a a unui graf orientat G este o mult ime maxi-
mala de varfuri U V , astfel ncat, pentru ecare pereche de varfuri {u, v} (u, v U) exista
atat un drum de la u la v cat si un drum de la v la u. Prin urmare se spune ca varfurile u
si v sunt accesibile unul din celalalt.
Un graf orientat ce are o singura componenta tare conexa astfel ncat U = V este un graf
tare conex.

In cazul n care un graf orientat nu este tare conex atunci el se poate descompune
n mai multe componente tare conexe. O astfel de componenta este determinata de un subgraf
al grafului init ial.
Denit ia 7.15 Graful orientat G se numeste tare conex daca pentru orice pereche de
varfuri u = v, exista un drum de la nodul u la nodul v si un drum de la nodul v la nodul u.
Se poate arata ca relat ia de tare conexitate este o relat ie de echivalent a. O relat ie (notata
cu ) este o relat ie de echivalent a daca prezinta proprietat ile de reexivitate, simetrie si
tranzitivitate:
143
reexivitate: a a;
simetrie: a b b a;
tranzitivitate: a b, b c a c.
O clasa de echivalent a este mult imea tuturor elementelor care se aa n relat ia ([x]

=
{y|x y}). Relat ia de echivalent a determina o partit ie n clase de echivalent a a mult imii
peste care a fost denita. Prin urmare relat ia de tare conexitate determina o partit ie a
mult imii V . Clasele de echivalent a determinate de relat ia de tare conexitate sunt componen-
tele tare conexe.
Pentru determinarea componentelor tare conexe exista mai mult i algoritmi, dintre care
amintim algoritmul lui Tarjan, algoritmul lui Kosaraju si algoritmul lui Gabow.
7.4.1 Algoritmul lui Kosaraju
Algoritmul lui KosarajuSharir a fost prezentat de Aho, Hopcroft si Ullmann lucrarea lor [2],
ind preluat dintrun manuscris al lui S. Rao Kosaraju (M. Sharir la prezentat n lucrarea
[110]).
Algoritmul foloseste graful transpus G
T
asociat grafului init ial G ([11], [23], [30]), ind
compus din urmatorii pasi:
Pas 1. Se realizeaza parcugerea grafului cu algoritmul de vizitare n adancime, pornind de la
un nod arbitrar.

In timpul vizitarii se realizeaza numerotarea n postordine a nodurilor
n cadrul vectorului postnum.
Pas 2. Se obt ine un nou graf G
T
= (V, E
T
) prin inversarea sensului arcelor grafului G (E
T
=
{(u, v)|(v, u) E, u, v V }).
Pas 3. Se cauta nodul nevizitat din graful G
T
ce are cel mai mare numar atribuit n urma
parcurgerii de la Pasul 1. Din acest nod se init iaza parcugerea grafului cu algoritmul
de vizitare n adancime.
Pas 4. Daca mai raman noduri nevizitate atunci se reia Pasul 3, altfel algoritmul se termina.
Fiecare arbore rezultat n urma parcurgerii de la Pasul 3 constituie o componenta tare conexa
a grafului G.
Prezentam implementarea n limbajul C a algoritmului anterior:
#include <stdio.h>
#include <mem.h>
#define MAX 100
#define TRUE 1
#define FALSE 0
/**
* Matricea de adiacenta
*/
char vecin[MAX][MAX];
/**
* Vector ce pastreaza starea unui nod: vizitat sau nevizitat.
*/
144
char vizitat[MAX];
/**
* Numarul de varfuri din graf
*/
int n;
int nump;
/**
* Numarul asociat fiecarui varf la vizitarea in postordine.
*/
int postnum[MAX];
void dfs(int k) {
int i;
vizitat[k] = TRUE;
for (i = 0; i < n; i++)
if ((vizitat[i] == FALSE) && (vecin[k][i] > 0))
dfs(i);
nump++;
postnum[k] = nump;
}
void dfs1(int k) {
int i;
vizitat[k] = TRUE;
for (i = 0; i < n; i++)
if ((vizitat[i] == FALSE) && (vecin[k][i] > 0))
dfs1(i);
printf("%d ", k);
}
void readInput(void) {
int i, j;
printf("n = "); scanf("%d", &n);
do{
printf("nod1 nod2 : "); scanf("%d %d", &i, &j);
if (i >= 0)
vecin[i][j] = 1;
} while (i >= 0);
}
void main(void) {
int i, j, k, tmp;
int maxim;
int nod;
readInput();
// prima etapa
memset(vizitat, 0, sizeof(vizitat));
145
nump = 0;
for (i = 0; i < n; i++)
if (vizitat[i] == FALSE)
dfs(i);
// etapa a doua
memset(vizitat, 0, sizeof(vizitat));
for (i = 0; i < n; i++)
for (j = i; j < n; j++) {
tmp = vecin[i][j];
vecin[i][j] = vecin[j][i];
vecin[j][i] = tmp;
}
k = 0;
while (TRUE) {
maxim = 0;
for (i = 0; i < n; i++)
if ((vizitat[i] == FALSE) && (maxim < postnum[i])) {
maxim = postnum[i];
nod = i;
}
if (maxim == 0)
break;
k++;
printf("Componenta %d : ", k);
dfs1(nod);
printf("\n");
}
}
Exemplul 7.17 Dupa parcurgerea n adancime a grafului 7.6, valorile vectorilor vizitat si
postnum sunt urmatoarele:
1 2 3 4 5 6 7 8
postnum 8 7 5 6 1 2 3 4
vizitat 1 1 1 1 1 1 1 1
Fig. 7.7: Graful transpus G
T
corespunzator grafului din gura 7.6
Se construieste graful transpus, G
T
(vezi gura 7.7). Se cauta primul nod u nca neviz-
itat (vizitat
u
= 0), caruia i corespunde cea mai mare valoare postnum
u
.

In acest mod se
146
identica componenta tare conexa compusa numai din nodul 1: {1}.
Urmatorul nod, ca valoarea a vectorului postnum ordonat descrescator, este 2. Din nodul
2 se parcurg nodurile 3 si 4, rezultand o alta componenta tare conexa: {2, 3, 4}.
Urmatorul nod nevizitat u ce are valoarea prenum
u
maxima este nodul 8. Se identica
mai ntai componenta tare conexa {7, 8} si apoi {5, 6}.
Analiza algoritmului
Algoritmul lui Kosaraju realizeaza doua parcurgeri ale tuturor elementelor grafului G: prima
data parcurge graful G si a doua oara parcurge graful G
T
. Prin urmare complexitatea timp a
algoritmului este (|V | +|E|) n cazul n care graful este reprezentat prin liste de adiacent a si
este patratican |V |
2
(O(|V |
2
)) atunci cand graful este reprezentat prin matricea de adiacent a.
7.4.2 Algoritmul lui Tarjan
Algoritmul lui Tarjan [117] este considerat drept o mbun atat ire a algoritmului lui Kosaraju
prin aceea ca nu mai este nevoie de parcurgerea grafului G de doua ori.
Algoritmul init iaza o parcurgere n adancime a nodurilor grafului G pornind de la un nod
oarecare. O componenta tare conexa a grafului G, daca exista, constituie un subarbore al
arborelui de acoperire n adancime, iar radacina acestui subarbore este reprezentantul clasei
de echivalent a.
Prin urmare componentele tare conexe se obt in prin descompunerea arborelui/arborilor
de acoperire n adancime daca eliminam anumite arce ale acestora. Un nod este capul unei
componente tare conexe (sau radacina), daca acesta constituie radacina subarborelui core-
spunzator componentei. Arcul ce are nodulcap drept extremitate nala este cel ce trebuie
eliminat. Dupa ce determinam toate nodurilecap, subarborii arborelui/arborilor de acoperire
n adancime ce i au drept radacini sunt componentele tare conexe.
Algoritmul lui Tarjan are drept scop determinarea nodurilorcap. Pentru a pastra o ordine
a vizitarii acestora pe parcursul algoritmului, nodurile vor adaugate pe o stiva. Ele vor
extrase din stivan momentul n care procedura de vizitare DFS a unui nod estencheiata: se
determina daca nodul curent este radacina unei componente tare conexe, si, n caz armativ,
toate nodurile care au fost vizitate din nodul curent n cadrul parcurgerii n adancime sunt
marcate ca ind elemente ale componentei tare conexe.
Vom numerota toate nodurile grafului n preordine (altfel spus acest numar indica pen-
tru nodul curent numarul de noduri vizitate naintea sa), valorile ind pastrate n vectorul
prenum (cititorul este invitat sa revada si sect iunea despre Muchie critica, cea de-a doua
solut ie). Pentru un nod u G denim low
u
astfel:
low
u
= min
_

_
prenum
u
prenum
x
, daca [u, x] este arc de ntoarcere sau de traversare si x S
low
y
, y descendent direct al lui u
Daca dintrun varf u G exista un arc de ntoarcere sau de traversare catre un nod v G
n afara subarborelui de vizitare n adancime determinat de u, atunci acest nod v trebuie sa
fost vizitat naintea lui u (prenum
u
> prenum
v
). Daca un astfel de nod nu exista atunci
low
u
= prenum
u
. Stiva S pastreaza nodurile grafului, pe masura ce sunt vizitate ele ind
adaugate la S. Daca u este un nodcap (low
u
= prenum
u
) se extrag din stiva toate nodurile
dintre varful stivei si u inclusiv: acestea formeaza o componenta tare conexa.
Se observa ca algoritmul lui Tarjan (algoritmul 54) seam ana foarte mult cu algoritmul 26
de determinare a muchiei critice (varianta a II-a).
147
Algoritm 54 Algoritmul lui Tarjan pentru determinarea componentelor tare conexe
1: procedure Tarjan(n, V ecin)
Input:
_
n - numarul de noduri din graf
V ecin - matricea de adiacent a
2: for i 1, n do
3: vizitat
i
0
4: end for
5: counter 0
6: S
7: for i 1, n do
8: if (vizitat
i
= 0) then
9: call DFSTarjan(i, n, V ecin) vizitarea n adancime a grafului
10: end if
11: end for
12: end procedure
13: procedure DFSTarjan(k, n, V ecin)
14: S k
15: vizitat
k
1
16: counter counter + 1
17: prenum
k
counter, low
k
counter
18: for i 1, n do
19: if (vecin
k,i
= 1) then
20: if (vizitat
i
= 0) then
21: call DFSTarjan(i, n, V ecin)
22: low
k
Min(low
k
, low
i
)
23: else
24: if (i S) then
25: low
k
Min(low
k
, prenum
i
)
26: end if
27: end if
28: end if
29: end for
30: if (low
k
= prenum
k
) then
31: repeat
32: S u
33: Output u
34: until (u = k)
35: end if
36: end procedure
Exemplul 7.18 La nceput valorile vectorilor vizitat si prenum sunt urmatoarele:
1 2 3 4 5 6 7 8
prenum 0 0 0 0 0 0 0 0
vizitat 0 0 0 0 0 0 0 0
Primul element nevizitat este nodul 1 (linia 9), prin urmare se apeleaza DFSTarjan(1, 8, V ecin).
Rezulta o secvent a de apeluri recursive:
DFSNum(1, 8, V ecin) DFSNum(2, 8, V ecin) DFSNum(3, 8, V ecin)
DFSNum(6, 8, V ecin) DFSNum(5, 8, V ecin).
148
1 2 3 4 5 6 7 8
prenum 1 2 3 0 5 4 0 0
vizitat 1 1 1 0 1 1 0 0
low 1 2 0 0 4 4 0 0
Stiva cont ine urmatoarele elemente (varful stivei ind n dreapta): {1, 2, 3, 6, 5}.
low
5
= min{prenum
6
, low
5
} = min{4, 5} = 4 (deoarece desi vizitat
6
= 1, avem 6 S,
adica nodul 6 se aa pe stiva). Astfel n momentul terminarii apelului DFSTarjan(5, 8, V ecin),
low
5
= 4.
Acum la nivelul lui DFSTarjan(6, 8, V ecin), n urma revenirii din DFSTarjan(5, 8, V ecin),
se calculeaza low
6
= min{low
6
, low
5
} = min{4, 4} = 4 (linia 22).
Nodul 6 este un nodcap (low
6
= prenum
6
) (vezi linia 30), si prin urmare se extrag de pe
stiva toate elementele dintre varful stivei si elementul 6 inclusiv, rezultand prima componenta
tare conexa: {5, 6}. Stiva ramane cu elementele (varful stivei ind n dreapta) {1, 2, 3}.
Din nodul 3 se continua cu vizitarea nodului 8, nca nevizitat:
DFSNum(3, 8, V ecin) DFSNum(8, 8, V ecin) DFSNum(7, 8, V ecin).
Cont inutul stivei este {1, 2, 3, 8, 7}.
La nivelul apelului DFSNum(7, 8, V ecin) nu se ia n considerare la calculului valorii lui
low
7
nodul 6: desi exista arcul (7, 6), nodul 6 a fost vizitat (vizitat
i
= 0) si nu se mai aa
pe stiva (i / S). Astfel low
7
= min{low
7
, prenum
8
} = min{7, 6} = 6.
La nivelul lui DFSNum(8, 8, V ecin), low
8
= min{low
8
, low
7
} = min{6, 6} = 6 (linia 22).
Avem ca (low
8
= prenum
8
) (linia 30) si prin urmare 8 este un nodcap. Se extrag de pe stiva
toate elementele dintre varful stivei si elementul 8 inclusiv, rezultand a doua componenta tare
conexa: {7, 8}.
Stiva ramane cu elementele (varful stivei ind n dreapta) {1, 2, 3}.
1 2 3 4 5 6 7 8
prenum 1 2 3 0 5 4 7 6
vizitat 1 1 1 0 1 1 1 1
low 1 2 0 0 4 4 6 6

In momentul terminarii apelului DFSTarjan(3, 8, V ecin), low


3
= 2.
Revenind la nivelul apelului DFSTarjan(2, 8, V ecin), se calculeaza low
2
= min{low
2
, low
3
} =
min{2, 2} = 2, si se continua cu urmatorul nod nca nevizitat, 4: DFSNum(2, 8, V ecin)
DFSNum(4, 8, V ecin).
Se adauga nodul 4 pe stiva (stiva devine {1, 2, 3, 4}), low
4
= prenum
4
= 8.
low
4
se calculeaza din low
4
= min{low
4
, prenum
3
} = min{8, 3} = 3 (exista arcul (4, 3),
nodul 3 a fost vizitat - vizitat
3
= 1 si 3 S - nodul 3 se aa pe stiva).
1 2 3 4 5 6 7 8
prenum 1 2 3 8 5 4 7 6
vizitat 1 1 1 1 1 1 1 1
low 1 2 2 3 4 4 6 6
Ne ntoarcem la nivelul apelului DFSTarjan(2, 8, V ecin), low
2
= min{low
2
, low
4
} =
min{2, 3} = 2. Arcul (2, 5) nu este luat n considerare la calculul lui low
2
deoarece nodul 5 a
fost vizitat (vizitat
5
= 1) si 5 nu se regaseste pe stiva. Astfel low
2
ramane cu valoarea 2.
Deoarece low
2
= prenum
2
, extragem de pe stiva elementele ce determina cea de-a treia
componenta tare conexa: {4, 3, 2}. Pe stiva mai ramane un singur element, {1}, ce va
determina ultima componenta tare conexa.
149

In nal, valorile low si prenum sunt urmatoarele:


1 2 3 4 5 6 7 8
prenum 1 2 3 8 5 4 7 6
vizitat 1 1 1 1 1 1 1 1
low 1 2 2 3 4 4 6 6
7.4.3 Algoritmul lui Gabow
Algoritmul a fost introdus de catre Joseph Cheriyan and Kurt Mehlhorn n 1996 [28] si apoi
independent de catre Harold Gabow n 1999 [56].
Algoritmul construieste un graf H [56] ce reprezinta o contract ie a grafului original G: unul
sau mai multe noduri din G pot sa corespunda unui nod din H. La nceput se init ializeaza
H = G. Se ncepe construirea unui drum P aleganduse un nod oarecare v H.
Fig. 7.8: Drumul P n algoritmul lui Gabow pentru graful din gura 7.6
La ecare pas al algoritmului se ncearca sa se augmenteze drumul P = P {w} =
[v
1
, . . . , v
k
, w] prin parcurgerea tuturor arcelor (v
k
, w):
- daca w / P, atunci se adauga nodul w la drumul P (P = [v
1
, . . . , v
k
, w]);
- daca w P, e w = v
j
. Contractam circuitul {v
j
, v
j+1
, . . . , v
k
, w} n graful H: n
locul mult imii de varfuri {v
j
, v
j+1
, . . . , v
k
} va ramane doar reprezentantul acesteia, e.g.
nodul ce are valoarea minima n urma numerotarii n preordine;
- daca nu avem nici un arc nevericat care sa aiba nodul v
k
ca extremitate init iala, se
marcheaza nodul v
k
ca apart inand unei componente conexe. Se sterge nodul v
k
din
graful H si din drumul P, mpreuna cu toate arcele ce l au ca extremitate. Daca
P = atunci se continua algoritmul ncercanduse augmentarea drumului P.

In caz
contrar se ncearca init ializarea unui drum nou P n H.
Si acest algoritm are la baza metoda de parcurgere n adancime a unui graf (DFS).

In
timpul vizitarii, algoritmul utilizeaza doua stive S si P: S cont ine toate nodurile ce nu au
fost atribuite nca unei componente tare conexe, n ordinea n care au fost ntalnite, iar P
cont ine toate nodurile despre care nca nu se poate spune nimic cu privire la apartenent a lor
la componente conexe diferite (cont ine nodurile drumului P din graful H). Altfel spus, se
150
observa faptul ca stiva P pastreaza nodurile radacina ce formeaza o subsecvent a a secvent ei
nodurilor ce se aa la un moment dat n cealalta stiva S.

In cadrul secvent ei urmatoare, pentru un nod i adiacent cu nodul curent k, se verica


daca nu a mai fost vizitat. Daca vizitat
i
= 0 atunci se continua vizitarea n adancime (call
DFSGabow(i, n, V ecin)). Altfel, se verica daca nodul i nu a fost deja asignat unei compo-
nente tare conexe, n caz armativ eliminanduse din drumul P circuitul {v
i
, . . . , v
k
, v
i
}:
1: if (vizitat
i
= 0) then
2: call DFSGabow(i, n, V ecin)
3: else
4: if (i S) then i
5: while (prenum
i
< prenum
peek(P)
) do
6: P u
7: end while
8: end if
9: end if
La nalul procedurii DFSGabow, se verica daca nodul curent este identic cu cel aat
n varful stivei P.

In caz armativ se extrag de pe stiva toate nodurile dintre varful curent
al stivei S si nodul k, si se marcheaza ca ind elemente ale componentei tare conexe a carei
radacina este nodul k:
if (k = peek(P)) then
P u
repeat
S u
Output u
until (u = k)
end if
7.5 Exercit ii
1. (Compilator)

In trecut compilatoarele erau foarte simple.

In acele vremuri oamenii
preferau sa includa tot programul ntr-un singur sier. Daca cineva facea o modicaren
program, trebuia recompilat tot codul sursa. Cresterea lungimii programelor conducea
la timpi de compilare tot mai mari, ceea ce constituia o piedica n ceea ce priveste
cresterea complexitat ii algoritmilor implementat i.
De aceea programatorii au dezvoltat o tehnica pentru eliminarea compilarilor redun-
dante. Ei au nceput prin a sparge programele n mai multe module mici pe care le
compilau separat. Astfel, pentru orice modicare care se opera ntr-un anumit modul,
se compila numai acesta, si nuntreaga aplicat ie. Fiecare modul cont ine la nceput lista
celorlaltor module pe care le foloseste.
Modulul A trebuie recompilat numai daca a fost modicat sau are n lista sa un modul
B care a fost recompilat la randul sau.

In celelalte cazuri nu este necesara recompilarea
modulului A.
Problema cere sa se realizeze un algoritm si pe baza acestuia un program, care sa decida
ce module trebuie recompilate si care nu. Pentru a avea un timp de recompilare minim,
va trebui sa cautam compilarea unui numar cat mai mic de linii.
Prima linie a datelor de intrare cont ine numarul de module N (1 N 100). Urmeaza
descrierea modulelor. Prima linie a descrierii cont ine numele modulului. A doua linie
151
Algoritm 55 Algoritmul lui Gabow pentru determinarea componentelor tare conexe
1: procedure Gabow(n, V ecin)
2: for i 1, n do
3: vizitat
i
0
4: end for
5: counter 0
6: S , P
7: for i 1, n do
8: if (vizitat
i
= 0) then
9: call DFSGabow(i, n, V ecin)
10: end if
11: end for
12: end procedure
13: procedure DFSGabow(k, n, V ecin)
14: vizitat
k
1
15: S k, P k
16: counter counter + 1
17: prenum
k
counter
18: for i 1, n do
19: if (vecin
k,i
= 1) then
20: if (vizitat
i
= 0) then
21: call DFSGabow(i, n, V ecin)
22: else
23: if (i S) then i nu a fost asignat nca unei componente tare conexe
24: while (prenum
i
< prenum
peek(P)
) do
25: P u
26: end while
27: end if
28: end if
29: end if
30: end for
31: if (k = peek(P)) then
32: P u
33: repeat
34: S u
35: Output u
36: until (u = k)
37: end if
38: end procedure
cont ine numarul liniilor din codul sursa. A treia linie cont ine numarul M (0 M < N)
de module de care depinde modulul actual. Linia urmatoare cont ine numele acestor
module, separate printrun spat iu. Numele unui modul nu depaseste 20 de caractere.
Descrierea modulelor este urmata de mai multe blocuri, cate unul pentru ecare versiune
a programului. Prima linie a ecarui bloc cont ine numarul k (1 k N) de module
ce au suferit modicari de la recompilarea versiunii precedente.
Linia urmatoare cont ine numele modulelor, separate prin spat iu, n care au survenit
modicari. Dupa ultimul bloc exista o singura linie ce cont ine doar numarul 0.
Pentru ecare versiune a programului se scrie o linie ce cont ine numarul liniilor codului
152
sursa care au trebuit sa e recompilate.
Intrare Iesire
3 127
MATH
20
0
MAIN
100
2
MATH IO
IO
7
0
3
MATH IO MAIN
0
(Propusa la CEOI 1997)
2. Se da un numar de k (k < 1000) reguli, numerotate de la 1 la k. O regula are forma
x y unde x si y sunt propozit ii cu urmatoarea semnicat ie: daca propozit ia x este
adevarata, atunci proprozit ia y este adevarata.
Sa consideram pentru k = 5 urmatoarele reguli:
(1) 1 2 (2) 1 3 (3) 3 4 (4) 4 5 (5) 1 5
Profesorul cere sa se demonstreze regula 1 5. Demonstrat ia optima consta n apli-
carea directa a regulii (5).
Un elev demonstreaza regula (5) astfel: 2 1 3 4 (1
(2)
3, 1
(1)
2, 3
(3)
4, 4
(4)
5). Aceasta
este o demonstrat ie corecta, ce cont ine n plus regula 1
(1)
2. Profesorul ar fost
mult umit cu demonstrat ia 2 3 4 (1
(2)
3, 3
(3)
4, 4
(4)
5).
Sa se realizeze un algoritm ce utilizeaza drept date de intrare k, x (propozit ia care se
considera adevarata), y (propozit ia ce trebuie demonstrata), sirul celor k reguli cat si
sirul numerelor de ordine ale regulilor ce constituie demonstrat ia elevului.
Algoritmul verica daca sirul numerelor de ordine ale regulilor constituie o demonstrat ie.

In caz negativ va asa



NU

, iar n caz armativ va asa



DA

, urmat pe linia urmatoare


de demonstrat ia elevului din care au fost eliminate armat iile inutile. Se considera ca
un sir de reguli fara reguli n plus constituie o demonstrat ie corecta a propozit iei y
pornind de la propozitia x, daca renunt area la orice regula ar conduce la o secvent a
prin care y nu se mai poate deduce din x.
(Marele premiu PACO, 1997)
3. Dupa cum se poate observa prin reclamele de la televizor, multe companii cheltuiesc
foarte mult i bani pentru a convinge oamenii ca ofera cele mai bune servicii la cel mai
scazut pret . O companie de telefoane ofera cercuri de apel (calling circles).
Un abonat poate sa faca o lista cu persoanele pe care le suna cel mai frecvent (si care
constituie cercul sau de prieteni). Daca acesta suna pe cineva inclus n aceasta lista,
si persoana respectiva este, de asemenea, abonata la aceeasi companie, va benecia de
un discount mai mare decat pentru o convorbire telefonica cu cineva din afara listei.
O alta companie a aat de aceasta init iativa si se ofer a sa determine ea lista de
cunostint e cu care un abonat vorbeste cel mai frecvent la telefon.
153
LibertyBellPhone este o companie noua de telefoane ce se g andeste sa ofere un plan
de apeluri mult mai avantajos decat alte companii. Ea ofer a nu numai reduceri pentru
cercul de apel, cat si determina pentru un abonat acest cerc. Iata cum procedeaza:
compania pastreaza numerele tuturor persoanelor participante la ecare apel telefonic.

In afara unui abonat, cercul sau de apel consta din toate persoanele pe care le suna si
care l suna, direct sau indirect.
De exemplu, daca Ben l suna pe Alexander, Alexander o suna pe Dolly si Dolly l
suna pe Ben, atunci ei tot i fac parte din acelasi cerc. Dac a Dolly l mai suna si pe
Benedict iar Benedict o suna pe Dolly, atunci Benedict este n acelasi cerc cu Dolly,
Ben si Alexander.

In ne, daca Alexander l suna pe Aron dar Aaron nu l sun a pe
Alexander, Ben, Dolly sau Benedict, atunci Aaron nu este n cerc.
Sa se realizeze un algoritm ce determina cercurile de apel, cunoscanduse lista apelurilor
telefonice dintre abonat i.
(Finala ACM 1995, Calling Circles)
4. La facultatea X exista doua alternative pentru ca student ii sa aiba timp sa asimileze
cunostint ele:
(a) Marirea zilei la 30 de ore, si
(b) Reducerea programei scolare.
Optand pentru a doua varianta, Liga Student ilor introduce o platforma program care:
(a) Stabileste care sunt materiile necesare pentru a putea studia o noua materie.
De exemplu, pentru a studia cursul Management este nevoie de cursul Teorie
Economica si de cursul Marketing.
(b) Stabileste care sunt materiile cu adevarat utile dintre toate cele studiate n fac-
ultate. De exemplu, cursul de Masurari electrice nu este util la absolut nimic.
(c) Cere sa se elimine din programa materiile care nu sunt nici folositoare, nici nu
servesc (direct sau indirect) la nvat area unor materii folositoare.
(d) Cere sa se indice care dintre materii nu pot predate n nici o ordine. De ex-
emplu, cursul Mecanica se bazeaza pe cursul Ecuat ii Diferent iale, dar cursul
de Ecuat ii Diferent iale si preia exemplele din Mecanica. Prin urmare nu ex-
ista nici o ordine n care aceste materii sa e predate fara a introduce cunostint e
nedemonstrate.
5. Distribuirea cart ilor cerute de catre cititorii de la sala de lectura a unei biblioteci este
facuta de catre un robot ce are posibilitatea sa ajunga la orice carte ce poate solicitata.
Din pacate, rafturile unde sunt depozitate cart ile sunt dispuse astfel ncat robotul nu
poate lua cart ile ntrun singur drum. Dupa recept ionarea comenzilor de la mai mult i
cititori, robotul cunoaste pozit ia cart ilor n rafturi si drumurile catre acestea. Din
pacate, de la pozit ia unei cart i, robotul nu se poate deplasa decat spre anumite cart i.
Acesta porneste si culege cart ile ce sunt accesibile ntrun drum, apoi porneste de la
o alta pozitie de carte si culege acele cart i ce sunt accesibile din acel punct si asa mai
departe.
154
Datele de intrare constau din numarul de cart i n precum si numarul m de legaturi
dintre pozit iile acestora (1 n 100, 11 m 10000), urmate de m perechi de
numere naturale, ce semnica legaturile directe ntre pozit iile cart ilor.
Datele de iesire constau din drumurile pe care le face robotul pentru a culege cart ile
cerute.
Fig. 7.9: Pozit iile cart ilor ntro biblioteca precum si posibilitat ile de deplasare ale robotului
6. Se considera o mult ime de n elevi dintro clasa. Fiecare elev are cunostint e mai avansate
ntrun anumit domeniu. Pentru ridicarea nivelului clasei, dirigintele vrea sai aranjeze
n grupuri astfel ncat tot i elevii dintrun grup sa ajunga sa cunoasca, ntro anumita
perioada de timp, toate cunostint ele tuturor celorlalt i colegi din acelasi grup.
Grupurile de elevi nu si vor schimba cunostint ele ntre ele. Se stie ca un elev nu se
poate face nt eles de catre oricine. El are o lista de preferint e fat a de care el le va
mpartasi cunostintele sale. Relat ia de preferint a nu este simetrica.
Sa se determine numarul minim de grupuri n care va mp art ita clasa precum si
component a acestora.
155
Capitolul 8
Distant e n grafuri
Ret eaua de drumuri europene, nat ionale si judet ene dintro t ara, ret eaua feroviara reprezentand
infrastructura cailor ferate absolut necesara pentru realizarea transportului de marfuri si
calatori cu trenul, ret eaua de bra optica folosita pentru tracul de date n Internet, ret eaua
de transport a energiei electrice folosita pentru alimentarea cu energie electrica a consumato-
rilor casnici si a celor industriali, ret eaua de canalizare dintrun oras folosita pentru evacuarea
deseurilor, ret eaua CATV a unui operator de televiziune prin cablu, ret eaua de linii de auto-
buz ce face parte din sistemul public de transport al unui oras sunt exemple tipice de grafuri
cu care interact ionam n viat a de zi cu zi.
Putem spune ca ret elele de transport si cele de comunicat ii de date ne inuent eaza n
mod direct modul de viat a, devenind elemente indispensabile ale omului modern, si astfel,
problemele referitoare la studiul cailor de comunicat ie, drumurilor, conexiunilor, capata un
interes special.
De obicei suntem interesat i de aspecte precum drumul cel mai scurt sau cel mai lung,
drumul cel mai ieftin sau drumul care se poate parcurge cel mai repede, drumul cel mai
sigur. Teoria grafurilor ne pune la dispozit ie mijloacele pentru aarea raspunsului la multe
astfel de ntrebari.
Denit iile pentru drum, lant , ciclu, circuit au fost prezentate n capitolele anterioare,
mpreuna cu multe alte concepte teoretice. Lungimea unui lant este determinata de numarul
muchiilor sale.

In mod analog, lungimea unui drum este egala cu numarul arcelor sale.

Intrun graf G se introduce o funct ie de cost ce asocieaza o valoare real a ecarei muchii
sau arc, dupa caz:
c : E R sau c : V V R
Notam costul unui drum ca ind suma costurilor arcelor componente. Astfel pentru un
drum D = [v
0
, v
1
, . . . , v
m
] de lungime m, costul acestuia va dat de urmatoarea formula:
c(D) =
m1

i=0
c((v
i
, v
i+1
))
Notam cu M
s,t
mult imea drumurilor dintre nodul x
s
si nodul x
t
, x
s
, x
t
V . Pentru doua
noduri oarecare x
s
si x
t
, se doreste sa se determine un drum
s,t
de la x
s
la x
t
a carui valoare
sa e optima (minima sau maxima):
c(
opt
s,t
) = min
s,tMs,t
c(
s,t
)
156
8.1 Drumul minim de la un varf la celelalte varfuri
8.1.1 Algoritmul lui Moore
Fie G = (V, E) un graf orientat unde V = {x
1
, x
2
, . . . , x
n
} este mult imea nodurilor si E este
mult imea arcelor (E V V ). Pentru reprezentarea grafului vom utiliza listele de adiacent a
(listele cu vecini).
Fie u un varf al grafului numit sursa. Dorim sa determinam pentru ecare varf w
V, w = u, daca exista, un drum de lungime minima de la u la w. Lungimea unui drum se
deneste ca ind numarul arcelor ce l compun.
Algoritmul lui Moore (algoritmul 56) se bazeaza pe structura algoritmului de parcurgere
n lat ime al unui graf (breadth rst search vezi algoritmul 20).

In lucrarea [98], Moore si
prezinta algoritmul astfel:
Write 0 on the source. Then look at all the neighbors of the source and write
1 on them. Then look at all the neighbors of nodes with 1 on them and write 2
on them. And so on.
Vom nota cu d
k
costul drumului minim de la varful u la varful x
k
, iar tata
k
varful anterior
lui x
k
, pe drumul de cost minim de la u la x
k
.
Algoritm 56 Algoritmul lui Moore
1: procedure Moore1(k, n, V ecin; d, tata)
Input:
_

_
k - nodul sursa
n - numarul de noduri din graf
V ecin - vector ce cont ine capetele listelor de vecini
Output:
_

_
d - vectorul distant elor de la nodul sursa la celelalte noduri
tata - vector ce cont ine pentru ecare nod k, predecesorul acestuia pe drumul
de cost minim de la nodul sursa la nodul k
2: for i 1, n do
3: d
i
+
4: end for
5: d
k
0 distant a de la un nod la el nsusi este 0
6: Q k inserarea nodului curent k n coada
7: while (Q = ) do cat timp coada nu este vida
8: Q k extrage nodul curent din coada
9: v vecin
k
se pleaca cu primul vecin din lista de vecini
10: while (v = NULL) do
11: if (d
v.nodeIndex
= +) then v.nodeIndex este indicele nodului vecin
12: d
v.nodeIndex
d
k
+ 1, tata
v.nodeIndex
k
13: Q v.nodeIndex inserarea nodului v.nodeIndex n coada
14: end if
15: v v.next se trece la urmatorul vecin
16: end while
17: end while
18: end procedure
Exemplul 8.1 Fie un graf orientat denit de catre urmatoarele liste de vecini:
157
1: (2, 4) 7: (8)
2: (3, 6) 8: (6, 7)
3: (2) 9: ()
4: (1, 5) 10: (11)
5: (4, 6, 9) 11: (10)
6: (7, 8)

In urma aplicarii algoritmului lui Moore pentru acest graf si avand nodul 1 drept sursa,
se obt in urmatoarele valori pentru vectorii d si tata:
1 2 3 4 5 6 7 8 9 10 11
d 0 1 2 1 2 2 3 3 3
tata 1 2 1 4 2 6 6 5
Urmarind valorile asate, putem spune ca drumul de lungime minima de la nodul 1 la
nodul 9 are costul 3 si este compus din nodurile [1, 4, 5, 9].
Algoritmul 57 calculeaza lungimea drumurilor minime de la un nod sursa la toate nodurile
accesibile din acesta, n cazul n care lungimea unui drum se deneste ca ind suma costurilor
asociate arcelor ce-l compun.
Algoritm 57 Algoritm lui Moore (a doua varianta)
1: procedure Moore2(k, n, C; d, tata)
Input:
_

_
k - nodul sursa
n - numarul de noduri din graf
C - matricea costurilor
2: for i 1, n do
3: d
i
+
4: end for
5: d
k
0 distant a de la un nod la el nsusi este 0
6: Q k inserarea nodului curent k n coada
7: while (Q = ) do cat timp coada nu este vida
8: Q k extrage nodul curent din coada
9: for ecare vecin (v = x
i
) al lui x
k
do
10: if (d
k
+ c
k,i
< d
i
) then
11: d
i
d
k
+ c
k,i
, tata
i
k
12: Q i inserarea nodului i n coada
13: end if
14: end for
15: end while
16: end procedure
8.1.2 Algoritmul lui Dijkstra
Fie G = (V, E) un graf orientat unde V = {1, 2, . . . , n} este mult imea nodurilor si E este
mult imea arcelor (E V V ). Pentru reprezentarea grafului se utilizeaza matricea costurilor
C:
c
i,j
=
_

_
0 , daca i = j
, daca (i, j) / E, i = j
d > 0 , daca (i, j) E
158
Fie u un varf al grafului numit sursa. Dorim sa determinam pentru ecare varf j V, j =
u, daca exista, un drum de lungime minima de la u la j. Lungimea unui drum se deneste
ca ind suma costurilor asociate arcelor ce-l compun.
Algoritmul lui Dijkstra [38] utilizeaza metoda generala de elaborare a algoritmilor Greedy,
drumurile de lungime minima ind generate n ordinea crescatoare a lungimii lor. Vom nota
cu S mult imea nodurilor grafului G pentru care se cunoaste (s-a calculat) drumul de lungime
minima de la sursa. La nceput mult imea S este formata doar din nodul sursa. La ecare
pas, se adauga la mult imea S un nod k V \ S cu proprietatea ca drumul de la sursa la
acel nod este cel mai mic dintre toate drumurile posibile de la sursa la noduri din mult imea
V \ S, cu proprietatea ca un astfel de drum are drept noduri intermediare numai elemente
din mult imea S, cu except ia extremitat ii nale. Vom utiliza un tablou D ce va pastra pentru
ecare nod k, lungimea drumului cel mai scurt de la sursa ce trece numai prin noduri din
mult imea S (vezi algoritmul 58).
Dupa ce am identicat un astfel de nod k, mult imea S se modica astfel: S = S {k}.
Este posibil ca lungimea unui drum de la sursa la un nod j V \ S, ce are drept noduri
intermediare noduri din mult imea S, sa se modice datorita faptului ca, mai nainte, nodul k
nu fusese luat n considerare, deoarece nu apart inea mult imii S. Astfel, se poate ca un drum
de la sursa la nodul j, ce trece prin nodul k, sa e mai mic decat drumul anterior de la sursa
la nodul j: d
k
+c
k,j
< d
j
.
Algoritm 58 Algoritmul lui Dijkstra (schema generala)
1: procedure Dijkstra1(n, C, u)
2: S {u}
3: for i 1, n do
4: d
i
c
u,i
5: end for
6: for i 1, n 1 do
7: k min{d
k
|k V \ S}
8: S S {k}
9: for each j V \ S do
10: d
j
min(d
j
, d
k
+ c
k,j
)
11: end for
12: end for
13: end procedure
Vom utiliza trei vectori (vezi algoritmul 59):
vizitat - vector caracteristic
vizitat
k
=
_
1 , daca nodul k S
0 , daca nodul k V \ S
d - vectorul distant elor de la nodul u la celelalte noduri ale grafului.

In momentul
init ial d
j
= c
u,j
. Fie k nodul ales la un moment dat. Atunci d
j
se modica numai daca
d
k
+c
k,j
< d
j
, ind actualizat astfel: d
j
= d
k
+c
k,j
.
tata
k
- cont ine pentru ecare nod k nodul anterior j (j S) pe drumul de cost minim
de la u la k. La nceput,
tata
k
=
_
0 , daca nodul k = u sau c
u,k
=
u , n rest (k = u si c
u,k
= )
159
Un element al acestui vector se poate modica atunci cand se modica d
j
, caz n care
tata
j
= k.
Algoritm 59 Algoritmul lui Dijkstra
1: function DistantaMinima(n, vizitat, d)
2: min
3: for j 1, n do
4: if (vizitat
j
= 1) (d
j
< min) then
5: min d
j
6: j
0
j
7: end if
8: end for
9: if (min = ) then
10: return 1
11: else
12: return j
0
13: end if
14: end function
15: procedure Dijkstra2(n, C, u)
16: vizitat
u
1
17: d
u
0, tata
u
0
18: for i 1, n do
19: if (i = u) then
20: vizitat
i
0
21: d
i
c
u,i
, tata
i
u
22: end if
23: end for
24: while (true) do
25: k DistantaMinima(n, vizitat, d)
26: if (k < 0) then
27: break forteaza iesirea dintr-o instructiune de ciclare
28: else
29: vizitat
k
1
30: for i 1, n do
31: if (vizitat
i
= 1) (d
k
+ c
k,i
< d
i
) then
32: tata
i
k
33: d
i
d
k
+ c
k,i
34: end if
35: end for
36: end if
37: end while
38: end procedure
Observat ia 8.2 Algoritmul lui Dijkstra prezinta asemanari cu algoritmul de cautare n
lat ime, la nal, vectorul tata pastrand un arbore al drumurilor minime ce are drept rad acina
nodul sursa.
160
u
k
x
j
Fig. 8.1: O cale speciala mai scurta
Demonstrarea corectitudinii algoritmului

In momentul n care alegem nodul k V \S avand proprietatea ca drumul de la sursa la acel


nod este cel mai mic dintre toate drumurile posibile de la sursa la noduri din mult imea V \S,
ce trec numai prin noduri din mult imea S, cu except ia extremitat ii nale, acel drum este cel
mai mic drum de la sursa la k dintre toate drumurile posibile. Denumim drum special un
drum de la sursa la un nod k ce are drept noduri intermediare numai elemente din mult imea
S, cu except ia extremitat ii nale.
Sa presupunem prin reducere la absurd, ca exista un drum de lungime mai mica de la
nodul sursa la nodul k, ce nu are toate nodurile intermediare din mult imea S. Fie j V \ S,
primul nod pe drumul de la nodul sursa la nodul k, ce nu apart ine mult imii S. Atunci drumul
de la nodul sursa u la nodul k se compune dintr-un drum de la u la j, si un drum de la j la
k. Datorita modului de alegere al lui j, drumul de la u la j are drept noduri intermediare
numai elemente din mult imea S (j este primul nod pe drumul de la nodul sursa la nodul
k, care nu apart ine mult imii S), deci este un drum special si are o lungime mai mica decat
drumul special de la sursa la nodul k. Prin urmare am gasit un alt drum special de lungime
mai mica, ceea ce contrazice modul de alegere al nodului k.
Trebuie sa demonstram ca n orice moment, d
k
pastreaza lungimea celui mai scurt drum
special de la nodul sursa u la nodul k V \ S.

In momentul n care nodul k este adaugat
mult imii S, avem grija sa vericam daca nu exista un drum special de la nodul u la un nod
j V \ S care sa aiba o lungime mai mica. Sa presupunem ca pentru un nod j xat exista
un nod x S astfel ncat drumul special u k + k x + (x, j) sa aiba o lungime mai
mica (vezi gura 8.1). Deoarece nodul x a fost adaugat mult imii S naintea nodului k avem
d
x
d
k
. Prin urmare d
x
+ c
x,j
d
k
+ c
x,j
< d
k
+ cost
kj
+ c
x,j
, adica drumul special de la
sursa la nodul j ce trece prin nodul x are lungimea mai mica decat drumul special compus
din drumul de la nodul sursa la nodul k, drumul de la nodul k la nodul x si arcul (x, j).
Exemplul 8.3 Sa presupunem ca nodul sursa este nodul 1 pentru graful din gura 8.2. Dupa
etapa de init ializare vom avea urmatoarele valori:
1 2 3 4 5
d 1 21
tata 0 1 1 1 1
vizitat 1 0 0 0 0
161
Fig. 8.2: Un exemplu de graf orientat ponderat
Dupa prima iterat ie avem:
d
2
+c
2,3
< d
3
1 + 8 < +
d
2
+c
2,4
< d
4
1 + < 21
d
2
+c
2,5
< d
5
1 + 4 < +
1 2 3 4 5
d 1 9 21 5
tata 0 1 2 1 2
vizitat 1 1 0 0 0

In timpul celei de-a doua iterat ii se calculeaza:


d
5
+c
5,3
< d
3
5 + 3 < 9
d
5
+c
5,4
< d
4
5 + < 21
1 2 3 4 5
d 1 8 21 5
tata 0 1 5 1 2
vizitat 1 1 0 0 1
Dupa pasul al treilea avem:
d
3
+c
3,4
< d
4
8 + 12 < 21
1 2 3 4 5
d 1 8 20 5
tata 0 1 5 3 2
vizitat 1 1 1 0 1
La sfasitul ultimei iterat ii vom obt ine:
1 2 3 4 5
d 1 8 20 5
tata 0 1 5 3 2
vizitat 1 1 1 1 1
Implementarea n limbajul C a algoritmului 59 este urmatoarea:
162
#include <stdio.h>
#include <values.h>
#define MAX 100
#define TRUE 1
#define FALSE 0
/* numarul de noduri din graf */
int n;
/* matricea costurilor */
int c[MAX][MAX];
/* vector care pastreaza starea unui nod: vizitat sau nevizitat */
char vizitat[MAX];
/* nodul fata de care se calculeaza drumurile de lungime minima */
int u;
/* tata[i] parintele varfului i in arborele rezultat */
int tata[MAX];
/* distanta de la fiecare nod la u */
int d[MAX];
/**
* Citirea datelor de intrare - +infinit = -1
*/
void readInput(void) {
int i, j;
printf("n = "); scanf("%d", &n);
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
scanf("%d", &c[i][j]);
if (c[i][j] < 0)
c[i][j] = MAXINT;
}
printf("Nodul initial : "); scanf("%d", &u);
}
int minim(int* d) {
int j, j0;
int min;
min = MAXINT;
for (j = 0; j < n; j++)
if (!vizitat[j] && d[j] < min) {
min = d[j];
j0 = j;
}
if (min == MAXINT)
return -1;
else
return j0;
}
163
/**
* Functia verifica daca a>b+c; variabilele sunt de tip long
* pentru ca daca suma depaseste 32767 se face trunchiere.
*/
int mai_mare(long a, long b, long c) {
return (a > b+c) ? 1 : 0;
}
void dijkstra(int u) {
int i, k;
//initializari
vizitat[u] = TRUE;
tata[u] = -1;
for (i = 0; i < n; i++)
if (i != u) {
vizitat[i] = FALSE;
d[i] = c[u][i];
tata[i] = u;
}
//partea principala
while (TRUE) {
k = minim(d);
if (k < 0)
break;
vizitat[k] = TRUE;
//actualizare
for (i = 0; i < n; i++)
if (!vizitat[i] && mai_mare(d[i],d[k],c[k][i])) {
tata[i] = k;
d[i] = d[k] + c[k][i];
}
}
}
void printSolution(void) {
int i;
for (i = 0; i < n; i++)
if (i != i0)
if (d[i] == MAXINT)
printf("Nu exista drum de la varful %d la
varful %d. \n", i0, i);
else
printf("Distanta de la varful %d la varful %d
este %d. \n", i0, i, d[i]);
}
void main(void) {
readInput();
dijkstra(u);
printSolution();
164
}
Utilizarea structurii coada cu prioritate n algoritmul lui Dijkstra
Complexitateatimp al algoritmului lui Dijkstra poate mbunatat ita prin utilizarea struc-
turii de date de coada cu prioritate (vezi algoritmul 60).
Algoritm 60 Algoritmul lui Dijkstra (varianta ce foloseste o coada cu prioritate)
1: procedure Dijkstra3(n, C, u)
2: for i 1, n do
3: d
i

4: tata
i
NULL
5: call Insert(Q, i, d
i
) insereaza n coada elementul i cu prioritatea d
i
6: end for
7: d
u
0
8: call DecreaseKey(Q, u, d
u
) actualizeaza prioritatea varfului u la d
u
9: S
10: for i 1, n 1 do
11: k DeleteMin(Q) sterge elementul de prioritate minima din coada
12: S S {k}
13: for fiecare j V \ S, astfel ncat (k, j) E do
14: if (d
j
> d
k
+ c
k,j
) then
15: d
j
d
k
+ c
k,j
16: tata
j
k
17: call DecreaseKey(Q, j, d
j
) actualizeaza prioritatea varfului j la d
j
18: end if
19: end for
20: end for
21: end procedure
Analizand algoritmul 60 obt inem ca timpul de lucru al acestuia depinde de formula:
T(n, m) = O(n T
Insert
+n T
DeleteMin
+m T
DecreaseKey
) (8.1)
unde n = numarul de noduri ale grafului G iar m = numarul de muchii ale aceluiasi graf.
Cele trei operat ii ntalnite n cadrul algoritmlui sunt (vezi si capitolul ??):
1. DeleteMin(Q) - sterge nodul ce cont ine cheia de valoare minima si reorganizeaza struc-
tura prin refacerea proprietat ii de coada cu prioritate.
2. Insert(Q, p, x) - insereaza nodul p n coada cu prioritate Q.
3. DecreaseKey(Q, p, v) - modica valoarea prioritat ii nodului p din coada cu prioritate
Q, atribuindui valoarea v si reorganizeaza aceasta structura.
Astfel pentru diferite implementari ale cozii cu prioritate Q, complexitatea algoritmului
va [30]:
1. Lista liniara dublu nlant uita neordonata:
T(n, m) = O(n 1 +n n +m 1) = O(n
2
)
165
2. Arbore 2 3:
T(n, m) = O(n 1 +n n +m 1) = O(n
2
)
3. Heap-uri Fibonacci:
T(n, m) = O(n 1 +n n +m 1) = O(n
2
)
8.2 Drumuri minime ntre toate perechile de varfuri
Fie G = (V, E) un graf orientat unde V = {x
1
, x
2
, . . . , x
n
} reprezinta mult imea nodurilor
si E reprezinta mult imea arcelor (E V V ). Fiecarui arc din E i se asociaza o valoare
pozitiva c
i,j
(c
i,j
0) ce reprezinta lungimea arcului. Se doreste calcularea drumurilor de
lungime minima pentru oricare pereche de noduri x
i
, x
j
.
Pentru a determina drumurile minime ntre toate perechile de varfuri, putem alege un
algoritm ce determina drumurile minime de sursa unica (drumurile minime de la acel varf la
toate celelalte), si pe care sal aplicam pentru ecare varf al grafului.
Un astfel de algoritm este algoritmul lui Dijkstra, algoritm ce a cunoscut multiplembunata-
t iri fat a de varianta orginala, ce se bazeaza pe utilizarea unor structuri de date avansate (de e-
xemplu heap-uri Fibonacci), menite sai optimizeze timpul de execut ie. Astfel complexitatea
timp n cazul cel mai defavorabil pentru calculul celor mai scurte drumuri pornind dintrun
varf al unui graf cu n noduri si m arce este O(m + nlog n). Daca aplicam acest algoritm
pentru toate cele n varfuri vom obt ine un timp de lucru de O(mn +n
2
log n).
Algoritmul 61 prezinta o varianta a algoritmului lui Dijkstra n care drumurile de lungime
minima ntre oricare doua varfuri sunt calculate incremental si intercalat [35]. Matricea D
va pastra pentru ecare pereche [x
i
, x
j
] lungimea d
i,j
a drumului minim dintre cele explorate
pana la momentul curent. Coada de prioritat i C pastreaza toate perechile (i, j), ordonate
crescator n funct ie de prioritatea d
i,j
a ecaruia. La ecare pas, se extrage din coada perechea
(i, j) avand prioritatea cea mai mica si se ncearca extinderea drumului [x
i
, x
j
] cu exact un
arc la ecare extremitate a drumului. Tehnica utilizata este cea a relaxarii, ntalnita si n
cadrul algoritmului lui Bellman, cu scopul de a micsora costul drumului de la x
i
la x
j
, prin
parcurgerea tuturor arcelor ce parasesc varful x
j
si a celor ce sosesc n varful x
i
.
8.2.1 Algoritmul lui Roy-Floyd-Warshall
Fie p = [x
1
, x
2
, . . . , x
k
] un drum elementar. Denim un varf intermediar orice varf u
{x
2
, . . . , x
k1
} (u = x
1
, u = x
k
varful intermediar este diferit de extremitat ile drumului p).
Fie U = {x
1
, x
2
, . . . , x
k
} o mult ime de noduri. Notam cu M
U
i,j
mult imea drumurilor de
la x
i
la x
j
ce au drept noduri intermediare elemente din mult imea U. Fie p drumul de cost
minim de la x
i
la x
j
(p M
U
i,j
). Un astfel de drum este elementar deoarece am presupus ca
nu exista cicluri al caror cost sa e negativ.
Notam d
k
i,j
costul drumului minim de la x
i
la x
j
ce are noduri intermediare numai din
mult imea {x
1
, x
2
, . . . , x
k
}. Daca x
k
/ p (x
k
nu apart ine drumului p) atunci drumul de
cost minim de la x
i
la x
j
avand toate nodurile intermediare din mult imea {x
1
, x
2
, . . . , x
k1
}
va si drum de cost minim de la x
i
la x
j
cu toate nodurile intermediare din mult imea
{x
1
, x
2
, . . . , x
k
}:
d
k
i,j
= d
k1
i,j
Daca x
k
este un varf intermediar al drumului p, e p
1
si p
2
subdrumuri ale lui p, p = p
1
p
2
(p
1
drumul de la x
i
la x
k
avand nodurile intermediare din mult imea {x
1
, x
2
, . . . , x
k
} si p
2
166
Algoritm 61 Algoritmul lui Dijkstra pentru toate perechile de varfuri
1: procedure DijkstraAll(n, C; D)
2: for i 1, n do
3: for j 1, n do
4: if ((i, j) E) then sau (c
i,j
> 0) (c
i,j
< )
5: d
i,j
c
i,j
6: else
7: d
i,j

8: end if
9: C (i, j) cu prioritatea d
i,j
10: end for
11: end for
12: while (C = ) do
13: C (i, j)
14: for k 1, n do
15: if (d
i,j
+ c
j,k
< d
i,k
) then
16: d
i,k
d
i,j
+ c
j,k
17: actualizeaza prioritatea lui (i, k) din C la d
i,k
18: end if
19: end for
20: for k 1, n do
21: if (c
k,i
+ d
i,j
< d
k,j
) then
22: d
k,j
c
k,i
+ d
i,j
23: actualizeaza prioritatea lui (k, j) din C la d
k,j
24: end if
25: end for
26: end while
27: end procedure
drumul de la x
k
la x
j
avand nodurile intermediare din mult imea {x
1
, x
2
, . . . , x
k
}). Deoarece
p
1
si p
2
sunt drumuri de cost minim si x
k
/ {x
1
, x
2
, . . . , x
k1
} avem: d
k1
i,k
= d
k
i,k
, d
k1
k,j
= d
k
k,j
.
c(p) = c(p
1
) +c(p
2
) d
k
i,j
= d
k1
i,k
+d
k1
k,j
Algoritmul va construi un sir de matrici D
0
, D
1
, . . . , D
k
, . . . , D
n
. Pentru ecare k (1
k n), d
k
i,j
va cont ine lungimea drumului minim de la nodul x
i
la nodul x
j
ce are drept
noduri intermediare numai noduri din mult imea {x
1
, x
2
, . . . , x
k
}.
Matricea D
0
se va init ializa astfel:
d
0
i,j
=
_

_
0 , daca i = j
+ , daca (x
i
, x
j
) / E, i = j
d > 0 , daca (x
i
, x
j
) E
(8.2)
(un drum ce nu are nici un varf intermediar este determinat de costul legaturii directe dintre
x
i
si x
j
).
Drumul de lungime minima de la x
i
la x
j
ce trece numai prin nodurile {x
1
, x
2
, . . . , x
k
} e
nu cont ine nodul x
k
caz n care d
k
i,j
= d
k1
i,j
, e l cont ine, si atunci d
k
i,j
= d
k1
i,k
+ d
k1
k,j
. Prin
urmare d
k
i,j
= min{d
k1
i,j
, d
k1
i,k
+d
k1
k,j
}.
Desi aceasta ultima relat ie sugereaza un algoritm recursiv, o abordare iterativa este mai
ecienta atat n ceea ce priveste complexitatea timp c at si din punctul de vedere al necesarului
167
de memorie. Se observa ca matricea D
k
nu mai este necesara de ndata ce matricea D
k+1
a
fost calculata.
D
n
= (d
n
i,j
), d
n
i,j
=
i,j
, x
i
, x
j
V.
Algoritm 62 Algoritmul FloydWarshall
1: procedure FloydWarshall1(n, C; D
n
)
2: for i 1, n do
3: for j 1, n do
4: d
0
i,j
c
i,j
5: end for
6: end for
7: for k 1, n do
8: for i 1, n do
9: for j 1, n do
10: d
k
i,j
min {d
k1
i,j
, d
k1
i,k
+ d
k1
k,j
}
11: end for
12: end for
13: end for
14: end procedure

In algoritmul 62 se poate renunt a la indicii superiori, obt inanduse astfel o economie de


spat iu de la (n
3
) la (n
2
) (vezi algoritmul 63).
Algoritm 63 Algoritmul FloydWarshall (varianta optimizata)
1: procedure FloydWarshall2(n, C; D)
2: for i 1, n do
3: for j 1, n do
4: d
i,j
c
i,j
5: end for
6: end for
7: for k 1, n do
8: for i 1, n do
9: for j 1, n do
10: d
i,j
min {d
i,j
, d
i,k
+ d
k,j
}
11: end for
12: end for
13: end for
14: end procedure
Exemplul 8.4 Fie graful din gura 8.2. Matricea costurilor asociata acestui graf este:
C =
_
_
_
_
_
_
0 1 + 21 +
+ 0 8 + 4
3 + 0 12 +
+ + 9 0 +
+ + 3 + 0
_
_
_
_
_
_
168
Sirul de matrice D
k
, rezultat al aplicarii algoritmului Roy-Floyd-Warshall pentru acest
graf, este:
D
0
=
_
_
_
_
_
_
0 1 21
0 8 4
3 0 12
9 0
3 0
_
_
_
_
_
_
D
1
=
_
_
_
_
_
_
0 1 21
0 8 4
3 4 0 12
9 0
3 0
_
_
_
_
_
_
D
2
=
_
_
_
_
_
_
0 1 9 21 5
0 8 4
3 4 0 12 8
9 0
3 0
_
_
_
_
_
_
D
3
=
_
_
_
_
_
_
0 1 9 21 5
11 0 8 20 4
3 4 0 12 8
12 13 9 0 17
6 7 3 15 0
_
_
_
_
_
_
D
4
=
_
_
_
_
_
_
0 1 9 21 5
11 0 8 20 4
3 4 0 12 8
12 13 9 0 17
6 7 3 15 0
_
_
_
_
_
_
D
5
=
_
_
_
_
_
_
0 1 8 20 5
10 0 7 19 4
3 4 0 12 8
12 13 9 0 17
6 7 3 15 0
_
_
_
_
_
_

Inchiderea tranzitiva
Denit ia 8.1 Fie G = (V, E) un graf orientat, simplu si nit, V = {x
1
, x
2
, . . . , x
n
}.

Inchiderea tranzitiv a a grafului G este un graf G


+
= (V, E
+
), unde E
+
= {(x
i
, x
j
)|
un drum de la x
i
la x
j
n G}.

Inchiderea tranzitiva a unui graf orientat prezinta multiple aplicat ii drept subproblema n
cazul unor probleme computat ionale cum ar : construirea unui automat de parsare utilizat
la realizarea unui compilator, evaluarea interogarilor recursive realizate asupra unei baze de
date sau analiza elementelor accesibile ntro ret ea de tranzit ie asociata unui sistem paralel
sau distribuit.
Prima varianta de a determina nchiderea tranzitiva presupune atribuirea unui cost unitar
(= 1) arcelor din E urmata de aplicarea algoritmului RoyFloydWarshall. Vom obt ine o
matrice n care, d
i,j
= + daca nu exista un drum de la x
i
la x
j
sau d
i,j
= c < n daca exista.

In cadrul celei de-a doua variante de calcul (vezi algoritmul 64), se nlocuiesc operat iile
min cu (sau logic) si respectiv + cu (si logic).
d
k
i,j
= 1 daca exista un drum de la x
i
la x
j
n graful G avand varfurile intermediare numai
din mult imea {x
1
, . . . , x
k
}.
d
k
i,j
=
_
1 , daca i = j sau (x
i
, x
j
) E
0 , daca i = j si (x
i
, x
j
) / E
(8.3)
d
k
i,j
= d
k1
i,j
(d
k1
i,k
d
k1
k,j
)
Exemplul 8.5 Fie graful din gura 8.2, din care am eliminat arcul (1, 2). Matricea cos-
turilor asociata acestui graf modicat este:
C =
_
_
_
_
_
_
0 21
0 8 4
3 0 12
9 0
3 0
_
_
_
_
_
_
169
Algoritm 64 Algoritm de calcul a nchiderii tranzitive
1: procedure InchidereTranzitiva(n, C; D)
2: for i 1, n do
3: for j 1, n do
4: if (x
i
= x
j
) (c
i,j
= +) then
5: d
0
i,j
1
6: else
7: d
0
i,j
0
8: end if
9: end for
10: end for
11: for k 1, n do
12: for i 1, n do
13: for j 1, n do
14: d
k
i,j
d
k1
i,j
(d
k1
i,k
d
k1
k,j
)
15: end for
16: end for
17: end for
18: end procedure
D
0
=
_
_
_
_
_
_
1 0 0 1 0
0 1 1 0 1
1 0 1 1 0
0 0 1 1 0
0 0 1 0 1
_
_
_
_
_
_
D
1
=
_
_
_
_
_
_
1 0 0 1 0
0 1 1 0 1
1 0 1 1 0
0 0 1 1 0
0 0 1 0 1
_
_
_
_
_
_
D
2
=
_
_
_
_
_
_
1 0 0 1 0
0 1 1 0 1
1 0 1 1 0
0 0 1 1 0
0 0 1 0 1
_
_
_
_
_
_
D
3
=
_
_
_
_
_
_
1 0 0 1 0
1 1 1 1 1
1 0 1 1 0
1 0 1 1 0
1 0 1 1 1
_
_
_
_
_
_
D
4
=
_
_
_
_
_
_
1 0 1 1 0
1 1 1 1 1
1 0 1 1 0
1 0 1 1 0
1 0 1 1 1
_
_
_
_
_
_
D
5
=
_
_
_
_
_
_
1 0 1 1 0
1 1 1 1 1
1 0 1 1 0
1 0 1 1 0
1 0 1 1 1
_
_
_
_
_
_
8.3 Exercit ii
1. Cutii ndimensionale Sa consideram o cutie ndimensionala, data prin lungimea ecarei
laturi (o cutie bidimensionala este un dreptunghi, o cutie tridimensionala este un par-
alelipiped, etc.).
Problema cere analizarea unui grup de k cutii ndimensionale: trebuie gasita o secvent a
de lungime maxima (b
1
, b
2
, . . .) din grupul de k cutii astfel ncat ecare cutie b
i
sa poata
introdusa n cutia b
i+1
.
Cutia D = (d
1
, d
2
, . . . , d
n
) poate introdusa n cutia E = (e
1
, e
2
, . . . , e
n
) numai daca
laturile cutiei D pot combinate n asa fel cu laturile cutiei E, astfel ncat lungimea
170
ecarei laturi a cutiei D sa nu depaseasca lungimea laturii corespunzatoare din cutia
E. De exemplu cutia (2, 6) poate introdusa n cutia (7, 3).
Cutiile egale pot introduse una ntralta. Masurile laturilor sunt numere reale mai
mici sau egale cu 1000. Numarul de cutii nu depaseste 100, iar numarul de dimensiuni
nu depaseste 20.
(Tuymaada, 1997)
2. Suntet i angajat la o companie ce asigura servicii de transport marfuri en-gross. Client ii
au magazine n orase din toata t ara si ei sunt aprovizionat i din depozitele locale ale
companiei.
Pentru o aprovizionare optima, compania vrea sa investeascan construirea unui depozit
central din care sa se aprovizioneze toate zonele; va deci necesar ca acest depozit sa
e plasat ntr-unul din orase n asa fel ncat timpul total de livrare din acest depozit
n toate orasele sa e minim. Camioanele companiei transporta marfa la depozitele
locale si se ntorc la depozitul central. Timpul de livrare este format din timpul necesar
parcurgerii drumului de la depozitul central la oras si napoi (se presupune ca soferul
va urma de ecare data calea cea mai rapida, iar n ecare oras depozitul local se aa
amplasat la intrare) si timpul de descarcare al camionului la destinat ie, ce este de exact
30 minute. Drumurile ce leaga orasele sunt de aceeasi calitate, dar pot exista drumuri
ce iau mai mult timp ntr-un sens decat n sens invers. Pot , de asemenea, drumuri
cu sens unic.
Pentru a simplica modelul, s-a stabilit pentru ecare oras o lista cu toate drumurile
ce pleaca din oras spre celelalte orase si cat timp ia parcurgerea ecarui drum.
(Concurs ACM Zona Pacicul de Sud)
3. Se da ret eaua hidrograca a unei t ari constituita din mult imea raurilor si auent ii lor.
Cele N rauri (2 n 1000) sunt numerotate de la 1 la N. Legatura dintre un rau v
si un auent al sau u este specicata prin perechea (u, v).
Pentru a se putea face estimari cu privire la potent ialul risc de inundai e pe cursul unui
rau trebuie sa se calculeze debitul ecarui rau n parte.
Debitul unui izvor se deneste ca ind cantitatea de apa ce trece prin sect iunea izvorului
n unitatea de timp. Debitul raului u la varsare va egal cu debitul izvorului raului u
plus suma debitelor auent ilor la varsare n raul u.
Se cere sa se realizeze un algoritm care sa calculeze debitul la varsare al ecarui rau.
4. Sa se determine drumul de lungime minima necesar deplasarii unui cal pe o tabla de
sah (avand dimensiunile 8 8) de la un punct de plecare la unui de sosire, stiind ca pe
tabla exista si gauri. Calul poate mutat numai n casut ele fara gauri.
(ACM, Eastern Europe, 1994)
5. Un traducator gaseste o carte scrisa cu litere latine, n care nsa ordinea literelor din
alfabet este schimbata. La sfarsitul cart ii se aa un index de cuvinte complet si necon-
tradictoriu. Se cere sa se determine ordinea literelor din noul alfabet.
(ONI, 1991)
6. Profesorul Heif realizeaza niste experimente cu o specie de albine din America de Sud
pe care lea descoperit n timpul unei expedit ii n jungla Amazonului. Mierea produsa
171
de aceste albine este superioara din punct de vedere calitativ mierii produse de albinele
din Europa sau din America de Nord. Din pacate, aceste albine nu se nmult esc n
captivitate. Profesorul Hei crede ca pozit iile larvelor (albine lucratoare, regina) din
fagure depind de condit iile de mediu, care sunt diferite n laborator fat a de padurea
tropicala.
Ca un prim pas pentru a-si verica teoria, profesorul Hei doreste sa calculeze diferent a
dintre pozit iile larvelor. Pentru aceasta el masoara distant a dintre celulele fagurelui
n care sunt plasate larvele. El a numerotat celulele aleg and n mod arbitrat una si
numerotando cu 1, apoi celelalte celule ramase sunt numerotate circular, n sensul
acelor de ceas, ca n gura.
__ __ __ __
__/ \__/ \__/ \__/ \__
__/ \__/ \__/53\__/ \__/ \__
/ \__/ \__/52\__/54\__/ \__/ \
\__/ \__/51\__/31\__/55\__/ \__/
/ \__/50\__/30\__/32\__/56\__/ \
\__/49\__/29\__/15\__/33\__/57\__/
/ \__/28\__/14\__/16\__/34\__/ \
\__/48\__/13\__/ 5\__/17\__/58\__/
/..\__/27\__/ 4\__/ 6\__/35\__/ \
\__/47\__/12\__/ 1\__/18\__/59\__/
/..\__/26\__/ 3\__/ 7\__/36\__/ \
\__/46\__/11\__/ 2\__/19\__/60\__/
/..\__/25\__/10\__/ 8\__/37\__/ \
\__/45\__/24\__/ 9\__/20\__/61\__/
/..\__/44\__/23\__/21\__/38\__/ \
\__/70\__/43\__/22\__/39\__/62\__/
/ \__/69\__/42\__/40\__/63\__/ \
\__/ \__/68\__/41\__/64\__/ \__/
/ \__/ \__/67\__/65\__/ \__/ \
\__/ \__/ \__/66\__/ \__/ \__/
\__/ \__/ \__/ \__/ \__/
\__/ \__/ \__/ \__/
De exemplu, doua larve pozit ionate n celulele 19 si 30 se aa la distant a de 5 celule.
Unul din drumurile minime ce unesc cele doua celule trece prin celulele 19-7-6-5-15-30.
Sa se scrie un algoritm ce calculeaza distant a minima dintre oricare doua celule.
Datele de intrare constau din doua numere naturale u si v (u, v 10.000) reprezentand
numarul celulelor ntre care se doreste sa se determine distant a minima.
(ACM Final, 1999)
7.

In ecare noapte un print intra n subsolurile unui castel unde locuieste o print esa.
Drumul catre print esa este ca un labirint. Sarcina print ului este sa se grabeasca si sa
gaseasca drumul prin labirint catre print esa, deoarece trebuie sa se ntoarca n zori.
Acesta are unelte potrivite cu ajutorul carora poate sa sparga numai un singur perete
pentru asi scurta drumul catre destinat ie.
(a) gasit i lungimea celui mai scurt drum din labirint din locul n care print ul intra n
labirint pana n locul n care traieste print esa;
172
(b) gasit i lungimea celui mai scurt drum daca se sparge un perete.
Castelul este de forma dreptunghiulara cu m n camere (1 n, m 100). Fiecare
camera poate avea peret i spre E, S, V si N codicat i cu un numar ntre 1 si 14: 1, 2,
4, 8. Se stie ca nu exista camere fara nici un perete (codul > 0) si nici camere care sa
aiba peret i n toate direct iile (codul < 15).
Lungimea celui mai scurt drum se deneste ca ind numarul de camere dintre sursa si
destinat ie inclusiv.
Datele de intrare constau din M linii ce cont in ecare N numere ntregi reprezentand
codicarea peret ilor din ecare camera, urmate se coordonatele print ului si ale print esei.
De exemplu, pentru datele de intrare
5 8
14 10 10 10 10 10 10 9
12 10 10 10 10 10 10 3
5 14 9 14 8 11 14 9
4 10 2 8 3 12 10 1
6 11 14 2 10 2 10 3
1 1 5 8
avem rezultatul 26 si 12.
(ACM Bucuresti, 1999)
173
Capitolul 9
Fluxuri n ret ele de transport
Problema studierii uxului n ret ele de transport si are originea n analiza unor probleme de
transport [108]. Un graf orientat poate modela procesul de transport dintre un producator si
un consumator prin intermediul unei ret ele de transport. Ceea ce se trimite pe un drum nu
poate depasi capacitatea sa de transport. La destinat ie nu poate sa ajunga o cantitate mai
mare decat cea care a fost realizata de catre producator.

In jurul nostru exista foarte multe ret ele cum ar ret eaua electrica, ret eaua de apa,
ret eaua de drumuri, ret eaua de legaturi telefonice, ce au devenit elemente indispensabile ale
modului de viat a actual. O ret ea de transport poate modela curgerea unui lichid ntr-o ret ea
de conducte, deplasarea curentului prin ret ele electrice, transportul de marfuri de-a lungul
unei ret ele de drumuri, etc.
Doua dintre lucrarile considerate a avea un caracter de pionierat n acest domeniu si
bazeaza studiul de caz pe ret eaua feroviara existenta n fosta U.R.S.S. [108]. Asa cum oberva
si autorii lui [63] o abordare a acestei probleme folosea algoritmi avand la baza programarea
liniara, mai exact metoda simplex [33], nsa algoritmii dezvoltat i independent de aceasta
metoda au condus la rezultate mai bune n ceea ce priveste complexitatea timp.
Prima formulare a problemei determinarii uxului maximntr-o ret ea de transport a fost
facuta de T. E. Harris n [70]:
Consider a rail network connecting two cities by way of a number of intermediate
cities, where each link of the network has a number assigned to it representing its
capacity. Assuming a steady state condition, nd a maximal ow from one given
city to the other.
1
Exista doua probleme celebre care s-a demonstrat matematic a duale una alteia: prob-
lema uxului maxim ntr-o ret ea de transport si problema determinarii taieturii de capacitate
minima.
9.1 Ret ea de transport. Flux. Taietura
Denit ia 9.1 Se numeste ret ea de transport o secvent a < G, c, s, t > ce prezinta urmatoarele
proprietat i:
1
Luat i n considerare o ret ea de cale ferata ce leaga doua orase prin intermediul unui num ar de orase
intermediare, unde ecare legatura are atribuit un numar ce reprezinta capacitatea acesteia. Presupun and
ca sistemul se aa ntr-o stare de echilibru, se cere sa se determine un ux maxim de la un oras specicat la
altul.
174
1. G = (V, E) este un graf orientat, unde ecarui arc (u, v) E i este asociata o valoare
pozitiva denumita capacitate, c(u, v) 0;
2. exista doua noduri speciale, s, t V (s - sursa, t - destinat ie);
3. u V \ {s, t}, nodul u se gaseste pe cel put in un drum de la sursa la destinat ie.
Observat ia 9.1 1. Daca (u, v) / E vom considera ca valoarea capacitat ii arcului este 0 (c(u, v) =
0).
2. Graful este conex si |E| |V | 1.
Denit ia 9.2 Pentru o ret ea de transport < G, c, s, t > denim uxul asociat ret elei de
transport drept o funct ie f : V V R ce satisface urmatoarele condit ii:
1. u, v V , avem 0 f(u, v) c(u, v) (restrict ie de capacitate);
2. u, v V , avem f(u, v) = f(v, u) (antisimetrie);
3. u V \ {s, t} avem

vV
f(u, v) = 0 (conservarea uxului).
Denit ia 9.3 Se spune ca arcul (u, v) este saturat daca f(u, v) = c(u, v).
Daca f(u, v) > 0 se spune ca uxul paraseste nodul u, iar daca pentru arcul (u, v) avem
f(u, v) < 0 (echivalent cu f(v, u) > 0) spunem ca uxul intra n nodul u.
Observat ia 9.2 f(u, u) = 0, u V .
Observat ia 9.3 Pentru doua submult imi oarecare A, B (A, B V ), se deneste f(A, B)
astfel:
f(A, B) =

uA

vB
f(u, v).
Condit ia de conservare a uxului ntr-un nod poate descrisa astfel: f(v, V ) = 0.
Propozit ia 9.4 1. A V , f(A, A) = 0;
2. A, B, C V avem:
f(A B, C) = f(A, C) +f(B, C) f(A B, C)
f(A, B C) = f(A, B) +f(A, C) f(A, B C); (9.1)
3. A, B, C V , B A
f(A\ B, C) = f(A, C) f(B, C)
f(C, A\ B) = f(C, A) f(C, B);
(9.2)
4. A, B V , avem f(A, B) = f(B, A);
5. A V , f(A, ) = f(, A) = 0.
175
Denim valoarea uxului f astfel: |f| =

vV
f(s, v) . Drept urmare, valoarea uxului
n exces ce paraseste nodul sursa s este:
|f| =

vV,f(s,v)>0
f(s, v)

uV,f(u,s)>0
f(u, s) (9.3)
Se poate demonstra ca |f| =

uV,f(u,t)>0
f(u, t)

vV,f(t,v)>0
f(t, v) (valoarea uxului
f este diferent a dintre suma uxurilor ce intra n destinat ie minus suma uxurilor ce parasesc
destinat ia).
Din regula de conservare a uxului rezulta ca:

vV,f(u,v)>0
f(u, v) =

vV,f(v,u)>0
f(v, u), u V \ {s, t} (9.4)
Cu alte cuvinte, suma uxurilor ce intra ntr-un nod u este egala cu suma uxurilor ce
parasesc acelasi nod u.

Intr-o ret ea de transport avem urmatoarea relat ie:

uV
(

vV,f(u,v)>0
f(u, v)

wV,f(w,u)>0
f(w, u)) = 0. (9.5)
Pe de alta parte

uV
(

vV,f(u,v)>0
f(u, v)

wV,f(w,u)>0
f(w, u)) = (

vV,f(s,v)>0
f(s, v)

uV,f(u,s)>0
f(u, s)) +
(

vV,f(t,v)>0
f(t, v)

uV,f(u,t)>0
f(u, t))
= |f| + (

vV,f(t,v)>0
f(t, v)

uV,f(u,t)>0
f(u, t))
Astfel rezulta ca
|f| =

uV,f(u,t)>0
f(u, t)

vV,f(t,v)>0
f(t, v). (9.6)
Denit ia 9.4 O < s, t > - taietura este o pereche de mult imi disjuncte (A, B) din V (AB =
, A B = V , A, B V ) cu proprietatea ca s A si t B.
Capacitatea unei < s, t > - taieturi este suma capacitat ilor arcelor ce au o extremitate n
mult imea A si cealalta extremitate n mult imea B:
c(A, B) =

uA,vB
c(u, v) (9.7)
Se deneste uxul de-a lungul taieturii (A, B) ca ind:
f(A, B) =

uA

vV
f(u, v) (9.8)
|f|
not
= f({s}, V \ {s}) =

vV
f(s, v) (uxul net ce paraseste nodul sursa) (9.9)
Problema uxului maxim presupune determinarea unui ux de valoare maxima de la s la
t pentru ret eaua de transport < G, c, s, t > [47], [48].
176
Lema 9.5 Pentru < G, c, s, t > ret ea de transport, (A, B) o < s, t >-taietura si f un ux
n ret eaua de transport, avem |f| = f(A, B) (valoarea uxului n ret eaua de transport este
egala cu valoarea uxului de-a lungul taieturii).
Demonstrat ie: Sa ne reamintim ca daca (A, B) este o < s, t >-taietura avem A B =
, A B = V . Atunci din propozit ia 9.4 obt inem
f(A, V ) = f(A, A B) = f(A, A) +f(A, B) f(A, A B) = f(A, B) (9.10)
deoarece f(A, A) = 0 si f(A, A B) = f(A, ) = 0. Astfel pentru o < s, t >-taietura avem
f(A, B) = f(A, V ). Consideram identitatea A = (A\ {s}) {s}.
f(A, V ) = f(A\ {s}, V ) +f({s}, V ) f(, V ) = f(A\ {s}, V ) +f({s}, V ) (9.11)
Pe de alta parte avem identitatea:
f(A\ {s}, V ) = 0. (9.12)
Din ultimele trei relat ii concluzionam faptul ca:
f(A, B)
9.10
= f(A, V )
9.11
= f({s}, V ) +f(A\ {s}, V )
9.12
= f({s}, V ) = |f|. (9.13)

Corolarul 9.6 Pentru un ux f oarecare n ret eaua de transport < G, c, s, t > avem inegal-
itatea: |f| c(A, B)
Demonstrat ie: Din Lema 9.5 avem:
|f|
L9.5
= f(A, B)
def
=

uA

vB
f(u, v)
def

uA

vB
c(u, v)
def
= c(A, B). (9.14)

Taietura minima reprezinta modalitatea cea mai ecienta / simpla de a ntrerupe uxul
(curgerea) de la s la t.
Problema taieturii minime se refera la a determina o < s, t > - taietura a carei capacitate
sa e maxima.
Exemplul 9.7

In gura 9.1 este prezentat un exemplu de ret ea de transport si un ux f.
Ca o ilustrare a celor discutate vom calcula suma uxurilor pentru nodul 1:

vV
f(1, v) = f(1, s) +f(1, 2) +f(1, 3) +f(1, 4) +f(1, t)
= f(s, 1) + (1) + 12 + 0 + 0
= 11 1 + 12 = 0
(9.15)
f(1, 2) = 0 1 = 1
Sau

vV
f(4, v) = f(4, s) +f(4, 1) +f(4, 2) +f(4, 3) +f(4, t)
= 0 + 0 + (f(2, 4)) + 7 + 4
= 11 + 7 + 4 = 0
(9.16)
177
Fig. 9.1: Un exemplu de ret ea de transport
9.2 Graf rezidual. Drum de ameliorare. Flux maxim
taietura minima
Denit ia 9.5 Denim capacitatea rezidual a a unui arc (u, v) apart inand grafului G ast-
fel:
c
R
(u, v) = c(u, v) f(u, v) . (9.17)
Denit ia 9.6 Graful rezidual[47] asociat cu graful G = (V, E) si capacitatea c, este graful
G
R
= (V, E
R
) si capacitate c
R
, unde E
R
se deneste astfel: E
R
= {(u, v) V V |c
R
(u, v) >
0}.
Observat ia 9.8

Intre doua noduri u si v din graful G vom avea cel mult doua arce n graful
rezidual G
R
:
1. daca (u, v) E si f(u, v) < c(u, v) atunci exista arcul (u, v) n graful rezidual ((u, v) E
R
)
si c
R
(u, v) = c(u, v) f(u, v) (c
R
(u, v) > 0);
2. daca (u, v) E si f(u, v) > 0 atunci exista arcul (v, u) n graful rezidual ((v, u) E
R
) si
c
R
(v, u) = f(u, v).
Altfel spus, n graful rezidual G
R
pot sa apara arce noi, care nu existau n graful init ial
G. Un alt element ce merita subliniat se refera la faptul ca daca ntre doua noduri nu exista
nici un arc n graful init ial G, atunci nu va exista nici un arc ntre cele doua noduri nici n
graful rezidual G
R
. Prin urmare, numarul total de arce din graful rezidual G
R
este cel mult
de doua ori mai mare decat numarul arcelor din graful G.
Lema 9.9 Fie < G, c, s, t > o ret ea de transport si f un ux n aceasta ret ea de transport.
Daca f
R
este un ux n ret eaua de transport < G
R
, c
R
, s, t > (G
R
este graful rezidual asociat
cu G), atunci f +f
R
este un ux n < G, c, s, t >, iar |f +f
R
| = |f| +|f
R
|.
Demonstrat ie: Pentru a arata ca f +f
R
este un ux n ret eaua de transport < G, c, s, t >
trebuie sa vericam daca condit iile din denit ia 9.2 sunt ndeplinite:
1. restrict ie de capacitate
Avem f
R
(u, v) c
R
(u, v), u, v V .
(f +f
R
)(u, v) = f(u, v) +f
R
(u, v) f(u, v) +c
R
(u, v)
= f(u, v) + (c(u, v) f(u, v)) = c(u, v)(9.18)
178
2. antisimetrie
(f +f
R
)(u, v) = f(u, v) +f
R
(u, v) = f(v, u) f
R
(v, u)
= (f(v, u) +f
R
(v, u)) = (f +f
R
)(v, u) (9.19)
3. conservarea uxului

vV
(f +f
R
)(u, v) =

vV
(f(u, v) +f
R
(u, v))
=

vV
f(u, v) +

vV
f
R
(u, v) = 0 + 0 = 0 (9.20)
Sa demonstram ca |f +f
R
| = |f| +|f
R
|:
|f +f
R
| =

vV
(f +f
R
)(s, v) =

vV
(f(s, v) +f
R
(s, v))
=

vV
f(s, v) +

vV
f
R
(s, v) = |f| +|f
R
|. (9.21)

Corolarul 9.10 Daca f

not
= f+f
R
, unde f
R
este un ux n ret eaua de transport < G
R
, c
R
, s, t >
a grafului rezidual, atunci f

este un ux n < G, c, s, t > si |f

| = |f| +|f
R
| > |f|.
Demonstrat ia acestui corolar rezulta imediat din lema 9.9.
Lema 9.11 Fie f un ux n < G, c, s, t > si G
R
graful rezidual asociat cu G. Atunci avem:
1. funct ia f
R
este un ux maxim n < G
R
, c
R
, s, t > daca f + f
R
este un ux maxim n <
G, c, s, t >;
2. valoarea funct iei este aditiva: |f +f
R
| = |f| +|f
R
|, |f f
R
| = |f| |f
R
|;
3. daca f este un ux oarecare si f

este uxul maxim n < G, c, s, t >, atunci valoarea uxului


maxim n < G
R
, c
R
, s, t > este |f

| |f|.
Denit ia 9.7 Fiind data o ret ea de transport < G, c, s, t > si un ux f n aceasta ret ea,
atunci o cale de crestere d (drum de ameliorare, drum de augmentare) este un drum de la
s la t n graful rezidual G
R
.
Numim capacitate rezidual a a lui d, cantitatea maxima a uxului ce poate transportat
de-a lungul drumului de ameliorare d:
c
R
(d) = min{c
R
(u, v)|(u, v) arc pe drumul d} (9.22)
Observat ia 9.12 Unui drum de ameliorare n graful rezidual G
R
i corespunde un lant n
graful G.
Denit ia 9.8 Un arc (u, v) se numeste arc critic daca face parte dintr-un drum de ame-
liorare d si daca capacitatea sa reziduala este egala cu capacitatea reziduala a drumului de
ameliorare (c(u, v) = c
R
(d)).
Teorema 9.13 (ux maxim - taietura minima) [46], [48], [49] Fie o ret ea de transport
< G, c, s, t > si f un ux n aceasta ret ea. Urmatoarele armat ii sunt echivalente:
179
1. f este un ux maxim n ret eaua de transport;
2. nu exista nici o cale de crestere (drum de ameliorare) n ret eaua de transport < G, c, s, t >;
3. exista o < s, t >-taietura a lui G pentru care |f| = c(A, B) (exista o < s, t >-taietura pentru
care valoarea uxului maxim este egala cu capacitatea taieturii).
Demonstrat ie: Vom demonstra aceasta teorema abordand urmatoarea serie de implicat ii:
1) 2) 3) 1).
1) 2)
Sa presupunem prin reducere la absurd ca exista un drum de ameliorare n ret eaua de trans-
port < G, c, s, t > pentru un ux maxim |f|.
Daca exista un drum de ameliorare atunci exista un ux nenul f
p
n ret eaua < G
R
, c
R
, s, t >.
Fie f

uxul construit astfel: f

= f + f
p
. Din corolarul 9.10 obt inem ca f

este un ux
n ret eaua de transport < G, c, s, t > si |f

| > |f|.
Am determinat astfel un ux f

n < G, c, s, t > a carui valoare este mai mare decat


cea a uxului f. Contradict ie cu faptul ca f este un ux maximal n ret eaua de transport
< G, c, s, t >.
2) 3)
Daca nu exista nici un drum de ameliorare n < G, c, s, t > atunci nu exista nici un drum de
la s la t n graful rezidual G
R
(G
R
= (V, E
R
)).
Sa notam S = {v V | un drum de la s la t n G
R
} si T = V \ S.
Deoarece nu exista nici un drum de la s la t n G
R
t T. De asemenea avem ca s S,
S T = , S T = V . Prin urmare S, T este o < s, t >-taietura.
Din cauza faptului ca nu exista nici nici un drum de la s la t n G
R
nu exista arce
n G
R
care sa aiba o extremitate n S si cealalta extremitate n T u S, v T, daca
(u, v) E atunci f(u, v) = c(u, v).
Aplicand Lema 9.5 obt inem ca |f| = f(S, T) = c(S, T).
3) 1)
Din Corolarul 9.6 avem |f| c(A, B), (A, B) < s, t >-taietura a lui G.
Deoarece |f| = c(A, B) rezulta ca f este uxul maxim ce se poate obt ine n ret eaua de
transport < G, c, s, t >.
Valoarea maxima a unui ux ntro ret ea de transport < G, c, s, t > este egala cu valoarea
capacitat ii taieturii minime pentru aceeasi ret ea de transport.
Corolarul 9.14 Fie f un ux ntr-o ret ea de transport < G, c, s, t >. Notam cu A
f
mult imea
nodurilor ce apart in unui drum de ameliorare. Fie B
f
= V \ A
f
. Atunci f este un ux
maximal daca si numai daca t B
f
.
Mai mult, A
f
, B
f
reprezinta o < s, t >-taietura minima (de cost minim): |f| = c(A
f
, B
f
).
9.3 Metoda Ford-Fulkerson
Pe baza rezultatelor anterioare a fost elaborat un algoritm cunoscut sub numele de algorit-
mul lui Ford si Fulkerson (vezi 65) [46], [48], [49].
Exemplul 9.15 Pentru ret eaua de transport din gura 9.1 construim ret eaua reziduala din
gura 9.2:
c
R
(s, 1) = c(s, 1) f(s, 1) = 16 11 = 5
c
R
(1, s) = c(1, s) f(1, s) = 0 (11) = 11
180
Algoritm 65 Algoritmul FordFulkerson (varianta simplicata)
1: se init ializeaza uxul cu valoarea 0
2: while ( un drum de ameliorare d n G
R
) do
3: mareste uxul f de-a lungul drumului de ameliorare d
4: end while
5: return |f|
Fig. 9.2: Ret eaua reziduala corespunzatoare ret elei de transport din gura 9.1
c
R
(1, 3) = c(1, 3) f(1, 3) = 12 12 = 0
c
R
(3, 1) = c(3, 1) f(3, 1) = 0 (f(1, 3)) = 12
c
R
(4, 3) = c(4, 3) f(4, 3) = 7 7 = 0
c
R
(3, 4) = c(3, 4) f(3, 4) = 0 (f(4, 3)) = f(4, 3) = 7
c
R
(2, 3) = c(2, 3) f(2, 3) = 0 (f(3, 2)) = f(3, 2) = 4
c
R
(3, 2) = c(3, 2) f(3, 2) = 9 4 = 5
c
R
(2, 1) = c(2, 1) f(2, 1) = 4 1 = 3
c
R
(1, 2) = c(1, 2) f(1, 2) = 10 (0 1)
. .
fluxul net
= 11
Fie d = (s, 2, 3, t) o cale de crestere (drum de ameriorare) n graful din gura 9.2. Capacitatea
reziduala a acestui drum este:
c
R
(d) = min{5, 4, 5} = 4
Vom mari uxul f pentru arcele din Gce suntntalnite dea lungul drumului de ameliorare
d. Avem doua tipuri de arce:
arc nainte - arc al carui sens corespunde cu sensul parcurgerii de la s la t; pentru un
astfel de arc, (u, v) E, f(u, v) = f(u, v) +c
R
(d);
arc napoi - arcul are sens contrar sensului de parcurgere de la s la t: (u, v) E,
f(u, v) = f(u, v) c
R
(d).
Astfel noul ux corespunzator grafului din gura 9.1 si drumului de augmentare d =
(s, 2, 3, t) poate urmarit n gura 9.3.
Vom prezenta o varianta mai elaborata a algoritmului FordFulkerson.
181
Fig. 9.3: Flux ntr-o ret ea de transport dupa o crestere pe baza unui drum de ameliorare
Algoritm 66 Algoritmul FordFulkerson (varianta a doua)
1: for (ecare arc (u, v) E) do
2: f(u, v) 0, f(v, u) 0
3: end for
4: while ( un drum d de la s la t n ret eaua reziduala < G
R
, c
R
, s, t >) do
5: c
R
(d) min{c
R
(u, v)|(u, v) arc pe drumul d}
6: for ecare arc (u, v) E corespunzator lant ului d do
7: f(u, v)
_
f(u, v) + c
R
(d) , daca (u, v) este arc de naintare pentru d
f(u, v) c
R
(d) , daca (u, v) este arc de ntoarcere pentru d
8: end for
9: end while
10: return |f|
Observat ia 9.16 Determinarea uxului maxim ntr-o ret ea de transport av and capacitat ile
arcelor numere rat ionale, precum si valorile uxului tot numere rat ionale, se reduce la de-
terminarea unui ux maxim avand componentele uxului cat si capacitat ile arcelor numere
naturale (aceasta reducere este posibila deoarece valorile rat ionale pot amplicate cu o val-
oare pozitiva, cel mai mic multiplu comun al numitorilor acestor numere).
Complexitatea algoritmului

In tabelul 9.1 [127] sunt prezentat i principalii algoritmi pentru determinarea uxului maxim
ntr-o ret ea de transport, anul n care au aparut precum si complexitatea lor. Astfel acestia se
pot compara din punct de vedere al complexitat ii teoretice si se poate alege varianta potrivita
rezolvarii unor probleme concrete.
9.3.1 Algoritmul Ford-Fulkerson (varianta)
Prezentam n continuare o varianta a algoritmului Ford-Fulkerson:
Pas 1. Se considera un ux init ial f
0
. De obicei se alege drept ux init ial uxul nul (f
0
(u, v) =
0, u, v V, (u, v) E).
Pas 2. Se construieste un ux maxim:
Pas 2.1. Se marcheaza nodul s cu semnul +.
182
Table 9.1: Principalii algoritmi pentru determinarea uxului maxim ntr-o ret ea de transport
Autor(i) Anul aparit iei Complexitate
Ford & Fulkerson 1956 [48] O(V EU)
Dinic 1970 [39] O(V
2
E)
Edmonds & Karp 1972 [42] O(V E
2
)
Karzanov 1974 [80] O(V
3
)
Cherkassky 1976 [29] O(V
2

E)
Malhotra, Kumar si Maheswari 1978 [94] O(V
3
)
Galil 1980 [58] O(V
5
3
E
2
3
)
Galil & Naamad 1980 [59] O(EV (log V )
2
)
Sleator 1980 [113] O(EV log V )
Shiloach & Vishkin 1982 [111] O(V
2
log V )
Sleator & Tarjan 1983 [114] O(EV log V )
Tarjan 1984 [120] O(V
3
)
Goldberg 1985 [61] O(V
3
)
Goldberg & Tarjan 1986 [62] O(EV log (
V
2
E
)
)
Ahuja & Orlin 1989 [4] O(V E +V
2
log U)
Pas 2.2. Pentru un varf u etichetat avem cazurile:
i. daca (u, v) E, v este neetichetat iar arcul (u, v) este nesaturat atunci se
eticheteaza v cu [+u];
ii. daca (v, u) E, v este neetichetat iar uxul corespunzator arcului (v, u)
este nenul atunci se eticheteaza v cu [u];
Se repeta pasul 2.2 atata timp cat este posibil (cat timp nu a fost etichetat nodul
t sau se mai pot eticheta noduri noi).
Pas 2.3. Daca t nu a fost etichetat, atunci uxul construit pana la momentul actual este
maxim si procesul se opreste.
Pas 2.4. Daca t a fost etichetat, atunci se identica un drum d de la s la t. Notam cu U
+
mult imea arcelor (u, v) d unde v a fost etichetat cu + si U

mult imea arcelor


(u, v) d unde v a fost etichetat cu .

0
= min
(u,v)U
+
{c(u, v) f(u, v)}

1
= min
(u,v)U

{f(u, v)}

= min{
0
,
1
} (9.23)
Valoarea uxului de-a lungul ecarui arc din d, devine f +

daca arcul apart ine


lui U
+
sau f

daca arcul apart ine lui U

.
Exemplul 9.17 Fie ret eaua de transport din gura 9.4 n care a fost considerat la nceput
uxul nul.
183
Fig. 9.4: Flux ntr-o ret ea de transport
Se eticheteaza varful s cu [+]. Deoarece arcele (s, 1) si (s, 2) sunt nesaturate, varfurile 1
si 2 pot etichetate cu [+s].

In continuare, deoarece arcele (1, 3) si (2, 4) sunt nesaturate vor
etichetate nodurile 3 si 4 cu [+1] respectiv [+2]. Arcul (3, 2) are uxul nul si astfel nodul
3 nu poate etichetat cu [2]. Analog, se eticheteaza nodul t cu [+3] (vezi gura 9.4).
Deoarece nodul destinat ie t a fost etichetat, se poate trage concluzia ca uxul curent nu
este maxim.
Trebuie subliniat faptul ca etichetarea nodurilor nu este unica, aceasta depinzand de modul
de parcurgerea al nodurilor grafului. Spre exemplu, nodul 3 poate etichetat si cu [+4]
ajungandu-se la el prin intermediul nodului 4 si al arcului (4, 3).
Pornind de la nodul t si mergand napoi pe secvent a de etichetare, se identica un drum
de la s la t, d
1
= (s, 1, 3, t).

= min
(u,v)U
+
{c(u, v) f(u, v)}
= min{c(s, 1) f(s, 1), c(1, 3) f(1, 3), c(3, t) f(3, t)} = min{16, 12, 20} = 12
Pe acest drum avem arcele (s, 1), (1, 3), (3, t) U
+
. Prin urmare valoarea uxului de-a
lungul acestor arce devine (vezi gura 9.5):
f(s, 1) = f(s, 1) +

= 0 + 12 = 12, f(1, 3) = 0 + 12 = 12, f(3, t) = 0 + 12 = 12

In gura 9.5 poate urmarita o noua etichetare a nodurilor grafului. Se marcheaza nodul
s cu [+]. Din nodul s prin intermediul arcelor nesaturate (s, 1) si (s, 2) pot etichetate
nodurile 1 si 2 cu [+s]. Arcul (1, 3) nu mai poate utilizat n procesul de etichetare deoarece
este saturat (f(1, 3) = c(1, 3) = 12).
Din nodul 1 mai avem arcul (1, 2) nsa nodul 2 a fost etichetat cu [+s]. Prin intermediul
arcului (2, 4) vom eticheta nodul 4 cu [+2]. Arcul (3, 2) nu poate utilizat pentru etichetarea
nodului 3 cu [2] deoarece uxul corespunzator are n continuare valoarea 0.
Din nodul 4 se eticheteaza nodurile 3 si t cu [+4] prin intermediul arcelor (4, 3) si (4, t).
Pornind de la nodul t si mergand napoi pe secvent a de etichetare, se identica un drum
de la s la t, d
2
= (s, 2, 4, t).

= min
(u,v)U
+
{c(u, v) f(u, v)}
= min{c(s, 2) f(s, 2), c(2, 4) f(2, 4), c(4, t) f(4, t)} = min{13, 14, 4} = 4
184
Fig. 9.5: Flux ntr-o ret ea de transport
Arcele ntalnite de-a lungul drumului d
2
, (s, 1), (1, 3), (3, t), apart in mult imii U
+
. Prin
urmare valoarea uxului de-a lungul acestor arce devine (vezi gura 9.6):
f(s, 2) = f(s, 2) +

= 0 + 4 = 4, f(2, 4) = 0 + 4 = 4, f(4, t) = 0 + 4 = 4
Fig. 9.6: Flux ntr-o ret ea de transport
Cea de-a treia etapa de etichetare este ilustrata n gura 9.6: nodul s se eticheteaza cu
[+]. Urmeaza apoi nodurile 1 si 2 cu [+s] ecare, si nodul 4 cu [+2]. De aici mai departe
nodul 3 se eticheteaza cu [+4] iar t cu [+3].
Pentru aceasta etichetare se identica drumul d
3
de la s la t: d
3
= (s, 2, 4, 3, t).

= min
(u,v)U
+
{c(u, v) f(u, v)}
= min{c(s, 2) f(s, 2), c(2, 4) f(2, 4), c(4, 3) f(4, 3), c(3, t) f(3, t)}
= min{13 4, 14 4, 7 0, 20 12} = 7
Toate arcele din care este alcatuit drumul d
3
apart in mult mii U
+
. Valoarea uxul calculat
pentru ecare arc n parte este (vezi gura 9.7):
f(s, 2) = f(s, 2)+

= 4+7 = 11, f(2, 4) = 4+7 = 11, f(4, 3) = 0+7 = 7, f(3, t) = 12+7 = 19


185
Fig. 9.7: Flux maxim ntr-o ret ea de transport
Analizand ret eaua de transport si uxul din gura 9.7 se observa ca nu se mai poate
eticheta nodul t pornind din s datorita prezent ei arcelor saturate (1, 3), (4, 3), (4, t) precum
si a arcului (3, 2) ce are nsa valoarea uxului nula.

In aceasta situat ie procesul iterativ de etichetare se opreste conform Pasului 2.3 din algo-
ritmul anterior.
Fluxul maxim determinat n ret eaua de transport este:
|f| = f(s, 1) +f(s, 2) = 11 + 12 = 23 sau |f| = f(3, t) +f(4, t) = 19 + 4 = 23.
9.4 Exercit ii
1. Aplicadu-se algoritmul Ford-Fulkerson sa se determine uxul maximn ret elele de trans-
port din gura 9.1. Nodul 0 este nodul sursa iar nodul 5 respectiv nodul 6 este nodul
destinat ie.
186
0
1
2
3
4
5
10
4
10
9
6
10
10
8
2
0
1
2
3
4
5
5
4
3
3
1
9
9
8
2
0
1
2
4
5 5
10
9
10
8
15
5 10
4
15
3
15
4
4
6
30
10
15
a) b)
c) d)
0
1
6
4
3
5
3
1
1
3
1
3
6
2
4
2
2
9
Fig. 9.8: Alte exemple de ret ele de transport
187
Appendix A
Probleme. Algoritmi. Complexitate
Vom considera o problema computat ionala ca ind o aplicat ie
P : I O (A.1)
unde I reprezinta mult imea intrarilor problemei, mult imea instant elor problemei, iar O reprezinta
mult imea iesirilor, raspunsurilor, solut iilor. Aceasta problema P pentru ecare intrare i I
ofera o iesire P(i) O.
Denit ia A.1 Daca O = {da, nu} atunci P se va numi problem a de decizie, P(i)
{da, nu} va raspunsul la ntrebarea pusa de P, iar forma uzuala de prezentare a pro-ble-
mei va :
P Intrare: i I.

Intrebare: . . ..
Exemplul A.1 Sa consideram urmatoarea problema:
NrCompus Intrare: n N, n 2.

Intrebare: Exista p, q N, p, q 2 si n = pq?


Un alt tip de probleme ce apar n mod frecvent sunt cele de cautare: mult imea O cont ine
pentru ecare i I macar o solut ie acceptabila n raport cu un anumit criteriu precizat, iar
problema cere gasirea unei astfel de solut ii.
O clasa speciala de astfel de probleme este cea a problemelor de optimizare, si care pot
probleme de maximizare sau de minimizare.
Exemplul A.2 Prezentam cateva exemple de astfel de probleme de optimizare:
Drum Intrare: G un graf, a, b doua varfuri ale lui G.
Iesire: P un drum n G de la a la b (daca ).
sau
DrumMin Intrare: G un graf, a, b doua varfuri ale lui G, o funct ie de lungime
a muchiilor lui G.
Iesire: P

un drum n G de la a la b cu suma lungimilor


muchiilor minima, printre toate drumurile de la a la b n G.
sau
MaxCut Intrare: G graf, o funct ie de lungime a muchiilor lui G.
Iesire: O bipartit ie (S, T) a mult imii varfurilor grafului G
cu suma lungimilor muchiilor dintre cele doua clase maxim a.
188
Oricarei probleme de optimizare i se poate asocia o problema de decizie (care ne va da
informat ii asupra dicultat ii ei computat ionale). Pentru cele doua probleme de optimizare
de mai sus, avem:
DrumMinD Intrare: G un graf, a, b varfuri ale lui G, k N
o funct ie de lungime a muchiilor lui G.

Intrebare: Exista P drum n G de la a la b cu suma lungimilor


muchiilor k?
sau
MaxCutD Intrare: G un graf, k N, o funct ie de lungime a muchiilor lui G.

Intrebare: Exista (S, T) bipartit ie a mult imii varfurilor grafului G


cu suma lungimilor muchiilor dintre cele doua clase k?
Vom considera n continuare doar probleme de decizie.
Pentru a rezolvate cu ajutorul calculatorului problemele sunt codicate. Fie o mult ime
nita, xata, numita alfabet, iar

mult imea tuturor cuvintelor peste .


Denit ia A.2 Obiectele care apar n descrierea unei probleme (numere rat ionale, grafuri,
funct ii, matrici etc.) vor reprezentate cu ajutorul unor cuvinte w

. Lungimea
cuvantului w se va nota cu |w|. Orice mult ime de cuvinte peste , adica orice submult ime a
lui

se numeste limbaj (peste ).


Problemele de decizie au urmatoarea forma: Fiind dat un anumit obiect, are el o anumita
proprietate?. Deoarece obiectele le reprezentam cu ajutorul cuvintelor nseamna ca problema
se reduce la ntrebarea: Fiind dat un cuvant, prezinta el o anumita proprietate?
Denit ia A.3 Vom considera problem a de decizie o funct ie
P :

{da, nu} (A.2)


Denit ia A.4 Limbajul asociat problemei P este
P
1
(da) = {w|w

si P(w) = da} (A.3)


Denit ia A.5 Vom considera ca un algoritm este o funct ie
A :

{da, nu, nedecidabil} (A.4)


Denit ia A.6 Limbajul L

este acceptat de algoritmul A daca L = {w|w

si A(w) = da}.
Denit ia A.7 Limbajul L

este decis de algoritmul A daca w L : A(w) = da si


w / L : A(w) = nu.
Denit ia A.8 Limbajul L

este acceptat de algoritmul A n timp polinomial


daca L este acceptat de A si k N astfel ncat pentru orice w L algoritmul A evalueaza
A(w) = da n timpul O(|w|
k
).
Denit ia A.9 Limbajul L

este decis de algoritmul A n timp polinomial daca


k N astfel ncat pentru orice w algoritmul A evalueaza A(w) = da, daca w L si
A(w) = nu, daca w / , n timpul O(|w|
k
).
Denit ia A.10 Clasa de complexitate P:
P = {L

|A alg. a.. L e decis de A n timp polinomial}. (A.5)


189
Daca P este o problema de decizie, atunci ea este rezolvabila n timp polinomial daca
limbajul L = P
1
(da) satisface L P. Se noteaza aceasta P P.
De exemplu, problema DrumMIN D este rezolvabila n timp polinomial daca funct ia
de lungime (specicata n intrarea ei) prezinta numai valori nenegative. Daca se permit si
valori negative, atunci nu se cunoaste nici o demonstrat ie a apartenent ei DrumMinD P
(si nici nu se crede ca ar exista una). De asemenea, NrCompus P s-a demonstrat destul
de recent, n 2002.
Observat ia A.3 1. Daca notam
P = {L

|A alg. a.. L este acceptat de A n timp polinomial},


se observa imediat ca P P

si nu este dicil sa se arate si incluziunea inversa. Prin urmare


avem P = P

.
2. Se verica usor ca daca P P atunci si

\ P P.
A.0.1 Vericare n timp polinomial
Un algoritm de vericare este o funct ie
A :

{da, nu, nedecidabil}.


Pentru A(x, y), x reprezinta intrarea iar y este certicatul.
Limbajul L

este vericat de algoritmul de vericare A daca


L = {w|w

si y

a.. A(w, y) = da}.


Denit ia A.11 Clasa de complexitate NP:
NP = {L

|A algoritm de vericare cu timp de lucru polinomial a.i.


L = {x

|y

, k N a.. |y| = O(|x|


k
) si A(x, y) = da}}
(A.6)
Daca P este o problema de decizie, atunci ea este o problema (din) NP daca limbajul
L = P
1
(da) satisface L NP.
NP este mnemonic pentru Nedeterminist Polinomial.
Nu este bine sa asimilam NP cu nepolinomial deoarece
textP NP. Justicarea este imediata: Daca L P, atunci exista A :

{da, nu, nedecidabil}


algoritm ce decide Ln timp polinomial. Consideram A

{da, nu, nedecidabil},


satisfacand A

(x, x) = A(x) pentru orice x

. Se vede usor ca L este vericat de A

n
timp polinomial.
Din denit iile de mai sus ar fost mai normal sa folosim notat ia VP (vericabil poli-
nomial ). Sintagma Nedeterminist Polinomial se justica daca am considera algoritmi nede-
terministi n care, dupa ecare pas, este posibil sa se execute unul dintre pasii specicat i
dintro mult ime nita de pasi succesori. Un astfel de algoritm accepta un cuvant de intrare
daca este posibila o execut ie care sa conduca la rezultatul da. Se poate arata ca aceasta
denit ie a acceptarii nedeterministe este echivalenta cu cea de vericare data mai sus, n
care certicatul este utilizat pentru efectuarea alegerilor corecte ale passilor urmatori ai unei
execut ii a algoritmului nedeterminist.
NP noteaza clasa problemelor de decizie pentru care raspunsurile armative au certicate
care pot folosite pentru a demonstra succint (n timp polinomial) corectitudinea lor.
190
Intuitiv, NP este clasa tuturor problemelor de decizie pentru care se poate verica un
raspuns pozitiv (da) rapid daca ni se da o solut ie.
De exemplu, pentru problema MaxCut D un raspuns armativ are drept certicat o
partit ie (S

, T

) a mult imii varfurilor grafului (iar proprietatea ca suma lungimilor muchiilor


cu o extremitate n S

si cealalta n T

nu depaseste pragul k se face n timp polinomial).


Prin urmare MaxCut D NP.
Daca am considera urmatoarea problema de decizie:
UnDrum Intrare: G un graf, a, b varfuri ale lui G.

Intrebare: Exista un drum unic de la a la b n G?


Cum s-ar putea justica un raspuns da la o problema UnDrum? Daca prezentam un
drum anume drept certicat, el nu ne asigura ca nu mai exista s altele. O demonstrat ie
succinta pare a nu exista. Prin urmare nu se cunoaste daca UnDrum NP.
Denit ia A.12 Clasa de complexitate coNP:
co NP = {L

\ L NP}.
O problema de decizie P co NP daca
L = P
1
(da) co NP (echivalent, L = P
1
(nu) NP).
Exemplu de problema din co NP:
NeHam Intrare: G un graf.

Intrebare: Este adevarat ca n G nu exista un circuit


care sa treaca exact o data prin ecare varf al sau?
Observat ia A.4 P NP co NP.
A.0.2 Reduceri polinomiale
Denit ia A.13 Fie L
1
, L
2

. Spunem ca L
1
se reduce polinomial la L
2
, si notam
aceasta prin L
1
L
2
, daca exista f :

o funct ie polinomial calculabila astfel ncat


w

: w L
1
daca si numai daca f(w) L
2
.
f se numeste funct ie de reducere si algoritmul polinomial F ce calculeaza f se numeste
algoritm de reducere polinomiala.
Observat ia A.5 1. Daca L P si L

L, atunci L

P.
Fie A un algoritm polinomial care decide L si F un algoritm de reducere polinomiala a lui L

la L. Atunci, A

= AF este un algoritm polinomial care decide L

. (x

, A

(x) = da
A(F(x)) = da F(x) L x L

; A

este polinomial deoarece mult imea polinoamelor


este nchisa la operat ia de compunere).
2. Relat ia este tranzitiva: L
1
L
2
, L
2
L
3
L
1
L
3
.
Denit ia A.14 Limbajul L

este NPdicil (engl. NP-hard) daca L

NP are loc
L

L.
Denit ia A.15 Limbajul L

este NPcomplet daca L NP si L este NPdicil.


Terminologia se transfera pentru probleme de decizie.
Spunem ca problema de decizie P
1
se reduce polinomial la problema de decizie P
2
, si
notam P
1
P
2
, daca L
1
= P
1
1
(da) L
2
= P
1
2
(da).
191
Denit ia A.16 Problema de decizie P este NPdicila daca
P

NP are loc P

P.
Denit ia A.17 Problema de decizie P este NPcompleta daca
P NP si P este NPdicila.
Folosind observat ia anterioara si faptul ca P NP rezulta urmatoarea teorema.
Teorema A.6 Daca P o problema oarecare NPcompleta satisface P P atunci P = NP.
Rezulta ca problemele NPcomplete formeaza o submult ime a lui NP ce cont ine cele mai
dicile probleme. Daca gasim un algoritm polinomial pentru una dintre ele, putem construi
un algoritm polinomial pentru oricare alta problema din NP. Din pacate, desi nu exista o
demonstrat ie, oamenii cred ca, de fapt, aceste probleme nu admit algoritmi polinomiali de
rezolvare.
Se obisnuieste sa se spuna ca o problema de optimizare este NPdicila, daca problema
de decizie asociata este asa. Pentru a consistent i fat a de denit iile precedente, vom spune
ca o problema oarecare P (nu neaparat de decizie) este NPdicila daca existent a unui
algoritm polinomial pentru P implica P = NP.
Sa prezentam un exemplu pentru clasa de complexitate a problemelor NPcomplete.
Primul om care a demonstrat existent a unei astfel de probleme este Cook, care n 1971 a
aratat ca SAT NP, unde
SAT Intrare: U = {u
1
, . . . , u
n
} o mult ime nita de variabile booleene.
C = C
1
C
2
. . . C
m
o formula n forma conjunctiva peste U:
C
i
= v
i
1
v
i
2
. . . v
i
k
i
, i = 1, m unde
i
j
{1, . . . , n} astfel ncat v
i
j
= u

sau v
i
j
= u

Intrebare: Exista o atribuire t : U {A, F} astfel ncat t(C) = A?


Evaluarea lui t(C) se bazeaza pe formulele uzuale din calculul boolean:
A A = A, F A = F F = A F = F, (A.7)
F F = F, F A = A F = A A = A, (A.8)
F = A, A = F, (F) = F, (A) = A, (A.9)
si se poate face n timp polinomial.
3SAT este restrict ia lui SAT n care ecare clauza C
i
are exact trei literali (k
i
= 3), un
literal v
i
j
ind, asa cum este descris mai sus, o variabila sau negat ia ei.
Se poate arata usor ca SAT 3SAT si astfel se obt ine faptul ca 3SAT este NP
completa (apartenent a la NP este clara ind o restrict ie a lui SAT care apart ine lui NP, iar
tranzitivitatea relat iei mpreuna cu teorema lui Cook termina demonstrat ia).

In concluzie, pentru a arata ca o problema de decizie P este NPcompleta se procedeaza


astfel:
1. Se arata ca L = P
1
(da) satisface L NP.
2. Se selecteaza un limbaj L

despre care stim ca este NPcomplet.


3. Se ncearca construirea unui algoritm de reducere F de la L

la L.
4. Se demonstreaza ca F este algoritm de reducere.
5. Se arata ca F este algoritm polinomial.
192
Appendix B
Metoda Backtracking
Metoda Backtracking este una dintre cele mai cunoscute metode de elaborare a algoritmilor.
Metoda se aplica numai n situat ia n care nu exista nici o alta modalitate de rezolvare a
problemei propuse deoarece timpul de execut ie depinde exponent ial de dimensiunea datelor
de intrare. Se utilizeaza o structura de tip stiva iar metoda poate implementata atat
iterativ cat si recursiv. Metoda se aplica acelor probleme n care solut ia se poate reprezenta
sub forma unui vector x = (x
1
, x
2
, . . . , x
n
) A
1
A
2
. . . A
n
, unde mult imile A
i
, (i = 1, n)
sunt nite si nevide (|A
i
| = n
i
> 0).

In plus, pentru ecare problema n parte este necesar ca
solut ia x
1
, x
2
, . . . , x
n
sa satisfaca anumite condit ii interne (x
1
, x
2
, . . . , x
n
) (vezi algoritmul
67).
Algoritm 67 Algoritm Backtracking (varianta generala)
1: procedure Backtracking(n, A)
2: k 1
3: x
k
prima valoare din afara domeniului de valori
4: while (k > 0) do
5: gasit false
6: while ( valori neverificate pentru x
k
) (gasit = true) do
7: x
k
urmatoarea valoare neverificata
8: if (
k
(x
1
, x
2
, . . . , x
k
) = true) then
9: gasit true
10: end if
11: end while
12: if (gasit = true) then
13: if (k = n) then
14: call Afis Solutie(x
1
, . . . , x
n
)
15: else
16: k k + 1
17: x
k
prima valoare din afara domeniului de valori
18: end if
19: else
20: k k 1
21: end if
22: end while
23: end procedure
De exemplu, sa consideram doua mult imi, S
1
= {a, b, c} si S
2
= {m, n}. Se doreste sa se
determine perechile (x
1
, x
2
), cu x
1
A
1
si x
2
A
2
, cu proprietatea ca daca x
1
este a sau b
193
atunci x
2
nu poate n. Rezolvarea conduce la urmatoarele variantele: (a, m), (b, m), (c, m), (c, n).
Din cele sase solut ii posibile (a, m), (a, n), (b, m), (b, n), (c, m), (c, n), numai acestea patru
ndeplinesc condit iile interne.
Mult imea A = A
1
A
2
... A
n
se numeste spat iul solut iilor posibile, iar elementele
x A ce satisfac condit iile interne se numesc solut ii rezultat. Ne propunem determinarea
tuturor solut iilor rezultat, eventual pentru a alege dintre ele pe aceea ce minimizeaza sau
maximizeaza o funct ie obiectiv.
Metoda Backtracking evita generarea tuturor solut iilor posibile (toate elementele pro-
dusului cartezian A
1
A
2
... A
n
). Construirea unei solut ii se face n mai mult i pasi,
elementele vectorului X primind valori pe rand: elementului x
k
A
k
, k = 1, n, i se atribuie
o valoare numai dupa ce au fost atribuite valori pentru componentele x
1
A
1
, x
2
A
2
,
. . ., x
k1
A
k1
. Metoda trece la atribuirea unei valori pentru x
k+1
A
k+1
doar daca
x
k
mpreuna cu x
1
, x
2
, . . . , x
k1
verica condit iile de continuare, notate cu
k
(x
1
, x
2
, . . . , x
k
).
Daca aceste condit ii
k
(x
1
, x
2
, . . . , x
k
) sunt ndeplinite se trece la cautarea unei valori pentru
elementul x
k+1
A
k+1
al solut iei.
Nendeplinirea condit iilor are urmatoarea semnicat ie: pentru orice alegere x
k+1
A
k+1
,
. . . , x
n
A
n
, nu vom putea ajunge la o solut ie rezultat n care condit iile interne sa e
ndeplinite.

In aceasta situat ie va trebui sancercam o alta alegere pentru x
k
, acest lucru ind
posibil doar daca nu am epuizat toate valorile disponibile din mult imea A
k
. Daca mult imea
A
k
a fost epuizata va trebui sa micsoram valoarea variabilei k cu o unitate (k k 1), si sa
trecem la alegerea unei alte valori pentru elementul x
k1
A
k1
. Micsorarea valorii curente
a variabilei k cu o unitate da numele metodei si semnica faptul ca atunci cand nu putem
avansa, vom urmari napoi secvent a curenta din solut ie. Faptul ca valorile v
1
, v
2
, . . . , v
k1
,
ale componentelor x
1
, x
2
, . . . , x
k1
, satisfac condit iile de continuare, nu este sucient pentru
a garanta obt inerea unei solut ii ale carei prime k 1 componente coincid cu aceste valori.
O alegere buna a condit iilor de continuare conduce la reducerea numarului de calcule,
ind de dorit ca aceste condit ii de continuare sa e nu numai necesare, dar si suciente
pentru obt inerea unei solut ii. Condit iile interne devin chiar condit ii de continuare pentru
k = n. Orice vector solut ie se obt ine progresiv ncepand cu prima componenta si deplasandu-
ne catre ultima, cu eventuale reveniri asupra valorilor atribuite anterior. Anumite valori sunt
consumate n urma unor atribuiri sau ncercari de atribuire esuate din cauza nendeplinirii
condit iilor de continuare.
Exista doua variante fat a de metoda standard:
solut iile pot avea numar variabil de componente;
dintre solut ii se alege cea care minimizeaza sau maximizeaza o funct ie cost sau o funct ie
obiectiv data.
Exemplul B.1 Enunt ul problemei: Se cere sa se genereze permutari de n elemente.
Rezolvare: Spat iul solut iilor este A =
n
i=1
A
i
, A
i
= {1, 2, . . . , n}, |A
i
| = n. Solut ia va
obt inuta n vectorul x = (x
1
, x
2
, . . . , x
n
) A
1
A
2
. . . A
n
.
La pasul k se ncearca atribuirea unui alt element din mult imea A
k
lui x
k
. Vom trece la
pasul k + 1 doar daca sunt ndeplinite condit iile de continuare: (x
1
, x
2
, . . . , x
k
) nu cont ine
elemente care se repeta. Deoarece aceasta vericare se face la ecare pas, este sucient sa
vericam daca valoarea elementului x
k
nu se regaseste printre valorile x
1
, x
2
, . . . , x
k1
(vezi
funct ia CanContinue() din algoritmul 68).
Exemplul B.2 Fie n = 4. Atunci A
i
va compus din elementele A
i
= {1, 2, 3, 4}.
Pentru k = 1, x
1
va primi valuarea 1 (vezi linia 15): 1
194
Pentru k = 2, se verica x
2
= 1, nsa nu se respecta condit iile de continuare (linia 16).
Astfel se trece la urmatoarea valoare, x
2
= x
1
+1 = 2 (linia 15). Pentru aceasta congurat ie
condit iile de continuare sunt ndeplinite, si se trece la pasul urmator, k = k + 1 = 3 (linia
24): 1 2
Se verica valorile 1, 2 si 3 pentru x
3
(linia 16), dintre care, numai ultima satisface
condit iile de continuare: 1 2 3
Ajunsi la ultimul pas, k = 4, se verica valorile 1, 2, 3 si 4 pentru x
4
.

In urma vericarii
condit iilor de continuare pentru x
4
= 4, se urmareste trecerea la pasul k = k+1 = 5. Deoarece
suntem la ultimul element al vectorului x (linia 21), se obt ine prima solut ie, ce se si aseaza:
1 2 3 4
Mai departe, nu mai exista valori netestate pentru x
4
(linia 14), si revenim la nivelul
anterior k = k1 = 3 (linia 28). Aici urmatoarea valoare din domeniul de valori nevericata
este x
3
= 4 (linia 15). Solut ia part iala respecta condit iile de continuare (linia 16), astfel ncat
se trece la nivelul urmator (linia 24), k = k + 1 = 4: 1 2 4
Pentru x
4
sunt vericate valorile, 1, 2, 3, 4 (liniile 1516), dintre acestea numai valoarea
3, conducand la o solut ie nala (linia 21): 1 2 4 3 Algoritmul se continua n acelasi
mod pana se obt in toate solut iile:
_

_
(1, 2, 3, 4)
(1, 2, 4, 3)
(1, 3, 2, 4)
(1, 3, 4, 2)
(1, 4, 2, 3)
(1, 4, 3, 2)
(2, 1, 3, 4)
(2, 1, 4, 3)
(2, 3, 1, 4)
(2, 3, 4, 1)
...
O varianta de implementare a algoritmului 68 n limbajul C este:
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define NN 100
int n;
int a[NN];
/**
* Functia citeste valorile datelor de intrare.
*/
void readInput(void) {
//se citeste numarul de elemente n
printf("n="); scanf("%d", &n);
}
195
Algoritm 68 Algoritm pentru generare permutari (varianta backtracking)
Input: n - numarul de elemente din mult imea init iala
1: function CanContinue(A, k)
2: for i 1, k 1 do
3: if (a
i
= a
k
) then
4: return false
5: end if
6: end for
7: return true
8: end function
9: procedure Permutari(n)
10: k 1
11: x
k
0
12: while (k > 0) do
13: gasit false
14: while (x
k
+ 1 n) (gasit = true) do
15: x
k
x
k
+ 1
16: if ((CanContinue(X, k)) = true) then
17: gasit true
18: end if
19: end while
20: if (gasit = true) then
21: if (k = n) then
22: Output {x
1
, . . . , x
n
}
23: else
24: k k + 1
25: x
k
0
26: end if
27: else
28: k k 1
29: end if
30: end while
31: end procedure
/**
* Functia afiseaza solutia calculata a problemei.
*/
void list(void) {
int i;
for (i = 1; i <= n; i++)
printf("%d ", a[i]);
printf("\n");
}
/**
* Functia de continuare: aici se verifica daca elementul de pe pozitia k
* nu se mai afla in sirul A.
*/
196
int canContinue(int k) {
int i;
for (i = 1; i <= k - 1; i++)
if (a[k] == a[i])
return FALSE;
return TRUE;
}
void run(void) {
int i;
int gata;
//initializare
i = 1; a[i] = 0;
while (i > 0) {
gata = FALSE;
while ((a[i] + 1 <= n) && !gata) {
/**
* cat timp exista elementul urmator si nu sunt verificate
* conditiile de continuare
*/
//treci la elementul urmator
a[i]++;
//verifica conditiile de continuare
if (canContinue(i))
gata = TRUE;
//sau: gata = canContinue(i);
}
if (gata)
//daca s-au verificat conditiile de continuare
if (i == n)
//daca suntem la ultimul element afisam solutia
list();
else { //altfel trecem la elementul urmator
i++;
a[i] = 0;
}
else
//altfel revenim la un element anterior si alegem o alta valoare
i--;
}
}
void main(void) {
read_data();
run();
}
Exemplul B.3 Enunt ul problemei: Sa se genereze combinari de n luate cate m (0
197
m n).
Rezolvare: Spat iul solut iilor este A =
m
i=1
A
i
, A
i
= {1, 2, . . . , n}, |A
i
| = n. Solut ia va
obt inuta n vectorul x = (x
1
, x
2
, . . . , x
m
) A
1
A
2
. . . A
m
(vezi algoritmul 69).
La pasul k se ncearca atribuirea unui alt element din mult imea A
k
lui x
k
. Condit ia de
continuare se refera la proprietatea ca elementele vectorului solut ie trebuie sa respecte relat ia
x
1
< x
2
< . . . < x
k
. Acest lucru se obt ine foarte usor prin urmatorul procedeu: la trecerea la
pasul k +1, variabila x
k+1
va primi, ca valoare init iala, valoarea curenta a variabilei x
k
(vezi
linia 15 din algorimul 69).
Pentru n = 5 si m = 3 avem: A =
3
i=1
A
i
= A
1
A
2
A
3
, unde A
1
= A
2
= A
3
=
{1, 2, 3, 4, 5}. Solut iile obt inute sunt:
_

_
(1, 2, 3)
(1, 2, 4)
(1, 2, 5)
(1, 3, 4)
(1, 3, 5)
(1, 4, 5)
(2, 3, 4)
(2, 3, 5)
(2, 4, 5)
(3, 4, 5)
Algoritm 69 Algoritm pentru generare combinari (varianta backtracking)
1: procedure Combinari(n, m)
2: k 1
3: x
k
0
4: while (k > 0) do
5: gasit false
6: while (x
k
+ 1 n) (gasit = true) do
7: x
k
x
k
+ 1
8: gasit true
9: end while
10: if (gasit = true) then
11: if (k = m) then
12: Output {x
1
, . . . , x
m
}
13: else
14: k k + 1
15: x
k
x
k1
16: end if
17: else
18: k k 1
19: end if
20: end while
21: end procedure

In continuare prezentam o implementare a algoritmului 69 n limbajul C:


198
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define NN 100
int n, m;
int a[NN];
/**
* Functia citeste valorile datelor de intrare.
*/
void readInput(void) {
printf("n="); scanf("%d", &n);
printf("m="); scanf("%d", &m);
}
/**
* Functia afiseaza solutia calculata de functia run().
*/
void list(void) {
int i;
for (i = 1; i <= m; i++)
printf("%d ", a[i]);
printf("\n");
}
void run(void) {
int i;
int gata;
//initializare
i = 1; a[i] = 0;
while (i > 0) {
gata = FALSE;
while ((a[i] + 1 <= n) && !gata) {
/**
* cat timp exista elementul urmator si nu sunt verificate
* conditiile de continuare, treci la elementul urmator
*/
a[i]++;
gata = TRUE;
}
if (gata)
//daca s-au verificat conditiile de continuare
if (i == m)
//daca suntem la ultimul element afisam solutia
list();
else { //altfel trecem la elementul urmator
i++;
199
a[i] = a[i - 1];
}
else
//altfel revenim la un element anterior si alegem o alta valoare
i--;
}
}
void main(void) {
readInput();
run();
}
Exemplul B.4 Problema damelor
Enunt ul problemei: Pe o tabla de sah cu n linii si n coloane (n n patrate), sa se
pozit ioneze n dame astfel ncat sa nu se atace reciproc.
Rezolvare: Tabla de sah va reprezentata prin matricea A = (a
ij
), i, j = 1, n. Doua
dame aate n pozit iile a
ij
si a
kl
se vor ataca reciproc daca:
i = k sau j = l sau |i k| = |j l|
Prima observat ie care se poate deduce se refera la faptul ca doua dame nu trebuie sa se
ae pe aceeasi linie sau pe aceeasi coloana.
Notam cu V = {1, 2, . . . , n} mult imea celor n coloane ale tablei de sah. Vectorul solut iei
rezultat X = (x
1
, x
2
, . . . , x
n
) V ... V are urmatoarea semnicat ie: componenta i a
vectorului (i = 1, n) reprezinta linia i de pe tabla de sah. Valoarea x
i
a acestei componente
reprezinta coloana pe care se aseaza dama de pe linia i (vezi algoritmul 70).
La nceput, toate damele sunt n afara tablei de sah, prin urmare x
i
= 0, i = 1, n.
La pasul k vom ncerca asezarea damei k (de pe linia k) pe coloana urmatoare (x
k
+ 1).
Init ial dama a k-a este pozit ionata n afara tablei (x
k
= 0 / V ). O dama poate asezata pe
o alta coloana daca vechea pozit ie satisface condit ia x
k
< n. Noua pozit ie (x
k
+1) trebuie sa
satisfaca condit iile interne
k
:
i, 1 i < k, x
i
= x
k
+ 1 (nu sunt pe aceeasi coloana);
|i k| = |x
i
(x
k
+ 1)| (nu sunt pe aceeasi diagonala).
Daca x
k
< n si
k
sunt adevarate, dama de pe linia k va pozit ionata pe coloana x
k
+ 1
si se trece la pasul k + 1, corespunzator pozit ionarii damei k + 1.

In caz contrar, dama k nu
poate asezata pe tabla si va trebui sa reluam pozit ionarea damei k 1.
Exemplul B.5 Problema colorarii hart ilor
Enunt ul problemei: Sa se coloreze o harta reprezentand n t ari folosind m culori
etichetate 1, . . . , m.
Rezolvare: Datele necesare pentru descrierea hart ii vor reprezentate de o matrice
A = (a
ij
), i, j = 1, n, ale carei elemente au urmatoarea semnicat ie:
a
ij
=
_
1 , daca t ara i are frontiera comuna cu t ara j
0 , n caz contrar
Matricea A M
nn
este simetrica si elementele de pe diagonala principala sunt nule:
a
ij
= a
ji
si a
ii
= 0.
200
Algoritm 70 Algoritm Problema damelor
Input: n - numarul de linii/coloane de pe tabla de sah
1: function CanContinue(A, k)
2: for j 1, k 1 do
3: if (a
j
= a
k
) ((k j) = |a
k
a
j
|) then
4: return false
5: end if
6: end for
7: return true
8: end function
9: procedure DameBacktracking(n)
10: i 1
11: x
i
0
12: while (i > 1) do
13: gasit false
14: while (x
i
+ 1 n) (gasit = true) do
15: x
i
x
i
+ 1
16: if (CanContinue(X, i) = true) then
17: gasit true
18: end if
19: end while
20: if (gasit = true) then
21: if (i = n) then
22: call Afis Solutie(x
1
, . . . , x
n
)
23: else
24: i i + 1
25: x
i
0
26: end if
27: else
28: i i 1
29: end if
30: end while
31: end procedure
Fie C = {c
1
, c
2
, . . . , c
m
} mult imea culorilor.
Vectorul solut iei rezultat X = (x
1
, x
2
, . . . , x
n
) C ... C, are urmatoarea semnicat ie:
t ara i are repartizata culoarea x
i
C, i = 1, n. La nceput, ecarei t ari i se va atribui valoarea
0.
La pasul k ncercam sa atribuim o noua culoare (x
k
+ 1) pentru t ara k, k = 1, n, daca
sunt ndeplinite condit iile:
1. x
k
< m (daca mai exista alte culori neatribuite pentru t ara k);
2. pentru i, 1 i < k cu a
i,k
= 1 avem x
i
= x
k
+ 1.
Daca cele doua condit ii anterioare sunt ndeplinite, atunci noua culoare pentru t ara k va
x
k
+1, si se va trece la pasul k +1 (stabilirea unei culori pentru t ara k +1).

In caz contrar,
t arii k nu i se mai poate atribui o alta culoare si ne ntoarcem la pasul k 1, corespunzator
alegerii unei noi culori pentru t ara k 1. Algoritmul se termina atunci cand nu mai exista
nici o culoare nevericata pentru t ara 1 (vezi algoritmul 71).
201
Algoritm 71 Algoritm Problema colorarii hart ilor
Input:
_

_
A - matricea de adiacent a/de vecinatate a t arilor
n - numarul de t ari
m - numarul de culori disponibile
1: function CanContinue(A, X, k)
2: for j 1, k 1 do
3: if (x
j
= x
k
) (a
j,k
= 1) then
4: return false
5: end if
6: end for
7: return true
8: end function
9: procedure ColorBacktracking(A, n, m)
10: k 1
11: x
k
0
12: while (k > 0) do
13: gasit false
14: while (x
k
+ 1 m) (gasit = true) do
15: x
k
x
k
+ 1
16: gasit CanContinue(A, X, k)
17: end while
18: if (gasit = true) then
19: if (k = n) then
20: call Afis Solutie(x
1
, . . . , x
n
)
21: else
22: k k + 1
23: x
k
0
24: end if
25: else
26: k k 1
27: end if
28: end while
29: end procedure
Exemplul B.6 Enunt ul problemei: Se da o suma s si n tipuri de monede avand valorile
a
1
, a
2
, . . . , a
n
lei. Realizat i un algoritm care sa determine o modalitate de plata a sumei s
utilizand un numar minim de monede.
Rezolvare:
#include <stdio.h>
#define FALSE 0
#define TRUE 1
#define NN 100
#define MAX 10000
int suma_plata; //suma ce trebuie platita
int n; //numarul de monezi
202
int limit[NN]; //limit[i] numarul maxim de monede de tipul val[i]
int val[NN]; //val[i] valoarea unei monede
int taken[NN]; //cate monede de valoare val[i] au fost luate
int minim; //numarul minim de monede cu care se poate face plata
int keep[NN]; //solutia optima pina la momentul curent
/**
* Se citesc datele de intrare: suma de plata, numarul de
* tipuri de monezi si valoarea fiecarui tip.
*/
void readInput(void) {
int i;
printf("Suma= "); scanf("%d", &suma_plata);
printf("Numarul de tipuri de monede: "); scanf("%d", &n);
for (i = 0; i < n; i++) {
printf("val[%d]=", i); scanf("%d", &val[i]);
limit[i] = suma_plata / val[i];
}
}
/**
* Se verifica daca sunt satisfacute conditiile de continuare:
* suma partiala sa nu depaseasca valoarea totala de platit.
* @param k - pasul curent
*/
int canContinue(int k) {
int i, suma_tmp;
suma_tmp = 0;
for (i = 0; i <= k; i++)
suma_tmp += val[i] * taken[i];
if ((k == n - 1 && suma_tmp == suma_plata)
|| (k != n - 1 && suma_tmp <= suma_plata))
return TRUE;
else
return FALSE;
}
/**
* Se pastreaza solutia actuala (taken) numai daca este
* mai buna decat cea anterioara (keep).
*/
void final(void) {
int i;
int monezi = 0;
//se numara cate monede sunt in solutie
for (i = 0; i < n; monezi += taken[i], i++);
if (monezi < minim) {
minim = monezi;
203
for (i = 0; i < n; i++)
keep[i] = taken[i];
}
}
/**
* Se afiseaza solutia optima sau mesajul Nu avem solutie.
*/
void print(void) {
int i, first = 0;
if (minim != MAX) { //verificam daca am obtinut o solutie
printf("%d =", suma_plata);
for (i = 0; i < n; i++)
if (keep[i] != 0) {
printf((first == 1) ? " + " : " ");
printf("%d X %d", keep[i], val[i]);
first = 1;
}
printf("\n");
}
else
printf("Nu avem solutie! \n");
}
/**
* Implementarea metodei backtracking.
*/
void run(void) {
int i;
int gata; /* are valoarea TRUE cand sunt verificate conditiile
de continuare */
minim = MAX;
i = 0; taken[i] = -1;
while (i >= 0) {
gata = FALSE;
while ((taken[i] + 1 <= limit[i]) && !gata) {
/* cat timp exista elementul urmator si nu sunt verificate conditiile
de continuare */
taken[i]++; //treci la elementul urmator
//verifica conditiile de continuare
if (canContinue(i))
gata = TRUE;
//sau: gata = canContinue(i);
}
if (gata) //daca s-au verificat conditiile de continuare
if (i == n-1)
//daca suntem la ultimul element pastram solutia
final();
else { //altfel trecem la elementul urmator
i++; taken[i] = -1;
204
}
else
//altfel revenim la un element anterior si alegem o alta valoare
i--;
}
}
void main(void) {
readInput();
run();
print();
}
205
Bibliograe
[1] A. Aho, J. Hopcroft, J. Ullman, On nding lowest common ancestors in trees, Proc. 5th
ACM Symp. Theory of Computing (STOC), pp. 253-265, 1973.
[2] A. V. Aho, J. E. Hopcroft, J. D. Ulmann, Data Structures and algorithms, Addison-
Wesley, 1983.
[3] A. V. Aho, J. D. Ulmann, Foundation of Computer Science, Computer Science Press,
1992.
[4] R. K. Ahuja, J. B. Orlin, A Fast and Simple Algorithm for the Maximum Flow Problem,
Operations Research, vol. 37(5), pp. 748759, 1989.
[5] R. Ahuja, T. Magnanti, J. Orlin, Network Flows, Prentice Hall, 1993.
[6] R. Andonie, I. Garbacea, Algoritmi fundamentali, o perspectiva C++, Editura Libris,
1995.
[7] C. Aragon, R. Seidel, Randomized Search Trees, in Proc. of 30th IEEE Symposium on
Foundations of Computer Science, pp. 540546, 1989.
[8] A. Atanasiu, Concursuri de informatica. Probleme propuse (1994), Editura Petrion,
Bucuresti, 1995.
[9] M.D. Atkinson, J.-R. Sack, N. Santoro, T. Strothotte, Min-max heaps and generalized
priority queues, Programming techniques and Data structures. Comm. ACM, vol. 29(10),
pp. 996-1000, 1986.
[10] M. Augenstein, A. Tenenbaum, Program eciency and data structures, Proceedings of
the eighth SIGCSE technical symposium on Computer science education, pp. 2127,
1977.
[11] S. Baase, Computer algorithms. Introduction to Design and Analysis, Addison-Wesley,
1992.
[12] P. Bazavan, Elemente de Teoria Algoritmilor, Editura Sitech, Craiova, 2007.
[13] R. Bellman, On a routing problem, Quarterly Applied Mathematics, XVI(1), pp. 87-90,
1958.
[14] M. A. Bender, M. Farach-Colton, The LCA problem revisited, Proceedings of the 4th
Latin American Symposium on Theoretical Informatics, LNCS, vol. 1776, Springer-
Verlag, pp. 88-94, 2000.
[15] J. Bentley, R. Sedgewick, Fast Algorithms for Sorting and Searching Strings, Proceedings
of the 8th Annual ACM-SIAM Symposium on Discrete Algorithms, 1997.
206
[16] J. Bentley, R. Sedgewick, Ternary Search Trees, Dr. Dobbs Journal, 1998.
[17] C. Bereanu, Algoritmica Grafurilor, Editura Sitech, Craiova, 2006.
[18] C. Berge, Graphes et hypergraphes, Dunod, Paris 1970.
[19] O. Berkman, D. Breslauer, Z. Galil, B. Schieber, si U. Vishkin, Highly parallelizable
problems, in Proceedings of the 21st Annual ACM Symposium on Theory of Computing,
pp. 309-319, 1989.
[20] O. Berkman, U. Vishkin, Recursive Star-Tree Parallel Data Structure, SIAM Journal on
Computing, vol.22(2), pp.221-242, 1993.
[21] O. Boruvka, O jistem problemu minimalnm (About a certain minimal problem), Acta
Societ. Scient. Natur. Moravicae, 3, pp. 37-58, 1926.
[22] R. P. Brent, An improved Monte Carlo factorization algorithm, BIT Numerical Mathe-
matics, Springer, vol. 20(2), pp. 176184, 1980.
[23] D. D. Burdescu, Analiza complexitat ii algoritmilor, Editura Albastra, ClujNapoca,
1998.
[24] D. D. Burdescu, M. Brezovan, M. Cosulschi, Structuri de date arborescente cu aplicat ii
n Pascal si C, Reprograa Universitat ii din Craiova, 2000.
[25] D. D. Burdescu, Liste, arbori, grafuri, Editura Sitech, Craiova, 2005.
[26] B. Chazelle, A minimum spanning tree algorithm with inverse-Ackerman type complexity,
J. ACM, 47, pp. 1028-1047, 2000.
[27] D. Cherition, R. E. Tarjan, Finding minimum spanning trees, SIAM Journal on Com-
puting, vol. 5, pp. 724-741, 1976.
[28] J. Cheriyan, K. Mehlhorn, Algorithms for dense graphs and networks on the random
access computer, Algorithmica, vol. 15, pp. 521-549, 1996.
[29] B. V. Cherkassky, Algorithm for construction of maximal ows in networks with com-
plexity of O(V
2

E), Mathematical Methods of Solution of Economical Problems, vol.


7, pp. 112125, 1977.
[30] T. H. Cormen, C. E. Leiserson, R. L. Rivest, Introducere n Algoritmi, Computer Libris
Agora, ClujNapoca, 1999.
[31] M. Cosulschi, M. Gabroveanu, Algoritmi o abordare pragmatica, Editia a 2-a, Universi-
taria, Craiova, 2004.
[32] C. Croitoru, Tehnici de baza n optimizarea combinatorie, Editura Univ. Al. I. Cuza Iasi,
Iasi, 1992.
[33] G. B. Dantzig, Linear programming and extensions, University Press, Princeton, 1962.
[34] S. Dasgupta, C. H. Papadimitriou, U. V. Vazirani, Algorithms, McGrawHill, 2006.
[35] C. Demetrescu, G. F. Italiano, Engineering Shortest Path Algorithms, WEA, Springer,
LNCS 3059, pp. 191198, 2004.
207
[36] R. B. Dial, Algorithm 360: shortest-path forest with topological ordering [H], Communi-
cations of the ACM, vol. 12:11, pp. 632633, 1969.
[37] Dict ionarul explicativ al limbii romane, Academia Romana, Institutul de Lingvistica
Iorgu Iordan, Editura Univers Enciclopedic, 1998.
[38] E. W. Dijkstra, A note on two problems in connections with graphs, Numerische Math-
ematik, 1, pp. 269-271, 1959.
[39] Y. Dinitz, Algorithm for solution of a problem of maximum ow in a network with power
estimation, Doklady Akademii nauk SSSR, vol. 11, pp. 1277-1280, 1970.
[40] Y. Dinitz, Dinitz Algorithm: The Original Version and Evens Version, in Oded Goldre-
ich, Arnold L. Rosenberg, and Alan L. Selman, Theoretical Computer Science: Essays
in Memory of Shimon Even, Springer, pp. 218-240, 2006.
[41] J. Edmonds, Paths, Trees and Flowers, Canadian J. Math, vol. 17, pp. 449-467, 1965.
[42] J. Edmonds, R. M. Karp, Theoretical improvements in algorithmic eciency for network
ow problems, Journal of the ACM, vol. 19(2), pp. 248-264, 1972.
[43] J. Egervary, Matrixok kombinatorius tulajdonsagairol, (in Hungarian), Matematikai es
Fizikai Lapok, vol. 38 pp. 16-28, 1931.
[44] J. Farey, On a Curious Property of Vulgar Fractions, London, Edinburgh and Dublin
Phil. Mag. 47, 385, 1816.
[45] J. Feng, G. Li, J. Wang, L. Zhou, Finding and ranking compact connected trees for
eective keyword proximity search in XML documents, Information Systems, vol. 35(2),
pp. 186203, 2010.
[46] L. R. Ford, Network ow theory, Technical Report P-923, RAND, Santa Monica, CA,
1956.
[47] L. R. Ford, Jr., D. R. Fulkerson, Maximal Flow Through a Network, Canadian Journal
of Mathematics, 8, pp. 399404, 1956.
[48] L. R. Ford, Jr., D. R. Fulkerson, A Simple Algorithm for Finding Maximal Network
Flows and an Application to the Hitchcock Problem, Canadian Journal of Mathematics,
9, pp. 210218, 1957.
[49] L. R. Ford, Jr., D. R. Fulkerson, Flows in Networks, Princeton University Press, Prince-
ton, 1962.
[50] C. L. Foster, The Design and Analysis of Algorithms, Springer Verlag, 1992.
[51] J.-C. Fournier, Graph Theory and Applications, Wiley-Blackwell, 2009.
[52] E. Fredkin, Trie Memory, Communications of the ACM, 3:(9), pp. 490, 1960.
[53] M. Fredman, R. Sedgewick, R. Sleator, R. Tarjan, The pairing heap: A new form of
self-adjusting heap, Algorithmica, 1, pp. 111129, 1986.
[54] M.L. Fredman, R.E. Tarjan, Fibonacci heaps and their use in improved network opti-
mization algorithms, Journal of the ACM, vol. 34, pp. 596-615, 1987.
208
[55] H. N. Gabow, R. E. Tarjan, A linear-time algorithm for a special case of disjoint set
union, Proceedings of the 15th ACM Symposium on Theory of Computing (STOC), pp.
246-251, 1983.
[56] H. N. Gabow, Path-based depth-rst search for strong and biconnected components, In-
formation Processing Letters, pp. 107-114, 2000.
[57] D. Gale, L. S. Shapley, College Admissions and the Stability of Marriage, American
Mathematical Monthly, vol. 69, pp. 914, 1962.
[58] Z. Galil, An O(V
5
3
E
frac23
) algorithm for the maximal ow problem, Acta Informatica,
vol. 14, pp. 221242, 1980.
[59] Z. Galil, A. Naamad, An O(EV (log V )
2
) algorithm for the maximal ow problem, Jour-
nal of Computer and System Sciences, vol. 21(2), pp. 203217, 1980.
[60] C. Giumale, Introducere n analiza algoritmilor, Editura Polirom, Iasi, 2004.
[61] A. V. Goldberg, A new max-ow algorithm, Technical Report MIT/LCS/TM-291, Lab-
oratory for Computer Science, MIT, 1985.
[62] A. V. Goldberg, R. E. Tarjan, A new approach to the maximum ow problem, in Pro-
ceedings of the 18th ACM Symposium on Theory of Computing, ACM, pp. 136146,
1986.
[63] A. V. Goldberg,

E. Tardos, R. E. Tarjan, Network ow algorithms, Algorithms and
Combinatorics, vol. 9. in B. Korte, L. Lovsz, H. J. Prmel, A. Schrijver, Editors, Paths,
Flows, and VLSI-Layout, Springer-Verlag, Berlin, pp.101-164, 1990.
[64] R. L. Graham, D. E. Knuth, O. Patashnik, Concrete Mathematics: A Foundation for
Computer Science, 2nd Edition, Addison-Wesley, 1994.
[65] D. Gries, The Science of Programming, Springer Verlag, Heidelberg, NewYork, 1981.
[66] L. Guo, F. Shao, C. Botev, J. Shanmugasundaram, XRANK: ranked keyword search over
XML documents, in Proceedings of the 2003 ACM SIGMOD International Conference
on Management of Data, pp. 1627, 2003.
[67] D. Guseld, Algorithms on Strings, Trees, and Sequences, Cambridge University Press,
1997.
[68] G. H. Hardy, E. M. Wright, An Introduction to the Theory of Numbers, 5th Edition,
Oxford University Press, 1979.
[69] D. Harel, R. E. Tarjan, Fast algorithms for nding nearest common ancestors, SIAM
Journal on Computing, vol. 13(2), pp. 338-355, 1984.
[70] T. E. Harris, F. S. Ross, Fundamentals of a Method for Evaluating Rail Net Capacities,
Research Memorandum RM-1573, The RAND Corporation, Santa Monica, California,
1955.
[71] I. N. Herstein, I. Kaplansky, Matters mathematical, 2nd Edition, Chelsea Publishing
Company, 1978.
209
[72] J. E. Hopcroft, R. Karp, An n
5
2
algorithm for maximum matchings in bipartite graphs,
SIAM Journal on Computing, vol. 2(4), pp.225-231, 1973.
[73] V. Hristidis , N. Koudas , Y. Papakonstantinou, D. Srivastava, Keyword Proximity
Search in XML Trees, IEEE Transactions on Knowledge and Data Engineering, vol.
18(4), pp. 525539, 2006.
[74] D. A. Human, A Method for the Construction of Minimum-Redundancy Codes, Pro-
ceedings of the I.R.E., 1952, pp. 1098-1102.
[75] C. Ionescu, I. Zsako, Structuri arborescente, Editura Tehnica, Bucuresti, 1990.
[76] V. Jarnk, O jistem problemu minimalnm (About a certain minimal problem), Prace
Moravske Prrodovedecke Spolecnosti, 6, pp. 5763, 1930.
[77] D. Jungnickel, Graphs, Networks and Algorithms, Algorithms and Computation in Math-
ematics, vol. 5, 3rd Edition, Springer, 2008.
[78] A. B. Kahn, Topological sorting of large networks, Communications of the ACM, vol.
5(11), pp. 558-562, 1962.
[79] D. Karger, P. Klein, R. Tarjan, A randomized linear-time algorithm to nd minimum
spanning trees, Journal of ACM, 42, pp. 321328, 1995.
[80] A. V. Karzanov, Determining the maximum ow in the network by the method of pre-
ows, Doklady Akademii nauk SSSR 15, pp. 434-437, 1974.
[81] B. W. Kernigham, D. M. Ritchie, The C Programming Language, 2nd Edition, Prentice
Hall, 1988.
[82] D. C. Kozen, The Design and Analysis of Algorithms. Texts and Monographs in Com-
puter Science, Springer, 1993.
[83] D. Konig, Theorie der endlichen und unendlichen Graphen, Leipzig: Akademische Ver-
lagsgesellschaft, 1936. Translated from German by Richard McCoart, Theory of nite
and innite graphs, Birkhauser, 1990.
[84] J. Kleinberg, E. Tardos, Algorithm Design, Addison-Wesley, 2005.
[85] D. E. Knuth, Arta programarii calculatoarelor, vol. 1 Algoritmi fundamentali, Teora,
Bucuresti, 1999.
[86] D. E. Knuth, Arta programarii calculatoarelor, vol. 2 Algoritmi seminumerici, Teora,
Bucuresti, 2000.
[87] D. E. Knuth, Arta programarii calculatoarelor, vol. 3 Sortare si Cautare, Teora, Bu-
curesti, 2001.
[88] J. B. Kruskal, On the shortest spanning subtree of a graph and the traveling salesman
problem, Proc. of the American Mathematical Society, 7, pp. 48-50, 1956.
[89] H. W. Kuhn, On combinatorial properties of matrices, Logistics Papers (George Wash-
ington University), vol. 11, pp. 1-11, 1955.
210
[90] H. W. Kuhn, The Hungarian Method for the assignment problem, Naval Research Lo-
gistics Quarterly, vol. 2, pp. 83-97, 1955.
[91] H. W. Kuhn, Variants of the Hungarian method for assignment problems, Naval Research
Logistics Quarterly, vol. 3, pp. 253-258, 1956.
[92] Y. Li , C. Yu , H. V. Jagadish, Schema-free XQuery, in Proceedings of the Thirtieth
International Conference on Very Large Databases (VLDB), pp. 7283, 2004.
[93] L. Livovschi, H. Georgescu, Analiza si sinteza algoritmilor, Ed. Stiint ica si Enciclope-
dica, Bucuresti, 1986.
[94] V. M. Malhotra, M. P. Kumar, S. N. Maheshwari, An O(|V |
3
) algorithm for nding
maximum ows in networks, Information Processing Letters, 7(6), pp.277278, 1978.
[95] K. Mehlhorn, Data Structures and Algorithms: Graph Algorithms and NP-Completeness,
Springer Verlag, 1984.
[96] S. Micali, V. V. Vazirani, An O(
_
|V | |E|) algorithm for nding maximum matching
in general graphs, Proc. 21st IEEE Symp. Foundations of Computer Science, pp. 17-27,
1980.
[97] V. Mitrana, Provocarea algoritmilor, Editura Agni, Bucuresti, 1994.
[98] E. F. Moore, The shortest path through a maze, in Proceedings of International Sympo-
sium on the Theory of Switching, Part II, pp. 285-292, 1959. (prezentat la simpozion la
Universitatea Harvard in aprilie 1957)
[99] R. Motwani, Average-case analysis of algorithms for matchings and related problems,
Journal of the ACM, vol. 41(6), pp. 1329-1356, 1994.
[100] J. Munkres, Algorithms for the Assignment and Transportation Problems, Journal of
the Society for Industrial and Applied Mathematics, vol. 5(1), pp. 32-38, 1957.
[101] G. Nivasch, Cycle detection using a stack, Information Processing Letters, vol. 90(3),
pp. 135140, 2004.
[102] I. Odagescu, F. Furtuna, Metode si tehnici de programare, Computer Libris Agora,
ClujNapoca, 1998.
[103] S. Pettie, A faster all-pairs shortest path algorithm for real-weighted sparse graphs, in
Proceedings of 29th International Colloquium on Automata, Languages, and Program-
ming (ICALP02), LNCS Vol. 2380, pp. 85-97, 2002.
[104] S. Pettie, V. Ramachandran, Computing shortest paths with comparisons and additions,
in Proceedings of the 13th Annual ACM-SIAM Symposium on Discrete Algorithms
(SODA02), SIAM, pp. 267-276, 2002.
[105] S. Pettie, V. Ramachandran, An optimal minimum spanning tree algorithm, Journal of
ACM, 49:1634, 2002.
[106] R. C. Prim, Shortest connection networks and some generalizations, Bell System Tech-
nical Journal, 36, pp. 1389-1401, 1957.
211
[107] B. Schieber, U. Vishkin, On nding lowest common ancestors: Simplication and par-
allelization, SIAM J. Comput., vol. 17, pp. 1253-1262, 1988.
[108] A. Schrijver, On the history of the transportation and maximum owproblems, Mathe-
matical Programming, vol. 91, issue 3, pp. 437-445, 2002.
[109] R. Seidel, C. Aragon, Randomized Search Trees, Algorithmica, vol. 16, pp. 464497,
1996.
[110] M. Sharir, A strong-connectivity algorithm and its applications in data fow analysis,
Computers and Mathematics with Applications, vol. 7(1), pp. 6772, 1981.
[111] Y. Shiloach, U. Vishkin, An O(n
2
log n) parallel max-ow algorithm, Journal of Algo-
rithms, vol. 3(2), pp. 128-146, 1982.
[112] S. Skiena, The Algorithm Design Manual, 2nd Edition, Springer, 2008.
[113] D. D. Sleator, An O(EV log V ) algorithm for maximum network ow, Technical Report,
STAN-CS-80-831, 1980.
[114] D. D. Sleator, R. E. Tarjan, A data structure for dynamic trees, Journal of Computer
Sciences, vol. 26, pp. 362391, 1983.
[115] J. Stasko, J. Vitter, Pairing heaps: Experiments and analysis, Communications of the
ACM, vol. 30(3), pp. 234-249, 1987.
[116] T. Takaoka, Theory of 2-3 heaps, Discrete Applied Mathematics, Vol. 126(1), 5th An-
nual International Computing and Combinatories Conference (COCOON99), pp. 115
128, 2003.
[117] R. Tarjan, Depthrst search and linear graph algorithms, SIAM Journal on Computing,
vol. 1(2), pp. 146160, 1972.
[118] R. E. Tarjan, Edge-disjoint spanning trees and depth-rst search, Algorithmica, vol.
6(2), pp. 171-185, 1976.
[119] R. E. Tarjan, Applications of path compression on balanced trees, Journal of the ACM,
vol. 26(4), pp. 690-715, 1979.
[120] R. E. Tarjan, A simple version of Karzanovs blocking ow algorithm, Operation Re-
search Letters, vol. 2, pp.265268, 1984.
[121] I. Tomescu, Grafuri si programare liniara, Ed. Didactica si Pedagogica, Bucuresti, 1975.
[122] I. Tomescu, Probleme de combinatorica si teoria grafurilor, Ed. Didactica si Pedagogica,
Bucuresti, 1981.
[123] I. Tutunea, Algoritmi, logica si programare, Reprograa Universitat ii din Craiova, 1993.
[124] I. Tutunea, S. Pescarus, Algoritmi si programe Pascal. (Culegere de probleme), Repro-
graa Universitat ii din Craiova, 1994.
[125] J. Vuillemin, A data structure for manipulating priority queues, Communications of
the ACM, vol. 21:4, pp. 309315, 1978.
212
[126] J. Vuillemin, A unifying look at data structures, Communications of the ACM, vol.
23:4, pp. 229-239, 1980.
[127] G. A. Waissi, A new Karzanov-type O(n
3
) max-ow algorithm, Mathematical and Com-
puter Modelling, vol. 16(2), pp.6572, 1992.
[128] H. S. Wilf, Algorithms and Complexity, Internet edition, 1996.
[129] J. W. J. Williams, Algorithm 232 - Heapsort, Communications of the ACM, vol. 7(6),
pp. 347-348, 1964.
[130] Y. Xu, Y. Papakonstantinou, Ecient keyword search for smallest LCAs in XML
databases, in Proceedings of the 2005 ACM SIGMOD International Conference on Man-
agement of Data, pp. 527538, 2005.
[131] D. Zaharie, Introducere n proiectarea si analiza algoritmilor, Eubeea, Timisoara, 2008.
213

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