cursuriag2014

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 variabil˘a .............................. 27 2.3 Metodaiterativ˘a .................................. 28 2.4 Teorema master ................................... 29 2.5 Exercit ¸ii ....................................... 31 3 Grafuri. Grafuri neorientate 34 3.1 Not ¸iuni de baz˘a ................................... 34 3.2 Operat ¸ii pe grafuri ................................. 39 3.3 Moduri de reprezentare ............................... 42 3.4 Parcurgerea grafurilor ............................... 46 3.4.1 Parcurgerea ˆ ınl˘at ¸ime (BF-Breadth-First) ................. 46 3.4.2 Parcurgerea D (D - Depth) ........................ 50 3.4.3 Parcurgerea ˆ ın adˆancime (DFS-Depth First Search) ........... 51 3.5 Componente conexe ................................. 55 3.6 Muchiecritic˘a .................................... 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 comis–voiajorului ........................ 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 c˘autare .............................. 97 5.3 Exercit ¸ii ....................................... 105 1

Upload: emilian-aei

Post on 20-Jan-2016

214 views

Category:

Documents


8 download

DESCRIPTION

Algoritmica grafurilor

TRANSCRIPT

Page 1: CursuriAG2014

Cuprins

1 Introducere ın algoritmi 31.1 Limbajul pseudocod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.2 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2 Elemente de analiza algoritmilor 232.1 Metoda substitutiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.2 Schimbarea de variabila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272.3 Metoda iterativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282.4 Teorema master . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292.5 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3 Grafuri. Grafuri neorientate 343.1 Notiuni de baza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343.2 Operatii pe grafuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.3 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.4 Parcurgerea grafurilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

3.4.1 Parcurgerea ın latime (BF-Breadth-First) . . . . . . . . . . . . . . . . . 463.4.2 Parcurgerea D (D - Depth) . . . . . . . . . . . . . . . . . . . . . . . . 503.4.3 Parcurgerea ın adancime (DFS-Depth First Search) . . . . . . . . . . . 51

3.5 Componente conexe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 553.6 Muchie critica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563.7 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

4 Grafuri euleriene si hamiltoniene 644.1 Grafuri Euleriene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

4.1.1 Algoritm pentru determinarea unui ciclu eulerian . . . . . . . . . . . . 654.1.2 Algoritmul lui Rosenstiehl . . . . . . . . . . . . . . . . . . . . . . . . . 684.1.3 Algoritmul lui Fleury . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

4.2 Grafuri Hamiltoniene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 744.2.1 Problema comis–voiajorului . . . . . . . . . . . . . . . . . . . . . . . . 76

5 Arbori. Arbori binari 875.1 Arbori binari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

5.1.1 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . 895.1.2 Metode de parcurgere . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

5.2 Arbori binari de cautare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 975.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105

1

Page 2: CursuriAG2014

6 Arbori oarecare 1096.1 Moduri de reprezentare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1096.2 Metode de parcurgere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126.3 Arbori de acoperire de cost minim . . . . . . . . . . . . . . . . . . . . . . . . . 117

6.3.1 Algoritmul lui Boruvka . . . . . . . . . . . . . . . . . . . . . . . . . . . 1196.3.2 Algoritmul lui Prim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1206.3.3 Structuri de date pentru multimi disjuncte . . . . . . . . . . . . . . . . 1236.3.4 Algoritmul lui Kruskal . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

6.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

7 Grafuri orientate 1347.1 Notiuni de baza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1347.2 Parcurgerea grafurilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1367.3 Sortarea topologica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1397.4 Componente tare conexe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

7.4.1 Algoritmul lui Kosaraju . . . . . . . . . . . . . . . . . . . . . . . . . . 1447.4.2 Algoritmul lui Tarjan . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1477.4.3 Algoritmul lui Gabow . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

7.5 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151

8 Distante ın grafuri 1568.1 Drumul minim de la un varf la celelalte varfuri . . . . . . . . . . . . . . . . . . 157

8.1.1 Algoritmul lui Moore . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1578.1.2 Algoritmul lui Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

8.2 Drumuri minime ıntre toate perechile de varfuri . . . . . . . . . . . . . . . . . 1668.2.1 Algoritmul lui Roy-Floyd-Warshall . . . . . . . . . . . . . . . . . . . . 166

8.3 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170

9 Fluxuri ın retele de transport 1749.1 Retea de transport. Flux. Taietura . . . . . . . . . . . . . . . . . . . . . . . . 1749.2 Graf rezidual. Drum de ameliorare. Flux maxim–taietura minima . . . . . . . 1789.3 Metoda Ford-Fulkerson . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

9.3.1 Algoritmul Ford-Fulkerson (varianta) . . . . . . . . . . . . . . . . . . . 1829.4 Exercitii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

A Probleme. Algoritmi. Complexitate 188A.0.1 Verificare ın timp polinomial . . . . . . . . . . . . . . . . . . . . . . . . 190A.0.2 Reduceri polinomiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

B Metoda Backtracking 193

2

Page 3: CursuriAG2014

Capitolul 1

Introducere ın algoritmi

Definitia 1.1 Algoritmul constituie o reprezentare finita a unei metode de calcul ce per-mite rezolvarea unei anumite probleme. Se poate spune ca un algoritm reprezinta o secventafinita de operatii, ordonata si complet definita, care, pornind de la datele de intrare, producerezultate.

Termenul de algoritm ıi este atribuit matematicianului persan Abu Ja‘far Mohammedibn Musa al-Khowarizmi (sec. VIII-IX), care a scris o carte de matematica cunoscuta ıntraducere 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 ıntelegeau prin algoritm o regula (sau o multime de reguli)pe baza careia se efectuau calcule aritmetice: de exemplu ın secolul al XVI-lea, algoritmii sefoloseau la ınmultiri sau ınjumatatiri de numere.

Fiecare propozitie ce face parte din descrierea unui algoritm este de fapt o comanda cetrebuie executata de cineva, acesta putand fi o persoana sau o masina de calcul. De altfel,un algoritm poate fi descris cu ajutorul oricarui limbaj, de la limbajul natural si pana lalimbajul de asamblare al unui calculator. Denumim limbaj algoritmic un limbaj al carui scopeste acela de a descrie algoritmi.

Algoritmul specifica succesiuni posibile de transformari ale datelor. Un tip de date poatefi caracterizat printr-o multime de valori ce reprezinta domeniul tipului de date si o multimede operatii definite peste acest domeniu. Tipurile de date pot fi organizate ın urmatoarelecategorii:

1. tipuri de date elementare (de exemplu tipul ıntreg, tipul real) - valorile sunt unitatiatomice de informatie;

2. tipuri de date structurate (de exemplu tipul tablou, tipul ınregistrare) - valorile suntstructuri relativ simple rezultate ın urma combinatiei unor valori elementare;

3. tipuri de date structurate de nivel ınalt (de exemplu stiva) - se pot descrie independentde limbaj iar valorile au o structura mai complexa.

Un algoritm trebuie sa posede urmatoarele trasaturi caracteristice:

1. claritate - la fiecare pas trebuie sa specifice operatia pe care urmeaza sa o efectuezealgoritmul asupra datelor de intrare;

2. corectitudine - rezultatele trebuie sa fie corecte;

3

Page 4: CursuriAG2014

3. generalitate - algoritmul trebuie sa ofere solutia nu numai pentru o singura problemaci pentru o ıntreaga clasa de probleme;

4. finitudine - algoritmul trebuie sa se termine ıntr-un timp finit;

5. eficienta - un algoritm poate fi utilizat numai ın situatia ın care resursele de calculnecesare acestuia sunt ın cantitati rezonabile, si nu depasesc cu mult posibilitatile 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, dinaceasta cauza nefiind posibila deprinderea numai pe cale mecanica. Pentru a facilitaobtinerea unei solutii la o problema concreta se recomanda folosirea tehnicilor generalede elaborare a algoritmilor la care se adauga ın mod hotarator intuitia programatorului;

• exprimare - implementarea unui algoritm intr-un limbaj de programare se poate faceutilizand mai multe stiluri: programare structurata, programare orientata pe obiecteetc.;

• validare - verificarea corectitudinii algoritmului prin metode formale;

• analiza - stabilirea unor criterii pentru evaluarea eficientei unui algoritm pentru a-iputea compara si clasifica.

Un model de reprezentare al memoriei unei masini de calcul este acela al unei structuriliniare compusa din celule, fiecare celula fiind identificata printr-o adresa si putand pastra ovaloare corespunzatoare unui anumit tip de data. Accesul la celule este facilitat de variabile.O variabila se caracterizeaza prin:

• un identificator - un nume ce refera variabila;

• o adresa - desemneaza o locatie 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 suficient de riguroasa a algoritmilor, de aceea, pentrureprezentarea acestora se folosesc alte modalitati de descriere precum:

• scheme logice;

• limbajul pseudocod.

In continuare vom prezenta pricipalele constructii din cadrul limbajului pseudocod.

Intrari/iesiri

Citirea datelor de intrare se poate realiza prin intermediul enuntului Input :1: Input lista variabile

Afisarea rezultatelor este reprezentata cu ajutorul instructiunii Output :1: Output lista de valori

4

Page 5: CursuriAG2014

Instructiunea de atribuire

Este instructiunea cel mai des utilizata ıntr-un algoritm si realizeaza ıncarcarea unei variabile(locatii 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 locatia de memorie asociata. Aceasta variabila trebuie sa fie de acelasi tipde data cu expresia sau un tip de data care sa includa si tipul expresiei.

O expresie este constituita din operanzi si operatori. Operanzii pot fi variabile si valoriconstante, iar operatorii pot fi:

• operatori aritmetici - + (adunare), − (scadere), ∗ (ınmultire), / (ımpartire), ˆ (ridicarela putere), div (catul ımpartirii ıntregi), mod (restul ımpartirii ıntregi);

• operatori relationali - = (egal), 6= (diferit), < (strict mai mic), ≤ (mai mic sau egal),> (strict mai mare), ≥ (mai mare sau egal);

• operatori logici - OR sau ∨ (disjunctie), AND sau ∧ (conjunctie), NOT sau ¬ (negatie).

Cea mai simpla expresie este formata dintr-o variabila sau o constanta (operand). Ex-presiile mai complicate se obtin din operatii efectuate ıntre variabile si constante. La scriereaexpresiilor trebuie sa se tina cont de faptul ca, ın momentul evaluarii lor, ın primul randse vor evalua expresiile din paranteze, iar operatiile se executa ın ordinea determinata deprioritatile lor.

Enunturi de ramificare

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

Enuntul if...then...else evalueaza mai ıntai expresia booleana pentru a determinaunul din cele doua drumuri pe care le poate lua executia algoritmului. Ea poate includeoptional o clauza else.

Daca <expresie-booleana> se evalueaza la valoarea de adevar true, atunci se executa<instructiune1> si se continua cu urmatoarea instructiune dupa if. Daca <expresie-booleana>are valoarea de adevar false, atunci se executa <instructiune2>. <instructiune1> si <instructiune2>sunt instructiuni compuse ce pot sa contina, la randul lor, o alta instructiune if.

Exemplul 1.1 Un algoritm simplu este cel ce rezolva ecuatia de gradul I, ax+b = 0, a, b ∈ R

(algoritmul 1). Acesta se bazeaza pe rezolvarea matematica generala a ecuatiei de gradul I:

1. daca a = 0, atunci ecuatia devine 0 · x + b = 0. Pentru cazul ın care b 6= 0 avem0 · x + b = 0, egalitate ce nu poate fi satisfacuta pentru nicio valoare a lui x ∈ R sau C.Spunem ın acest caz ca ecuatia este incompatibila. Daca b = 0, avem 0·x+0 = 0, relatiafiind adevarata pentru orice valoare a lui x ∈ R. Spunem ca ecuatia este compatibilnedeterminata.

5

Page 6: CursuriAG2014

Algoritm 1 Algoritm pentru rezolvarea ecuatiei de gradul I1: Input a, b2: 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← − ba

10: Output ’Solutia este:’, x 11: end if

2. daca a 6= 0, ecuatia are o singura solutie, x1 = − ba∈ R.

Avand acest algoritm drept model sa se realizeze un algoritm pentru rezolvarea ecuatiei degradul al II-lea, ax2 + bx + c = 0, unde a, b, c ∈ R.

Enunturi repetitive

Enunturile repetitive permit descrierea unor prelucrari ce trebuie efectuate ın mod repetat,ın functie de pozitia conditiei de continuare existand doua variante de structuri repetitive:structura repetitiva conditionata anterior si structura repetitiva conditionata posterior.

Structura repetitiva conditionata anterior while (sau instructiune de ciclare cu test initial)are sintaxa:

1: while <expresie-booleana> do

2: <instructiune>3: end while

1: sum← 02: i← 13: while (i ≤ n) do

4: sum← sum + i5: i← i + 16: 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 fie realizataniciodata. Acest comportament este exact opus celui corespunzator structurii repetitiveconditionata posterior repeat, unde <instructiune> este executata cel putin o data. (Dacao expresie are valoarea de adevar true spunem atunci ca expresia este adevarata; daca oexpresie are valoarea de adevar false spunem atunci ca expresia nu este adevarata – estefalsa).

Exemplul 1.2 Vom realiza un algoritm pentru calculul catului si restului ımpartirii a douanumere ıntregi, prin scaderi succesive (vezi algoritmul 2).

Mai ıntai se initializeaza catul cu valoarea zero (linia 3) si restul cu valoarea deımpartitului(linia 4). Apoi, atata timp cat restul este mai mare decat valoarea ımpartitorului (liniile 5 -8), vom incrementa catul cu o unitate, si decrementa restul cu valoarea ımpartitorului. Lafinal, sunt afisate valorile catului si restului.

Un caz particular de structura repetitiva conditionata anterior este for, utilizata ın cazulın care o instructiune sau un grup de instructiuni trebuie sa se repete de 0 sau mai multeori - numarul de repetitii fiind cunoscut ınainte de ınceperea sa. Enunturile repetitive bazate

6

Page 7: CursuriAG2014

Algoritm 2 Algoritm pentru calculul ımpartirii ıntregi

1: Input a, b2: if ((a > 0) ∧ (b > 0)) then

3: cat← 04: rest← a5: while (rest ≥ b) do

6: rest← rest− b7: cat← cat + 18: end while

9: Output cat, rest10: else

11: Output ’Numerele trebuie sa fie strict pozitive!’12: end if

pe instructiunile while si repeat sunt mult mai potrivite ın cazul ın care conditia de ter-minare trebuie reevaluata ın timpul ciclarii (atunci cand numarul de repetitii nu este cunoscutapriori).

Instructiunea for are urmatoarea sintaxa:

1: for <Var> ← <Expresie1>, <Expresie2>,Step < p > do

2: <instructiune>3: end for

1: sum← 02: for i← 1, n do

3: sum← sum + i4: end for

Comportamentul enuntului repetitiv for se descrie cel mai bine prin comparatie cuenuntul repetitiv while. Astfel secventa urmatoare de limbaj pseudocod1: for v ← e1, e2 STEP p do

2: < instructiune >3: end for

este echivalenta cu secventa ce contine enuntul repetitiv while:1: v ← e1

2: while (v ≤ e2) do

3: <instructiune>4: v ← v + p5: end while

e1 reprezinta valoarea initiala, e2 limita finala, iar p pasul de lucru: la fiecare pas, valoareavariabilei v este incrementata cu valoarea lui p, ce poate fi atat pozitiva cat si negativa. Dacap ≥ 0 atunci v va lua valori ın ordine crescatoare, iar daca p < 0 atunci v va primi valori ınordine descrescatoare.

In cazul ın care pasul de incrementare este 1, atunci el se poate omite din enuntul repetitivfor, variabila contor fiind incrementata automat la fiecare repetitie cu valoarea 1. Daca pasulde incrementare p are valoarea 1 atunci avem urmatoarele situatii posibile pentru constructiafor:

• Expresie1 > Expresie2: <instructiune> nu se executa niciodata;

• Expresie1 = Expresie2: <instructiune> se executa exact o data;

• Expresie1 < Expresie2: <instructiune> se executa de Expresie2−Expresie1+1 ori.

Exemplul 1.3 Un caz destul de frecvent ıntalnit ın practica este cel ın care se cere aflareaelementului maxim, respectiv minim dintr-un sir de elemente. Acest sir de elemente poate fi

7

Page 8: CursuriAG2014

pastrat ıntr-o structura de date elementara, cunoscuta sub numele de vector. Un vector esteun caz particular de matrice avand o singura linie si n coloane.

Prezentam ın continuare algoritmul pentru determinarea elementului de valoare minimace face parte dintr-un sir de numere naturale (vezi algoritmul 3).

Algoritm 3 Algoritm pentru calculul elementului de valoare minima dintr–un sir1: Input N,x1, x2, ..., xN 2: min← x1

3: for i← 2, N do

4: if (min > xi) then

5: min← xi

6: end if

7: end for

8: Output min

In acest algoritm se observa utilizarea enuntului repetitiv for, ıntalnit, ın general, ınsituatiile ın care se cunoaste apriori numarul de pasi pe care trebuie sa-l realizeze instructiunearepetitiva.

Mai ıntai se initializeaza variabila min cu x1, presupunand ca elementul de valoareminima este primul element din cadrul vectorului X (linia 2). In continuare vom com-para valoarea variabilei min cu valoarea fiecarui element din sir (liniile 3–7): daca vom gasiun element a carui valoare este mai mica decat cea a minimului calculat pana la momentulcurent (linia 4), vom retine noua valoare ın variabila min (linia 5).

Structura repetitiva conditionata posterior repeat. . .until prezinta urmatoarea sintaxa:

1: repeat

2: <instructiune>3: until <expresie-booleana>

1: sum← 02: i← 13: repeat

4: sum← sum + i5: i← i + 16: until (i > n)

Atata timp cat <expresie-booleana> este falsa, se executa <instructiune>. Se observafaptul ca instructiunile dintre repeat si until se vor executa cel putin o data.

Exemplul 1.4 Algoritmul 4 prezentat ın continuare calculeaza suma primelor n numerenaturale, S = 1 + 2 + 3 + . . . + n.

Notam cu Sn suma primelor n numere naturale (Sn = 1 + 2 + 3 + . . . + n). Aceasta sepoate calcula ıntr-o maniera incrementala astfel:

S1 = 1

S2 = 1 + 2 = S1 + 2

S3 = (1 + 2) + 3 = S2 + 3

S4 = (1 + 2 + 3) + 4 = S3 + 4

. . .

Sn = (1 + 2 + . . . + n− 1) + n = Sn−1 + n

Observatia 1.5 1. Algoritmul 4 utilizeaza enuntul repetitiv cu test final, repeat ...until.

8

Page 9: CursuriAG2014

Algoritm 4 Algoritm pentru calculul sumei primelor n numere naturale (prima varianta)

1: Input N2: S ← 03: i← 14: repeat

5: S ← S + i6: i← i + 17: until (i > N)8: Output S

2. Enunturile S ← 0 si i ← 1 au rolul de a atribui valori initiale variabilelor S si i.Intotdeauna variabilele trebuie initializate corect din punctul de vedere al algoritmuluide calcul. Variabila ce retine rezultatul unui proces de ınsumari succesive se va initializaıntotdeauna cu 0, valoare ce nu va influenta rezultatul final. O variabila ce pastreazarezultatul unei sume sau al unui produs se va initializa cu elementul neutru fata deoperatia respectiva.

3. Atribuirile i = i + 1 si S = S + i (liniile 5 si 6) sunt lipsite de sens din punct de vederealgebric. Insa atunci cand ne referim la un sistem de calcul electronic, aceste operatiise refera la valoarea curenta si la cea anterioara a unei variabile. De asemenea, trebuiesa se faca o distinctie clara ıntre operatia de atribuire si cea de egalitate: operatia deatribuire (’←’) face ca valoarea curenta a variabilei din stanga operatorului de atribuiresa fie initializata cu valoarea expresiei din dreapta acestuia (ın expresia ’k ← i + 2’variabila k primeste valoarea rezultata ın urma evaluarii expresiei ’i + 2’), pe candoperatia de egalitate verifica daca valoarea elementului din stanga operatorului ’=’ (saua expresiei aflate ın partea stanga a operatorului) este egala cu valoarea expresiei dindreapta acestuia (de exemplu rezultatul evaluarii expresiei k = i + 2) are valoarea deadevar true daca valoarea variabilei ’k’ este egala cu valoarea rezultata ın urma evaluariiexpresiei ’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 valoareaanterioara 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 sesimplifica foarte mult (vezi algoritmul 5).

Algoritm 5 Algoritm pentru calculul sumei primelor n numere naturale (a doua varianta)

1: Input N2: S ← n · (n + 1)/23: Output S

Proceduri si functii

Procedurile sunt subrutine ale caror instructiuni se executa ori de cate ori acestea sunt apelateprin numele lor.

9

Page 10: CursuriAG2014

Apelarea procedurilor se face ın unitatea de program apelanta prin numele procedurii,primit la definire, urmat de lista parametrilor actuali. Aceasta trebuie sa corespunda canumar si tip cu lista parametrilor formali, ın situatia ın care exista o lista de parametriformali ın antetul subrutinei. Definitia unei proceduri are urmatoarea sintaxa:1: procedure <nume>(<lista parametri formali>)2: <instructiune>3: end procedure

lista parametri formali (optionala) simbolizeaza o lista de identificatori (parametri) cepermite transferul datelor ıntre subrutina apelanta si subrutina apelata. Acesti parametri sespecifica prin nume (identificator) urmat, eventual, de tipul de data al parametrului. Maimulti parametri de acelasi tip pot fi grupati, folosindu-se drept separator virgula.

De fapt, lista parametrilor formali poate fi descrisa mai detaliat astfel:1: procedure <nume>(<PFI; PFO>)2: end procedure

undePFI = lista parametrilor formali de intrare.PFO = lista parametrilor formali de iesire.Enuntul 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.Corespondenta se face de la stanga la dreapta si trebuie sa fie de acelasi tip cu parametriiformali.

PAO - lista parametrilor actuali de iesire.

Exemplul 1.6 Sa se realizeze un algoritm care determina cel mai mare divizor comun adoua numere naturale.

Reamintim cateva rezultate teoretice ce vor fi folositoare pentru ıntelegerea procesului decalcul al algoritmului ce va fi prezentat.

Teorema 1.7 (Teorema ımpartirii cu rest) Pentru doua numere ıntregi a si b, cu b 6=0, ∃ doua numere ıntregi q si r, unice, astfel ıncat:

a = b · q + r, 0 ≤ r < |b|

unde a se numeste deımpartitul, b ımpartitorul, q catul iar r restul.

Definitia 1.2 Cel mai mare divizor comun (notat cmmdc) a doua numere naturale a si beste un numar natural d cu proprietatile:

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 dividesi pe d).

Observatia 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 urmatoarearelatie:

cmmmc(a, b) =a · b

cmmdc(a, b)(1.1)

10

Page 11: CursuriAG2014

Metoda de calcul pentru a obtine cel mai mare divizor comun a doua numere a si b prinımpartiri succesive, cunoscuta sub numele de algoritmul lui Euclid, se poate descrie astfel:

Se ımparte a la b si se retine restul r. Daca r este nul atunci cel mai mare divizor comuneste b. In caz contrar, se ımparte b la r si se pastreaza noul rest. Calculele se continua,folosindu-se ca deımpartit vechiul ımpartitor iar ca ımpartitor ultimul rest obtinut, panacand restul obtinut devine nul.

Operatiile anterioare pot fi transpuse prin intermediul urmatoarelor formule matematice:

a = bq1 + r1 0 ≤ r1 < b

b = r1q2 + r2 0 ≤ r2 < r1

r1 = r2q3 + r3 0 ≤ r3 < r2

. . .

rk = rk+1qk+2 + rk+2 0 ≤ rk+2 < rk+1

. . .

rn−2 = rn−1qn + rn 0 ≤ rn < rn−1

rn−1 = rnqn+1 + rn+1 0 ≤ rn+1 < rn

Aceste ımpartiri nu se constituie ıntr-un proces infinit, deoarece secventa de numere natu-rale r1, r2, . . . , rn+1, . . . este strict descrescatoare (r1 > r2 > . . . > rn > . . .) si marginitainferior de 0. Rezulta ca ∃p ∈ N astfel ıncat rp 6= 0, si rp+1 = 0.

Algoritm 6 Algoritmul lui Euclid pentru calculul cmmdc a doua numere

1: procedure cmmdc(x, y; b)2: a← x3: b← y4: if (b = 0) then

5: b← a6: else

7: r ← a mod b8: while (r 6= 0) do ⊲ Procesul se ıncheie atunci cand r ia valoarea 09: a← b

10: b← r11: r ← a mod b12: end while

13: end if

14: end procedure

Daca analizam ıntregul proces de calcul, se observa faptul ca deımpartitul este ımpartitorulde la etapa anterioara, iar ımpartitorul este restul de la etapa anterioara. De asemenea, tre-buie mentionat ca ın acest proces de calcul catul nu participa activ.

Algoritmul 6 este un foarte bun exemplu de utilizare a instructiunii de ciclare cu testinitial, while. Din analiza algoritmului reiese faptul ca, mai ıntai se efectueaza o evaluare arestului r (calculul sau, liniile 7 si 11), dupa care se testeaza conditia egalitatii acestuia cu 0(linia 8).

Functiile au aceeasi sintaxa ca si procedurile:1: function <nume>(<parametri>)2: <instructiune>3: end function

Functiile pot fi apelate prin numele lor, ca termen al unei expresii.

11

Page 12: CursuriAG2014

1.2 Exemple

Exemplul 1.9 Sa se verifice printr-un algoritm daca un numar natural este prim sau nu.

Definitia 1.3 Un numar natural k ≥ 2 se numeste prim daca singurii sai divizori naturalisunt 1 si k.

Pe baza acestei definitii se poate concluziona ca un numar natural k este prim daca nu areniciun divizor propriu ın intervalul [2, k − 1].

Algoritm 7 Algoritm pentru verificarea daca un numar este prim

1: Input N 2: if (n < 2) then

3: Output ’Numarul nu este prim.’4: else

5: i← 26: prim← true7: while ((i ≤ n− 1) ∧ (prim = true)) do

8: if (n mod i = 0) then

9: prim← false10: else

11: i← i + 112: 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 enuntului de ciclare while se va executa de n − 2 ori(vezi algoritmul 7).

Conditia i ≤ n− 1 poate fi ımbunatatita cu i ≤ n/2, deoarece ıntre jumatatea numaruluisi 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 nueste divizor al lui n atunci nici n/2 nu este divizor al lui n. Un enunt asemanator este valabilsi pentru numerele 3, 4, 5, . . .. Astfel se formeaza doua siruri:

2corespunde→ n

2

3corespunde→ n

3

4corespunde→ n

4...

...

k︸︷︷︸

corespunde→ n

k︸︷︷︸

Sir1 Sir2

Se observa faptul ca primul sir (Sir1) este compus din elemente cu valori consecutive,iar al doilea sir (Sir2) nu respecta aceasta proprietate. Numerele dintr–o pereche (p, n

p) sunt

12

Page 13: CursuriAG2014

legate ıntre ele astfel: ın momentul ın care am verificat faptul ca numarul p nu este divizoral lui n, implicit am dedus ca nici n/p nu este un divizor al lui n. Prin urmare nu mai estenevoie sa verificam si valoarea n/p. Primul sir este strict crescator iar cel de-al doilea estestrict descrescator. Elementele din primul sir devin mai mari decat cele din al doilea atuncicand k ≅ n/k ⇒ k2 ≅ n ⇒ k ≅

√n. Astfel rezulta conditia pentru limita superioara a

ciclarii: i ≤ ⌊√n⌋ (vezi algoritmul 8).

Algoritm 8 Algoritm pentru verificarea 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← 26: prim← true7: while ((i ≤ ⌊√n⌋) ∧ (prim = true)) do

8: if (n mod i = 0) then

9: prim← false10: else

11: i← i + 112: 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 an,n ≥ 0:

an =n∑

k=0

1

k!. (1.2)

Analizand structura termenului general al sirului an,

an =1

0!+

1

1!+

1

2!+ . . . +

1

(n− 1)!+

1

n!(1.3)

se observa ca avem relatia:

an+1 − an =1

(n + 1)!.

Se noteaza tn = 1n!

. Vom calcula termenul an pana cand diferenta dintre doi termeni consecu-tivi ai sirului este mai mica decat ǫ:

|an − an−1| < ǫ⇒ 1

n!< ǫ⇒ tn < ǫ. (1.4)

Pe de alta parte avem urmatoarea relatie ıntre doi termeni consecutivi ai sirului tn

tn+1 =tn

n + 1, (1.5)

pe care o vom folosi pentru a reduce numarul de calcule efectuate de algoritmul 9.

13

Page 14: CursuriAG2014

Algoritm 9 Algoritm pentru calculul limitei unui sir de numere cu aproximare1: Input ǫ2: a← 1, t← 1, k ← 13: while (t ≥ ǫ) do

4: a← a + t5: t← t

k+16: k ← k + 17: end while

8: a← a + t9: 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 verifica daca un vector de numere ıntregi estesimetric.

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 elementeledin vector corespunzatoare variabilelor de indiciere sunt egale, se incrementeaza variabila dinstanga si se decrementeaza variabila din dreapta. Dupa parasirea instructiunii de ciclare, seface o verificare pentru determinarea conditiei care nu a mai fost ındeplinita si a condus laiesirea din bucla. Daca i ≥ j atunci conditia (i < j) nu a mai fost ındeplinita. Acest lucruconduce la concluzia ca cealalta conditie, (xi = xj) a fost ındeplinita tot timpul (∀i < j, i, j =1, n). Deci sirul este simetric ın aceasta situatie.

Algoritm 10 Algoritm pentru verificarea simetriei unui vector

1: Input N,x1, x2, ..., xN 2: i← 1, j ← N3: while ((i < j) ∧ (xi = xj)) do

4: i← i + 15: j ← j − 16: 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, . . .. Pentruun numar natural n dat, sa se determine cel de-al n-lea element al sirului. De exemplu, celde-al 5-lea element al sirului prezentat este 2.

Dupa cum se observa din constructia sirului, acesta este format din concatenarea maimultor secvente de numere naturale consecutive, fiecare secventa ıncepand cu valoarea 1.Lungimea fiecarei subsecvente este cu o unitate mai mare decat lungimea subsecventei ante-rioare: astfel prima subsecventa are lungimea 1, a doua subsecventa are lungimea 2, a treiasubsecventa 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 esteposibil acest lucru. Valoarea cu care ramane variabila index reprezinta cel de-al n-lea elemental sirului.

Se poate optimiza algoritmul 11 astfel ıncat sa renuntam la enuntul de ciclare cu testinitial while, procesul de calcul efectuand astfel mai putine calcule (exercitiu).

14

Page 15: CursuriAG2014

Algoritm 11 Algoritm pentru determinarea celui de–al n–lea element

1: Input N2: k ← 13: index← N4: while (k < index) do

5: index← index− k6: k ← k + 17: end while

8: Output ’Cel de-al n-lea element este’, index

Exemplul 1.13 Se dau doua siruri de numere naturale, a1, a2, . . . , an si b1, b2, . . . , bn (ai, bi ∈N). Sa se determine doua numere naturale d si e (d, e ∈ N) astfel ıncat:

(a21 + b2

1) · (a22 + b2

2) · . . . (a2n + b2

n) = d2 + e2

Vom demonstra prin inductie matematica faptul ca

∀ai, bi ∈ N, i = 1, n, ∃d, e ∈ N astfel ıncat (a21 + b2

1) · (a22 + b2

2) · . . . (a2n + b2

n) = d2 + e2 (1.6)

Fie n = 2. Ar trebui sa determinam valorile necunoscutelor d si e astfel ıncat sa avem(a2

1 + b21) · (a2

2 + b22) = d2 + e2.

Daca vom considera

d = a1a2 + b1b2

e = a1b2 − b1a2

atunci, dupa efectuarea calculelor obtinemd2+e2 = (a1a2+b1b2)

2+(a1b2−b1a2)2 = a2

1a22+b2

1b22+2a1a2b1b2+a2

1b22+b2

1a22−2a1a2b1b2 =

a21a

22 + b2

1b22 + a2

1b22 + b2

1a22 = (a2

1 + b21) · (a2

2 + b22),

si relatia anterioara devine adevarata.Presupunem ca relatia (1.6) este adevarata ∀k ≤ n.Vom arata ca ea este adevarata si pentru n + 1:

∀ai, bi ∈ N, i = 1, n + 1, ∃d, e ∈ N astfel ıncat (a21 + b2

1) · (a22 + b2

2) · . . . (a2n+1 + b2

n+1) = d2 + e2

(1.7)Aplicand de doua ori ipoteza de inductie avem:

(a21 + b2

1) · (a22 + b2

2) · . . . (a2n + b2

n)︸ ︷︷ ︸

u2+v2

·(a2n+1 + b2

n+1) = (u2 + v2) · (a2n+1 + b2

n+1) = d2 + e2 (1.8)

unde e = uan+1 + vbn+1 si e = ubn+1 − van+1.Algoritmul 12 se bazeaza pe modelul de constructie pentru d si e, prezentat ın demonstratia

anterioara.

Exemplul 1.14 Se da un numar de 9 monede de acelasi tip. Printre ele s-a strecurat omoneda falsa: ea este mai grea sau mai usoara decat celelalte. Avem la dispozitie o balantafara greutati. Se cere un algoritm care sa determine moneda falsa, stiind ca putem folosicantarul doar pentru 3 operatii de cantarire.

Fie a1, a2, . . . , a9 cele 9 monede. Vom ımparti monedele ın trei grupe egale: A = a1, a2, a3,B = a4, a5, a6 si C = a7, a8, a9. Pentru a determina moneda falsa avem nevoie de douainformatii:

15

Page 16: CursuriAG2014

Algoritm 12 Algoritm pentru calculul elementelor unei expresii

1: Input N, a1, . . . , aN , b1, . . . , bN2: d← a1

3: e← b1

4: for i← 2, N do

5: u = d · ai + e · bi

6: v = d · bi − e · ai

7: d← u8: e← v9: end for

10: Output d, e

1. ın ce grupa se afla moneda falsa;

2. cum este moneda falsa (mai grea sau mai usoara fata de restul).

Notam cu g(·) greutatea unei monede sau a unei multimi de monede. Vom compara grupurileA si B cu ajutorul balantei. Avem urmatoarele cazuri:

1. g(A) = g(B).In aceasta situatie moneda falsa se afla ın cea de–a treia grupa, C = a7, a8, a9.Comparam monedele a7 si a8, rezultand una din situatiile urmatoare:

(a) g(a7) = g(a8) ⇒ a9 este moneda falsa.

(b) g(a7) < g(a8).Mai departe comparam monedele a7 cu a9 si avem:

i. g(a7) = g(a9) ⇒ a8 este moneda falsa si este mai grea decat restul monedelor.

ii. g(a7) > g(a9) ⇒ a8 > a7 > a9 (imposibil deoarece doua monede trebuie sa fieegale).

iii. g(a7) < g(a9) ⇒ a7 este moneda falsa si este mai usoara decat restul monede-lor.

(c) g(a7) > g(a8).Se trateaza ın mod analog cu situatia de la punctul b).

2. g(A) < g(B).In continuare comparam grupa A cu grupa C si vom obtine una din situatiile urmatoare:

(a) g(A) = g(C) ⇒ moneda falsa se afla ın grupa B si este mai grea.

Mai departe comparam moneda a4 cu moneda a5:

i. g(a4) = g(a5) ⇒ a6 este moneda falsa.

ii. g(a4) < g(a5) ⇒ a5 este moneda falsa (deoarece este mai grea).

iii. g(a4) > g(a5) ⇒ a4 este moneda falsa.

(b) g(A) < g(C)g(A)<g(B)⇒ g(B) = g(C)⇒ moneda falsa se afla ın grupa A si este mai

usoara.

In acest caz, comparam moneda a1 cu moneda a2:

i. g(a1) = g(a2) ⇒ a3 este moneda falsa.

ii. g(a1) < g(a2) ⇒ a1 este moneda falsa (deoarece este mai usoara).

16

Page 17: CursuriAG2014

iii. g(a1) > g(a2) ⇒ a2 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 fie egale ın greutate.

3. g(A) > g(B).Rationamentul este analog cu cel de la punctul 2).

Exemplul 1.15 Se dau n numere naturale a1, a2, . . . , an (ai ∈ N). Se cere sa se determinenumarul de cifre de 0 ın care se termina produsul a1 · a2 · . . . · an.

La o prima evaluare a cerintei, se poate schita urmatoarea solutie: se calculeaza produsulcelor 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 fie un numar mare ce depaseste valoareamaxima ce poate fi pastrata ıntr–o variabila dintr–unul din tipurile elementare. Intr-o astfelde situatie este necesar sa se implementeze operatii cu numere mari.

Se pune ıntrebarea daca se poate raspunde la cerinta problemei fara a se face calcululefectiv al produsului celor n numere.

Fie exp2 valoarea exponentului numarului 2 din descompunerea ın factori primi a ter-menului produs a1 ·a2 ·. . .·an, si exp5 valoarea exponentului numarului 5 din descompunerea ınfactori primi a aceluiasi termen. Numarul de zerouri ın care se termina produsul a1 ·a2 ·. . .·an

este min (exp2, exp5) (vezi algoritmul 13).

Algoritm 13 Algoritm pentru calculul numarului de zerouri ale unui produs de numere

1: Input N, a1, . . . , aN2: exp2← 03: exp5← 04: for i← 1, N do

5: while ((ai 6= 0) ∧ (ai mod 2 = 0)) do

6: exp2← exp2 + 17: ai ← ai/28: end while

9: while ((ai 6= 0) ∧ (ai mod 5 = 0)) do

10: exp5← exp5 + 111: ai ← ai/512: end while

13: end for

14: if (exp2 < exp5) then

15: min← exp216: else

17: min← exp518: end if

19: Output min

Exemplul 1.16 Se da un numar format din n cifre. Vom prezenta un algoritm ın care sedetermina cel mai mare numar obtinut prin eliminarea a k cifre (k < n) dintre cele n (vezialgoritmul 14).

Compararea a doua numere naturale ce prezinta acelasi numar de cifre se face ıncepandde la stanga spre dreapta (de la cifrele mai semnificative catre cele mai putin semnificative).

17

Page 18: CursuriAG2014

Fie A = a1a2 . . . an numarul nostru.Vom nota prin m numarul de cifre ce vor ramane dinnumarul initial dupa eliminarea celor k cifre (m = n−k). Problema se reduce la determinareacelui mai mare numar format cu m cifre dintre cele n cifre initiale.

La ınceput numarul contine n cifre, pastrate ın ordine, ın vectorul A: a1, a2, . . . , an.Solutia se construieste ın mod iterativ, la pasul i alegandu–se o valoare corespunzatoare: sedetermina prima cifra de valoare maxima si pozitia acesteia ın cadrul subsecventei de limitel si n−m + i, al, . . . , an−m+i.

Algoritm 14 Algoritm pentru determinarea numarului maxim obtinut dupa eliminarea a kcifre

1: Input n, a1, . . . , an, k2: m← n− k3: l← 04: for i← 1,m do

5: l← l + 16: j ← l7: max← 08: while (j ≤ n−m + i) do

9: if (max < aj) then

10: max← aj

11: l← j12: end if

13: j ← j + 114: end while

15: Output max16: end for

• In instructiunea for (linia 4) pentru fiecare pozitie libera din numarul rezultat, se vaalege cifra maxima dintre cele disponibile;

• linia 5 - se trece la pozitia urmatoare: l reprezinta indexul din sirul A al cifrei aleasala pasul anterior (i − 1) si contine pozitia pe care a fost gasita cifra maxima. Ciframaxima pentru pasul curent va fi cautata ın intervalul l . . . n−m + i, unde n−m + ireprezinta limita superioara a indexului pana la care se poate alege un element la pasulcurent;

a1 . . . al . . . an−m+i︸ ︷︷ ︸

subsecventa pentru care se determina cifra maxima

. . . an

• liniile 6, 7 - se initializeaza variabila de ciclare j cu l si valoarea maxima cu 0; Deoareceai ≥ 0, ∀i = 1, n, se poate initializa variabila max (unde se va pastra valoarea maxima)cu 0;

• linia 8 - se cauta cifra maxima pana la limita din dreapta n−m+ i (daca se merge maila dreapta dincolo de aceasta limita nu se mai pot alege restul de m− i cifre);

• linia 10 - se actualizeaza valoarea maxima;

• linia 11 - se actualizeaza pozitia valorii maxime.

18

Page 19: CursuriAG2014

Exemplul 1.17 Vom prezenta doi algoritmi ce determina toate tripletele de numere naturale(a, b, c) ce verifica relatia a2 + b2 = c2 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 verifica relatia k · k = i · i + j · j. Daca vomconsidera doar instructiunea de ciclare 4, atunci conditia 5 se va verifica de n− (j +1)+1 =n− j ori. Deoarece j = i + 1, n− 1, vom obtine faptul ca instructiunea 5 se va executa de:

(n− i− 1) + (n− i− 2) + . . . + (n− n + 1) =n−i−1∑

j=1

j =(n− i) · (n− i− 1)

2

ori.Din i = 2, n− 2 rezulta ca

n−2∑

i=2

n−i−1∑

j=1

j =

n−2∑

i=2

(n− i) · (n− i− 1)

2=

1

2

n−2∑

i=2

(i2 + (1− 2n)i + n2 − n)

=1

2[

n−2∑

i=2

i2 + (1− 2n)

n−2∑

i=2

i + (n2 − n) · (n− 3)]

1: Input n2: for i← 2, n− 2 do3: for j ← i + 1, n− 1 do4: for k ← j + 1, n do5: if (k · k = i · i + j · j) then6: Output i, j, k7: end if8: end for9: end for

10: end for11: return

1: Input n2: for i← 2, n − 1 do3: for j ← i + 1, n do4: s← i · i + j · j5: k ← ⌊√s⌋6: if ((k · k = s) ∧ (k ≤ n)) then7: Output i, j, k8: end if9: end for

10: end for11: return

Pentru cea de-a doua varianta, cea din dreapta, se genereaza perechile de numere (i, j) cuproprietatea ca 2 ≤ i < j ≤ n, se calculeaza s ← i · i + j · j si se verifica daca numarulobtinut este patrat perfect (linia 6: (⌊√s⌋)2 = s). Conditia de la linia 6 se va executa den− (i + 1) + 1 = n− i ori.

Deoarece linia 2 se va executa de n− 1− 2 + 1 = n− 2 ori, valoarea totala reprezentandnumarul de verificari (linia 6) va fi:

n−1∑

i=2

(n− i) =

n−1∑

i=1

(n− i)− (n− 1) =

n−1∑

i=1

i− (n− 1) =n(n− 1)

2− n + 1

1.3 Exercitii

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

Page 20: CursuriAG2014

(d) Sa se determine forma corespunzatoare ın baza 10 a unui numar reprezentat ınbaza 2.

(e) Sa se elimine dintr–un numar natural toate cifrele de forma 3k + 1 si sa se afisezenumarul rezultat.

(f) Pentru un numar natural dat sa se construiasca din cifrele acestuia cel mai marenumar prin amplasarea mai ıntai a cifrelor impare si apoi a cifrelor pare.

2. (a) Sa se determine toti divizorii unui numar natural.

(b) Sa se verifice daca doua numere naturale sunt prime ıntre ele.

(c) Sa se determine toti divizorii comuni a doua numere naturale.

(d) Sa se calculeze toate numerele prime mai mici decat o valoare specificata.

(e) Sa se descompuna ın factori primi un numar natural.

(f) Sa se determine cel mai mare divizor comun a doua numere naturale folosindu–sedescompunerea ın factori primi.

3. Pentru un numar natural b (1 < b < 10) sa se determine toate numerele naturale maimici decat o valoare specificata n, (1 ≤ n ≤ 105) care scrise ın baza b, contin numaicifrele 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 nenulaa lui n!.

(b) Pentru un numar natural n dat (n < 1000), sa se determine numarul de cifre alelui n!.

5. Se da un numar natural n (0 ≤ n ≤ 106). Se aplica asupra numarului n una dintreurmatoarele transformari:

(a) Se calculeaza suma factorialelor cifrelor numarului n si se obtine un nou numar.

(b) Se calculeaza suma cuburilor cifrelor numarului n.

Dupa aceasta, procedeul se repeta aplicandu-se de fiecare data numai una din cele douaoperatii (a) sau (b) (cea cu care s-a ınceput).

Sa se afiseze sirul de numere astfel obtinut pana cand elementele lui ıncep sa se repete.Se cere lungimea listei pana la prima repetitie si pozitia elementului care se repetaprimul.

6. O secventa Farey [44] de ordinul n este un sir de numere rationale ab

unde 0 ≤ a ≤ b ≤n, (a, b) = 1. De exemplu, secventele Farey de ordinul 1, 2 si 3 sunt:

F1 = 01,1

1

F2 = 01,1

2,1

1

F3 = 01,1

3,1

2,2

3,1

1

20

Page 21: CursuriAG2014

Pentru un numar natural n (n < 216) sa se determine elementele secventei Farey deordinul 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)

Indicatie Fie a1

b1, a2

b2, a3

b3trei elemente consecutive ale unei secvente Farey de ordinul n.

Atunci avem relatiile ([68]):

b1a2 − a1b2 = 1 (1.9)a2

b2=

a1 + a3

b1 + b3(1.10)

Daca a1

b1si a3

b3sunt doua elemente consecutive ale unei secvente Farey de ordinul n,

atunci a1+a3

b1+b3este un element al secventei Farey de ordinul n + 1.

Fie a1

b1si a2

b2doua elemente consecutive ale unei secvente Farey de ordinul n. Elementul

urmator ce apartine secventei, a3

b3, se poate determina astfel: a2

b2= a1+a3

b1+b3. ∃k ∈ N∗ astfel

ıncat ka2 = a1 + a3 si kb2 = b1 + b3 ⇒ a3 = ka2 − a1 si b3 = kb2 − b1. Valoarea lui ktrebuie aleasa astfel ıncat fractia a3

b3sa fie cat mai apropiata de a2

b2. Astfel k trebuie sa

fie cat mai mare, ınsa respectand restrictia k ≤ n+b1b2

.

7. Fiind date doua numere ıntregi X si Y , sa se determine cea mai mica baza pentru Yastfel ıncat X si Y sa reprezinte aceeasi valoare.

De exemplu numerele 12 si 5 nu sunt egale ın baza 10 (1210 6= 510), ınsa ele sunt egaledaca le consideram ca fiind reprezentate ın bazele 3 si respectiv 6: 123 = 510, 56 = 510.

Bazele ın care se vor considera reprezentate numerele au valoarea maxima 36.

Intrare Iesire12 5 123 = 56

10 A 1010 = A11

12 34 1217 = 345

123 456 no solution10 2 102 = 23

(ACM, 1995)

8. Sa se calculeze 2n pentru 30 < n < 100.

9. Fie D o dreapta avand ecuatia ax + by + c = 0 si un cerc C(O, r) unde O(x0, y0) estecentrul cercului iar r este raza acestuia.

Sa se realizeze un algoritm care sa stabileasca pozitia dreptei fata de cercul C ın functiede valorile parametrilor reali a, b, c, x0, y0, r.

10. Sa se determine toate numerele naturale n (1 ≤ n ≤ 106) cu proprietatea ca atat n catsi oglinditul sau sunt numere prime.

21

Page 22: CursuriAG2014

11. Sa se scrie un algoritm ce calculeaza coeficientii polinomului urmator, fiind 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 rationale ale unei ecuatii cu coeficienti ıntregi.

Fie ecuatia:anxn + an−1x

n−1 + . . . + a1x + a0 = 0. (1.12)

O radacina rationala a ecuatiei 1.12 va avea forma pq

unde p|a0 si q|an.

13. Pentru o secventa de numere naturale de lungime n, sa se realizeze un algoritm care sadetermine cea mai lunga subsecventa de elemente consecutive avand aceeasi valoare.

14. Sa se realizeze un algoritm care sa determine primele n numere prime, pentru un numarnatural n dat.

15. Sa se realizeze un algoritm pentru calcularea tuturor solutiilor ecuatiei:

3x + y + 4xz = 100, x, y, z ∈ N. (1.13)

Indicatie Pentru o valoare z ≥ 25 si x 6= 0 (x > 0) avem:

3x + y + 4xz ≥ 3x + 4xz ≥ 3 + 4z > 100.

Astfel pentru z obtinem ca 0 ≤ z ≤ 24.

Ecuatia 1.13 se poate scrie astfel:

3x + y + 4xz = 100⇔ x(3 + 4z) = 100− y ⇔ x =100− y

3 + 4z(1.14)

Daca x 6= 0 si y ≥ 0 ⇒ x = 100−y3+4z

≥[

100−y3+4z

]⇒ x ∈ [1,

[100−y3+4z

]].

Astfel, pentru fiecare pereche de numere (z, x) vom calcula pe y astfel: y = 100− 3x−4xz.

De asemenea, ın 1.14 daca luam x = 0 obtinem multimea de solutii (0, 100, z), ∀z ∈ N.

16. Un moment de timp este specificat ın formatul ora:min:sec:sutimi.

• Sa se elaboreze o subrutina ce calculeaza timpul (ın sutimi de secunda) trecut dela momentul 00 : 00 : 00 : 00 al fiecarei zile si pana la momentul curent;

• Sa se calculeze timpul scurs ıntre doua momente de timp hh1 : mm1 : ss1 : tt1 sihh2 : mm2 : ss2 : tt2;

• Fiind dat un numar natural n, ce reprezinta numarul de secunde trecute de lamomentul 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

Page 23: CursuriAG2014

Capitolul 2

Elemente de analiza algoritmilor

Gradul de dificultate al unei probleme P poate fi pus in evidenta prin timpul de executie alalgoritmului corespunzator si/sau prin spatiul de memorie necesar. Timpul de executie ıncazul cel mai defavorabil ne da durata maxima de executie a algoritmului. Timpul mediude executie se obtine prin ınsumarea timpilor de executie pentru toate multimile de date deintrare urmata de raportarea la numarul acestora.

Definitia 2.1 Timpul de executie ın cazul cel mai defavorabil al unui algoritm A este ofunctie TA : N −→ N unde TA(n) reprezinta numarul maxim de instructiuni executate decatre A ın cazul unor date de intrare de dimensiune n.

Definitia 2.2 Timpul mediu de executie al unui algoritm A este o functie TmedA : N −→ N

unde TmedA (n) reprezinta numarul mediu de instructiuni executate de catre A ın cazul unor

date de intrare de dimensiune n.

Fiind data o problema P , o functie T (n) se spune ca este o margine superioara daca existaun algoritm A ce rezolva problema P iar timpul de executie ın cazul cel mai defavorabil alalgoritmului A este cel mult T (n).

Fiind data o problema P , o functie T (n) se spune ca este o margine pentru cazul mediudaca exista un algoritm A ce rezolva problema P iar timpul mediu de executie al algoritmuluiA este cel mult T (n).

Fiind data o problema P , o functie T (n) se spune ca este o margine inferioara daca oricealgoritm A ce rezolva problema P va avea cel putin un timp T (n) pentru unele date de intrarede dimensiune n, atunci cand n tinde la infinit (n→∞).

Definitia 2.3 Fiind data o functie g : N −→ R vom nota cu O(g(n)) multimea: O(g(n)) =f(n)| ∃c > 0, n0 ≥ 0 a.ı. 0 ≤ f(n) ≤ c · g(n), ∀n ≥ n0.

Vom spune despre f ca nu creste ın mod sigur mai repede decat functia g. Pentru a indicafaptul ca o functie f(n) este un membru al multimii O(g(n)), vom scrie f(n) = O(g(n)), ınloc de f(n) ∈ O(g(n)).

Observatia 2.1 Vom prezenta cateva proprietati ale lui O(·):

• O(f(n) + g(n)) = O(max(f(n), g(n))).

De exemplu pentru functia f(n) = 7 · n5 − n2 + 3 · log n aplicand regula valorii maximevom avea: O(f(n)) = O(max(7 · n5, n2, 3 · log n)) adica O(f(n)) = O(n5).

• O(loga n) = O(logb n);

23

Page 24: CursuriAG2014

• f(n) = O(f(n)) (reflexivitate);

• f(n) = O(g(n)) si g(n) = O(h(n)) atunci f(n) = O(h(n)) (tranzitivitate).

Definitia 2.4 Fiind data o functie g : N −→ R vom nota cu Θ(g(n)) multimea: Θ(g(n)) =f(n)| ∃c1, c2 > 0, ∃n0 ≥ 0 a.ı. 0 ≤ c1 · g(n) ≤ f(n) ≤ c2 · g(n), ∀n ≥ n0

Spunem ca g(n) este o margine asimptotic tare pentru f(n).

Definitia 2.5 Fiind data o functie g : N −→ R vom nota cu Ω(g(n)) multimea: Ω(g(n)) =f(n)| ∃c > 0, n0 ≥ 0 a.ı. 0 ≤ c · g(n) ≤ f(n), ∀n ≥ n0

La fel cum O furnizeaza o delimitare asimptotica superioara pentru o functie, Ω furnizeazao delimitare asimptotica inferioara pentru aceasta.

Teorema 2.2 Pentru orice doua functii f(n) si g(n), avem f(n) = Θ(g(n)) ⇐⇒ f(n) =O(g(n)) si f(n) = Ω(g(n)).

Definitia 2.6 Fiind data o functie g : N −→ R vom nota cu o(g(n)) multimea: o(g(n)) =f(n)| ∀c > 0, ∃n0 > 0 a.ı. 0 ≤ f(n) < c · g(n), ∀n ≥ n0

Observatia 2.3 f(n) = o(g(n)) ⇐⇒ limn→∞f(n)g(n)

= 0.

Definitia 2.7 f(n) ∈ ω(g(n)) ⇐⇒ g(n) ∈ o(f(n))ω(g(n)) este o multime ce se defineste astfel:ω(g(n)) = f(n)| ∀c > 0, ∃n0 > 0 a.ı. 0 ≤ c · g(n) < f(n), ∀n ≥ n0

Observatia 2.4 1. f(n) = Θ(g(n)), g(n) = Θ(h(n)) =⇒ f(n) = Θ(h(n)) (tranzitivitate);

2. f(n) = Θ(f(n)) (reflexivitate);

3. f(n) = Θ(g(n)) ⇐⇒ g(n) = Θ(f(n)) (simetrie).

Definitia 2.8 O functie f are o crestere exponentiala daca ∃c > 1 a.i. f(x) = Ω(cx) si∃d a.ı. f(x) = O(dx). O functie f este polinomiala de gradul d daca f(n) = Θ(nd) sif(n) = O(nd′), ∀d′ ≥ d.

Teorema 2.5

limn→∞

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 xn ∈ o(n!).

Deoarecexn

n!<

xn

x4 . . . x4︸ ︷︷ ︸

⌈n/2⌉ori

≤ xn

(x4)n/2=

xn

x2n= (

1

x)n (2.2)

rezulta ca

limn→∞

xn

n!= 0 (2.3)

24

Page 25: CursuriAG2014

• log n ∈ o(n).

limx→∞

log x

x= lim

x→∞

(log x)′

(x)′= lim

x→∞

1x ln 2

1= 0

• pentru a, b > 1, a, b ∈ R∗ avem loga n ∈ Θ(logb n).

Calcularea cu exactitate a timpului de executie al unui program oarecare se poate dovedio activitate dificila. De aceea, ın practica se utilizeaza estimari ıncercandu-se eliminareaconstantelor si simplificarea formulelor ce intervin ın cadrul evaluarii.

Daca doua parti ale unui program, P1 si P2, au timpii de executie corespunzatori T1(n) siT2(n), unde T1(n) = O(f(n)) si T2(n) = O(g(n)), atunci programul P1 ⊕ P2 va avea timpulde executie T1(n) + T2(n) = O(max(f(n), g(n))) (regula sumei), unde ⊕ reprezinta operatiade concatenare.

Prin aplicarea acestei reguli rezulta faptul ca timpul necesar executiei unui numar finitde operatii este, neluand ın considerare constantele, caracterizat ın principal de catre timpulde executie al operatiei cele mai costisitoare.

Cea de–a doua regula, regula produsului, spune ca fiind date doua funtii f(n) si g(n) astfelıncat T1(n) = O(f(n)) si T2(n) = O(g(n)), atunci avem T1(n) · T2(n) = O(f(n) · g(n)).

Pe baza regulilor produsului si sumei putem face urmatoarele reduceri:

O(1) ⊆ O(log n) ⊆ O(n) ⊆ O(n log n) ⊆ O(n2) ⊆ O(n3) ⊆ O(2n)

Prezentam ın continuare cateva reguli generale pentru evaluarea complexitatii unui algoritm:

• timpul de executie al unei instructiuni de atribuire, citire sau afisare a unei variabileeste O(1).

• timpul de executie al unei secvente de instructiuni este proportional cu timpul instructiuniicare dureaza cel mai mult.

• timpul de executie al unei instructiuni de decizie (if ) este timpul executarii instructiu-nilor de pe ramura aleasa plus timpul necesar evaluarii conditiei.

• timpul de executie pentru o instructiune de ciclare este suma, dupa numarul de pasipe care ıi realizeaza instructiunea de ciclare, dintre timpul necesar executarii corpuluiinstructiunii plus timpul necesar evaluarii conditiei.

1: for i← 1, n do

2: A(i)3: end for

Daca instructiunii compuse A(i) ıi corespunde un timp de executie constant t, ce nudepinde de i, atunci timpul corespunzator ıntregii instructiuni de ciclare for anterioareeste:

n∑

i=1

t = tn∑

i=1

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

In cazul general, timpul de executie al instructiunii compuse A(i) depinde de pasul i,notat cu ti. Astfel timpul total corespunzator instructiunii for este

∑ni=1 ti.

• Instructiunile de ciclare al caror numar de pasi depinde de ındeplinirea unei conditii(while) sau de neındeplinirea acesteia (repeat ... until), sunt mult mai dificilde analizat deoarece nu exista o metoda generala de a afla cu exactitate numarul derepetari al corpului instructiunii. De exemplu, pentru fragmentul urmator

25

Page 26: CursuriAG2014

1: i← l2: while (ai < x) do

3: . . . ⊲ calcule ce pot modifica, direct sau indirect, valoarea lui ai

4: i← i + 15: end while

nu se poate preciza de cate ori se va ajunge la realizarea instructiunii de incrementaredin interiorul instructiunii while. In marea majoritate a cazurilor se utilizeaza teoriaprobabilitatilor ın vederea obtinerii unei estimari a acestui numar.

Exemplul 2.7 De exemplu

1: for i← 1, n do2: instructiune13: end for

are timpul de executie O(n).

1: for i← 1, n do2: for j ← 1,m do3: instructiune24: end for5: end for

Timpul de executie pentru secventa de cod ce contine doua instructiuni de ciclare imbricateeste O(n ·m).

Exemplul 2.8 Sa consideram un alt exemplu: se da un sir A de n numere reale, si se dorestecalcularea elementelor unui sir B astfel ıncat bi = 1

i·∑i

j=1 aj, pentru i = 1, n.

1: for i← 1, n do2: s← 03: for j ← 1, i do4: s← s + aj

5: end for6: bi ← s

i7: end for8: return

Daca notam cu o constanta cx timpul necesar pentru efectuarea unei operatii atomice,vom obtine: costul efectuarii liniei 1 este c1 · n, al liniei 2 este c2 · n, al liniei 3 este c3 · i, alliniei 4 este c4 · i, al liniei 6 este c5 · n iar al liniei 8 este c6.

T (n) = c1n + c2n +

n∑

i=1

c3i +

n∑

i=1

c4i + c5n + c6 = c1n + c2n + c3

n∑

i=1

i + c4

n∑

i=1

i + c5n + c6

=n(n + 1)

2(c3 + c4) + n(c1 + c2 + c5) + c6

=1

2(c3 + c4)n

2 +1

2(c3 + c4)n + n(c1 + c2 + c5) + c6

=1

2(c3 + c4)n

2 + [1

2(c3 + c4) + c1 + c2 + c5]n + c6 = n2 · p + n · q + c6

De obicei nu se efectueaza o analiza asa de detaliata a algoritmului, dar se ıncearca o eval-uare a blocurilor principale cum ar fi instructiunile de ciclare, atribuindu–le direct valoricorespunzatoare complexitatii timp, atunci cand este posibil:

T (n) = O(n2) + O(n) + O(1) = O(n2) (2.5)

26

Page 27: CursuriAG2014

Vom modifica algoritmul anterior astfel ıncat sa reducem numarul de calcule efectuate:

1: s← 02: for i← 1, n do3: s← s + ai

4: bi ← si

5: end for6: return

Pentru aceasta varianta de lucru, complexitatea timp este urmatoarea:

T (n) = O(1)(linia 1) + O(n)(liniile 2–4) + O(1)(linia 6) = O(n) (2.6)

In urma analizei de complexitate, putem concluziona ca cea de-a doua varianta a algoritmuluiruleaza ıntr–un timp liniar.

2.1 Metoda substitutiei

Metoda substitutiei presupune mai ıntai ghicirea (estimarea) formei solutiei pentru relatiade recurenta si apoi demonstrarea prin inductie matematica a corectitudinii solutiei alese.

Metoda poate fi aplicata ın cazul unor ecuatii pentru care forma solutiei poate fi estimata.Sa consideram urmatoarea relatie de recurenta:

T (n) =

1 , daca n = 1

2T (n2) + n , ın rest

(2.7)

Vom presupune ca solutia acestei relatii de recurenta este T (n) = O(n log n) (notamlog2 n = log n). Folosind metoda inductiei matematice, vom ıncerca sa demonstram inegali-tatea:

T (n) ≤ cn log n. (2.8)

Presupunem mai ıntai ca inecuatia (2.8) are loc pentru ∀k < n, inclusiv pentru n2, adica

T (n2) ≤ c · n

2· log (n

2).

Vom demonstra ca inecuatia (2.8) este ındeplinita si pentru n: T (n) = 2T (n2) + n.

T (n) ≤ 2(cn

2log

n

2) + n = cn log

n

2+ n

= cn log n− cn log 2 + n = cn log n− cn + n

≤ cn log n

(2.9)

Metoda inductiei matematice presupune sa aratam ca solutia respecta si cazurile particulare(T (1) = 1). Pentru n = 1 vom avea T (1) = c ·1 · log 1 = 0 ceea ce contrazice relatia T (1) = 1.

Aceasta situatie poate fi rezolvata daca consideram ca T (n) = cn log n, ∀n ≥ n0 (n0 esteo constanta).

Din T (2) = 4 si T (3) = 5 vom alege valoarea parametrului c astfel ıncat sa fie ındepliniteinegalitatile T (2) ≤ 2c log 2 si T (3) ≤ 3c log 3. Se observa ca orice valoare a lui c ≥ 2 satisfaceinegalitatile anterioare.

2.2 Schimbarea de variabila

Aceasta metoda presupune realizarea unei schimbari de variabila ın vederea simplificariiformulei sau pentru regasirea unei formule deja cunoscuta.

27

Page 28: CursuriAG2014

Sa consideram ecuatia T (n) = 2T (√

n) + log n. Daca ınlocuim pe n cu 2m obtinem:

T (2m) = 2T (2m2 ) + log 2m = 2T (2

m2 ) + m (2.10)

Notam cu S(m) = T (2m) si ınlocuind ın (2.10) obtinem o noua relatie de recurenta:

S(m) = 2S(m

2) + m (2.11)

Se observa ca aceasta relatie are o forma similara cu cea din formula (2.7).Solutia relatiei (2.11) este:

S(m) = O(m log m)⇒ T (n) = T (2m) = S(m) = O(m log m) = O(logn log log n) (2.12)

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

2.3 Metoda iterativa

Metoda iterativa este mult mai eficienta deoarece nu presupune ’ghicirea’ solutiei, variantace conduce deseori la rezultate gresite si timp pierdut. De exemplu, sa consideram formulade recurenta:

T (n) =

1 , daca n = 1

T (n2) + 1 , ın rest

(2.13)

Pentru rezolvarea acestei recurente vom substitui succesiv pe n cu n2:

T (n) = T (n

2) + 1

= T (n

4) + 2

= T (n

8) + 3

. . .

= T (n

2k) + k

(2.14)

Prin urmare atunci cand 1 = n2k ⇒ k = log n, vom avea

T (n) = 1 + k = 1 + log n⇒ T (n) = O(log n).Fie o alta formula de recurenta:

T (n) =

1 , daca n = 1

2T (n2) + n , ın rest

(2.15)

Inlocuind succesiv pe n cu n2

vom obtine urmatoarea serie de identitati:

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

. . .

= 2kT (n

2k) + kn

(2.16)

Deoarece substitutia se opreste atunci cand n2k = 1 adica pentru k = log n, vom avea:

T (n) = 2k + kn = n + n log n = O(n log n) (2.17)

28

Page 29: CursuriAG2014

2.4 Teorema master

Metoda master pune la dispozitie o varianta de rezolvare a unor recurente de forma

T (n) = aT (n

b) + f(n) (2.18)

unde a ≥ 1, b > 1 sunt constante, iar f(n) este o functie asimptotic pozitiva. Formula derecurenta (2.18) descrie timpul de executie al unui algoritm ce presupune descompunerea uneiprobleme de dimensiune n ın a subprobleme, fiecare avand dimensiunea datelor de intrare n

b.

f(n) reprezinta costul asociat ımpartirii datelor de intrare cat si costul combinarii rezultatelorcelor a subprobleme.

Teorema 2.9 (Teorema master) [30] Fie a ≥ 1 si b > 1 doua constante, f(n) o functieasimptotic pozitiva, si T (n) definita de relatia de recurenta T (n) = aT (n

b) + f(n), unde n

bva

fi ⌊nb⌋ sau ⌈n

b⌉.

Atunci T (n) este marginita asimptotic dupa cum urmeaza:

1. daca f(n) = O(nlogb a−ǫ) pentru o constanta ǫ > 0, atunci T (n) = Θ(nlogb a);

2. daca f(n) = Θ(nlogb a logk n), atunci T (n) = Θ(nlogb a logk+1 n) (de obicei k = 0);

3. daca f(n) = Ω(nlogb a+ǫ) pentru o constanta ǫ > 0, si daca af(nb) ≤ cf(n) pentru o

constanta c < 1 si oricare numar n suficient de mare, atunci T (n) = Θ(f(n)).

Corolarul 2.10 Pentru o functie f de tip polinomial unde f(n) = cnk avem:

1. daca a > bk atunci T (n) = O(nlogb a);

2. daca a = bk atunci T (n) = O(nk log n);

3. daca a < bk atunci T (n) = O(nk).

Exemplul 2.11 • Fie T (n) = 2T (n2)+n. Avem a = 2, b = 2, k = 1, f(n) = nk. Aplicand

corolarul pentru cazul a = bk, solutia este T (n) = O(nk log n) = O(n log n).

• Fie T (n) = 9T (n3) + n. Avem a = 9, b = 3, k = 1. Aplicand corolarul pentru cazul

a > bk, se obtine solutia T (n) = O(nlog3 9) = O(n2).

• Fie T (n) = 4T (n2) + n3. Avem a = 4, b = 2, k = 3, f(n) = n3. Aplicand corolarul

pentru cazul a < bk, se obtine solutia T (n) = O(n3).

• Fie T (n) = 2nT (n2) + nn. Nu se poate aplica Teorema master deoarece a = 2n nu este

constant.

• Fie T (n) = 2T (n2) + n log n. Atunci avem a = 2, b = 2, k = 1, f(n) = Θ(nlog2 2 logk n),

si aplicand Teorema master, cazul al doilea, obtinem: T (n) = Θ(n log2 n).

• Fie T (n) = 12T (n

2) + 1

n. Nu se poate aplica Teorema master deoarece a = 1

2< 1.

• Fie T (n) =√

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

√2, b = 2, f(n) =

O(n1

2−ǫ) obtinem: T (n) = Θ(

√n).

• Fie T (n) = 3T (n4) + n log n. Aplicand Teorema master pentru a = 3, b = 4, f(n) =

Ω(nlog4 3+ǫ) obtinem: T (n) = Θ(n log n).

29

Page 30: CursuriAG2014

• Fie T (n) = 16T (n4) − n log n. Nu se poate aplica Teorema master deoarece f(n) =

−n log n nu este o functie asimptotic pozitiva.

Exemplul 2.12 Analiza actiunilorDeschiderea unei actiuni la o anumita data calendaristica se calculeaza drept numarul

maxim de zile consecutive (pana la acea data) ın care pretul actiunii a fost mai mic sau egalcu pretul din ziua respectiva. Fie pk pretul unei actiuni ın ziua k iar dk deschiderea calculataın aceeasi zi.

In continuare se prezinta un exemplu de calcul al deschiderii unei actiuni pentru un numarde 7 zile:

p0 p1 p2 p3 p4 p5 p6

9 6 3 4 2 5 7d0 d1 d2 d3 d4 d5 d6

1 1 1 2 1 4 6

Algoritm 15 Algoritm de calcul al deschiderii unei actiuni (prima varianta)

1: procedure ComputeSpan1(p, n; d)2: for k ← 0, n− 1 do

3: j ← 14: while (j < k) ∧ (pk−j ≤ pk) do

5: j ← j + 16: end while

7: dk ← j8: end for

9: return

10: end procedure

Algoritmul 15 calculeaza deschiderea unei actiuni pentru un interval mai lung de timp pebaza evolutiei preturilor acesteia. Timpul de executie al acestui algoritm este O(n2).

Vom prezenta un alt mod de calcul al deschiderii unei actiuni folosind o stiva (vezi algo-ritmul 16).

Stiva este o structura de date de tip container deoarece ea depoziteaza elemente de unanumit tip. Pentru a putea sa operam asupra unei colectii de elemente pastrate ıntr–o stivase definesc urmatoarele operatii, ın afara de operatiile 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 goalaavem o situatie ce genereaza o exceptie.

• peek():object – ıntoarce valoarea obiectului din varful stivei fara a–l extrage.

• size():integer – ıntoarce numarul de obiecte din stiva.

• isEmpty():boolean – ıntoarce true daca stiva nu contine nici un obiect.

• isFull(): boolean – ıntoarce true daca stiva este plina.

• init(capacitate:integer) – initializeaza stiva.

Timpul de executie al noului algoritm este O(n).

30

Page 31: CursuriAG2014

Algoritm 16 Algoritm de calcul al deschiderii unei actiuni (a doua varianta)

1: procedure ComputeSpan2(p, n; d)2: call init(S)3: for k ← 0, n− 1 do

4: ind← 15: while (isEmpty(S) = false) ∧ (ind = 1) do

6: if (pk ≥ ppeek(S)) then

7: call pop(S)8: else

9: ind← 010: end if

11: end while

12: if (ind = 1) then

13: h← −114: else

15: h← peek(S)16: end if

17: dk ← k − h18: call push(S, k)19: end for

20: return

21: end procedure

2.5 Exercitii

1. Sa se evalueze complexitatea algoritmului 17, ce realizeaza descompunerea ın factoriprimi a unui numar natural.

Algoritm 17 Algoritm pentru descompunerea ın factori primi a unui numar natural

1: Input n2: j ← 23: while (j ≤ n) do

4: if (n mod j = 0) then

5: k ← 06: while (n mod j = 0) do

7: k ← k + 18: n← n div j9: end while

10: Output jk11: end if

12: j ← j + 113: end while

2. Pentru fiecare dintre urmatoarele relatii de recurenta calculati complexitatea timp:

(a) T (n) = 2T (n2) + n

log n;

(b) T (n) = 16T (n4) + n!;

(c) T (n) = 3T (n3) +√

n;

31

Page 32: CursuriAG2014

(d) T (n) = 3T (n3) + 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 ← n3: 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← n2: while (i ≥ 1) do

3: j ← i4: while (j ≤ n) do

5: . . .6: j ← j · 27: end while

8: i← ⌊ i2⌋

9: end while

5. Intr-o secventa de n numere naturale (a1, a2, . . . , an, ai ∈ N, 1 ≤ ai ≤ 65535, 1 ≤ n ≤107) se spune ca un numar este majoritar daca numarul de aparitii este cel putin n

2+1.

Sa se realizeze un algoritm ce determina daca avem vreun numar majoritar ın secventade n elemente, si ın caz afirmativ sa se afiseze aceasta valoare.

6. Sa se rezolve urmatoarele ecuatii recurente:

• T (n) = 2 · T (n2) + n lg n, n = 2k;

• T (n) = 3 · T (n2) + c · n, n = 2k > 1.

7. Sa se rezolve ecuatia recurenta T (n) = n · T 2(n2), n = 2k, T (1) = 6.

8. Sa se arate ca ex = 1 + x + Ω(x2) unde x→∞.

9. Sa se determine primele n elemente ale sirurilor ak si bk date prin urmatoarele relatiide recurenta:

ak+1 =5ak + 3

ak + 3, bk =

ak + 3

ak + 1, k ≥ 0, a0 = 1. (2.19)

10. Fie [P1P2 . . . Pn] un poligon convex dat prin coordonatele carteziene ale varfurilor sale,ın ordine trigonometrica. Sa se calculeze aria poligonului.

11. Sa se verifice daca urmatoarele afirmatii sunt adevarate:

(a) n2 ∈ O(n3);

32

Page 33: CursuriAG2014

(b) n3 ∈ O(n2);

(c) 2n+1 ∈ O(2n);

(d) (n + 1)! ∈ O(n!);

(e) ∀f : N −→ R∗, f ∈ O(n)⇒ f 2 ∈ O(n2);

(f) ∀f : N −→ R∗, f ∈ O(n)⇒ 2f ∈ O(2n).

12. Sa se realizeze un algoritm ce verifica daca un text dat T constituie o permutare circu-lara a unui alt text T0.

13. Se da o secventa de numere ıntregi ın care pot sa existe si numere duplicate. Sa serealizeze un algoritm care sa determine o pereche de numere apartinand secventei, acaror suma sa fie egala cu o valoare specificata k.

14. Sa se realizeze o subrutina ce verifica daca un sir de caractere S reprezinta o anagramaa altui sir de caractere S0.

15. O secventa S contine n− 1 numere naturale distincte ale caror valori apartin multimiide valori 1, 2, . . . , n. Sa se realizeze un algoritm ce determina ce numar din intervalul[1, n] lipseste din secventa.

16. Sa se elaboreze un algoritm pentru stergerea dintr–un vector a unui element aflat pepozitia k.

33

Page 34: CursuriAG2014

Capitolul 3

Grafuri. Grafuri neorientate

3.1 Notiuni de baza

Fie V o multime finita si nevida avand n elemente (V = x1, x2, . . . , xn). Fie E o multimefinita astfel ıncat E ⊆ V ×V (unde V ×V este produsul cartezian al multimii V cu ea ınsasi)si E = (x, y)|x, y ∈ V (E este multimea perechilor (x, y) cu proprietatea ca x si y apartinmultimii V ).

Definitia 3.1 Se numeste graf o pereche ordonata G = (V, E).Elementele xi ∈ V se numesc noduri sau varfuri. Elementele multimii E sunt arce

sau muchii. O muchie (xk, xl) ∈ E se mai noteaza si cu [xk, xl].

|V | se numeste ordinul grafului G si reprezinta numarul varfurilor acestuia, iar |E| senumeste dimensiunea grafului G si reprezinta numarul muchiilor/ arcelor grafului G.

Graful Φ = (∅, ∅) se numeste graful vid.Daca ıntr-o pereche [xk, xl] nu tinem cont de ordine atunci graful este neorientat iar

perechea reprezinta o muchie ([xk, xl] = [xl, xk]). Daca se introduce un sens fiecarei muchiiatunci aceasta devine arc iar graful se numeste orientat ([xk, xl] 6= [xl, xk]). Muchiile ce auaceleasi 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 extremitati pentrucel mult o muchie. Un graf este finit daca multimile V si E sunt finite.

In continuare vom considera un graf neorientat, simplu si finit. Daca [x, y] ∈ E vomspune 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 K5

34

Page 35: CursuriAG2014

mai numesc capetele muchiei. Doua muchii sunt adiacente daca au un varf comun. Un grafeste trivial daca are un singur varf. Daca E = ∅ atunci graful G = (V, E) se numeste grafnul.

Observatia 3.1 Un graf neorientat, simplu, finit poate fi utilizat drept model de reprezentareal unei relatii simetrice peste o multime.

Definitia 3.2 Se numeste graf complet de ordinul n, si se noteaza cu Kn, un graf cu pro-prietatea ca oricare doua varfuri distincte ale sale sunt adiacente (∀x ∈ V, y ∈ V, x 6= y ⇒[x, y] ∈ E).

Exemplul 3.2 Sa consideram grafurile din figura 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] (vezifigura 3.1 a));

b) K5 este graful complet cu 5 varfuri. Varfurile 3 si 5 sunt adiacente (vezi figura 3.1 b)).

Fig. 3.2: a) Un exemplu de graf neorientat cu 5 varfuri. b) Subgraf al grafului din figura 3.1 b). c) Grafpartial al grafului din figura 3.1 b).

Definitia 3.3 Un graf partial al unui graf dat G = (V, E) este un graf G1 = (V, E1) undeE1 ⊆ E.

Definitia 3.4 Un subgraf al unui graf G = (V, E) este un graf H = (V1, E1) unde V1 ⊂ Viar muchiile din E1 sunt toate muchiile din E care au ambele extremitati ın multimea V1

(E1 = E|V1×V1= [x, y]|[x, y] ∈ E, x, y ∈ V1).

Se spune ca graful H este indus sau generat de submultimea de varfuri V1 si se noteazaH = G|V1

sau H = [V1]G.Iata alte cateva notatii des ıntalnite:

- G− V1 = subgraful ce se obtine din G prin eliminarea submultimii de varfuri V1 (V1 ⊆V );

- G− x = subgraful G− x;

- < E1 >G = graful partial al lui G generat de E1;

35

Page 36: CursuriAG2014

- G−E1 =< E \ E1 >G;

- G− e = G− e, graful partial obtinut prin eliminarea unei muchii e.

Exemplul 3.3 Graful partial din figura 3.2 c) se obtine din graful 3.1 b) prin stergereamuchiilor [2, 4], [2, 5], [3, 5], [4, 5]. Subgraful din figura 3.2 b) este indus de multimea V1 =1, 3, 4, 5 din graful complet K5 (H = K5|V1).

Definitia 3.5 Gradul unui varf este egal cu numarul muchiilor incidente cu varful x si senoteaza cu d(x) (d(x) = |[x, u]|[x, u] ∈ E, u ∈ V |). Un varf cu gradul 0 (d(x) = 0) senumeste varf izolat.

Notam δ(G) = mindG(u)|u ∈ G si ∆(G) = maxdG(u)|u ∈ G.

Fig. 3.3: Graful lui Petersen

Exemplul 3.4 Graful lui Petersen din figura 3.3 este un exemplu de graf trivalent sau cubic(toate varfurile grafului au acelasi grad, 3).

Propozitia 3.5 Pentru un graf G = (V, E), V = x1, x2, . . . , xn, |E| = m, avem urmatoarearelatie:

n∑

k=1

d(xk) = 2m. (3.1)

Astfel ın orice graf G exista un numar par de varfuri al caror grad este un numar impar.

Definitia 3.6 Se numeste secventa grafica un sir de numere naturale d1, d2, . . . , dn cuproprietatea ca ele reprezinta gradele varfurilor unui graf neorientat.

Corolarul 3.6 Pentru ca o secventa de numere naturale d1, d2, . . . , dn sa fie secventa grafica,este necesar ca:

1. ∀k = 1, n, dk ≤ n− 1;

2.∑n

k=1 dk este un numar par.

Definitia 3.7 Un lant L = [v0, v1, . . . , vm] este o succesiune de varfuri cu proprietatea caoricare doua varfuri vecine sunt adiacente ([vi, vi+1] ∈ E, ∀i = 0, m− 1). Varfurile v0 si vm

se numesc extremitatile lantului, iar m reprezinta lungimea lantului.

36

Page 37: CursuriAG2014

Daca varfurile v0, v1, . . . , vm sunt distincte doua cate doua, lantul se numeste elementar(vi 6= vj , ∀i, j = 0, m).

Definitia 3.8 Un lant L pentru care v0 = vm se numeste ciclu.

Definitia 3.9 Se numeste ciclu hamiltonian un ciclu elementar ce trece prin toate varfurilegrafului. Un graf ce admite un ciclu hamiltonian se numeste graf Hamilton sau grafhamiltonian.

Definitia 3.10 Un lant L ce contine fiecare muchie exact o singura data se numeste lanteulerian. Daca v0 = vm si lantul este eulerian atunci ciclul se numeste ciclu eulerian.Un graf ce contine un ciclu eulerian se numeste graf eulerian.

Exemplul 3.7 [1, 2, 3, 1, 4] este un exemplu de lant ın graful din figura 3.2 c). Varfurile 1si 4 sunt extremitatile lantului. Lantul nu este elementar deoarece varful 1 se ıntalneste dedoua 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 figura 3.2 a). [4, 5, 1, 2, 4, 3] este unlant eulerian, precum si [2, 4, 3, 2, 1, 5, 4]. In acest graf nu exista nici un ciclu eulerian.

Fig. 3.4: Componente conexe

Definitia 3.11 Un graf se numeste conex daca pentru orice pereche de varfuri x si y existaun lant de la x la y (∀x, y ∈ V, ∃x y).

Se numeste componenta conexa un subgraf conex maximal, adica un subgraf conex ıncare nici un varf din subgraf nu este adiacent cu unul din afara lui prin intermediul uneimuchii apartinand grafului initial.

Definitia 3.12 O muchie e ∈ E se numeste muchie critica daca prin eliminarea acesteiao componenta conexa se ımparte ın doua sau mai multe componente conexe.

Exemplul 3.8 Graful din figura 3.4 are doua componente conexe: 1, 2, 3, 4, 5, 6 si 7, 8, 9.Muchia [2, 5] este muchie critica.

Definitia 3.13 Un graf planar este un graf ce poate fi reprezentat ın plan astfel ıncatmuchiile sale sa nu se intersecteze doua cate doua.

Definitia 3.14 Un graf G = (V, E) se numeste graf bipartit daca exista o partitie amultimii nodurilor V1, V2 (V = V1∪V2, V1∩V2 = ∅, V1, V2 6= ∅) astfel ıncat orice muchie dinE va avea o extremitate ın multimea V1 si cealalta extremitate ın multimea V2 (∀[x, y] ∈ Eavem x ∈ V1 si y ∈ V2).

37

Page 38: CursuriAG2014

Propozitia 3.9 Un graf este bipartit daca si numai daca nu contine cicluri de lungimeimpara.

Definitia 3.15 Un graf bipartit este complet daca ∀x ∈ V1, ∀y ∈ V2, ∃[x, y] ∈ E (G =(V, E), V = V1 ∪ V2, V1 ∩ V2 = ∅). Daca |V1| = p, |V2| = q atunci graful bipartit complet senoteaza Kp,q.

Fig. 3.5: Un exemplu de graf bipartit si graf bipartit complet.

Exemplul 3.10 In figura 3.5 a) este ilustrat un graf bipartit (V1 = 1, 2, 3, V2 = 4, 5),iar ın cazul b) avem un graf bipartit complet, K2,3.

Definitia 3.16 Se numeste izomorfism de la graful G la graful G′ o functie bijectiva ϕ :V (G)→ V (G′) astfel ıncat [u, v] ∈ E(G) ⇔ ϕ([u, v]) ∈ E(G′).

Daca exista un izomorfism de la graful G la graful G′ atunci se spune ca G este izomorfcu G′ si notam acest lucru astfel: G ≅ G′.

Definitia 3.17 Un graf etichetat este un graf ın care fiecare muchie si varf poate aveaasociata o eticheta.

Vom prezenta ın continuare cateva operatii dintre cele mai ıntalnite ce se pot efectuaasupra unui graf oarecare:

• fiind dat un nod se cere lista vecinilor sai. Aceasta operatie este cea mai utilizata pentruo serie ıntreaga de algoritmi pe grafuri;

• fiind data o pereche de noduri u, v se cere sa se determine daca aceasta constituie omuchie sau un arc al grafului;

• adaugarea sau stergerea unui nod sau a unei muchii/arc;

• translatarea dintr–un mod de reprezentare ın altul. De foarte multe ori modul dereprezentare sub forma caruia au fost introduse datele, difera de modul de reprezentareoptim recomandat pentru un anumit algoritm. In aceasta situatie este indicata trans-formarea primului mod de reprezentare ın modul de reprezentare optim;

• fiind data o muchie sau un nod se cere o informatie asociata acestui element: de exemplulungimea muchiei sau distanta de la sursa la nodul specificat.

38

Page 39: CursuriAG2014

3.2 Operatii pe grafuri

1. Complementarul grafului G = (V, E) se defineste astfel: este graful Gc = (V c, Ec), undeV c = V si Ec = [x, y]|x, y ∈ V, [x, y] /∈ E. Altfel spus Ec = (V × V ) \ E.

Fig. 3.6: Un exemplu de graf complementar altui graf.

In figura 3.6 b) este reprezentat graful complementar Gc al grafului G = (V, E), dinfigura 3.6 a) (V = 1, 2, 3, 4, 5, E = [1, 2], [1, 5], [2, 3], [3, 4], [4, 5]). Conform definitieiGc = (V c, Ec) unde V c = V si Ec = [1, 3], [1, 4], [2, 4], [2, 5], [3, 5].

2. Graful obtinut din G = (V, E) prin insertia unui varf v /∈ V pe o muchie [x, y] ∈ Eeste graful Gi = (V i, Ei) unde V i = V ∪ v, Ei = (E \ [x, y]) ∪ [x, v], [v, y].Considerand graful din figura 3.6 a), prin insertia varfului 6 pe muchia [1, 5] se obtinegraful din figura 3.7 a).

3. Graful obtinut din G = (V, E) prin contractia unei muchii u = [x, y] la un varf t estegraful Gct = (V ct, Ect), unde V ct = (V \ x, y) ∪ t.

Fig. 3.7: a) Graful obtinut prin inserarea varfului 6 ın graful din figura 3.6 a). b) Graful obtinut princontractia muchiei [3, 4] ın graful din figura 3.6 a).

In figura 3.7 b) este reprezentat graful obtinut prin contractia muchiei [3, 4] din grafulG = (V, E) (vezi figura 3.6 a)).

4. Se numeste graf reprezentativ al muchiilor unui graf G = (V, E), graful GR = (VR, ER)ın care |VR| = |E| si ER = [e, f ]|e, f ∈ E adiacente (vezi figura 3.8).

5. Definim graful total al unui graf G = (V, E) ca fiind graful GT = (VT , ET ) unde VT =V ∪ E si ET = [u, v]|u, v ∈ V ∪ E iar u si v sunt adiacente sau incidente ın G.

39

Page 40: CursuriAG2014

Fig. 3.8: Figura b) prezinta graful reprezentativ al muchiilor grafului din figura a).

Fig. 3.9: a) Un exemplu de graf neorientat. b) Graful total al grafului din figura a).

Graful total GT = (VT , ET ), unde VT = 1, 2, 3, 4, v1, v2, v3, v4, si E = [1, 2], [1, 4],[2, 3], [3, 4], [v1, v2], [v1, v4], [v2, v3], [v3, v4], [v1, 1], [v1, 2], [v2, 2], [v2, 3], [v3, 3], [v3, 4], [v4, 4], [v4, 1],corespunde grafului G = (V, E), V = 1, 2, 3, 4, E = [1, 2], [1, 4], [2, 3], [3, 4] (vezifigura 3.9).

6. Reuniunea si intersectia a doua grafuri se definesc astfel:

• daca V1 = V2 atunci: G1 ∪G2 = (V1, E1 ∪E2), G1 ∩G2 = (V1, E1 ∩E2);

• daca V1∩V2 6= ∅ atunci: G1∪G2 = (V1∪V2, E1∪E2), G1∩G2 = (V1∩V2, E1∩E2);

• daca V1 ∩ V2 = ∅ atunci G1 ∪G2 se numeste reuniune disjuncta a grafurilor G1 siG2, iar G1 ∩G2 este graful vid.

7. Definim suma grafurilor G1 si G2 ca fiind graful complementar al reuniunii comple-mentarelor celor doua grafuri: G1 ⊕G2 = (Gc

1 ∪Gc2)

c.

Pentru grafurile complete Kp si Kq avem: Kp ⊕ Kq = (Kcp ∪ Kc

q)c = Kp+q. Un alt

exemplu de suma a doua grafuri poate fi urmarit ın figura 3.10.

8. Se numeste produsul cartezian al grafurilor G1 = (V1, E1) si G2 = (V2, E2), grafulG1×G2 = (V ×, E×), unde V × = V1×V2 si E× = [(u1, u2), (v1, v2)]|u1, v1 ∈ V1, u2, v2 ∈V2; u1 = v1 si [u2, v2] ∈ E2 sau u2 = v2 si [u1, v1] ∈ E1.

40

Page 41: CursuriAG2014

Fig. 3.10: a) Doua grafuri neorientate, G1 si G2. b) Grafurile complementare Gc1 si Gc

2. c) Reuniuneagrafurilor Gc

1si Gc

2. d) Graful complementar al grafului reuniune (Gc

1∪Gc

2)c.

Fig. 3.11: Graful produs cartezian a doua grafuri

Fie G1 = (V1, E1) unde V1 = u1, v1 si E1 = [u1, v1], si G2 = (V2, E2), unde V2 =u2, v2, w2 si E2 = [u2, v2], [v2, w2], doua grafuri neorientate. Atunci graful produscartezian al grafurilor G1 si G2 este G1 ×G2 = (V ×, E×) unde:

V × = (u1, u2), (u1, v2), (u1, w2), (v1, u2), (v1, v2), (v1, w2), si

E× = [(u1, u2), (v1, u2)], [(u1, u2), (u1, v2)], [(u1, v2), (v1, v2)], [(u1, v2), (u1, w2)],[(u1, w2), (v1, w2)], [(v1, u2), (v1, v2)], [(v1, v2), (v1, w2)] (vezi figura 3.11).

9. Se numeste radacina patrata a grafului G, un graf neorientat H cu proprietatea caH2 = G (H2 = H ×H).

10. Operatia de compunere a doua grafuri neorientate G1 = (V1, E1) si G2 = (V2, E2),notata cu G1[G2], se realizeaza astfel: varful (x1, y1) este adiacent cu varful (x2, y2) ıngraful rezultat daca varful x1 este adiacent cu varful x2 ın graful G1 sau (x1 = x2 sivarful y1 este adiacent cu varful y2 ın graful G2) (vezi figura 3.12).

41

Page 42: CursuriAG2014

Fig. 3.12: Graful rezultat ın urma compunerii grafurilor G1 si G2 din figura 3.11

3.3 Moduri de reprezentare

Fig. 3.13: Un exemplu de graf neorientat

Pentru o multime 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 adiacenta - este o matrice A ∈ Mn×nZ unde n = |V |, iar ai,j = 1 dacaexista o muchie ıntre nodurile numerotate i si j (ıntre xi si xj), sau ai,j = 0 daca nuexista o muchie ıntre acestea.

ai,j =

1 , daca [xi, xj] ∈ E

0 , daca [xi, xj] /∈ E

Pentru un graf neorientat aceasta matrice este simetrica (ai,j = aj,i).

Exemplul 3.11 Matricea de adiacenta corespunzatoare grafului din figura 3.13 este:

A =

0 1 1 1 0 0 0 01 0 0 0 1 0 0 01 0 0 0 1 0 0 01 0 0 0 0 1 0 00 1 1 0 0 0 1 00 0 0 1 0 0 1 10 0 0 0 1 1 0 00 0 0 0 0 1 0 0

42

Page 43: CursuriAG2014

Fig. 3.14: Un exemplu de graf neorientat ponderat

Matricea de adiacenta are un numar de n2 elemente, iar elementele neredundante suntın numar de n(n−1)

2. Prin urmare complexitatea–spatiu a matricii de adiacenta este

O(n2).

2. Matricea costurilor - reprezinta o varianta a matricei de adiacenta ce se obtine ın modnatural luandu–se ın considerare graful ponderat: fiecarei muchii i se ataseaza un costd, iar valorile matricii A se definesc astfel:

ai,j =

0 , daca xi = xj

+∞ , daca [xi, xj] /∈ E

d > 0 , daca [xi, xj] ∈ E

(3.2)

sau

ai,j =

0 , daca xi = xj

−∞ , daca [xi, xj ] /∈ E

d > 0 , daca [xi, xj ] ∈ E.

(3.3)

Exemplul 3.12 Matricea costurilor corespunzatoare grafului din figura 3.14 are urmatoarelevalori:

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

Notatia (3.2) este folosita ın aplicatii ın care se cere un drum de lungime minima iar(3.3) este folosita ın aplicatii ın care se cere un drum de lungime maxima ıntre douanoduri.

Matricea costurilor va ocupa un spatiu de memorie mai mare decat cel ocupat dematricea de adiacenta: pentru reprezentarea unui element al matricii de adiacenta estesuficient un bit, pe cand pentru reprezentarea unui element al matricii costurilor sefoloseste un byte, un ıntreg (lung) sau un numar real.

43

Page 44: CursuriAG2014

Prin urmare pentru reprezentarea unei matrici de adiacenta de dimensiuni n× n suntnecesari n · ⌈n

8⌉ octeti, pe cand pentru reprezentarea unei matrici de costuri cu elemente

numere ıntregi sunt necesari 2 · n2 octeti (daca presupunem ca un numar ıntreg farasemn este pastrat pe 2 octeti).

3. Liste de adiacenta - pentru fiecare nod se retine lista nodurilor adiacente. Astfel unuinod xk i se va atasa lista tuturor vecinilor sai.

Aceasta reprezentare se preteaza mai bine pentru grafuri cu un numar mare de nodurisi un numar mic de muchii (graf rar). In cazul unui graf neorientat numarul elementelordin listele de adiacenta este 2 · |E|, deoarece o muchie [u, v] va fi prezenta de doua ori,atat ın lista de adiacenta a nodului u cat si ın lista de adiacenta a nodului v.

Exemplul 3.13 Listele de adiacenta pentru graful din figura 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 adiacenta (sau liste de vecini) pot fi reprezentate prin intermediultablourilor sau prin intermediul listelor simplu sau dublu ınlantuite.

Pentru reprezentarea ce utilizeaza tablouri, se vor defini doua tablouri Cap si List(Cap ∈ R1×n, List ∈ R2×m, m = |E|) unde:

Capk =

0 , nodul respectiv nu are vecini

j , indica numarul coloanei din matricea List unde se afla primul vecin

al varfului xk.

List1,j - indicele varfului ce se afla ın lista de vecini a varfului xk.

List2,j =

0 , daca varful respectiv este ultimul (aceasta valoare are aceeasi

semnificatie ca si valoarea NIL sau NULL utilizata ın lucrul cu pointeri)

i , indica numarul coloanei unde se afla urmatorul vecin din lista

de vecini a nodului xk.

Exemplul 3.14 Pentru exemplul din figura 3.13 avem urmatoarea configuratie pentrucei doi vectori considerati:

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 62 3 0 5 0 7 0 9 0 11 12 0 14 15 0 17 0 0

)

In limbajul C definim urmatoarele structuri de date avand rolul de a ne ajuta lamentinerea ın memorie a listelor de adiacenta ale unui graf oarecare folosind liste liniaresimplu ınlantuite (vezi si figura 3.15):

44

Page 45: CursuriAG2014

1

2

3

4

5

6

7

8

2 3 4

1 5

2 3 7

4 7 8

5 6

6

1 51 6

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

Fig. 3.15: Liste de adiacenta

typedef struct nod

int nodeIndex;

struct nod *next;

NOD;

#define MAX 100

NOD* vecini[MAX];

NOD* vecini[MAX] este un array de pointeri ce contine ın vecini[i] capul listei de veciniai nodului de indice i. struct nod *next reprezinta un pointer catre urmatoareaınregistrare de tip NOD ce pastreaza informatii cu privire la urmatorul vecin.

Cantitatea de memorie necesara pentru pastrarea listelor de adiacenta este:

• reprezentarea folosind matricile Cap si List - putem presupune ca n, m ≤ 65535adica sunt suficienti 2 octeti pentru reprezentarea acestor numere ın memorie(216 − 1 = 65535). In aceasta situatie cantitatea de memorie necesara pentrumatricea Cap este 2n, iar pentru matricea List este 8m. Astfel complexitatea–spatiu este O(n + m).

• reprezentarea folosind pointeri - presupunem ca avem 2 octeti pentru informatiautila si 2 octeti pentru informatia de legatura. Numarul de octeti folositi pentrureprezentarea unui pointer ın limbajul C poate depinde de modelul de memorieales (small, huge, etc.) sau de dimensiunea instrutiunilor (pe 16, 32 sau 64 debiti).

Astfel se utilizeaza 2n octeti pentru vectorul ce contine adresele primului element(capul) al fiecarei liste de vecini, si 8m octeti pentru ınregistrarile listelor de vecini.

Din aceasta cantitate de memorie, 4m reprezinta informatie utila (indicii vecinilor)iar 2n + 4m informatie 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. Operatia deadaugare a unui nod sau a unei muchii se face ıntr–un timp constant, pe cand, alteoperatii sunt mai costisitoare: de exemplu, determinarea listei de vecini a unui nodnecesita un timp Ω(m).

Exemplul 3.15 Pentru pastrarea ın memorie se poate folosi o matrice M cu doua liniisi |E| coloane (M ∈M2×|E|), unde:

45

Page 46: CursuriAG2014

M1,i - indicele varfului ce se afla ın prima extremitate a muchiei i;

M2,i - indicele varfului ce se afla ın cea de–a doua extremitate a muchiei i.

M =

(1 1 1 2 3 4 5 6 62 3 4 5 5 6 7 7 8

)

Vom sintetiza complexitatea timp pentru diverse operatii folosind fiecare dintre modurilede reprezentare prezentate:

Matricea de adiacenta Liste de vecini Lista de muchii

Gradul unui nod xi O(n) O(d(xi)) O(m)

(xi, xj) ∈ E? O(1) O(d(xi)) O(m)

Urmatorul vecin al lui xi O(n) O(d(xi)) O(m)

3.4 Parcurgerea grafurilor

Pentru un graf dat este important sa se determine o modalitate sistematica de vizitare atuturor varfurilor grafului, vizitare ce se realizeaza ın scopul prelucrarii informatiei continutede acestea.

3.4.1 Parcurgerea ın latime (BF-Breadth-First)

Metoda de parcurgere ın latime viziteaza nodurile grafului ın felul urmator (vezi algoritmul20):

• se viziteaza mai ıntai varful de pornire k;

• urmeaza ın ordine toti vecinii ınca nevizitati ai acestuia;

• se continua cu vecinii ınca nevizitati ai acestora, s.a.m.d.

Fig. 3.16: Arbore de acoperire ın latime

Pentru graful considerat ın figura 3.13 ordinea de parcurgere este urmatoarea: 1, 2, 3, 4,5, 6, 7, 8. Daca consideram muchiile folosite ın timpul parcurgerilor (muchiile prin intermediulcarora s–a ınaintat ın graf) se obtine un arbore/padure de parcurgere/vizitare/acoperire.In figura 3.16 este reprezentat arborele de acoperire ın latime rezultat ın urma parcurgeriigrafului din exemplu.

46

Page 47: CursuriAG2014

Algoritmul de parcurgere utilizeaza o structura de date de tip coada ın care vor fi intro-duse nodurile vizitate, dar care nu au fost ınca prelucrate (nu au fost cercetati vecinii lor).Reamintim ca numarul de noduri din multimea V este n. Vectorul vizitat pastreaza situatiavizitarii nodurilor grafului G:

vizitatk =

1 , daca nodul k a fost vizitat

0 , daca nodul k nu a fost vizitat.

Algoritm 20 Algoritm de vizitare ın latime

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 adiacenta a grafului2: for i← 1, n do

3: vizitati ← 04: end for

5: vizitatk ← 1 ⊲ marcarea nodului curent ca fiind vizitat6: Q⇐ k ⊲ inserarea nodului curent k ın coada7: call V izitare(k) ⊲ vizitarea nodului curent8: while (Q 6= ∅) do

9: Q⇒ k ⊲ extragere nod curent din coada10: for i← 1, n do

11: if (vizitati = 0) ∧ (vecink,i = 1) then

12: vizitati ← 1 ⊲ marcarea nodului i ca fiind vizitat13: Q⇐ i ⊲ inserarea nodului i ın coada14: call V izitare(i) ⊲ vizitarea nodului i15: 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

Page 48: CursuriAG2014

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

Page 49: CursuriAG2014

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 functia de citire readInput() este foarte simpla: se citeste maiıntai numarul de noduri al grafului, si apoi se citeste matricea de adiacenta a grafului.Variabilele n si vecin sunt declarate drept variabile globale. Deoarece matricea vecineste simetrica si pentru a reduce numarul de citiri, se vor solicita numai valorile aflatedeasupra 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];

• Functia memset() este o functie de biblioteca a carei declaratie poate fi gasita ın header-ele mem.h si string.h la Borland C sau memory.h si string.h la Visual C++ 2010 1.Functia are urmatoarea semnatura2

1http://msdn.microsoft.com/en-us/library/1fdeehz6.aspx2http://en.wikibooks.org/wiki/C_Programming/Strings#The_memset_function

49

Page 50: CursuriAG2014

void *memset(void *dest, int c, size t count);

si are rolul de a initializa cu valoarea c primii count octeti din zona de memorie ceıncepe de la adresa identificata de pointerul dest.

• vida este o variabila globala ce ia valoarea true atunci cand coada nu contine nici unelement 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 explorarea spatiului solutiilor, cat si ın cadrul problemelor de determinare a distantei minime de laun varf la toate celelalte varfuri ın cazul ın care lungimea unui drum dintre doua noduri seconsidera ca fiind numarul de noduri intermediare ale acestuia.

3.4.2 Parcurgerea D (D - Depth)

Metoda de parcurgere D este asemanatoare cu metoda de parcurgere ın latime (BF ):

• la ınceput se viziteaza varful de pornire k;

• urmeaza ın ordine toti vecinii ınca nevizitati ai acestuia;

• la pasul urmator se considera ultimul nod vizitat v si se ıncearca vizitarea vecinilor ıncanevizitati ai acestuia. Daca nodul v nu mai are vecini nevizitati, se continua procesulde parcurgere cu nodul ce a fost vizitat exact ınaintea nodului v, etc.

Metoda de parcurgere D este o combinatie ıntre metoda de parcurgere ın latime (vezisectiunea 3.4.1) si metoda de parcurgere ın adancime (vezi sectiunea 3.4.3). Pentru un nodse viziteaza toti vecinii ınca nevizitati ai acestuia, ınsa spre deosebire de metoda de parcurgereın latime unde ordinea ın care au fost vizitate nodurile se pastreaza si la parcurgere, la metodade parcurgere D se prelucreaza mereu ultimul nod vizitat.

Pentru aceasta ın algoritmul D se ınlocuieste structura de date de tip coada utilizata ınalgoritmul BF, cu o structura de date de tip stiva (vezi algoritmul 21).

Fig. 3.17: Arbore de acoperire pentru parcurgerea D

In figura 3.17 poate fi urmarit arborele de acoperire pentru parcurgerea D a grafului Gdin figura 3.13.

50

Page 51: CursuriAG2014

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 adiacenta a grafului2: for i← 1, n do

3: vizitati ← 04: end for

5: vizitatk ← 1 ⊲ marcarea nodului curent ca fiind vizitat6: S ⇐ k ⊲ inserarea nodului curent k ın stiva7: call V izitare(k) ⊲ vizitarea nodului curent8: while (S 6= ∅) do

9: S ⇒ k ⊲ extragerea nodului curent din stiva10: for i← 1, n do

11: if (vizitati = 0) ∧ (vecink,i = 1) then

12: vizitati ← 1 ⊲ marcarea nodului i ca fiind vizitat13: S ⇐ i ⊲ inserarea nodului i in stiva14: call V izitare(i) ⊲ vizitarea nodului i15: 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: prelucrareaunui varf consta ın prelucrarea primului dintre vecinii sai ınca nevizitati.

• 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 caretoti vecinii sai au fost vizitati. In acest caz, se revine ın nodul sau parinte (nodul dincare a fost vizitat nodul curent), si se continua algoritmul.

Pentru graful considerat (vezi figura 3.13), ın urma parcurgerii ın adancime, vom obtinenodurile ın ordinea urmatoare: 1, 2, 5, 3, 7, 6, 4, 8 (vezi figura 3.18). Daca ne propunem savizitam exact o singura data toate nodurile unui graf, aplicand algoritmul DFS de cate orieste nevoie, si selectam numai muchiile utilizate ın timpul explorarii, rezulta o padure dearbori. Fiecare dintre acesti arbori constituie un arbore de acoperire ın adancime.

In urma parcurgerii ın adancime muchiile unui graf pot fi clasificate ın urmatoarele cate-gorii:

1. muchie a arborelui de acoperire - muchia [u, v] este o muchie a arborelui de acoperiredaca dfs(u) apeleaza direct dfs(v) sau invers;

2. muchie de ıntoarcere - muchia [u, v] este o muchie de ıntoarcere daca dfs(u) apeleazaindirect dfs(v) (∃x ∈ V a.i. dfs(u)→ dfs(x)→ dfs(v)) sau invers.

51

Page 52: CursuriAG2014

Fig. 3.18: Arbore de acoperire ın adancime

Exemplul 3.16 Pentru graful din figura 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 adiacenta a grafului2: vizitatk ← 1 ⊲ marcarea nodului curent ca fiind vizitat3: call V izitare(k) ⊲ vizitarea nodului curent4: for i← 1, n do

5: if (vizitati = 0) ∧ (vecink,i = 1) then

6: call DFS(i, n, vecin) ⊲ apelul recursiv al subrutinei DFS pentru nodul i7: end if

8: end for

9: end procedure

Implementarea algoritmului se poate realiza fie ın varianta recursiva (vezi algoritmul 22),fie ın varianta nerecursiva (vezi algoritmul 23). Ca si la algoritmul de parcurgere ın latime,vectorul vizitat pastreaza situatia vizitarii nodurilor grafului G:

vizitatk =

1 , daca nodul k a fost vizitat

0 , ın caz contrar.

Subrutina DFS (algoritmul 22) ıncepe cu marcarea nodului curent ca fiind vizitat (vizitatk ←1) si apelul procedurii V izitare (call V izitare(k)). Apoi se cauta primul vecin nevizitat ial varfului curent k ((vizitati = 0) ∧ (vecink,i = 1)) si se reia secventa de operatii pentruacesta, printr–un apel recursiv (call DFS(i)). Enuntul repetitiv for i ← 1, n poate fi opti-mizat astfel ıncat sa nu se mai verifice toate varfurile grafului, ci numai nodurile adiacentecu nodul curent: ın aceasta situatie reprezentarea cu liste de adiacenta este optima din punct

52

Page 53: CursuriAG2014

de vedere al numarului de operatii efectuate, fiind preferata reprezentarii prin matricea deadiacenta.

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 adiacenta a grafului2: for i← 1, n do

3: vizitati ← 04: end for

5: vizitatk ← 1 ⊲ marcarea nodului curent ca fiind vizitat6: call V izitare(k) ⊲ vizitarea nodului curent7: S ⇐ k ⊲ inserarea nodului curent k ın stiva8: found← false9: while (S 6= ∅) do ⊲ cat timp stiva nu este vida

10: if (¬(found)) then

11: S ⇒ k ⊲ extragerea nodului curent din stiva12: end if

13: i← 114: found← false15: while (i ≤ n) ∧ (found = false) do

16: if (vizitati = 0) ∧ (vecink,i = 1) then

17: vizitati ← 1 ⊲ marcarea nodului i ca fiind vizitat18: S ⇐ k ⊲ inserarea nodului curent k ın stiva19: call V izitare(i) ⊲ vizitarea nodului i20: k ← i21: found← true22: else

23: i← i + 124: 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-aajuns la nodul curent (tatal nodului curent din arborele de acoperire ın adancime). Secventade instructiuni 23.13–23.25 nu este optima deoarece, de fiecare data cand se revine la un nodparinte, se verifica ıntreaga multime V pentru a identifica un vecin nevizitat al acestuia. Invederea reducerii numarului de verificari, se va utiliza reprezentarea prin liste de adiacenta,si se salveaza pe stiva, pe langa valoarea nodului curent k, valoarea vecinului nevizitat gasit,astfel ıncat, la revenire, sa se continue cautarea urmatorului vecin nevizitat al nodului curentk pornind de la acest nod. Daca nu mai exista nici un vecin nevizitat al varfului k (linia10), atunci se revine la parintele nodului curent aflat pe stiva. Algoritmul se opreste ıncazul ın care stiva este vida (atunci cand nodul curent este radacina arborelui de vizitare ınadancime).

Am ales aici varianta recursiva pentru usurinta de programare si eleganta ei. Prezentamın continuare implementarea ın limbajul C a algoritmului 22:

#include <stdio.h>

53

Page 54: CursuriAG2014

#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 prezentati este O(n2) deoarece se utilizeaza matricea de adiacen-ta drept modalitate de reprezentare a grafului. Daca se utilizeaza reprezentarea prin liste de

54

Page 55: CursuriAG2014

vecini, atunci complexitatea algoritmilor devine O(n + m), unde m = |E|.Matricea de adiacenta Liste de vecini Lista de muchii

BFS O(n2) O(n + m) O(n + m2)

D O(n2) O(n + m) O(n + m2)

DFS O(n2) O(n + m) O(n + m2)

3.5 Componente conexe

Se poate defini pe multimea varfurilor unui graf neorientat G o relatie ρ astfel: xρy dacax = y sau exista ın G un lant de la x la y.

Se demonstreaza foarte usor ca relatia ρ este o relatie de echivalenta. Se cunoaste faptul cao relatie de echivalenta determina pe multimea pe care este definita o partitie. Componenteleconexe vor fi elementele acestei partitii formate din varfurile ce sunt echivalente ıntre ele(conform relatiei de echivalenta).

Cu alte cuvinte, exista o partitie a multimii varfurilor V

V =m⋃

i=1

Vi, Vi ∩ Vj = ∅, ∀i, j = 1, m, i 6= j

si o partitie a multimii muchiilor E

E =m⋃

i=1

Ei, Ei ∩ Ej = ∅, ∀i, j = 1, m, i 6= j

astfel ıncat fiecare graf Gi = (Vi, Ei), ∀i = 1, m, este conex.

Algoritm 24 Algoritm pentru determinarea componentelor conexe

Input:

n - numarul de noduri din graf

V ecin - matricea de adiacenta a grafului1: for i← 1, n do

2: vizitati ← 03: end for

4: cmp conex nr← 05: for i← 1, n do

6: if (vizitati = 0) then

7: cmp conex nr← cmp conex nr + 18: call DFS(i, n, V ecin) ⊲ determinarea componentei conexe ce contine nodul i9: end if

10: end for

Pentru determinarea componentelor conexe vom utiliza metoda de vizitare ın adancime aunui graf. Pasii algoritmului descrisi ın limbaj natural sunt urmatorii (algoritmul 24 prezintadescrierea formalizata ın pseudo–cod):

Pas 1. Se cauta un nod ınca nevizitat.

Pas 2. Incepand cu acesta se parcurg toate nodurile accesibile si nevizitate, avand grija samarcam 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

Page 56: CursuriAG2014

3.6 Muchie critica

Reamintim faptul ca ıntr–un graf neorientat G = (V, E), o muchie critica este acea muchiecare 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.

Solutia I

Pentru simplitate, vom trata situatia ın care graful considerat este conex (daca graful nueste conex se determina numarul de componente conexe si se aplica algoritmul pentru fiecarecomponenta conexa ın parte). Se elimina, pe rand, fiecare muchie a grafului si apoi se verificadaca 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 adiacenta2: for k ← 1,m do

3: elimina muchia k4: if (conex(n, vecin) = false) then

5: Output ’Muchia k este critica’6: end if

7: adauga muchia k ⊲ reface graful initial8: end for

9: end procedure

10: function Conex(n, V ecin)11: for i← 1, n do

12: vizitati ← 013: end for

14: call DFS(1, n, V ecin) ⊲ vizitarea ın adancime a grafului15: for i← 1, n do

16: if (vizitati = 0) then

17: return false18: end if

19: end for

20: return true21: end function

Subrutina Conex verifica daca graful identificat prin matricea de adiacenta V ecin esteconex. Subrutina ıntoarce valoarea 1 ın cazul ın care graful considerat este conex si 0 ıncaz contrar. Pentru aceasta, la ınceput se marcheaza toate nodurile ca fiind 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

Page 57: CursuriAG2014

#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

Page 58: CursuriAG2014

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;

Observatia 3.17 Am presupus ca numerotarea nodurilor se face de la 0 si ca exista un nodcu eticheta 0.

Complexitatea–timp a acestui algoritm (presupunem ca avem o singura componentaconexa), este O(m(n + m)): se ia fiecare muchie (O(m)), se elimina din graf, si se verificadaca graful ramas este conex (O(n + m)).

Solutia a II–a

Cea de–a doua varianta de abordare pentru identificarea unei solutii foloseste urmatoareaproprietate:

Observatia 3.18 O muchie nu este critica daca ea face parte din cel putin un ciclu elemen-tar al grafului respectiv.

In urma vizitarii DFS, toate muchiile unui graf se ımpart ın muchii ale arborelui deacoperire si muchii de ıntoarcere.

Vom numerota toate nodurile grafului ın preordine - ın momentul ın care un nod estemarcat ca fiind vizitat - toate valorile fiind pastrate ıntr-un vector prenum. Fie lowu valoareaunui nod u, calculata dupa formula:

lowu = min

prenumu , si

prenumx , daca [u, x] este muchie de ıntoarcere, si

lowy , ∀y descendent direct al lui u.

Daca prenumu ≥ lowv, ∀v descendent direct al lui u, atunci ınseamna ca v sau undescendent al lui v are o muchie de ıntoarcere la u sau la un stramos al acestuia. Astfel muchia[u, v] apartine unui ciclu elementar, si prin urmare nu este muchie critica (vezi algoritmul26). Prin negatie, daca exista cel putin un varf v, descendent direct al lui u, cu proprietateaca prenumu < lowv atunci [u, v] este muchie critica. Dupa fiecare apel recursiv al subrutineiDFS (linia 16) se verifica gradul de adevar al expresiei (prenumk < lowi) (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 prenumk ←counter. Cand un nod i este vecin cu nodul curent k, si nu a fost ınca vizitat, valoarea luilowk se calculeaza astfel: lowk ← min lowk, lowi. Pentru un nod i vecin cu nodul curentk, deja vizitat, avem o muchie de ıntoarcere (nodului k i s–a atribuit deja un numar ınpreordine): astfel valoarea lui lowk se calculeaza dupa formula lowk ← min lowk, prenumi.

Implementarea ın limbajul C a algoritmului 26 este:

58

Page 59: CursuriAG2014

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 adiacenta2: for i← 1, n do

3: vizitati ← 04: end for

5: counter ← 06: call DFS critic(1, n, V ecin) ⊲ vizitarea ın adancime a grafului7: end procedure

8: procedure DFS critic(k, n, V ecin)9: vizitatk ← 1

10: counter ← counter + 111: prenumk ← counter, lowk ← counter12: for i← 1, n do

13: if (vecink,i = 1) then

14: if (vizitati = 0) then

15: tatai ← k16: call DFS critic(i, n, V ecin)17: lowk ←Min(lowk, lowi)18: if (prenumk < lowi) then

19: Output ’Muchia (k,i) este critica’20: end if

21: else

22: if (tatak 6= i) then

23: lowk ←Min(lowk, prenumi)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

Page 60: CursuriAG2014

* 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

Page 61: CursuriAG2014

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 figura 3.13

Exemplul 3.19 Pentru graful din figura 3.13, valorile prenum si low sunt cele din figura3.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). Conditia prenumu <lowv, unde [u, v] este o muchie a grafului, este ındeplinita doar pentru u = 6 si v = 8. Prinurmare [6, 8] este muchie critica ın graful considerat.

Deoarece acest algoritm este constituit din algoritmul modificat de vizitare ın adancimea unui graf, complexitatea–timp este O(n + m) atunci cand graful este reprezentat prin listede adiacenta si O(n2) ın situatia ın care graful este reprezentat prin matricea de adiacenta.

3.7 Exercitii

1. Un graf neorientat cu n noduri, G = (V, E) se numeste graf scorpion daca poseda treinoduri speciale:

(a) acul - dG(u) = 1 si este legat de coada;

(b) coada - dG(u) = 2 si este legata de ac si corp;

(c) corpul - dG(u) = n− 2 fiind legat de toate nodurile din graf cu exceptia acului.

61

Page 62: CursuriAG2014

Fig. 3.20: Un exemplu de graf neorientat cu 8 varfuri

Nu exista alte restrictii 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 deordine. Se da lista celor m perechi de bazine ce trebuie unite prin canale. Un numarde bazine poate sa apara ın mai multe perechi. Canalele pot fi realizate ın interiorulsau ın exteriorul cercului, cu conditia ca ele sa nu se intersecteze.

Daca problema are solutie, vor fi afisate doua liste: cea a perechilor de bazine uniteprin canale interioare si cea a perechilor de bazine unite prin canale exterioare. Dacaproblema nu are solutie, atunci se va raporta acest lucru.

In cazul ın care problema are solutie sa se determine toate posibilitatile de unire princanale exterioare sau interioare.

(ONI, 1993)

3. Sa se parcurga ın latime si ın adancime graful din figura 3.20, sa se construiasca arboriide parcurgere si sa se puna ın evidenta muchiile de ıntoarcere.

4. Compania TLC (Telephone Line Company) a stabilit o noua retea de cablu telefonic.Ea leaga mai multe locuri numerotate cu numere ıntregi de la 1 la N . Nu exista doualocuri numerotate cu acelasi numar. Liniile sunt bidirectionale si leaga doua locuri;fiecare loc are un post telefonic. Din orice loc poate fi apelat oricare alt loc, prinlegatura directa sau conexiuni intermediare. Uneori reteaua cade ın unele locuri siconexiunea aferenta nu mai este posibila. Tehnicienii de la TLC au realizat ca ın acestcaz, nu numai ca locul respectiv nu mai poate fi apelat, dar el rupe legatura si ıntrealte locuri pentru care asigura conexiunea. In aceasta situatie spunem ca locul (undea aparut caderea) este critic.

Se cere sa de dezvolte un algoritm care sa calculeze numarul tuturor acestor punctecritice.

(ACM Europa Centrala, 1996)

5. Fiind dat un graf G = (V, E), sa se verifice daca este aciclic.

6. Fiind dat un graf G = (V, E), sa se verifice daca este bipartit.

62

Page 63: CursuriAG2014

7. Intr–un oras intersectiile sunt numerotate de la 1 la n (se considera intersectie nunumai locul unde se intersecteaza mai multe strazi ci si punctele terminale – capetelede strazi). Edilii orasului doresc sa numeroteze si strazile orasului, dar ıntr–un modcare sa tina seama de numerotarea intersectiilor, si anume: doua strazi diferite vor aveanumere diferite si ın fiecare intersectie trebuie sa soseasca o strada care sa aiba numarulintersectiei.

Se cere sa se realizeze un algoritm care sa determine o astfel de numerotare, daca exista.

Datele de intrare constau dintr–un numar n reprezentand numarul de puncte de inter-sectie; fiecare punct este identificat prin numarul cu care este numerotat, ıntre 1 si n,urmat de lista punctelor cu care acesta comunica direct printr–o strada. Prin strada seıntelege o portiune de drum aflata ıntre doua puncte de intersectie, neglijand faptul caın practica strazile cuprind mai multe intersectii.

8. Se considera o tabla de sah de dimensiune n × n (n ≤ 100) pe care sunt dispuseobstacole. Se cere sa se determine numarul minim de mutari necesare unui nebunpentru a se deplasa, respectand regulile jocului de sah si ocolind obstacolele, dintr–opozitie initiala data ıntr–o pozitie finala data.

Se considera ca obstacolele nu coincid cu pozitia initiala si nici cu cea finala a nebunului.

(Concurs studentesc, 1993)

9. Pe o tarla agricola sunt mai multe parcele ce trebuie cosite. Parcelele de diferite culturi(lucerna, trifoi, iarba, furaje) vor fi cosite de muncitori diferiti ce lucreaza numai la unanumit fel de cultura (de exemplu este specializat numai pe cositul lucernei).

Terenul agricol se modeleaza printr–o matrice n×m. Fiecare element al matricii core-spunde unei multimi de un anumit tip. Doua elemente ale matricii sunt vecine dacaau o latura comuna. O parcela este o multime maximala de elemente astfel ıncat unmuncitor se poate deplasa ıntre oricare doua elemente de–a lungul a doua elementevecine.

Se cere sa se determine numarul de muncitori care pot sa coseasca o cultura data.

63

Page 64: CursuriAG2014

Capitolul 4

Grafuri euleriene si hamiltoniene

4.1 Grafuri Euleriene

In anul 1736, matematicianul Leonhard Euler publica o lucrare asupra problemei podurilordin Konigsberg1 (figura 4.1) ın care se prezinta un studiu teoretic asupra lanturilor si ciclurilorEuleriene.

Fig. 4.1: Podurile din Konigsberg

Sa consideram un graf neorientat G = (V, E).

Definitia 4.1 Un lant L ce contine fiecare muchie a unui graf G o singura data se numestelant Euler sau lant eulerian. Daca extremitatile lantului sunt identice si lantul esteeulerian atunci ciclul se numeste ciclu Euler sau ciclu eulerian. Un graf ce contine unciclu eulerian se numeste graf eulerian.

O problema mai cunoscuta legata de notiunile de ciclu si lant eulerian este aceea de adesena cu o singura linie neıntrerupta o anumita figura (vezi figura 4.2).

Teorema 4.1 (Euler) Un graf G conex (|V | ≥ 3) este eulerian daca si numai daca gradulfiecarui varf este par.

1http://en.wikipedia.org/wiki/Seven Bridges of Konigsberg

64

Page 65: CursuriAG2014

Fig. 4.2: Doua figuri geometrice ce pot fi desenate folosind o singura linie

Demonstratie: ” ⇒ ” Fie G un graf conex eulerian ⇒ ∃ un ciclu eulerian C. Acestatrece o singura data prin toate muchiile grafului. Gradul fiecarui varf u este par deoarecepentru fiecare muchie incidenta cu u prin intermediul careia se ajunge ın varful u, exista oalta muchie prin intermediul careia se paraseste varful u.

”⇐ ” Presupunem ca ∀u ∈ V , dG(u) este par. Fie L un lant de lungime maxima ın G sifie u si v extremitatile lantului.

Presupunem ca u 6= v. Deoarece dG(v) este par, ∃[v, w] ∈ E astfel ıncat [v, w] /∈ L. LantulL ∪ [v, w] are lungimea mai mare decat L, contradictie. Prin urmare u = v. Rezulta caL = 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 six ∈ C (exista o muchie a grafului G ce nu apartine ciclului C cu proprietatea ca cel putin oextremitate apartine ciclului).

Fie L1 = [x, . . . , u, v, . . . , x] un lant ın G ce contine exact muchiile lui C.Atunci L2 = [x, . . . , u, v, . . . , x, y] este un lant ın G ce are lungimea mai mare decat L,contradictie. 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 exactdoua varfuri ın G al caror grad sa fie impar.

Demonstratie: ”⇒ ” 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 obtinut din G prin adaugarea nodului w si amuchiilor [u, w], [v, w]. Atunci dG′(u) este par, ∀u ∈ V ′ ⇒ exista un ciclu eulerian C ın G′.Daca eliminam muchiile [u, w] si [v, w] obtinem un lant eulerian ın G.

Corolarul 4.3 Un graf G conex (|V | ≥ 3) este eulerian daca si numai daca multimea muchi-ilor sale poate fi descompusa ın cicluri disjuncte.

Teorema 4.4 Pentru un graf conex cu 2k varfuri de grad impar, k ≥ 1, exista k lanturiın G ale caror multimi de muchii formeaza o partitie a lui E, si din care cel mult unul arelungime 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 plecareun varf oarecare al grafului. La fiecare pas se alege pentru varful curent u, un varf adiacent

65

Page 66: CursuriAG2014

Fig. 4.3: Exemplu de graf eulerian

v, diferit de varful din care s–a ajuns ın u. Parcurgerea se continua pana ın momentul ıncare ajungem ıntr–un varf ce a fost deja vizitat si se ınchide ciclul C. Daca ciclul C nueste eulerian, atunci se elimina din graful G toate muchiile ciclului C, rezultand mai multecomponente conexe G1

1, G12, . . . , G

1k.

Pentru fiecare astfel de componenta G1i , ce are cel putin doua varfuri, aplicam recursiv

algoritmul. Conform teoremei 4.1, fiecare componenta G1i este euleriana. Fie C1

i cicluleulerian corespunzator componentei G1

i .Ciclul C are cel putin cate un varf comun cu fiecare ciclu C1

i . Fie acest varf ui. Definimun ciclu C0 astfel: pentru fiecare i, i = 1, k, adaugam la ciclul C, ın varful ui, ciclul C1

i .Ciclul C0 contine toate muchiile grafului G, prin urmare este eulerian.

Funtia IsEulerian() verifica daca un graf este eulerian conform teoremei 4.1 (vezi algo-ritmul 27).

Algoritm 27 Algoritm de verificare daca un graf conex este eulerian

1: function IsEulerian(G = (V,E))2: if (|V | < 3) then

3: return false4: end if

5: for i← 1, n do

6: s← 07: for j ← 1, n do

8: s← s + vecini,j

9: end for

10: if (s mod 2 = 1) then

11: return false12: end if

13: end for

14: return true15: end function

Dupa cum se poate vedea din functia IsEulerian numai componentele conexe ce auordinul mai mare sau egal cu 3 vor fi luate ın considerare.

In algoritmul 28 este prezentata functia EulerRec pentru determinarea unui ciclu eulerian.

66

Page 67: CursuriAG2014

Procedura FindCycle(G) (vezi algoritmul 28) construieste un ciclu: se alege un varf u0 sise cauta prima muchie [u0, u1]. In varful u1 se cauta o muchie [u1, u2] astfel ıncat varful u2 safie distinct de varful din care s–a ajuns ın u1 (u2 6= u0) si sa nu mai fi fost vizitat. Daca u2 afost vizitat atunci functia se termina. Se continua procedeul de cautare pana cand se ajungela un varf ce a fost vizitat anterior si se returneaza ciclul cuprins ıntre cele doua aparitii aleaceluiasi varf.

Procedura FindComponents(G′; k, G11, G

12, . . . , G

1k) determina componentele conexe ale

grafului G′ = G − E(C), obtinut prin eliminarea din graful G a muchiilor ciclului C, undeG1

1, G12, . . . , G1

k sunt cele k componente conexe returnate de aceasta.Procedura MergeCycles(C, C1

1 , . . . , C1k ; C0) construieste un ciclul C0 obtinut prin adaugarea

la ciclul C, succesiv, a ciclurilor C11 , . . . , C

1k .

Algoritm 28 Algoritm de determinare a unui ciclu eulerian ıntr–un 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 C8: end if

9: G′ ← G− E(C)10: call FindComponents(G′; k,G1

1, G12, . . . , G

1k)

11: for i← 1, k do

12: C1i ← EulerRec(G1

i )13: end for

14: call MergeCycles(C,C11 , . . . , C1

k ;C0)15: return C0

16: end function

Fig. 4.4: Grafurile partiale obtinute ın urma primelor doua etape ale algoritmului 28

Exemplul 4.5 Sa aplicam algoritmul 28 pentru graful din figura 4.3. Presupunem ca primulelement (elementul de start) este varful u0 = 1. Procedura FindCycle construieste lantul

67

Page 68: CursuriAG2014

Fig. 4.5: Grafurile partiale obtinute ın urma etapelor 3 si 4 ale algoritmului 28

L = [1, 2, 3, 4, 5, 3]. Se observa prezenta ciclului C1 = [3, 4, 5, 3]. In urma eliminarii acestuiaramane graful din figura 4.4 a) care este un graf conex.

Continuam procesul de construire a unui ciclu eulerian, prin apelul procedurii FindCyclepentru noul graf. Aceasta returneaza ciclul C2 = [1, 2, 3, 9, 1]. Prin eliminarea muchiiloracestuia, E(C2), se obtine graful din figura 4.4 b). In continuare se construieste lantulL = [2, 8, 7, 5, 6, 4, 10, 2], ce contine ciclul C3 = [2, 8, 7, 5, 6, 4, 10, 2]. Graful obtinut prineliminarea muchiilor ciclului este cel din figura 4.5 a). Apelul procedurii FindCycle conducela determinarea lantului L = [6, 7, 9, 8, 10, 6] si a ciclului C4 = [6, 7, 9, 8, 10, 6].

Ciclul eulerian se formeaza prin reuniunea ciclurilor intermediare determinate: C =(((C4 ∪C3)∪C2)∪C1) adica C = [1, 2, 8, 7, 5, 6, 7, 9, 8, 10, 6, 4, 10, 2, 3, 4, 5, 3, 9, 1] (C4 ∪C3 =[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 final 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 nodulcurent u se cauta o muchie incidenta cu el, si care sa nu mai fi fost parcursa la unul din pasiianteriori. 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 muchiinevizitate, se adauga lantului L, si se extrage de pe stiva nodul anterior (din care s–a ajunsın u) (vezi algoritmul 29). Vectorul vizit are drept scop sa pastreze situatia muchiilor:

vizite =

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 figura 4.3. Sa presupunem cavarful u de la care porneste algoritmul este varful 1. La sfarsitul primului pas al enuntuluirepetitiv 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 acestuiaavem:

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

Page 69: CursuriAG2014

Algoritm 29 Algoritm lui Rosenstiehl de determinare a unui ciclu eulerian ıntr–un grafconex

1: function Rosenstiehl(u, G)2: for e ∈ E do

3: vizite ← 04: end for

5: S ⇐ u ⊲ Se insereaza pe stiva nodul u6: while (S 6= ∅) do

7: S ⇒ u ⊲ Se extrage din stiva nodul curent8: while (∃e = [u, v] ∈ E) ∧ (vizite = 0)) do

9: vizite ← 1 ⊲ Se marcheaza muchia e ca fiind utilizata10: S ⇐ u ⊲ Se salveaza pe stiva nodul curent u11: u← v ⊲ Nodul curent devine nodul v12: end while

13: L⇐ u ⊲ Se adauga la lista L nodul curent14: end while

15: return L16: end function

In continuare, deoarece nu mai exista muchii nevizitate, se vor extrage elementele aflate pestiva S cate unul la fiecare pas, formand secventa (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 obtinut se afla ı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

Page 70: CursuriAG2014

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 fi preluate dintr-un fisier. Continutul fisierului de intrare graf1.txtcorespunzator grafului din figura 4.6 este urmatorul:

70

Page 71: CursuriAG2014

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 multimii V ), si ıncepandcu cea de-a doua linie avem valorile matricei de adiacenta, separate prin spatii, cate un randal acesteia pe fiecare 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-urilordin cadrul librariei Standard Template Library - STL2 3:

• stiva - stack 4. Am folosit o stiva de numere ıntregi: stack<int> s;.

• lista - list5. Pentru a pastra elementele ciclului eulerian am folosit o lista liniara,informatia utila din cadrul nodurilor fiind constituita din valori ıntregi: list<int> l

= list<int>();.

• vector - vector 6. Matricea de adiacenta am implementat-o sub forma unui vector devectori 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 agrafului s-a folosit matricea de adiacenta.

2http://en.wikipedia.org/wiki/Standard_Template_Library,3http://www.sgi.com/tech/stl/4http://www.sgi.com/tech/stl/stack.html5http://www.sgi.com/tech/stl/List.html6http://www.sgi.com/tech/stl/Vector.html

71

Page 72: CursuriAG2014

• Parcurgerea elementelor listei se realizeaza cu ajutorul unui iterator - iterator 7. Declarareaunui obiect de tip list<int>::iterator se poate face astfel: list<int>::iteratorit;.

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 anu mai pastra o structura auxiliara care sa marcheze faptul ca o muchie a fost vizitata, vommarca parcurgerea unei muchii prin stergerea acesteia din matricea de adiacenta astfel:

ma[u][v] = 0;

ma[v][u] = 0;

Ciclul eulerian obtinut pentru graful din figura 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 fiecare pas a unei muchii nealeasa la pasii anteriori, sicare, de preferat, sa nu fie muchie critica ın graful partial obtinut prin eliminarea muchiilordeja alese.

Sa consideram ca, la un moment dat, avem construit un lant Lk = [v0, [v0, v1], v1, . . . ,[vk−1, vk], vk]. Cautam o muchie ek+1 = [vk, vk+1] astfel ıncat ek+1 /∈ Lk si care nu este muchie

7http://www.sgi.com/tech/stl/Iterators.html

72

Page 73: CursuriAG2014

critica ın graful partial Gk = G − e1, e2, . . . , ek (graful obtinut prin eliminarea tuturormuchiilor lantului Lk). Daca nu exista decat muchii critice ın graful partial Gk incidente cuvk atunci alegem una dintre ele.

Daca exista o muchie ek+1 cu aceste proprietati atunci construim lantul Lk+1 = [Lk, ek+1, vk+1](Lk+1 = [v0, [v0, v1], v1, . . . , [vk−1, vk], vk, [vk, vk+1], vk+1]). In momentul ın care E(Lk) = E(G)algoritmul lui Fleury se opreste (vezi algoritmul 30).

Algoritm 30 Algoritm lui Fleury de determinare a unui ciclu eulerian ıntr–un graf conex

1: function Fleury(u0, G = (V,E))2: k ← 03: L0 ← [u0]4: while (k ≤ m) do

5: caut ek+1 = [vk, vk+1] a.i. ek+1 /∈ Lk si ek+1, de preferat, nu este muchie critica ın grafulGk = G− e1, e2, . . . , ek

6: Lk+1 ← [Lk, ek+1, vk+1]7: k ← k + 18: end while

9: return Lk

10: end function

Exemplul 4.7 Sa aplicam algoritmul 30 pentru graful din figura 4.7. La ınceput L0 = [u1].Apoi se intra ın ciclul while (liniile 4 – 8): tabelul urmator indica muchia ce a fost aleasala fiecare pas k, precum si configuratia lantului Lk.

Pasul k Muchia aleasa Lk

1 [u1u4] L1 = [u1, [u1u4], u4]

2 [u4u10] L2 = [u1, [u1u4], u4, [u4u10], u10]

3 [u10u3] L3 = [u1, [u1u4], u4, [u4u10], u10, [u10u3], u3]

4 [u3u2] L4 = [. . . , [u10u3], u3, [u3, u2], u2]

5 [u2u6] L5 = [. . . , u2, [u2u6], u6]

6 [u6u1] L6 = [. . . , u6, [u6u1], u1]

7 [u1u5] L7 = [. . . , u1, [u1u5], u5]

8 [u5u6] L8 = [. . . , u5, [u5u6], u6]

9 [u6u7] L9 = [. . . , u6, [u6u7], u7]

10 [u7u2] L10 = [. . . , u7, [u7u2], u2]

11 [u2u8] L11 = [. . . , u2, [u2u8], u8]

12 [u8u3] L12 = [. . . , u8, [u8u3], u3]

13 [u3u9] L13 = [. . . , u3, [u3u9], u9]

14 [u9u8] L14 = [. . . , u9, [u9u8], u8]

15 [u8u7] L15 = [. . . , u8, [u8u7], u7]

16 [u7u13] L16 = [. . . , u7, [u7u13], u13]

17 [u13u5] L17 = [. . . , u13, [u13u5], u5]

18 [u5u12] L18 = [. . . , u5, [u5u12], u12]

19 [u12u4] L19 = [. . . , u12, [u12u4], u4]

73

Page 74: CursuriAG2014

Pasul k Muchia aleasa Lk

20 [u4u11] L20 = [. . . , u4, [u4u11], u11]

21 [u11u10] L21 = [. . . , u11, [u11u10], u10]

22 [u10u9] L22 = [. . . , u10, [u10u9], u9]

23 [u9u13] L23 = [. . . , u9, [u9u13], u13]

24 [u13u11] L24 = [. . . , u13, [u13u11], u11]

25 [u11u12] L25 = [. . . , u11, [u11u12], u12]

26 [u12u1] L26 = [. . . , u12, [u12u1], u1]

La final, lantul are urmatoarea componenta: L2 = [u1, u4, u10, u3, u2, u6, u1, u5, u6, u7, u2,u8, u3, u9, u8, u7, u13, u5, u12, u4, u11, u10, u9, u13, u11, u12, u1] (s-au omis din aceasta enumeraremuchiile grafului).

4.2 Grafuri Hamiltoniene

Definitia 4.2 Se numeste lant Hamilton sau lant hamiltonian un lant L ce trece osingura data prin toate varfurile unui graf.

Definitia 4.3 Se numeste ciclu hamiltonian un ciclu elementar ce trece prin toate varfurilegrafului. Un graf ce admite un ciclu hamiltonian se numeste graf hamiltonian.

Problema determinarii daca un graf oarecare G este hamiltonian este o problema dificila,atentia cercetatorilor ındreptandu–se catre enuntarea unor conditii suficiente de existenta aunui ciclu hamiltonian.

Lema 4.8 Fie G = (V, E) un graf neorientat si fie u si v doua varfuri neadiacente ale grafului(u, v ∈ V , u 6= v, [u, v] /∈ E), astfel ıncat dG(u) + dG(v) ≥ n. Atunci G este hamiltonian ⇔G + [u, v] este hamiltonian.

Demonstratie: ”⇒ ” 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 grafhamiltonian.

2. daca [u, v] ∈ C atunci C = [u, v, x3, x4, . . . , xn−1, xn, u]. Pentru fiecare muchie [u, xk] ∈E putem avea urmatoarele situatii:

(a) [v, xk+1] ∈ E. Atunci ciclul C1 = [u, xk, xk−1, . . . , x3, v, xk+1, . . . , xn, u] este hamil-tonian ın graful G ⇒ graful G este hamiltonian.

(b) [v, xk+1] /∈ E. Notam dG+[u,v](u) = k. Atunci dG+[u,v](v) ≤ n− k − 1. si De aici,rezulta ca dG(u) + dG(v) < dG+[u,v](u) + dG+[u,v](v) ≤ n− k + k − 1 = n− 1 < n.Contradictie cu dG(u) + dG(v) ≥ n, ∀u, v ∈ V, u 6= 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 ∈ Vavem dG(u) ≥ n

2(orice varf al grafului are gradul mai mare decat jumatate din numarul de

varfuri din graf).

74

Page 75: CursuriAG2014

Teorema 4.10 (Ore, 1961) Un graf G = (V, E) (|V | ≥ 3) este hamiltonian daca ∀u, v ∈ Vavem dG(u) + dG(v) ≥ n unde u 6= 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 d1, d2, . . . , dn osecventa grafica. Daca este satisfacuta relatia

∀k a.i. dk ≤ k ≤ n

2⇒ dn−k ≥ n− k

atunci graful este hamiltonian.

Definitia 4.4 Pentru un graf G construim un sir de grafuri G = G1, G2, . . . astfel: grafulGk+1 se obtine din graful Gk prin adaugarea muchiei [uk, vk], unde varfurile uk, vk ∈ V nusunt adiacente ın Gk si dG(uk) + dG(vk) ≥ n. Procesul se ıncheie ın momentul ın care numai exista doua varfuri neadiacente distincte astfel ıncat dG(up) + dG(vp) ≥ n. Graful Gp senumeste ı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) ≅ Kn (dacaınchiderea lui G este izomorfa cu graful complet de ordinul n).

Definim δ(G) = mindG(u)|u ∈ V si ∆(G) = maxdG(u)|u ∈ V .

Corolarul 4.14 Un graf G = (V, E) (|V | ≥ 3) este hamiltonian daca δ(G) ≥ n2.

Definitia 4.5 O multime de varfuri A a unui graf G se spune ca este independenta dacaoricare doua elemente distincte din A sunt independente. Numarul de independenta al lui G,notat cu β(G), reprezinta numarul maxim de varfuri dintr–o multime independenta.

β(G) = 1 daca si numai daca graful G este complet.

Definitia 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 submultime U a lui V astfelıncat graful G− U sa fie neconex.

Teorema 4.15 Un graf G = (V, E) avand ordinul n ≥ 3, este hamiltonian daca κ(G) ≥β(G).

Observatia 4.16 Pentru un graf bipartit G = (V1, V2, E) conditia necesara pentru a fi hamil-tonian este |V1| = |V2|.

Problema comis–voiajorului include problema determinarii existentei unui ciclu hamilto-nian ıntr–un graf.

Cautarea optimului printre toate variantele de cicluri nu este o solutie fezabila deoarecepentru un graf G numarul de cicluri poate fi foarte mare. De exemplu pentru graful completKn avem (n−1)!

2cicluri hamiltoniene distincte.

Exemplul 4.17 Graful din figura 3.20 nu este hamiltonian (nu admite un ciclu hamilto-nian).

75

Page 76: CursuriAG2014

• Graful din figura 4.6 are mai multe cicluri hamiltoniene: de exemplu ciclurile C1 = [1, 5,

2, 3, 6, 4, 1] si C2 = [1, 3, 6, 4, 2, 5, 1].

Nod 1 2 3 4 5 6dG 4 4 4 4 2 2

Teorema lui Dirac (1952) nu se poate aplica deoarece nu este ındeplinita conditia ”orice varfal grafului are gradul mai mare decat jumatate din numarul de varfuri din graf”:

dG(5) = 2 <n

2=

6

2= 3.

De asemenea, pentru teorema lui Ore (1961) nu este ındeplinita conditia ”pentru oricare douavarfuri dinstincte, neadiacente, ale grafului suma gradelor lor este mai mare decat numarulde varfuri din graf”: fie varfurile 5 si 6, neadiacente, pentru care avem

dG(5) + dG(6) = 2 + 2 = 4 < 6.

• Pentru graful din figura 4.8 avem:

Nod 1 2 3 4 5 6 7 8dG 3 4 3 4 4 5 3 4

– conditia teoremei lui Dirac (1952), nu este ındeplinita: dG(1) = 3 < 4 = n2;

– conditia teoremei lui Ore (1961), nu este ındeplinita: dG(2) + dG(7) = 4 + 3 = 7 < 8;

– observam ca nici conditiile teoremei lui Chvatal (1972) nu sunt ındeplinite: fie d1, d2, . . . , dn

o secventa grafica.

Nod 1 3 7 2 4 5 8 6dG 3 3 3 4 4 4 4 5

Relatia urmatoare nu este satisfacuta:

∀k a.i. dk ≤ k ≤ n

2⇒ dn−k ≥ n− k.

4.2.1 Problema comis–voiajorului

Un comis-voiajor trebuie sa viziteze n orase etichetate cu numerele de la 1 la n. Pentru asimplifica problema, acesta va pleca ıntotdeauna din orasul numarul 1 si se va ıntoarce tot ın1, trecand prin fiecare oras o singura data (cu exceptia orasului 1 care va fi vizitat de douaori). Cunoscand distantele ıntre orase, sa se determine o parcurgere (ciclu hamiltonian) decost minim.

Pentru a reprezenta drumurile directe dintre orase (existenta unei legaturi directe ıntreacestea) utilizam matricea costurilor A = (aij), i, j = 1, n:

ai,j =

0 , daca xi = xj

+∞ , daca [xi, xj ] /∈ E

d > 0 , daca [xi, xj ] ∈ E

. (4.1)

Vectorul solutiilor rezultat va fi X = (x1, x2, . . . , xn+1) ∈ V × . . .×V unde x1 = xn+1 = 1:la pasul i, i = 2, n + 1, se viziteaza orasul xi ∈ V . Primul oras, orasul din care se pleaca,este fixat la 1 (vezi algoritmul 31).

76

Page 77: CursuriAG2014

La pasul k (2 ≤ k ≤ n + 1) se ıncearca vizitarea orasului xk + 1 daca nu a fost vizitatla un pas anterior, si daca costul partial al lantului este mai mic decat costul celui mai bunciclu hamiltonian obtinut pana ın acel moment ın graf:

1 ≤ xk < n si vizitatxk+1 = 0 si cost + axk−1,xk+1 ≤ costoptim (4.2)

(pentru k = n + 1 trebuie verificata si conditia xk = 1).La ınceput costul celui mai scurt ciclu hamiltonian poate fi determinat cu un algoritm

de tip Greedy sau i se poate atribui valoarea +∞ (o valoare suficient de mare, de exemplun ·maxai,j |∀i, j = 1, n, i 6= j, ai,j 6=∞).

Daca conditiile anterioare sunt ındeplinite, atunci xk ← xk + 1. Se marcheaza orasul alesla pasul k ca fiind vizitat (vizitatk ← 1), se actualizeaza costul drumului pana ın momentulcurent (cost← cost + axk−1,xk

), si se trece la pasul k + 1.

In caz contrar, nu exista nici o alegere convenabila pentru orasul de pe pozitia k si vatrebui sa ne ıntoarcem pentru o alta alegere pentru orasul vizitat la pasul k−1. Pentru aceastase marcheaza orasul ales la pasul anterior ca nefiind vizitat (vizitatxk

← 0), si se scade dincostul drumului pana ın momentul curent, costul muchiei [xk−1, xk] (cost← cost− axk−1,xk

).

Fig. 4.8: Exemplu de graf pentru problema comis-voiajorului

Exemplul 4.18 Matricea costurilor corespunzatoare grafului din figura 4.8 are urmatoarelevalori:

A =

0 14 6 ∞ 5 ∞ ∞ ∞14 0 ∞ 12 16 20 ∞ ∞6 ∞ 0 ∞ ∞ 12 ∞ 12∞ 12 ∞ 0 21 ∞ 24 105 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:

• C1 = [1, 2, 4, 5, 6, 7, 8, 3, 1].

• C2 = [1, 2, 5, 4, 8, 7, 6, 3, 1].

• C3 = [1, 5, 6, 2, 4, 7, 8, 3, 1].

77

Page 78: CursuriAG2014

Algoritm 31 Algoritm pentru problema comis-voiajorului

Input:

A - matricea de costuri ce contine distantele dintre orase

n - numarul de orase

1: function CanContinue(A, X, k, cost)2: if (vizitatxk

= 1) ∨ (cost + axk−1,xk> costoptim) ∨ ((k 6= n + 1) ∧ (xk = x1))) then

3: return false4: else

5: return true6: end if

7: end function

8: procedure Evaluare Solutie(X, cost)9: Xoptim ← X

10: costoptim ← cost11: end procedure

12: procedure ComisVoiajorBacktracking(A,n)13: x1 ← 1, cost← 0, costoptim ←∞14: k ← 2, xk ← 115: while (k > 1) do

16: gasit← false17: while ((xk + 1 ≤ n) ∧ (gasit = false)) do

18: xk ← xk + 119: 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 + axk−1,xk)

24: else

25: vizitatxk← 1

26: cost← cost + axk−1,xk

27: k ← k + 128: xk ← 029: end if

30: else

31: k ← k − 132: vizitatxk

← 033: if (k > 1) then

34: cost← cost− axk−1,xk

35: end if

36: end if

37: end while

38: Output ’Solutia optima: ’, xoptim1 , . . . , xoptim

n+1 , costoptim39: end procedure

• C4 = [1, 3, 6, 7, 8, 4, 2, 5, 1].

Programul corespunzator scris ın limbajul C este urmatorul:

#include <stdio.h>

#include <memory.h>

78

Page 79: CursuriAG2014

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

Page 80: CursuriAG2014

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

Page 81: CursuriAG2014

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

Continutul fisierului 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 fisierul de test valoarea negativa −1. In timpulcitirii datelor aceasta a fost ınlocuita cu o constanta suficient de mare:

...

scanf("%d", &a[i][j]);

if (max < a[i][j])

81

Page 82: CursuriAG2014

max = a[i][j];

if (a[i][j] < 0)

a[i][j] = LIMIT;

In timpul citirii se determina valoarea maxima, maxai,j|∀i, j = 1, n, i 6= j, ai,j 6= ∞,pentru a se initializa mai apoi costul optim cu valoarea n ·max.

Functia ın care se verifica conditiile 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 functie (mai mare()) cu scopul de a realiza verificarea inegalitatii cost +axk−1,xk+1 > costoptim:

int mai_mare(long a, long b, long c)

if (a + b > c)

return 1;

else

return 0;

si a preveni eventualele depasiri (overflow)8 ın timpul calculelor.Nu am afisat numai solutia optima, ci am ales sa afisam toate ciclurile hamiltoniene care

ımbunatateau solutia 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 functia:

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;

8http://en.wikipedia.org/wiki/Arithmetic_overflow

82

Page 83: CursuriAG2014

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, multimea Ai va fi alcatuita din elementele 1, 2, . . . , 8. La ınceput, x1 vaprimi valoarea 1, iar pentru k = 2, x2 va primi tot valoarea 1:

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 1

Pentru k = 2, se verifica conditiile de continuare pentru x2 = x2 + 1 = 1 + 1 = 2, sideoarece acestea sunt respectate, se trece la pasul urmator (orasul urmator) (la initializareavem k = k + 1 = 3, x3 = 0):

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 0

Se verifica mai multe valori (1, 2 si 3) pentru x3, pentru care conditiile de continuare nusunt ındeplinite. Pentru x3 = 4 conditiile de continuare sunt ındeplinite, si se trece la pasulurmator, k = k + 1 = 4:

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 0

Pentru k = 4, prima valoare ce verifica conditiile de continuare este 5:x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 0

In mod asemanator se aleg valorile pentru pasii k = 5, 6, 7, 8:x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 3 8 7 0

La pasul k = 9, nici una dintre valorile 1, 2, . . . , 8 nu verifica conditiile de continuare (fiindla ultimul oras, acesta ar trebui sa fie 1, adica orasul de unde s-a pornit). Astfel, se trece lapasul anterior:

k = k - 1;

vizitat[x[k]] = 0;

83

Page 84: CursuriAG2014

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 neverificata si singura ce mai

ramasese de atribuit pentru x8, nu verifica conditiile de continuare, si deoarece nu mai suntvalori 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 multimea A7 = 1, 2, . . . , 8,se trece la pasul k = 6:

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 3

Aici continuam cu verificarea valorilor 4, 5, 6 si 7. Pentru x6 = 7 sunt verificate conditiilede continuare si se poate trece la pasul urmator, k = 7:

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 7 0

Doar pentru valoarea 8 sunt ındeplinite conditiile de continuare:x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 7 8 0

La pasul k = 8, xk = 3 ındeplineste contiile de continuare si se poate trece la nivelulurmator, k = 9:

x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 7 8 3 0

Aici solutia optima gasita este urmatoarea:x1 x2 x3 x4 x5 x6 x7 x8 x9

1 2 4 5 6 7 8 3 1

avand un cost al ciclului hamiltonian de 105.Se pastreaza solutia optima identificata pana ın acest moment, se afiseaza, si se continua

efectuarea calculelor metodei pana la epuizarea spatiului solutiilor posibile.

84

Page 85: CursuriAG2014

Fig. 4.10: Pasii efectuati de algoritm pentru determinarea ciclului hamiltonian asociat grafului din figura 4.8

85

Page 86: CursuriAG2014

Fig. 4.11: Pasii efectuati de algoritm pentru determinarea ciclului hamiltonian asociat grafului din figura 4.8(continuare)

86

Page 87: CursuriAG2014

Capitolul 5

Arbori. Arbori binari

Definitia 5.1 Fiind data o multime M de elemente denumite noduri, vom numi arbore osubmultime finita de noduri astfel ıncat:

1. exista un nod cu destinatie speciala, numit radacina arborelui;

2. celelalte noduri sunt repartizate ın n multimi distincte, disjuncte doua cate doua, A1, A2, . . . , An,fiecare multime Ai constituind la randul ei un arbore.

Aceasta definitie este una recursiva, constructia unui arbore depinzand de alti arbori.Descendentii directi ai radacinii arborelui sunt radacinile subarborilor A1, A2, . . . , An, n ≥ 1.Orice nod al unui arbore cu radacina constituie radacina unui subarbore compus din nodulrespectiv si toti descendentii sai.

Se observa ca un arbore impune o structura de organizare ierarhica asupra elementelorunei multimi.

Definitia 5.2 Se numeste arbore liber (”free tree”) un graf G = (V, E) neorientat, conexsi aciclic.

Teorema 5.1 (Proprietatile arborilor liberi) Fie G = (V, E) un graf neorientat. Urmatoareleafirmatii 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 obtinut 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 obtinut contine un ciclu.

Daca se alege un varf sau nod drept radacina arborelui, atunci un arbore liber devinearbore cu radacina. In general vom folosi termenul de arbore ın loc de termenul corect arborecu radacina.

Un varf terminal (frunza) este un varf fara descendenti. Varfurile care nu sunt terminalesunt neterminale (sau noduri interioare). De obicei, se considera ca exista o ordonare adescendentilor aceluiasi parinte.

87

Page 88: CursuriAG2014

1

2

5

1110

4

98

3

7

1514

6

1312

Fig. 5.1: Exemplu de arbore binar plin cu 24 − 1 varfuri

Definitia 5.3 Adancimea unui varf este data de lungimea drumului de la radacina la acelvarf. Inaltimea unui varf se determina ca fiind lungimea celui mai lung drum dintre acel varfsi un varf terminal. Inaltimea radacinii determina ınaltimea arborelui. Nivelul unui varf secalculeaza ca diferenta dintre ınaltimea arborelui si adancimea acestui varf.

Toate varfurile unui arbore ce au aceeasi adancime se spune ca sunt pe acelasi nivel. Unarbore oarecare cu radacina este n-ar daca fiecare varf are pana la n descendenti directi.

O multime de arbori disjuncti formeaza o padure.Din punct de vedere grafic, un arbore se poate reprezenta descriind nodurile cu ajutorul

unor cercuri sau patrate ın care se afla informatia aferenta, iar relatia de descendenta prinlegaturile ce unesc nodurile cu fii lor.

5.1 Arbori binari

Definitia 5.4 Un arbore binar este un arbore oarecare cu radacina, fiecare varf al sauavand cel mult doi descendenti, indicandu-se cine este descendentul stang al radacinii si cineeste cel drept.

Trebuie mentionat ca un arbore binar nu este un caz particular de arbore oarecare,deoarece ın cazul unui arbore oarecare este suficient sa spunem ca ca un varf are un singurdecendent spre deosebire de cazul arborelui binar cand trebuie precizat daca descendentuleste drept sau stang. Arborele binar ce nu contine nici un nod se numeste arbore vid sauarbore nul.

Definitia 5.5 Se numeste arbore binar plin un arbore binar cu 2k − 1 varfuri asezate pek nivele astfel ıncat pe fiecare nivel i avem 2i−1 varfuri.

Se observa ca fiecare varf al arborelui are doi descendenti, descendentul stang si descen-dentul drept, cu exceptia nodurilor terminale.

In figura 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.

Definitia 5.6 Se numeste arbore binar complet cu n varfuri un arbore binar plin avandk nivele, unde 2k−1 ≤ n < 2k, din care se elimina varfurile numerotate n+1, n+2, . . . , 2k−1.

88

Page 89: CursuriAG2014

1

2

5

1110

4

9

3

76

128

Fig. 5.2: Exemplu de arbore binar complet cu 12 varfuri

In figura 5.2 este ilustrat un exemplu de arbore binar complet.Un arbore binar poate fi transformat ıntr–un arbore binar plin ın modul urmator: com-

pletam arborele cu noi varfuri astfel ıncat fiecare varf sa aiba doi descendenti sau nici unul,renumerotam varfurile iar varfurilor nou introduse li se asociaza o valoare ce va indica faptulca ele sunt fictive.

5.1.1 Moduri de reprezentare

Cele mai cunoscute modalitati de reprezentare a arborilor binari sunt:

1. expresii cu paranteze;

2. forma standard ;

3. reprezentarea tip tata.

1

2 8

5

76

93

4

Fig. 5.3: Exemplu de arbore binar

1. expresii cu paranteze– expresia ıncepe cu radacina si dupa fiecare varf k urmeaza expre-siile subarborilor ce au ca radacini descendentii varfului respectiv, separate prin virgulasi incluse ıntre paranteze. Daca un descendent al unui varf nu exista atunci expresiarespectiva este ınlocuita cu 0 sau NULL. Un arbore cu un singur varf (radacina),etichetat cu a1, se reprezinta astfel: a1(0, 0). Un arbore format din radacina a1 si doidescendenti, a2 si a3, se reprezinta astfel: a1(a2(0, 0), a3(0, 0)).

Pentru arborele din figura 5.3 avem:

1(2(3(0, 4(0, 0)), 5(6(0, 0), 7(0, 0))), 8(0, 9(0, 0)))

89

Page 90: CursuriAG2014

2. forma standard – se indica radacina arborelui, iar pentru fiecare varf k se precizeazadescendentul sau stang si/sau drept.

Stangk =

i , daca nodul i este descendentul stang al nodului k

0 , daca nu exista descendentul stang

Dreptk =

i , daca nodul i este descendentul drept al nodului k

0 , daca nu exista descendentul drept.

Pentru arborele din figura 5.3 avem urmatoarea reprezentare (Rad = 1):

Nod 1 2 3 4 5 6 7 8 9Stang 2 3 0 0 6 0 0 0 0Drept 8 5 4 0 7 0 0 9 0

Fig. 5.4: Exemplu de arbore binar cu 8 noduri

Dupa modelul listei liniare dublu ınlatuita, putem folosi o structura de date asemanatoarepentru reprezentarea unui arbore binar. Un nod al arborelui are urmatoarea configuratie:

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 adresaunei zone de memorie ce contine date numerice de tip Nod). rad desemneaza adresaradacinii arborelui.

In figura 5.5 avem reprezentarea arborelui din figura 5.4.

3. reprezentarea tip tata – fiecarui varf k i se indica tatal nodului respectiv.

tatak =

i , daca nodul i este parintele nodului k

0 , nu exista

Nod 1 2 3 4 5 6 7 8 9Tata 0 1 2 3 2 5 5 1 8

Observatia 5.2 Urmatoarea numerotare este utilizata pentru anumite tipuri de arboribinari, si are drept caracteristica faptul ca structura arborelui se poate deduce printr-onumerotare adecvata a varfurilor:

90

Page 91: CursuriAG2014

Fig. 5.5: Exemplu de arbore binar cu 8 noduri

Tatai =

⌊ i2⌋ , i ≥ 2

nu exista , i = 1

Stangi =

2 · i , 2 · i ≤ n

nu exista , 2 · i > nDrepti =

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 fata de subarborii sai stang si drept, avem:

• parcurgere ın preordine (radacina, subarbore stang, subarbore drept).

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

In figura 5.6 este prezentata parcurgerea ın preordine a unui arbore binar, descrisa ınmai multi pasi, conform descrierii recursive a acestei metode.

Vom da exemplu de o procedura nerecursiva de vizitare ın preordine (vezi algoritmul32). Se pleaca de la radacina si se merge spre stanga atata timp cat este posibil (liniile5–8). Daca nu se mai poate merge spre stanga se ıncearca continuarea algorimuluidin 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 (liniile12–22), pana cand se ajunge ın situatia 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 s–a ajuns ın nodul radacina venind din dreapta, algoritmul se ıncheie. Datoritafaptului ca atunci cand se urca ın arbore trebuie sa stim din ce descendent venim, vomutiliza si vectorul tata.

Aceasta procedura poate fi utilizata si pentru celelalte moduri de parcurgere, modificarilenecesare referindu–se la momentul cand trebuie vizitat nodul curent (prin apelul pro-cedurii V izit - instructiunea call V izit(k)).

91

Page 92: CursuriAG2014

Fig. 5.6: Parcurgerea ın preordine a unui arbore binar a) arborele initial; 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

Page 93: CursuriAG2014

Algoritm 32 Algoritm de parcurgere ın preordine

1: procedure Preordine(Rad, Stang,Drept, Tata)2: k ← rad3: q ← 04: while (q = 0) do

5: while (stangk 6= 0) do

6: call V izit(k) ⊲ prelucrarea informatiei din nodul vizitat7: k ← stangk

8: end while

9: call V izit(k)10: while (q = 0) ∧ (dreptk = 0) do

11: found← 012: while (q = 0) ∧ (found = 0) do

13: j ← k14: k ← tatak

15: if (k = 0) then

16: q ← 117: else

18: if (j = stangk) then

19: found← 120: end if

21: end if

22: end while

23: end while

24: if (q = 0) then

25: k ← dreptk26: 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

Page 94: CursuriAG2014

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 utilizao stiva S unde se vor introduce nodurile din care se coboara spre stanga (liniile 6–9).Atunci cand nu se mai poate merge spre stanga se ıncearca continuarea algoritmului dindescendentul drept al nodului curent. Daca acesta nu exista, se reface drumul ınapoispre radacina, compus numai din descendentii stangi (liniile 11–18). Parcurgerea setermina ı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

Page 95: CursuriAG2014

Algoritm 33 Algoritm de parcurgere ın inordine

1: procedure Inordine(Rad, Stang,Drept)2: k ← rad3: q ← 04: S ← ∅ ⊲ initializare stiva vida5: while (q = 0) do

6: while (stangk 6= 0) do

7: S ⇐ k ⊲ S.push(k)8: k ← stangk

9: end while

10: call V izit(k)11: while (q = 0) ∧ (dreptk = 0) do

12: if (S = ∅) then ⊲ verificare daca stiva este vida13: q ← 114: 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 ← dreptk21: 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

Page 96: CursuriAG2014

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 6= 0) then

3: call Postordine(stangk, stang, drept)4: call Postordine(dreptk, stang, drept)5: call V izit(k)6: end if

7: return

8: end procedure

Modalitatea de vizitare recursiva a arborilor binari este exemplificata la arborii binari desortare.

Daca presupunem realizarea unei actiuni de vizitare pe exteriorul frontierei arborelui,deplasarea efectuandu-se ın sens trigonometric si avand drept punct de plecare radacinaacestuia, vom ajunge sa vizitam cel putin o data toate nodurile arborelui (vezi figura 5.7).Tinand cont de momentul vizitarii se poate obtine 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 oaradaca este un nod interior, iar la postordine vom marca un nod ın momentul ın care ıl vizitampentru ultima oara.

96

Page 97: CursuriAG2014

1

2 8

5

76

93

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:

• fiecarui operator ıi corespunde un nod neterminal avand drept subarbori stang si dreptcei doi operanzi corespunzatori.

• fiecare nod terminal este etichetat cu o variabila sau o constanta.

Arborele din figura 5.8 corespunde expresiei matematice: 2 · ((a + b)− (c + b)). In urmavizitarii ın postordine a acestui arbore se obtine forma poloneza postfixata asociata expresieianterioare: 2ab + cb + −∗. Pentru a obtine valoarea expresiei respective, arborele poate fiparcurs ın postordine.

5.2 Arbori binari de cautare

Definitia 5.7 [93] Se numeste arbore binar de cautare un arbore binar ce verifica urmatoareaproprietate:

97

Page 98: CursuriAG2014

pentru orice varf i apartinand arborelui, avem

Infi ≥ Infj , pentru toate varfurile j ce apartin descendentului stang al varfului i

Infi ≤ Infj , pentru toate varfurile j ce apartin descendentului drept al varfului i

unde Infi este informatia asociata varfului i. Aceasta informatie este de un tip de date pestecare avem o relatie 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 sortaredeoarece parcurgerea ın inordine a unui arbore binar de cautare ne conduce la obtinereaelementelor vectorului Inf ın ordine crescatoare. In principal aceasta structura de date esteutilizata pentru regasirea eficienta a unor informatii.

Operatiile de creare a arborelui, stergere a unui nod, modificare a informatiei asociateunui nod sau inserare a unui nod se pot realiza ıntr-un mod optim astfel ıncat sa nu sedistruga proprietatea de arbore de cautare.

Daca dorim ca arborele sa nu contina chei duplicate, vom modifica definitia de mai susastfel:

pentru orice varf i apartinand arborelui, avem

Infi < Infj , pentru toate varfurile j ce apartin descendentului stang al varfului i

Infi > Infj , pentru toate varfurile j ce apartin descendentului drept al varfului i.

In continuare vom utiliza aceasta definitie pentru descrierea algoritmilor ce urmeaza.

Crearea unui arbore de cautare

Crearea (construirea) unui arbore de cautare se face aplicand ın mod repetat operatia deinserare.

Cautarea unei informatii ıntr-un arbore de cautare

Informatia 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 informatia asociata radacinii arborelui (vezi algoritmul 35):

1. daca cheia x este mai mica decat cheia radacinii, atunci se va continua cautarea ınsubarborele stang;

2. daca cheia x este mai mare decat cheia radacinii, atunci se va continua cautarea ınsubarborele 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 operatie prezinta urmatoarele particularitati (vezi algoritmul 36):

• se verifica prin intermediul operatiei de cautare daca cheia x a nodului care se dorestesa fie inserat mai exista ın arbore;

• ın cazul ın care cautarea se ıncheie cu succes, inserarea nu va mai avea loc;

• ın cazul ın care operatia de cautare se termina fara succes, atunci se va crea un nodnou ın locul subarborelui vid unde s-a terminat cautarea.

In figura 5.9 este ilustrata inserarea unui nod ıntr–un arbore binar.

98

Page 99: CursuriAG2014

Algoritm 35 Algoritm de cautare a unei valori ıntr-un arbore binar de cautare

1: function SearchNode(p,Key)2: if (p 6= 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 p10: end if

11: end if

12: else

13: return NULL14: 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 p14: end function

Stergerea unui nod dintr-un arbore de cautare

Mai ıntai se va cauta nodul ce se doreste sa fie eliminat.Sa presupunem ca am gasit nodul ce urmeaza a fi sters. Avem urmatoarele situatii (vezi

algoritmul 38):

1. nodul ce urmeaza sa fie sters este un nod terminal - se face stergerea normal avandgrija sa se ınlocuiasca legatura din nodul parinte catre el cu null;

2. nodul ce urmeaza sa fie sters are un singur descendent - nodul respectiv se sterge iarparintele va contine acum noua legatura catre descendentul fostului fiu;

3. nodul ce urmeaza a fi sters (notat A) are doi descendenti:

• se determina cel mai din stanga nod (notat B) din subarborele drept al noduluice trebuie sters (vezi algoritmul 37); acesta va fi sters ın mod fizic, dar la un pasulterior;

99

Page 100: CursuriAG2014

Fig. 5.9: Arbore binar de cautare. Inserarea unui nod.

• toate informatiile legate de datele continute ın nodul B vor fi copiate ın nodul A;

• subarborele drept al nodului B se va lega fie ca descendent drept al nodului A(daca nodul B este descendent direct al nodului A), fie ca descendent stang altatalui nodului B;

• se va sterge fizic nodul B.

Exemplul 5.3 Fie un arbore binar, eticheta fiecarui nod fiind un sir de caractere (un cuvant).Se cere sa se realizeze un program care sa creeze un arbore binar de sortare, sa-l parcurga ıninordine si sa permita inserarea si stergerea unui nod specificat.

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <conio.h>

typedef struct nod

100

Page 101: CursuriAG2014

Fig. 5.10: Arbore binar de cautare. Stergerea unui nod. a) Nod fara descendenti b) Nod cu un singurdescendent c) Nod cu doi descendenti.

101

Page 102: CursuriAG2014

Algoritm 37 Algoritm pentru determinarea celui mai din stanga nod

1: function LeftmostNode(Parent, Curent)2: while (curent.left 6= NULL) do

3: parent← curent4: curent← curent.left5: end while

6: if (parent.right = curent) then

7: parent.right← curent.right8: else

9: parent.left← curent.right10: end if

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

Page 103: CursuriAG2014

Algoritm 38 Algoritm de stergere a unui nod ıntr-un arbore binar de cautare

1: function DeleteNode(p,Key)2: if (p 6= 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 6= NULL) then

11: tmp← p.left12: else

13: tmp← p.right14: end if

15: call DisposeNode(p)16: p← tmp17: else

18: tmp← p.right19: tmp← LeftmostNode(p, tmp)20: tmp.left← p.left21: tmp.right← p.right22: call DisposeNode(p)23: p← tmp24: end if

25: end if

26: end if

27: end if

28: return p29: 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

Page 104: CursuriAG2014

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

Page 105: CursuriAG2014

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 Exercitii

1. (a) Sa se realizeze o subrutina ce determina cea mai mare valoare pastrata ıntr–unarbore binar de cautare;

(b) Aceeasi cerinta pentru cea mai mica valoare.

2. Sa se realizeze o subrutina ce determina toate nodurile unui arbore binar de cautare cuproprietatea ca informatia k asociata unui nod verifica relatia a ≤ k ≤ b, unde a si bsunt date.

3. (a) Sa se realizeze un algoritm care determina numarul arborilor binari distincti cun noduri, unde n este un numar natural dat.

105

Page 106: CursuriAG2014

Fig. 5.11: Exemplu de arbore binar complet cu 7 varfuri

(b) Aceeasi problema pentru arbori binari de cautare.

4. Sa consideram o secventa de intrare compusa din termeni definiti 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 redusdaca nu contine nici un subtermen care sa poata fi redus. Un termen poate fi consideratca subtermen pentru el ınsusi.

Sa se realizeze un algoritm care determina pentru un termen de intrare, termenul reduscorespunzator. Un termen contine doar simbolurile ’X’, ’(’ si ’)’, fara spatii ıntre ele.Lungimea unui termen de intrare este 100.

Observatia 5.4 O expresie va avea maxim 9 nivele de parantezare. Numarul de redu-ceri ce pot fi efectuate este finit. Liniile de iesire contin maxim 80 caractere. Caractereleposibile 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 complet ıntelegem un arbore binar ın care un nod are fie doi descendenti,fie nu are nici unul.

Un arbore binar complet poate fi reprezentat prin codificarea drumurilor de la radacinala fiecare frunza utilizand numai valorile 0 si 1: atunci cand coboram ın arbore sprestanga se adauga valoarea 0 iar atunci cand coboram spre dreapta se adauga valoarea1.

106

Page 107: CursuriAG2014

Pentru arborele din figura 5.11 drumurile de la radacina la fiecare frunza se codificaastfel:

ABC : 00ABDE : 010ABDF : 011AG : 1

Concatenand toate drumurile de la radacina catre frunze, arborele anterior poate fireprezentat prin secventa ce poate fi interpretata ca reprezentarea ın baza 2 a unuinumar (000100111).

Fiind date m si n doua numere naturale, se cere sa se determine daca exista un arborebinar complet a carui reprezentare va contine exact m cifre 0 si n cifre 1 (0 < m, n ≤100).

(Timisoara-pregatire, 1996)

6. Scrieti o subrutina nerecursiva care numara nodurile frunza ale unui arbore binar.

7. Realizati o subrutina care sa determine nivelul cu cele mai multe noduri frunze dintr–unarbore binar.

8. Determinati ınatimea unui arbore binar printr–o functie nerecursiva.

9. Se considera un dictionar ce este implementat sub forma unei structuri de arbore.Pentru fiecare cuvant se cunoaste traducerea acestuia precum si probabilitatea lui deaparitie ın texte.

Se cere sa se realizeze un algoritm care sa conduca la o cautare optima a cuvintelorın dictionar. Se mentioneaza faptul ca probabilitatea de a cauta un cuvant care nu segaseste ın dictionar este zero.

Datele de iesire constau din afisarea arborelui optimal de cautare compus din cuvinteleintroduse.

Spre exemplu, un set de date de intrare poate fi:

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 tinaevidenta comenzilor ın ordinea datelor la care au fost onorate, iar ın cadrul fiecarei datede livrare, ın ordine lexicografica dupa numele produsului. Sa se scrie un program carefoloseste structuri de date de tip arbore.

Intrarea este formata din mai multe linii. Pe fiecare linie avem cate o comanda datasub forma: [numeprodus] [zi] [luna] [an]. Intrarea se termina cu o linie pe care avemdoar ’&’.

Iesirea este formata prin afisarea comenzilor ın ordinea datei la care au fost onorate,iar ın cadrul unei date, ın ordine lexicografica ın functie de numele comenzii.

Indicatie: Se va crea un arbore de cautare dupa data de livrare si ın fiecare nod va fiun arbore de cautare dupa numele comenzii.

107

Page 108: CursuriAG2014

11. Se considera o expresie logica formata din n variabile logice reprezentate printr–o sin-gura litera si operatorii & (AND), | (OR), ! (NOT) (nu avem paranteze). Expresia estereprezentata sub forma unui arbore binar.

Se cere sa se realizeze un algoritm care pentru o expresie logica data cerceteaza existentaunei combinatii de valori logice (true/false), pentru care expresia data ia valoarea logicatrue.

De exemplu pentru expresia a|!b|c&d solutia este a = false, b = false, c = false,d = false, iar pentru expresia !a&a nu avem solutie.

12. Se considera o expresie matematica reprezentata printr-un arbore binar. Operatoriicorespund operatiilor matematice uzuale +, −, ∗, /, si ? (pentru ridicare la putere).Nu avem paranteze si toti operatorii sunt operatori binari. Operanzii sunt identificatiprintr–o singura litera.

Se cere sa se realizeze un algoritm ce creaza structura de date corespunzatoare uneiexpresii date si sa evalueaze expresia pentru o multime de valori ale operanzilor.

Pentru expresia a + b ∗ c unde a = 2, b = 3 si c = −1 avem valoarea −1, iar ın urmaevaluarii expresiei a− b/c?a cu a = 2, b = 9 si c = 3 obtinem valoarea 1.

108

Page 109: CursuriAG2014

Capitolul 6

Arbori oarecare

Reamintim definitia unui arbore oarecare:

Definitia 6.1 Fiind data o multime M de elemente denumite noduri, vom numi arbore osubmultime finita de noduri astfel ıncat:

1. exista un nod cu destinatie speciala, numit radacina arborelui;

2. celelalte noduri sunt repartizate ın n multimi disjuncte doua cate doua, A1, A2, · · · , An, fiecaremultime Ai constituind la randul ei un arbore.

6.1 Moduri de reprezentare

Pentru reprezentarea arborilor oarecare pot fi utilizate urmatoarele metode:

• legaturi fiu-frate: fiuk - este primul descendent al varfului k, fratek - urmatorul descen-dent al tatalui nodului k, ce urmeaza dupa k. Intre descendentii unui varf se presupuneca definim o relatie de ordine.

Radacina arborelui din figura 6.1 este Rad = 1.

1

2 4

5 96 7 8

3

10

Fig. 6.1: Exemplu de arbore oarecare

Table 6.1: Reprezentarea cu legaturi fiu–frate a arborelui din figura 6.1.

Nod 1 2 3 4 5 6 7 8 9 10Fiu 2 0 5 7 0 0 0 0 0 0

Frate 0 3 4 0 6 0 8 9 10 0

109

Page 110: CursuriAG2014

Daca identificam Fiu cu Stang si Frate cu Drept, unui arbore oarecare i se poateasocia un arbore binar.

Pentru reprezentarea unui arbore oarecare, modelul de reprezentare fiu-frate ın variantade alocare statica poate fi usor extins la o varianta de alocare dinamica, folosind pointeripentru legaturile catre primul descendent respectiv pentru urmatorul frate. Astfel unnod al arborelui poate avea urmatoarea configuratie:

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 detip pointer la Nod (variabila pastreaza adresa unei zone de memorie). rad desemneazaadresa radacinii arborelui.

Fig. 6.2: Exemplu de arbore oarecare cu 10 noduri reprezentat prin legaturi fiu-frate

In figura 6.2 este reprezentat arborele din figura 6.1 prin legaturi fiu-frate.

• lista descendentilor. In cadrul acestui mod de reprezentare fiecare varf este descris prinlista descendentilor sai. Pentru memorare se va utiliza un vector cu n componente:

Ck =

0 , varful respectiv nu are descendenti

j , j indica adresa (coloana) unde ıncepe lista descendentilor varfului k.

Listele de descendenti se pastreaza prin intermediul unei matrice L cu 2 linii si N − 1coloane:

L1,k - un descendent al varfului a carui lista contine coloana k a matricei date.

L2,k =

0 , daca descendentul respectiv este ultimul

j , j indica coloana unde se afla urmatorul descendent

110

Page 111: CursuriAG2014

Table 6.2: Reprezentarea arborelui din figura 6.1 folosind liste cu descendenti.

Nod 1 2 3 4 5 6 7 8 9 10C 1 0 4 6 0 0 0 0 0 0

L =

(2 3 4 5 6 7 8 9 102 3 0 5 0 7 8 9 0

)

Exploatand mai departe aceasta idee, ıntr-un nod al arborelui oarecare se poate pastra olista cu adresele descendentilor sai, lista fiind reprezentata sub forma unui tablou alocatstatic sau dinamic. Oricum modelul se recomanda atunci cand numarul descendentilorunui nod este limitat superior, sau cand acesta este cunoscut/stabilit ın momentul ıncare se construieste arborele. Modificarile efectuate asupra arborelui, cum ar fi inseraride descendenti noi, atunci cand intrarile alocate pentru acesti descendenti sunt dejaalocate nu poate conduce decat la realocarea spatiului de memorie cu un cost reflectatın complexitatea algoritmului. Astfel daca numarul de descendenti este limitat superiorputem defini

#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 descendenti nu poate fi cunoscut decat ın momentulconstruirii arborelui. Astfel, ın acel moment, se aloca spatiu pentru un tablou depointeri catre structura de tip Nod definita (children = malloc(sizeof(Nod*) *no of children)).

In figura 6.3 este reprezentat arborele din figura 6.1 folosind liste cu descendenti.

• Tata - fiecarui nod k se indica nodul parinte.

Table 6.3: Reprezentarea arborelui din figura 6.1 folosind vectorul tata.

Nod 1 2 3 4 5 6 7 8 9 10Tata 0 1 1 1 3 3 4 4 4 4

Acest mod de reprezentare are dezavantajul ca nu pastreaza ın mod explicit ordineadescendentilor unui nod. Aceasta ordine poate fi dedusa printr–o numerotare adecvata anodurilor. De obicei reprezentarea cu vectorul tata nu este folosita singura ci ımpreunacu alte moduri de reprezentare, ca o completare.

111

Page 112: CursuriAG2014

31

02 23 44

05 06

rad

07 08 09 010

Fig. 6.3: Exemplu de arbore oarecare cu 10 noduri reprezentat prin liste cu descendenti

De exemplu, reprezentarea unui nod propusa la primul punct, poate fi modifcata astfelıncat sa incorporeze si informatii 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

NULL8 9

NULLNULL NULL

NULL

NULL

NULL

NULL

Fig. 6.4: Exemplu de arbore oarecare cu 10 noduri reprezentat prin legaturi fiu-frate-tata

In figura 6.4, reprezentarea din figura 6.2 este ımbunatatita 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 obtine ın urmarealizarii corespondentei Fiu⇒ Stang si Frate⇒ Drept.

112

Page 113: CursuriAG2014

In plus fata de acestea, avem si doua metode de parcurgere pe care putem sa le numimspecifice unui arbore oarecare. Acestea se pot clasifica dupa momentul ın care se realizeazavizitarea nodului parinte astfel:

• A–preordine: se viziteaza mai ıntai radacina, si apoi, ın ordine, subarborii sai [93],[123]. Metoda este identica cu metoda de parcurgere ın preordine a arborelui binaratasat: 1, 2, 3, 5, 6, 4, 7, 8, 9, 10 (vezi algoritmul 39). Parcurgerea ın A–preordine esteexemplificata pe arborele oarecare din figura 6.1.

Algoritm 39 Algoritm de parcurgere ın A-preordine

1: procedure APreordine(Rad, F iu, Frate)2: k ← rad3: q ← 04: S ← ∅ ⊲ initializare stiva vida5: while (q = 0) do

6: if (k 6= 0) then

7: call V izit(k)8: S ⇐ k ⊲ S.push(k)9: k ← fiuk

10: else

11: if (S = ∅) then ⊲ verificare daca stiva este vida12: q ← 113: else

14: S ⇒ k ⊲ S.pop(k)15: k ← fratek

16: end if

17: end if

18: end while

19: return

20: end procedure

• A–postordine: se viziteaza mai ıntai toti subarborii ce au drept radacini, descendentiiradacinii arborelui si apoi radacina arborelui [93], [123]. In urma parcurgerii ın A–postordine a arborelui din figura 6.1 se obtine 2, 5, 6, 3, 7, 8, 9, 10, 4, 1.

Exemplul 6.1 [31] In continuare se prezinta implementarea ın limbajul de programare Ca variantelor recursive pentru fiecare dintre cele doua metode de vizitare ale unui arboreoarecare.

#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

Page 114: CursuriAG2014

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

Page 115: CursuriAG2014

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

Page 116: CursuriAG2014

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

Page 117: CursuriAG2014

aPostordine(rad);

6.3 Arbori de acoperire de cost minim

Fie G = (V, E) un graf neorientat si fie c : E −→ R o functie de cost ce asocieaza o valoarereala fiecarei muchii. Notam cu TG multimea arborilor partiali ai grafului G (un arborepartial este un graf partial conex si fara cicluri al grafului initial).

Cerinta problemei este aceea de a determina un arbore T ′ ∈ TG avand costul cel mai micdintre toti arborii ce apartin multimii TG:

c(T ′) = minc(T )|T ∈ TG

unde costul unui arbore T se definette ca c(T ) =∑

e∈ETc(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 partial de cost minim sau arbore partialminim.

Altfel spus, se cere sa se determine un graf partial conex G1 = (V, E1) (E1 ⊆ E) cuproprietatea ca suma costurilor tuturor muchiilor este minima, graful partial de cost minimfiind chiar un arbore.

Determinarea arborelui de acoperire de cost minim are multe aplicatii practice: de exem-plu, daca se dau n orase precum si costul legaturilor ıntre acestea, se cere sa se determine oconectare a tuturor oraselor astfel ıncat oricare doua orase sa fie conectate direct sau indirectiar costul conectarii sa fie minim.

Lema 6.2 (Proprietatea taieturii) Fie S o submultime de noduri a lui V si e muchia ce arecostul minim dintre toate muchiile ce au o singura extremitate ın S. Atunci arborele partialde cost minim va contine muchia e.

Demonstratie: Fie T ′ un arbore partial de cost minim. Presupunem prin reducere laabsurd ca e /∈ ET ′ . Daca adaugam muchia e la T ′ se obtine un ciclu C. In acest ciclu existao alta muchie f ce are exact o extremitate ın multimea S.

Inlocuind muchia f cu muchia e ın arborele T ′, obtinem 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

obtinut un arbore de acoperire T ′′ ce are costul mai mic decat T ′, contradictie cu faptul caT ′ este un arbore de acoperire de cost minim.

Definitia 6.2 Se numeste taietura a grafului G o partitie de doua submultimi a multimiinodurilor 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 dintretoate muchiile ce apartin lui C. Atunci arborele partial de cost minim T ′ nu contine muchiaf .

Demonstratie: Fie T ′ un arbore partial de cost minim. Presupunem prin reducere laabsurd ca f ∈ ET ′. Daca stergem muchia f din arborele T ′, se obtine o taietura < S, V \S >.Avem ca f ∈ C si o extremitate a lui f apartine lui S. Exista atunci o alta muchie e cuproprietatea ca e ∈ C si e are o extremitate ce apartine lui S.

117

Page 118: CursuriAG2014

Inlocuind muchia f cu muchia e ın arborele T ′, obtinem un alt arbore de acoperire T ′′ =T ′ ∪ e \ f.

Deoarece c(e) < c(f)⇒ c(T ′′) < c(T ′) adica am obtinut un arbore de acoperire T ′′ ce arecostul mai mic decat T ′, contradictie.

Majoritatea algoritmilor ce calculeaza arborele de acoperire de cost minim prezinta aceeasitehnica generala de calcul. La ınceput se porneste cu o padure de arbori, T 0 = T 0

1 , T 02 , . . . , T 0

nunde T 0

i = xi, i = 1, n este un arbore format dintr–un singur nod. La pasul k vom aveamultimea T k compusa din n− k arbori: T k = T k

1 , T k2 , . . . , T k

n−k.La fiecare pas, se alege un arbore T k

i si o muchie (u′, v′) avand costul minim dintre toatemuchiile (u, v) cu proprietatea ca o extremitate apartine multimii de noduri a arborelui T k

i

(u′ ∈ T ki ) si cealalta extremitate apartine multimii V \ VT k

i(v′ ∈ V \ VT k

i).

Prin urmare, multimea T k+1 se obtine din multimea T k prin reuniunea arborilor T ki si

T kj (i 6= j), unde u′ ∈ T k

i si v′ ∈ T kj (T k+1 = T k \ T k

i , T kj ∪ T k

i ∪ T kj ).

In final, la pasul n− 1, multimea T n−1 = T n−11 va fi compusa dintr–un singur element,

acesta fiind arborele de acoperire de cost minim.Algoritmii cei mai cunoscuti 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: initializeaza padurea de arbori P compusa din n arbori, fiecare arbore fiind compus dintr–un

singur nod3: L← ∅4: while (|P| > 1) do

5: for T ∈ P do

6: alege e muchia de cost minim de la T la G \ T7: L⇐ e ⊲ adauga muchia e la lista de muchii alese ce vor forma arborele de acoperire

de cost minim8: end for

9: adauga toate muchiile selectate ın cadrul for-ului anterior la P10: 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(n2)[30] si atinge o com-plexitate de O(m logn) daca se folosesc heap–uri Fibonacci [54], sau pairing heaps [115].

In tabelul 6.4 sunt prezentati mai multi algoritmi dezvoltati de–a lungul timpului pentrudeterminarea arborelui de acoperire minimal si complexitatile lor. Karger, Klein si Tarjan [79]pornind de la algoritmul lui Boruvka au realizat un algoritm randomizat pentru determinareaarborelui de acoperire minimal, avand o complexitate liniara, iar Chazelle [26] a dezvoltatun algoritm avand complexitatea O(nα(m, n)) (α(m, n) este inversa functiei lui Ackerman).Pe de alta parte, Pettie si Ramachandran [105] au propus un algoritm demonstrat ca fiindoptimal, avand complexitatea cuprinsa ıntre O(n + m) si O(nα(m, n)).

118

Page 119: CursuriAG2014

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: di ← cu,i

5: end for

6: for i← 1, n − 1 do

7: k ← min dk|k ∈ V \ S8: L⇐ (tatak, k)9: S ← S ∪ k

10: for each j ∈ V \ S do

11: dj ← min dj , ck,j12: 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 cost3: L← ∅4: for each u ∈ V do

5: creaza o multime compusa din u6: end for

7: count← 08: while count < n− 1 do

9: alege muchia (u, v)10: if (u si v sunt ın multimi diferite) then

11: L⇐ (u, v)12: reuneste multimile ce contin pe u si v13: count← count + 114: end if

15: end while

16: end procedure

Fie G(V, E) un graf neorientat unde V = 1, 2, ..., n este multimea nodurilor si E estemultimea muchiilor (E ⊆ V × V ). Pentru reprezentarea grafului se utilizeaza matriceacosturilor C:

ci,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 alti cercetatori. Dintre acestia, Sollin (1961) estecel care a mai dat numele algoritmului, acesta fiind cunoscut ın literatura de specialitate sisub numele de algoritmul lui Sollin. Pentru ca acest algoritm sa poata fi aplicat, trebuie camuchiile grafului sa aiba costuri distincte (vezi algoritmul 43).

119

Page 120: CursuriAG2014

Table 6.4: Algoritmi pentru determinarea arborelui de acoperire minim

Anul Complexitate Autori1975 E log log V Yao1976 E log log V Cheriton-Tarjan1984 E log∗ V, E + V log V Friedman-Tarjan1986 E log log∗V Gabow-Galil-Spencer-Tarjan1997 Eα(V ) log α(V ) Chazelle2000 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: Vi ← i4: end for

5: L← ∅,M ← V1, . . . , Vn6: while (|T | < n− 1) do

7: for U ∈M do

8: fie (u, v) muchia pentru care se obtine valoarea minima minc(u′, v′)|(u′, v′) ∈ E, u′ ∈U, v′ /∈ V \ U

9: determina componenta U ′ ce contine pe v10: L⇐ (u, v)11: end for

12: for U ∈M do

13: reuneste multimile ce contin pe u si v, U si U ′

14: end for

15: end while

16: end procedure

Exemplul 6.4 Sa consideram graful din figura 6.5:

G = (V, E), V = 1, 2, 3, 4, 5, 6, 7, 8

Aplicand algoritmul lui Boruvka, la pasul ıntai vor fi selectate muchiile (1, 2), (3, 6), (4, 5),(4, 7) si (7, 8). In urma operatiilor de reuniune a componentelor conexe pe baza muchiilorselectate, vor mai ramane trei componente conexe ın multimea M .

La pasul al doilea sunt alese muchiile (2, 5) si (1, 3) ce conduc, ın urma operatiilor dereuniune, 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 multime S formata dintr-un singur nod (S = v0). La fiecare pas sealege muchia de cost minim ce are numai o extremitate ın multimea S. Procesul se ıncheiedupa n − 1 pasi, rezultand un graf partial aciclic. Din teorema 5.1 rezulta faptul ca acestgraf partial aciclic cu n− 1 muchii este un arbore (de acoperire).

120

Page 121: CursuriAG2014

Fig. 6.5: Exemplu de graf ponderat - aplicatie algoritmul lui Boruvka

Conform Proprietatii taieturii, toate muchiile alese apartin arborelui partial de cost minimde unde rezulta ca acest arbore de acoperire este un arbore partial minim.

Vom utiliza trei vectori de dimensiune n, unde n reprezinta numarul de varfuri al grafului(vezi algoritmul 44):

• vizitat - vector caracteristic

vizitatk =

1 , daca nodul k ∈ S

0 , daca nodul k ∈ V \ S

• d - pentru un nod k /∈ S, dk va contine distanta minima de la k la un nod j ∈ S. Laınceput, dj = cv0,j. Pentru un nod k ales la un moment dat, dj (j ∈ S) se modificanumai daca ck,j < dj astfel dj = ck,j.

• tata - contine pentru fiecare nod k /∈ S nodul j ∈ S astfel ıncat ck,j = minck,i|i ∈ S.La ınceput,

tatak =

0 , daca nodul k = v0

v0 , daca nodul k 6= v0

In momentul ın care se modifica dj , se va modifica si valoarea lui tataj = k.

Exemplul 6.5 Fie graful din figura 6.6:

G = (V, E), V = 1, 2, 3, 4, 5, 6, 7, 8Vom lua nodul initial v0 = 1. La ınceput, dupa etapa de initializare avem:

1 2 3 4 5 6 7 8d 14 6 ∞ 5 ∞ ∞ ∞

tata 0 1 1 1 1 1 1 1vizitat 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

Page 122: CursuriAG2014

Algoritm 44 Algoritmul Prim (varianta detaliata)

1: function DistantaMinima(n, vizitat, d)2: min←∞3: for j ← 1, n do

4: if (vizitatj 6= 1) ∧ (dj < min) then

5: min← dj

6: j0 ← j7: end if

8: end for

9: if (min =∞) then

10: return −111: else

12: return j0

13: end if

14: end function

15: procedure Prim2(n,C, v0; d, tata)16: vizitatv0

← 117: tatav0

← 018: for i← 1, n do

19: if (i 6= v0) then

20: vizitati ← 021: di ← cv0,i

22: tatai ← v0

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: vizitatk ← 1 ⊲ (k, tatak) este o muchie ce apartine arborelui partial minim32: for j ← 1, n do

33: if (vizitatj 6= 1) ∧ (dj > ck,j) then

34: tataj ← k35: dj ← ck,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 ∞ 12tata 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 distante la noduri din multimea S suntegale: 6 si 8. Alegem primul nod - 6 si muchia (3, 6):

122

Page 123: CursuriAG2014

Fig. 6.6: Exemplu de graf ponderat - aplicatie algoritmul lui Prim

1 2 3 4 5 6 7 8d 14 6 21 5 12 14 6

tata 0 1 1 5 1 3 6 6vizitat 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 6tata 0 1 1 8 1 3 8 6

vizitat 1 0 1 0 1 1 0 1

La pasul cinci, nodul aflat la distanta minima este 7:1 2 3 4 5 6 7 8

d 14 6 10 5 12 10 6tata 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 6tata 0 4 1 8 1 3 8 6

vizitat 1 0 1 1 1 1 1 1

La final, ultimul nod ales este 2 ımpreuna cu muchia (4, 2).

Trebuie sa remarcam faptul ca algoritmul lui Prim (vezi algoritmul 44) este aproapeidentic cu algoritmul lui Dijkstra (vezi algoritmul 59).

Dupa cum am subliniat, implementarea optima se realizeaza folosind niste structuri dedate avansate - heap–uri Fibonacci sau pairing heaps (vezi algoritmul 45).

6.3.3 Structuri de date pentru multimi disjuncte

O partitie a unei multimi A este o secventa finita de multimi (submultimi) A1, . . . , Am

disjuncte doua cate doua, cu proprietatea ca reuniunea acestora este chiar multimea A(A =

⋃mi=1 Ai si Ai ∩ Aj = ∅, ∀i, j = 1, m, i 6= j).

123

Page 124: CursuriAG2014

Algoritm 45 Algoritmul lui Prim folosind structuri de date avansate

1: procedure Prim3(n,C, u)2: for fiecare v ∈ V do

3: dv ←∞4: end for

5: Q← ∅ ⊲ initializeaza coada cu prioritate Q cu multimea vida6: for fiecare v ∈ V do

7: Q⇐ v8: end for

9: S ← ∅ ⊲ initializeaza multimea S cu multimea vida10: while Q 6= ∅ do

11: u← deleteMin(Q) ⊲ extrage nodul de prioritate minima din Q12: S ← S ∪ u13: for fiecare muchie e = (u, v) ∈ E do

14: if (v /∈ S) ∧ (c(e) < dv) then

15: actualizeaza prioritatea lui v: dv ← 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 operatiiefectuate asupra elementelor partitiei: verificarea daca doua elemente fac parte din aceeasisubmultime precum si operatia de reuniune a doua submultimi.

O structura de date pentru multimi disjuncte memoreaza o colectie de multimi disjunctedinamice. Fiecare multime este identificata printr–un reprezentant [30]. Operatiile de bazaale acestei structuri de date sunt [2]:

• init(x, B) - procedura creaza o multime B formata dintr–un singur element x;

• find(x) - ıntoarce reprezentantul multimii careia ıi apartine x;

• merge(A, B) - reuneste multimile distincte A si B (x ∈ A, y ∈ B) ıntr–o noua multimece contine elementele celor doua multimi.

O astfel de structura de date pentru multimi disjuncte se mai numeste si structura de dateunion–find (eng. union–find data structure).

Reprezentarea folosind vectori

Vom folosi un vector C de dimensiune n, unde n reprezinta numarul de elemente, iar ck = uindica faptul ca elementul k apartine multimii u.

Init consta din initializarea lui cx cu identificatorul multimii, u. Find ıntoarce valoarealui cx (valoarea identificatorului multimii). In functia Merge se cauta toate elementele cefac parte din multimea de identificator cy si se trec ın multimea al carui identificator este cx

(vezi algoritmul 46).

Exemplul 6.6 Pentru o putea opera cu modul de reprezentare ales, cel cu vectori, trebuieca elementele multimii sa ia valori naturale ın intervalul [1,. . . ,n]. Daca acest lucru nueste posibil atunci folosim un vector auxiliar A ce pastreaza valorile elementelor, ın cadrulreprezentarii utilizandu–se indicele acestora. Sa presupunem ca avem multimea de elemente

124

Page 125: CursuriAG2014

Algoritm 46 Algoritmi pentru operatiile init, find, merge (varianta ıntai)

1: procedure Init(x, u)2: cx ← u3: end procedure

4: function Find(x)5: return cx

6: end function

7: function Merge(x, y)8: setx← cx

9: sety ← cy

10: for k ← 1, n do

11: if (ck = sety) then

12: ck ← setx13: end if

14: end for

15: return setx16: end function

A = a, b, e, x, y, z, u, v si partitia a, x, y, b, z, v, e, u. Atunci conform modului dereprezentare descris avem:

1 2 3 4 5 6 7 8A ’a’ ’b’ ’e’ ’x’ ’y’ ’z’ ’u’ ’v’C 1 2 3 1 1 2 2 3

a2 =′ b′ are semnificatia urmatoare: elementul de pe pozitia 2 are valoarea ′b′. c2 = 2 -elementul de pe pozitia 2 face parte din multimea de identificator 2. Sau a4 =′ x′ - elementulde pe pozitia 4 are valoarea ′x′, si c4 = 1 - elementul de pe pozitia 4 face parte din multimeade identificator 1.

Reprezentarea folosind liste ınlantuite

In cadrul acestei metode fiecare multime este reprezentata printr–o lista simplu ınlantuita,elementul reprezentant fiind elementul aflat ın capul listei. Un nod al listei va avea un campce pastreaza informatia cu privire la un element al unei multimi, si un camp ce continelegatura catre urmatorul nod al listei.

Vom folosi un vector de adrese (List), ce contine adresa primului element din fiecare lista(Listi).

Procedura Init aloca un nod si initializeaza campurile acestuia. Adresa nodului alocateste pastrata ın Listk (vezi algoritmul 47).

Functia Find cauta un element printre elementele pastrate de fiecare lista ın parte. Separcurge vectorul List si se obtine reprezentantul fiecarei submultimi pastrate. Se parcurgelista (cautare liniara) si se cauta un element cu valoarea x. Daca elementul este gasit atuncise ıntoarce capul listei ın care a fost gasit. Daca pana la sfarsit nu a fost identificat elementulx, atunci functia returneaza valoarea NULL.

Functia Merge reuneste doua liste: practic se adauga o lista la sfarsitul celeilalte. Pentrua realiza aceasta operatie pe langa adresa primului element avem nevoie de adresa ultimuluielement. Acest lucru se poate obtine indirect prin parcurgerea listei de la primul la ultimulelement, fie direct daca ın momentul crearii pastram pentru fiecare lista ınca o variabila cecontine adresa ultimului element (last).

125

Page 126: CursuriAG2014

Algoritm 47 Algoritmi pentru operatiile init, find, merge (varianta a II-a)

1: procedure Init(x, k)2: Listk ← new node ⊲ aloca spatiu pentru un nod al listei3: Listk.data← x4: Listk.next← NULL5: end procedure

6: function Find(x)7: for i← 1,m do

8: p← Listi, reprezentant← p9: while (p 6= NULL) ∧ (p.data 6= x) do

10: p← p.next11: end while

12: if (p 6= NULL) then

13: return reprezentant14: end if

15: end for

16: return NULL17: end function

18: function Merge(x, y)19: capx ← Find(x)20: capy ← Find(y)21: curent← capx

22: while (curent.next 6= NULL) do

23: curent← curent.next24: end while

25: curent.next← capy

26: return capx

27: end function

Reprezentarea folosind o padure de arbori

In cadrul acestei modalitati de reprezentare fiecare multime este pastrata sub forma unuiarbore. Pentru fiecare nod pastram informatia despre parintele sau: tatak reprezinta indicelenodului parinte al nodului k.

Se poate observa foarte usor (vezi algoritmul 48) faptul ca arborele obtinut ın urma unoroperatii repetate Merge poate deveni degenerat (o lista liniara). Pentru a putea sa evitam oastfel de situatie, reuniunea se poate realiza tinand cont de una din urmatoarele caracteristici:

1. numarul de elemente din fiecare arbore - radacina arborelui ce are mai putine elemente(notam arborele cu TB) va deveni descendentul direct al radacinii arborelui ce posedamai multe elemente (notat cu TA). Astfel toate nodurile din arborele TA vor ramane cuaceeasi adancime, pe cand nodurile din arborele TB vor avea adancimea incrementatacu 1. De asemenea, arborele rezultat ın urma reuniunii va avea cel putin de doua orimai multe noduri decat arborele TB.

126

Page 127: CursuriAG2014

Algoritm 48 Algoritmi pentru operatiile init, find, merge (varianta a III-a)

1: procedure Init(x)2: tatax ← x3: end procedure

4: function Find(x)5: while (x 6= tatax) do

6: x← tatax

7: end while

8: return x9: end function

10: function Merge(x, y)11: radx← Find(x)12: rady ← Find(y)13: tatarady ← radx14: return radx15: end function

1: procedure Init(x)2: tatax ← −13: end procedure

4: function Find(x)5: while (tatax > 0) do

6: x← tatax

7: end while

8: return x9: end function

1: function Merge(x, y)2: radx← Find(x)3: rady ← Find(y)4: size← |tataradx|+ |tatarady|5: if (|tataradx| > |tatarady|) then

6: tatarady ← radx7: tataradx ← −size8: return radx9: else

10: tataradx ← rady11: tatarady ← −size12: return rady13: end if

14: end function

Prin aceasta euristica simpla se urmareste o echilibrare a arborelui rezultat pentru a seevita cazurile degenerate. Complexitatea timp a procedurii Find este O(log n).

2. ınaltimea fiecarui arbore - radacina arborelui ce are ınaltimea mai mica (notam arborelecu TB) va deveni descendentul direct al radacinii arborelui cu ınaltimea mai mare (notatcu TA). Daca ınaltimile lui TA si TB sunt egale si TA devine subarbore al lui TB atunciınaltimea lui TB creste cu o unitate.

Inaltimea fiecarui subarbore de radacina u se pastreaza ıntr–o variabila noua hu. Pentrua economisi cantitatea de memorie utilizata, se poate pastra ınaltimea unui arbore ınvectorul tata: tatax = −valoarea ınaltimii arborelui, atunci cand x reprezinta nodulradacina al unui arbore.

127

Page 128: CursuriAG2014

1: procedure Init(x)2: tatax ← x3: hx ← 04: end procedure

5: function Find(x)6: while (tatax 6= x) do

7: x← tatax

8: end while

9: return x10: end function

1: function Merge(x, y)2: radx← Find(x)3: rady ← Find(y)4: if (hradx > hrady) then

5: tatarady ← radx6: return radx7: else

8: tataradx ← rady9: if (hradx = hrady) then

10: hrady ← hrady + 111: end if

12: return rady13: end if

14: end function

Cea de–a doua tehnica utilizata pentru a reduce complexitatea timp a operatiilor Find siMerge este reprezentata de comprimarea drumului. Aceasta consta ın a apropia fiecare nodde radacina arborelui caruia ıi apartine. Astfel ın timpul operatiei Find(x) se determina maiıntai radacina arborelui caruia ıi apartine (rad) si apoi se mai parcurge o data drumul de lanodul x la radacina, astfel tatay ← rad, ∀y ∈ lantul de la x la rad.1: function Find(x)2: y ← x3: while (tatay 6= y) do

4: y ← tatay

5: end while

6: rad← y7: y ← x8: while (tatay 6= y) do

9: y ← tatay

10: tatax ← rad11: x← y12: end while

13: return rad14: end function

6.3.4 Algoritmul lui Kruskal

Algoritmul lui Kruskal [88] este o ilustrare foarte buna a metodei generale Greedy (vezialgoritmul 49). La ınceput se pleaca cu o padure de arbori, fiecare arbore fiind alcatuitdintr–un singur nod. La fiecare pas se alege o muchie: daca cele doua extremitati (noduri)fac parte din acelasi arbore atunci nu se va adauga muchia curenta la arborele partial respectivdeoarece ar conduce la un ciclu, ceea ce ar strica proprietatea de graf aciclic. Altfel, daca celedoua noduri fac parte din arbori partiali distincti, se adauga muchia curenta la multimea demuchii alese anterior, iar cei doi arbori partiali devin unul singur. La fiecare pas, numarulde arbori partiali scade cu 1. Dupa n − 1 alegeri padurea initiala compusa din n arbori s–atransformat ıntr–un singur arbore.

Pentru a pastra muchiile grafului vom utiliza o matrice A cu m coloane si 3 linii: primeledoua linii contin extremitatile muchiilor, iar linia a 3-a costul muchiei respective. Pentru a seaplica o strategie Greedy, datele de intrare – muchiile – se vor ordona crescator ın functie decostul asociat. Deoarece graful partial respectiv este un arbore cu n noduri el va avea n− 1muchii.

128

Page 129: CursuriAG2014

O verificare eficienta cu privire la apartenenta la acelasi arbore a celor doua extremitatiale unei muchii se poate face daca vom utiliza o structura de date pentru multimi disjuncte.

Ca implementare, am ales reprezentarea cu padure de arbori. Vom folosi un vector tatacare, pentru fiecare nod, va pastra tatal acestuia ın arborele partial caruia ıi apartine.

Cand sunt preluate ca date de intrare, muchiile vor fi prezentate ın ordinea crescatoare aextremitatilor 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← 06: j ← 1, L← ∅7: for i← 1, n − 1 do

8: q ← 09: while (q = 0) do

10: r1 ← Find(A1,j)11: r2 ← Find(A2,j)12: if (r1 6= r2) then

13: cost← cost + A3,j

14: call Merge(r1, r2)15: L← L ∪ (A1,j , A2,j)16: q ← 117: end if

18: j ← j + 119: end while

20: end for

21: end procedure

Exemplul 6.7 Sa consideram graful din figura 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 motivede spatiu):

A 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15linia 1 1 1 1 2 2 2 3 3 4 4 4 5 6 6 7linia 2 2 3 5 4 5 6 6 8 5 7 8 6 7 8 8linia 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 4linia 2 5 3 8 8 8 4 6 8 2 7 5 6 6 5 7linia 3 5 6 6 10 10 12 12 12 14 14 16 16 20 21 24

In figura 6.7, sunt ilustrati pasii algoritmului lui Kruskal aplicat pe graful considerat.La ınceput se initializeaza padurea de arbori, fiecare arbore fiind alcatuit dintr–un singurnod, acesta fiind si radacina arborelui. Apoi la fiecare pas se alege o muchie si se verificadaca extremitatile acesteia fac parte din arbori diferiti. Daca raspunsul este afirmativ atuncimuchia respectiva este selectata, altfel se trece la muchia urmatoare.

129

Page 130: CursuriAG2014

Fig. 6.7: Algoritmului lui Kruskal exemplificat pe graful din figura 6.6

La pasul ıntai evaluam muchia (1, 5), si deoarece cele doua extremitati fac parte din arboridistincti, vom selecta aceasta muchie (L = (1, 5)). Reunim arborii din care fac parte celedoua extremitati, (vezi figura 6.7 (1)).

La pasul al doilea, se ia ın considerare muchia (1, 3) si multimea muchilor selectate devineL = (1, 5), (1, 3) (vezi figura 6.7 (2)).

La pasul al patrulea, ajungem la muchia (4, 8) ce are costul 10. Nodul 4 face parte dinarborele de radacina 4 iar nodul 8 face parte din arborele de radacina 6. Deoarece extremitatilemuchiei sunt amplasate ın arbori distincti selectam muchia curenta pentru arborele partialde cost minim, L = (1, 5), (1, 3), (6, 8), (4, 8). In urma reuniunii arborilor corespunzatoricelor doua noduri se obtine configuratia din figura 6.7 (4).

130

Page 131: CursuriAG2014

Subliniem faptul ca arborii reprezentati ın figura 6.7 sunt diferiti de arborii ce con-duc la obtinerea solutiei problemei: arborii din figura constituie suportul necesar pentrureprezentarea structurii de date pentru multimi disjuncte, ce este utilizata pentru efectuareaeficienta a operatiilor Find si Merge. Acest lucru justifica faptul ca desi la pasul al patruleaselectam muchia (4, 8) pentru arborele partial de cost minim, ea nu se regaseste ın configuratia(4) (nodul 4 este unit direct cu nodul 6, vezi figura 6.7). Singura legatura dintre un arboresuport pentru reprezentarea unei multimi si un arbore folosit pentru obtinerea arborelui partialde cost minim, este multimea 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 diferiti,astfel ıncat muchia curenta poate fi selectata pentru solutia problemei, L = (1, 5), (1, 3), (6, 8),(4, 8), (7, 8), (2, 4), (3, 6).

6.4 Exercitii

1. Sa se realizeze o subrutina ce ıntoarce numarul de noduri dintr–un arbore oarecare.

2. Se da o secventa formata din n numere naturale d1, d2, . . . , dn. Sa se realizeze unalgoritm prin care sa se verifice daca exista un arbore cu n noduri ale caror grade suntd1, d2, . . . , dn.

Daca exista un astfel de arbore, acesta va fi reprezentat prin liste ale nodurilor. O listaa unui nod contine numarul nodului urmat de fii sai.

Intrare Iesire

1 1 2 3 1 1 3 DA1 2 3 42 5 63 74567

(Timisoara-pregatire, 1996)

3. Fie un graf G cu n varfuri si m muchii de cost pozitiv. Alegand un nod, numit nodcentral, sa se determine un subarbore al lui G astfel ıncat drumurile de la nodul centralla toate celelalte noduri sa aiba lungimea minima.

4. Fiind date n puncte ın spatiulR3 determinate prin coordonatele (x, y, z), sa se elaborezeun algoritm ce determina sfera de raza minima cu centrul ıntr–unul din punctele datesi care contine ın interiorul ei toate cele n puncte.

5. Se considera procesul de proiectare a unei placi electronice cu N componente (1 ≤ N ≤100). Pentru fiecare componenta electronica C se cunoaste numarul de interconexiuni.Se considera graful determinat de multimea pinilor si multimea interconectarilor posi-bile ale tuturor componentelor, precum si lungimile lor. Dintre toate modalitatile deinterconectare posibile se cere cea corespunzatoare arborelui de acoperire minim (inter-conectarea pentru care suma tuturor circuitelor imprimate are lungimea minima).

131

Page 132: CursuriAG2014

Datele de intrare sunt alcatuite din descrierile mai multor placi electronice. Descriereafiecarei placi contine numarul N de componente si numarul M de interconexiuni. Oconexiune se caracterizeaza prin trei valori: doua varfuri, u si v, precum si lungimeaacesteia l.

Datele de iesire constau dintr-un raspuns pentru fiecare multime de date de test, compusdin numarul testului (se ıncepe numerotarea cu 1), precum si costul interconectarii delungime 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 obtine rezultatul

Cazul 1: [1 5] [4 5] [2 3] [1 2]

Interconectarea de cost minim are valoarea 132.

In figura 6.8 este reprezentat graful corespunzator datelor de intrare.

Fig. 6.8: Descrierea conexiunilor posibile dintre componentele unei placi electronice

6. Realizati o subrutina nerecursiva care sa determine cheia minima dintr–un arbore oare-care.

7. Determinati ınaltimea unui arbore oarecare printr–o functie nerecursiva.

8. Pentru asigurarea securitatii activitatilor dintr–un combinat chimic s–a apelat la o com-panie de pompieri. Desfasurarea activitatilor companiei presupune stabilirea locurilorde instalare a comandamentului precum si a posturilor de supraveghere. Pentru aceastasunt disponibile ın cadrul combinatului n puncte de control. Pentru fiecare pereche depuncte de control se cunoaste daca exista o legatura directa ıntre ele si, ın caz afirmativ,distanta dintre ele. Se cunoaste, de asemenea, faptul ca ıntre oricare doua puncte decontrol exista un drum direct sau indirect.

Odata stabilite amplasamentele comandamentului si ale punctelor de supraveghere ıncate unul dintre cele n puncte de control este posibil sa se ajunga de la comandament

132

Page 133: CursuriAG2014

la fiecare punct de supraveghere parcurgand un anumit drum. Evident este de dorit calungimea acestui drum sa fie minima si valoarea maxima dintre lungimile drumurilorminime pentru fiecare punct de supraveghere ın parte sa fie cat mai mica posibila.

Se cere sa se determine punctul de control ın care trebuie instalat comandamentul catsi drumurile ce vor fi parcurse de la comandament la fiecare punct de supraveghere,astfel ıncat aceste drumuri sa aiba valoarea lungimii minima si cel mai lung dintre elesa fie cat mai scurt posibil.

133

Page 134: CursuriAG2014

Capitolul 7

Grafuri orientate

7.1 Notiuni de baza

Fie o multime finita V = x1, x2, . . . , xn. Fie E ⊆ V × V (unde V × V este produsulcartezian al multimii V cu ea ınsasi).

In cazul unui graf orientat, notiunea de muchie este ınlocuita cu notiunea de arc (opereche de noduri (x, y) devine ordonata, adica (x, y) 6= (y, x)). Pentru un arc (x, y) ∈ E,varful x reprezinta extremitatea initiala a arcului, iar varful y reprezinta extremitatea finala.Vom spune ca varfurile x si y sunt adiacente.

Definitia 7.1 Un graf orientat este o pereche ordonata G = (V, E), unde V este omultime de varfuri sau noduri, iar E este o multime 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 grafse poate reprezenta ca ın figura 7.1.

Definitia 7.2 Un graf partial al unui graf orientat G = (V, E) este un graf orientatG1 = (V, E1) unde E1 ⊂ E.

Exemplul 7.2 Pentru graful G din exemplul anterior (G = (V, E)), consideram grafulpartial G1 = (V, E1), cu E1 = (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.

Definitia 7.3 Un subgraf al unui graf orientat G = (V, E) este un graf orientat H =(V1, E1) unde V1 ⊂ V iar arcele din E1 sunt toate arcele din E ce au ambele extremitati ınmultimea V1 (E1 = E|V1×V1

).

Exemplul 7.3 Fie subgrafurile H1 si H2 ale grafului G din exemplul anterior: H1 = (V1, E1),unde V1 = 1, 2, 3, 5, iar E1 = (1, 2), (1, 3), (2, 1), (3, 5), (5, 2), si H2 = (V2, E2), undeV = 4, 6, 7, 8 si E2 = (4, 6), (6, 4), (6, 8), (7, 6).

Definitia 7.4 Gradul exterior al unui varf d+(x) este egal cu numarul arcelor ce au caextremitate initiala pe x. Gradul interior al unui varf d−(x) este egal cu numarul arcelor ceau ca extremitate finala pe x (d+(x) = |(x, u)|(x, u) ∈ E, u ∈ V |, d−(x) = |(u, x)|(u, x) ∈E, u ∈ V |).

134

Page 135: CursuriAG2014

Fig. 7.1: Un exemplu de graf orientat

Definitia 7.5 Se numeste lant o secventa de arce L = l1, . . . , lp cu proprietatea ca oricaredoua arce consecutive ale secventei au o extremitate comuna. (L = [v0, v1, . . . , vp] unde(vi, vi+1) ∈ E sau (vi+1, vi) ∈ E, ∀i = 0, p− 1).

Definitia 7.6 Un drum D = [v0, v1, . . . , vp] este o succesiune de varfuri cu proprietatea caoricare doua varfuri vecine sunt adiacente. ((vi, vi+1) ∈ E, i = 0, p− 1).

Daca varfurile v0, v1, . . . , vp sunt distincte doua cate doua, drumul se numeste elementar.

Exemplul 7.4 L1 = (6, 8), (7, 6), (7, 5), (3, 5), (1, 3) si L2 = (6, 8), (6, 4), (1, 4) sunt lanturide la varful 8 la varful 1, iar D1 = (1, 3), (3, 5), (5, 7), (7, 6), (6, 8) siD2 = (1, 4), (4, 6), (6, 8) sunt drumuri elementare de la varful 1 la varful 8.

Definitia 7.7 Un drum D pentru care v0 = vp se numeste circuit.

Definitia 7.8 Se numeste circuit hamiltonian un circuit elementar ce trece prin toatevarfurile grafului. Un graf ce admite un circuit hamiltonian se numeste graf hamiltonianorientat.

Definitia 7.9 Un drum D ce contine fiecare arc exact o singura data se numeste drum eu-lerian. Daca v0 = vp si drumul este eulerian atunci circuitul se numeste circuit eulerian.Un graf ce contine un circuit eulerian se numeste graf eulerian orientat.

Definitia 7.10 Un graf se numeste conex daca pentru orice pereche de varfuri x si y existaun lant Lxy de la x la y.

Definitia 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 naturalpentru reprezentarea unui graf orientat, ınlocuind notiunea de muchie cu cea de arc.

135

Page 136: CursuriAG2014

Fig. 7.2: Arbore de acoperire ın latime pentru graful orientat din figura 7.1

7.2 Parcurgerea grafurilor

In urma vizitarii unui graf neorientat de obicei nu rezulta numai un arbore de acoperire ci opadure de arbori de acoperire.

In urma unei parcurgeri ın latime a unui graf orientat, se ıntalnesc urmatoarele tipuri dearce:

• arc al arborelui de acoperire - arcul (u, v) este un arc al arborelui de acoperire ın latime.

• arc de ıntoarcere - arcul (u, v) se numeste arc de ıntoarcere daca are sensul contrar unuidrum de la v la u ın arborele de acoperire (v u) (se spune ca u este un descendental 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 descendentdirect, nici stramos al lui u.

In figura 7.2 este prezentat arborele de acoperire ın latime corespunzator grafului dinfigura 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 schita unui algoritm mai general pentru parcurgerea unui graf (vezi al-goritmul 50). Pentru aceasta se utilizeaza doua multimi de noduri, V izitat si Neexplorat,unde V izitat reprezinta multimea nodurilor vizitate iar Neexplorat (Neexplorat ⊂ V izitat)reprezinta multimea nodurilor vizitate dar neexplorate (noduri ce prezinta vecini ınca nevizitati).

In urma unei parcurgeri ın adancime a unui graf orientat, fiecare arc din multimea arcelorpoate fi ıncadrat ıntr–unul 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 dela u la v din arborele de acoperire (u v) (nu face parte din arborele de acoperire).

136

Page 137: CursuriAG2014

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← u3: Neexplorat← V izitat4: while (Neexplorat 6= ∅) do

5: extrage un nod x din Neexplorat6: determina y, urmatorul vecin al lui x ce nu a fost vizitat7: if (y = NULL) then

8: elimina x din Neexplorat9: else

10: if (y /∈ V izitat) then

11: V izitat← V izitat ∪ y12: Neexplorat← Neexplorat ∪ y13: 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 unuidrum 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 s–aterminat ınainte de apelul lui dfs(u).

Fig. 7.3: Arbore de acoperire ın adancime pentru graful orientat din figura 7.1

Pentru fiecare nod v al unui graf vom introduce doua numere, prenumv si postnumv,numere ce depind de ordinea ın care sunt ıntalnite nodurile acestuia ın timpul vizitarii ınadancime: prenumv marcheaza momentul cand este ıntalnit nodul v pentru prima oara

137

Page 138: CursuriAG2014

iar postnumv momentul ın care prelucrarea nodului v s–a ıncheiat. Variabila counter esteinitializata cu valoarea 1:1: procedure Prenum(v)2: prenumv ← counter3: counter ← counter + 14: end procedure

si1: procedure Postnum(v)2: postnumv ← counter3: counter ← counter + 14: end procedure

Un arc (u, v) va avea urmatoarele proprietati, ın functie de una din cele patru categoriide arce introduse anterior ın care se ıncadreaza:

1. arc al arborelui de acoperire: prenumu < prenumv si postnumu > postnumv;

2. arc de ınaintare: prenumu < prenumv si postnumu > postnumv;

3. arc de ıntoarcere: prenumu > prenumv si postnumu < postnumv;

4. arc de traversare: prenumu > prenumv si postnumu > postnumv.

Arborele de acoperire ın adancime corespunzator grafului din figura 7.1 ilustreaza acestetipuri de arce: arc de ınaintare – (1, 4), arce de ıntoarcere – (2, 1), (7, 5), (4, 6) arc detraversare – (5, 2), arce ale arborelui de acoperire – (1, 2), (1, 3), (3, 5), (5, 7), (7, 6), (6, 8),(6, 4). (vezi figura 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 adiacenta a grafului2: vizitatk ← 1 ⊲ marcarea nodului curent ca fiind vizitat3: call Prenum(k)4: call V izitare(k) ⊲ vizitarea nodului curent5: for i← 1, n do

6: if (vizitati = 0) ∧ (vecink,i = 1) then

7: call DFSNum(i, n, V ecin) ⊲ apelul recursiv al subrutinei DFSNum pentru noduli

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 apartin aceluiasiarbore de acoperire ın adancime rezultat ın urma parcurgerii cu metoda DFS a grafului Gavem:

1. daca (u, v) este un arc al arborelui de acoperire sau un arc de ınaintare sau un arc de traver-sare ⇒ postnumu > postnumv;

138

Page 139: CursuriAG2014

2. daca (u, v) este un arc de ıntoarcere ⇒ postnumu < postnumv.

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 rezultati ın urma vizitarii ınadancime a grafului G ⇔ intervalul [prenumv, postnumv] este inclus ın intervalul [prenumu,postnumu];

2. nu exista nici o legatura ıntre u si v ın padurea de arbori de acoperire rezultati ın urmavizitarii ın adancime a grafului G⇔ intervalele [prenumu, postnumu] si [prenumv, postnumv]sunt disjuncte;

3. situatii prenumu < prenumv < postnumu < postnumv sau prenumv < prenumu < postnumv

< postnumu nu sunt posibile.

Lema 7.7 Fiind dat un graf neorientat G, daca pentru doua noduri oarecare u, v ∈ G avemrelatia prenumu < prenumv < postnumu atunci:

• prenumu < prenumv < postnumv < postnumu.

• 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-venta de apeluri recursive ale procedurii DFSNum este ilustrata prin arborele de acoperireın adancime din figura 7.3.

Numerotarea nodurilor ın preordine si postordine rezultata ın urma vizitarii este urmatoarea:

1 2 3 4 5 6 7 8prenum 1 2 4 8 5 6 7 10postnum 16 3 15 9 14 13 12 11

Pentru arcul (1, 4) avem prenum1 = 1, postnum1 = 16, prenum4 = 8 si postnum4 = 9.Deoarece relatia prenumu < prenumv < postnumu este adevarata conform lemei 7.7 artrebui sa avem prenumu < prenumv < postnumv < postnumu si sa existe un drum de la ula v, lucruri care sunt adevarate (prenum1 < prenum4 < postnum4 < postnum1 si exista undrum de la 1 la 4 ın arborele de acoperire ın adancime).

7.3 Sortarea topologica

Fig. 7.4: Un graf orientat aciclic

139

Page 140: CursuriAG2014

Definitia 7.12 Un graf orientat si care nu poseda circuite se numeste graf orientat aciclic(directed acyclic graph - DAG).

Lema 7.9 Intr–un graf orientat aciclic, daca prenumu < prenumv si exista un drum de lau la v ın G, atunci prenumu < prenumv < postnumv < postnumu.

In practica, exista mai multe situatii ın care o multime de activitati sau sarcini, trebuieorganizate ıntr–o anumita ordine, ıntre acestea existand, de obicei, o multime de restrictiisau dependente. In activitatea de construire a unei cladiri, anumite activitati nu pot fiıncepute decat dupa finalizarea altor activitati: spre exemplu, nu se poate ıncepe ridicareaperetilor decat dupa turnarea fundatiei si finalizarea structurii de rezistenta, nu se poate rea-liza instalatia electrica daca nu au fost ridicate zidurile, s.a.m.d. Sau daca un student dorestesa ısi alcatuiasca un plan de studiu individual ce va contine pe langa cursurile obligatorii, sio serie de cursuri optionale, va trebui sa tina cont de anul de studiu ın care se preda fiecarematerie, precum si de cerintele obligatorii ale acestora: un curs nu poate fi inclus ın planul destudiu individual al unui student decat daca acesta a parcurs si a obtinut creditele la toatemateriile 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 contine listele cu vecini ai fiecarui nod2: for k ← 1, n do

3: dminusk ← 04: end for

5: for ∀(u, v) ∈ E do

6: dminusv = dminusv + 17: end for

8: Q← ∅ ⊲ se initializeaza coada9: for k ← 1, n do

10: if (dminusk = 0) then

11: Q⇐ k ⊲ se insereaza ıntr–o coada nodurile cu gradul interior 012: end if

13: end for

14: while (Q 6= ∅) do

15: Q⇒ k ⊲ se extrage din coada un nod16: L⇐ k ⊲ se insereaza nodul ıntr-o lista17: w ← V ecink ⊲ v ia valoarea capului listei de vecini a nodului k18: while (w 6= NULL) do

19: dminusw.nodeIndex ← dminusw.nodeIndex − 120: if (dminusw.nodeIndex = 0) then

21: Q⇐ w.nodeIndex ⊲ se insereaza ın coada nodul w.nodeIndex22: end if

23: w ← w.next ⊲ se trece la urmatorul vecin24: end while

25: end while

26: end procedure

Dependenta dintre doua activitati A si B o putem modela prin introducerea a doua noduriın graf xi si xj , asociate celor doua activitati. Daca activitatea A trebuie realizata ınainteaactivitatii B, atunci se adauga arcul (xi, xj).

140

Page 141: CursuriAG2014

Definitia 7.13 Se numeste sortare topologica pentru un graf orientat G = (V, E) o or-donare x1, x2, . . . , xn a nodurilor grafului astfel ıncat pentru orice arc (xi, xj) sa avemi < j.

Prin urmare o sortare topologica presupune aranjarea liniara a varfurilor unui graf astfelıncat toate arcele sale sa fie 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.

Observatia 7.12 Intr–un graf orientat aciclic exista cel putin un nod al carui grad interioreste 0 (graful nu poseda arce care sa aiba nodul v drept extremitate finala).

Pornind de la aceasta observatie se schiteaza urmatorul algoritm [78]: ıntr–un graf G sedetermina un nod v astfel ıncat gradul sau interior sa fie zero (d−(v) = 0); se adauga acestnod la o lista ce va contine ordonarea topologica, se sterge nodul din graf ımpreuna cu toatearcele ce ıl au ca extremitate initiala, si se reia algoritmul pentru graful G′ = (V ′, E ′), undeV ′ = 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 ıncatd−(v) = 0).

Fig. 7.5: Sortare topologica cu algoritmul 52 pentru graful orientat din figura 7.4

Exemplul 7.13 Fie graful orientat din figura 7.5. Varful 3 are d−(v) = 0. Se adauga acestnod la lista finala ce va contine nodurile ordonate, se sterge nodul ımpreuna cu arcele care ılau drept extremitate initiala. In graful rezultat, varful 1 are proprietatea ca d−(v) = 0. Seadauga la lista de rezultate, si se elimina din graf ımpreuna cu arcele ce pleaca din el. Secontinua procedeul pana cand graful devine vid (ıntregul proces poate fi urmarit ın figura 7.5).

141

Page 142: CursuriAG2014

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 adiacenta a grafului2: for k ← 1, n do

3: prenumk ← 0, postnumk ← 04: vizitatk ← 05: end for

6: for k ← 1, n do

7: if (vizitatk = 0) then

8: call DFSNum(k, n, V ecin)9: end if

10: end for

11: se ordoneaza descrescator nodurile dupa postnumk

12: end procedure

Lema 7.14 Un graf orientat G este aciclic daca si numai daca ın urma unei vizitari ınadancime 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 dinfigura 7.4. Dupa etapa de initializare (liniile 2 - 5) avem:

1 2 3 4 5 6 7prenum 0 0 0 0 0 0 0postnum 0 0 0 0 0 0 0vizitat 0 0 0 0 0 0 0

Se apeleaza mai ıntai DFSNum(1, 7, V ecin). Secventa rezultata de apeluri recursive esteurmatoarea: 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 secvente valorile vectorilor prenum si postnum sunt urmatoarele:

1 2 3 4 5 6 7prenum 1 2 0 3 4 6 5postnum 12 11 0 10 9 7 8vizitat 1 1 0 1 1 1 1

Mai ramane nevizitat un singur nod, 3, drept pentru care vom mai avea un apelDFSNum(3, 7, V ecin) din procedura principala SortTop2:

1 2 3 4 5 6 7prenum 1 2 13 3 4 6 5postnum 12 11 14 10 9 7 8vizitat 1 1 1 1 1 1 1

Ordonarea descrescatoare a nodurilor multimii V dupa valorile vectorului postnum con-duce la urmatoarea asezare:

142

Page 143: CursuriAG2014

postnum 14 12 11 10 9 8 73 1 2 4 5 7 6

Astfel sortarea topologica a nodurilor grafului obtinuta ın urma aplicarii algoritmului 53este: 3, 1, 2, 4, 5, 7, 6.

Observatia 7.16 O optimizare a algoritmului 53 se refera la adaugarea nodului v ıntr-ostiva atunci cand se termina vizitarea acestui nod v si se calculeaza postnumv. Aceasta stivala sfarsit va contine nodurile grafului ın ordinea descrescatoare a valorilor postnumv.

Prin urmare nu mai este nevoie sa ordonam descrescator valorile vectorului postnumpentru a obtine o sortare topologica a nodurilor grafului G, iar complexitatea algoritmului 53devine 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 multimea nodurilor si E estemultimea arcelor (E ⊆ V × V ).

Definitia 7.14 O componenta tare conexa a unui graf orientat G este o multime maxi-mala de varfuri U ⊆ V , astfel ıncat, pentru fiecare pereche de varfuri u, v (u, v ∈ U) existaatat un drum de la u la v cat si un drum de la v la u. Prin urmare se spune ca varfurile usi v sunt accesibile unul din celalalt.

Un graf orientat ce are o singura componenta tare conexa astfel ıncat U = V este un graftare 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 subgrafal grafului initial.

Definitia 7.15 Graful orientat G se numeste tare conex daca pentru orice pereche devarfuri u 6= 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 relatia de tare conexitate este o relatie de echivalenta. O relatie (notatacu ∼) este o relatie de echivalenta daca prezinta proprietatile de reflexivitate, simetrie sitranzitivitate:

143

Page 144: CursuriAG2014

• reflexivitate: a ∼ a;

• simetrie: a ∼ b⇒ b ∼ a;

• tranzitivitate: a ∼ b, b ∼ c⇒ a ∼ c.

O clasa de echivalenta este multimea tuturor elementelor care se afla ın relatia ∼ ([x]∼ =y|x ∼ y). Relatia de echivalenta determina o partitie ın clase de echivalenta a multimiipeste care a fost definita. Prin urmare relatia de tare conexitate determina o partitie amultimii V . Clasele de echivalenta determinate de relatia de tare conexitate sunt componen-tele tare conexe.

Pentru determinarea componentelor tare conexe exista mai multi algoritmi, dintre careamintim algoritmul lui Tarjan, algoritmul lui Kosaraju si algoritmul lui Gabow.

7.4.1 Algoritmul lui Kosaraju

Algoritmul lui Kosaraju–Sharir a fost prezentat de Aho, Hopcroft si Ullman ın lucrarea lor [2],fiind preluat dintr–un manuscris al lui S. Rao Kosaraju (M. Sharir l–a prezentat ın lucrarea[110]).

Algoritmul foloseste graful transpus GT asociat grafului initial G ([11], [23], [30]), fiindcompus din urmatorii pasi:

Pas 1. Se realizeaza parcugerea grafului cu algoritmul de vizitare ın adancime, pornind de laun nod arbitrar. In timpul vizitarii se realizeaza numerotarea ın postordine a nodurilorın cadrul vectorului postnum.

Pas 2. Se obtine un nou graf GT = (V, ET ) prin inversarea sensului arcelor grafului G (ET =(u, v)|(v, u) ∈ E, u, v ∈ V ).

Pas 3. Se cauta nodul nevizitat din graful GT ce are cel mai mare numar atribuit ın urmaparcurgerii de la Pasul 1. Din acest nod se initiaza parcugerea grafului cu algoritmulde 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 conexaa 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

Page 145: CursuriAG2014

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

Page 146: CursuriAG2014

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 sipostnum sunt urmatoarele:

1 2 3 4 5 6 7 8postnum 8 7 5 6 1 2 3 4vizitat 1 1 1 1 1 1 1 1

Fig. 7.7: Graful transpus GT corespunzator grafului din figura 7.6

Se construieste graful transpus, GT (vezi figura 7.7). Se cauta primul nod u ınca neviz-itat (vizitatu = 0), caruia ıi corespunde cea mai mare valoare postnumu. In acest mod se

146

Page 147: CursuriAG2014

identifica 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 prenumu maxima este nodul 8. Se identifica

mai ıntai componenta tare conexa 7, 8 si apoi 5, 6.

Analiza algoritmului

Algoritmul lui Kosaraju realizeaza doua parcurgeri ale tuturor elementelor grafului G: primadata parcurge graful G si a doua oara parcurge graful GT . Prin urmare complexitatea timp aalgoritmului este Ω(|V |+ |E|) ın cazul ın care graful este reprezentat prin liste de adiacenta sieste patratica ın |V |2 (O(|V |2)) atunci cand graful este reprezentat prin matricea de adiacenta.

7.4.2 Algoritmul lui Tarjan

Algoritmul lui Tarjan [117] este considerat drept o ımbunatatire a algoritmului lui Kosarajuprin aceea ca nu mai este nevoie de parcurgerea grafului G de doua ori.

Algoritmul initiaza o parcurgere ın adancime a nodurilor grafului G pornind de la un nodoarecare. O componenta tare conexa a grafului G, daca exista, constituie un subarbore alarborelui de acoperire ın adancime, iar radacina acestui subarbore este reprezentantul claseide echivalenta.

Prin urmare componentele tare conexe se obtin prin descompunerea arborelui/arborilorde acoperire ın adancime daca eliminam anumite arce ale acestora. Un nod este capul uneicomponente tare conexe (sau radacina), daca acesta constituie radacina subarborelui core-spunzator componentei. Arcul ce are nodul–cap drept extremitate finala este cel ce trebuieeliminat. Dupa ce determinam toate nodurile–cap, subarborii arborelui/arborilor de acoperireın adancime ce ıi au drept radacini sunt componentele tare conexe.

Algoritmul lui Tarjan are drept scop determinarea nodurilor–cap. Pentru a pastra o ordinea vizitarii acestora pe parcursul algoritmului, nodurile vor fi adaugate pe o stiva. Ele vor fiextrase din stiva ın momentul ın care procedura de vizitare DFS a unui nod este ıncheiata: sedetermina daca nodul curent este radacina unei componente tare conexe, si, ın caz afirmativ,toate nodurile care au fost vizitate din nodul curent ın cadrul parcurgerii ın adancime suntmarcate ca fiind 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 fiind pastrate ın vectorulprenum (cititorul este invitat sa revada si sectiunea despre Muchie critica, cea de-a douasolutie). Pentru un nod u ∈ G definim lowu astfel:

lowu = min

prenumu

prenumx , daca [u, x] este arc de ıntoarcere sau de traversare si x ∈ S

lowy , ∀y descendent direct al lui u

Daca dintr–un 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 safi fost vizitat ınaintea lui u (prenumu > prenumv). Daca un astfel de nod nu exista atuncilowu = prenumu. Stiva S pastreaza nodurile grafului, pe masura ce sunt vizitate ele fiindadaugate la S. Daca u este un nod–cap (lowu = prenumu) se extrag din stiva toate noduriledintre varful stivei si u inclusiv: acestea formeaza o componenta tare conexa.

Se observa ca algoritmul lui Tarjan (algoritmul 54) seamana foarte mult cu algoritmul 26de determinare a muchiei critice (varianta a II-a).

147

Page 148: CursuriAG2014

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 adiacenta2: for i← 1, n do

3: vizitati ← 04: end for

5: counter ← 06: S ← ∅7: for i← 1, n do

8: if (vizitati = 0) then

9: call DFSTarjan(i, n, V ecin) ⊲ vizitarea ın adancime a grafului10: end if

11: end for

12: end procedure

13: procedure DFSTarjan(k, n, V ecin)14: S ⇐ k15: vizitatk ← 116: counter ← counter + 117: prenumk ← counter, lowk ← counter18: for i← 1, n do

19: if (vecink,i = 1) then

20: if (vizitati = 0) then

21: call DFSTarjan(i, n, V ecin)22: lowk ←Min(lowk, lowi)23: else

24: if (i ∈ S) then

25: lowk ←Min(lowk, prenumi)26: end if

27: end if

28: end if

29: end for

30: if (lowk = prenumk) then

31: repeat

32: S ⇒ u33: 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 8prenum 0 0 0 0 0 0 0 0vizitat 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 secventa 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

Page 149: CursuriAG2014

1 2 3 4 5 6 7 8prenum 1 2 3 0 5 4 0 0vizitat 1 1 1 0 1 1 0 0low 1 2 0 0 4 4 0 0

Stiva contine urmatoarele elemente (varful stivei fiind ın dreapta): 1, 2, 3, 6, 5.low5 = minprenum6, low5 = min4, 5 = 4 (deoarece desi vizitat6 = 1, avem 6 ∈ S,

adica nodul 6 se afla pe stiva). Astfel ın momentul terminarii apelului DFSTarjan(5, 8, V ecin),low5 = 4.

Acum la nivelul lui DFSTarjan(6, 8, V ecin), ın urma revenirii din DFSTarjan(5, 8, V ecin),se calculeaza low6 = minlow6, low5 = min4, 4 = 4 (linia 22).

Nodul 6 este un nod–cap (low6 = prenum6) (vezi linia 30), si prin urmare se extrag de pestiva toate elementele dintre varful stivei si elementul 6 inclusiv, rezultand prima componentatare conexa: 5, 6. Stiva ramane cu elementele (varful stivei fiind ı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).

Continutul stivei este 1, 2, 3, 8, 7.La nivelul apelului DFSNum(7, 8, V ecin) nu se ia ın considerare la calculului valorii lui

low7 nodul 6: desi exista arcul (7, 6), nodul 6 a fost vizitat (vizitati 6= 0) si nu se mai aflape stiva (i /∈ S). Astfel low7 = minlow7, prenum8 = min7, 6 = 6.

La nivelul lui DFSNum(8, 8, V ecin), low8 = minlow8, low7 = min6, 6 = 6 (linia 22).Avem ca (low8 = prenum8) (linia 30) si prin urmare 8 este un nod–cap. Se extrag de pe stivatoate elementele dintre varful stivei si elementul 8 inclusiv, rezultand a doua componenta tareconexa: 7, 8.

Stiva ramane cu elementele (varful stivei fiind ın dreapta) 1, 2, 3.

1 2 3 4 5 6 7 8prenum 1 2 3 0 5 4 7 6vizitat 1 1 1 0 1 1 1 1low 1 2 0 0 4 4 6 6

In momentul terminarii apelului DFSTarjan(3, 8, V ecin), low3 = 2.Revenind la nivelul apelului DFSTarjan(2, 8, V ecin), se calculeaza low2 = minlow2, low3 =

min2, 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), low4 = prenum4 = 8.low4 se calculeaza din low4 = minlow4, prenum3 = min8, 3 = 3 (exista arcul (4, 3),

nodul 3 a fost vizitat - vizitat3 = 1 si 3 ∈ S - nodul 3 se afla pe stiva).1 2 3 4 5 6 7 8

prenum 1 2 3 8 5 4 7 6vizitat 1 1 1 1 1 1 1 1low 1 2 2 3 4 4 6 6

Ne ıntoarcem la nivelul apelului DFSTarjan(2, 8, V ecin), low2 = minlow2, low4 =min2, 3 = 2. Arcul (2, 5) nu este luat ın considerare la calculul lui low2 deoarece nodul 5 afost vizitat (vizitat5 = 1) si 5 nu se regaseste pe stiva. Astfel low2 ramane cu valoarea 2.

Deoarece low2 = prenum2, extragem de pe stiva elementele ce determina cea de-a treiacomponenta tare conexa: 4, 3, 2. Pe stiva mai ramane un singur element, 1, ce vadetermina ultima componenta tare conexa.

149

Page 150: CursuriAG2014

In final, valorile low si prenum sunt urmatoarele:

1 2 3 4 5 6 7 8prenum 1 2 3 8 5 4 7 6vizitat 1 1 1 1 1 1 1 1low 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 apoiindependent de catre Harold Gabow ın 1999 [56].

Algoritmul construieste un graf H [56] ce reprezinta o contractie a grafului original G: unulsau mai multe noduri din G pot sa corespunda unui nod din H . La ınceput se initializeazaH = G. Se ıncepe construirea unui drum P alegandu–se un nod oarecare v ∈ H .

Fig. 7.8: Drumul P ın algoritmul lui Gabow pentru graful din figura 7.6

La fiecare pas al algoritmului se ıncearca sa se augmenteze drumul P = P ∪ w =[v1, . . . , vk, w] prin parcurgerea tuturor arcelor (vk, w):

- daca w /∈ P , atunci se adauga nodul w la drumul P (P = [v1, . . . , vk, w]);

- daca w ∈ P , fie w = vj . Contractam circuitul vj, vj+1, . . . , vk, w ın graful H : ınlocul multimii de varfuri vj , vj+1, . . . , vk va ramane doar reprezentantul acesteia, e.g.nodul ce are valoarea minima ın urma numerotarii ın preordine;

- daca nu avem nici un arc neverificat care sa aiba nodul vk ca extremitate initiala, semarcheaza nodul vk ca apartinand unei componente conexe. Se sterge nodul vk dingraful H si din drumul P , ımpreuna cu toate arcele ce ıl au ca extremitate. DacaP 6= ∅ atunci se continua algoritmul ıncercandu–se augmentarea drumului P . In cazcontrar se ıncearca initializarea unui drum nou P ın H .

Si acest algoritm are la baza metoda de parcurgere ın adancime a unui graf (DFS). Intimpul vizitarii, algoritmul utilizeaza doua stive S si P : S contine toate nodurile ce nu aufost atribuite ınca unei componente tare conexe, ın ordinea ın care au fost ıntalnite, iar Pcontine toate nodurile despre care ınca nu se poate spune nimic cu privire la apartenenta lorla componente conexe diferite (contine nodurile drumului P din graful H). Altfel spus, se

150

Page 151: CursuriAG2014

observa faptul ca stiva P pastreaza nodurile radacina ce formeaza o subsecventa a secventeinodurilor ce se afla la un moment dat ın cealalta stiva S.

In cadrul secventei urmatoare, pentru un nod i adiacent cu nodul curent k, se verificadaca nu a mai fost vizitat. Daca vizitati = 0 atunci se continua vizitarea ın adancime (callDFSGabow(i, n, V ecin)). Altfel, se verifica daca nodul i nu a fost deja asignat unei compo-nente tare conexe, ın caz afirmativ eliminandu–se din drumul P circuitul vi, . . . , vk, vi:1: if (vizitati = 0) then

2: call DFSGabow(i, n, V ecin)3: else

4: if (i ∈ S) then ⊲ i5: while (prenumi < prenumpeek(P )) do

6: P ⇒ u7: end while

8: end if

9: end if

La finalul procedurii DFSGabow, se verifica daca nodul curent este identic cu cel aflatın varful stivei P . In caz afirmativ se extrag de pe stiva toate nodurile dintre varful curental stivei S si nodul k, si se marcheaza ca fiind elemente ale componentei tare conexe a careiradacina este nodul k:

if (k = peek(P )) then

P ⇒ urepeat

S ⇒ uOutput ”u”

until (u = k)end if

7.5 Exercitii

1. (Compilator) In trecut compilatoarele erau foarte simple. In acele vremuri oameniipreferau sa includa tot programul ıntr-un singur fisier. Daca cineva facea o modificare ınprogram, trebuia recompilat tot codul sursa. Cresterea lungimii programelor conduceala timpi de compilare tot mai mari, ceea ce constituia o piedica ın ceea ce privestecresterea complexitatii algoritmilor implementati.

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 lecompilau separat. Astfel, pentru orice modificare care se opera ıntr-un anumit modul,se compila numai acesta, si nu ıntreaga aplicatie. Fiecare modul contine la ınceput listacelorlaltor module pe care le foloseste.

Modulul A trebuie recompilat numai daca a fost modificat sau are ın lista sa un modulB care a fost recompilat la randul sau. In celelalte cazuri nu este necesara recompilareamodulului A.

Problema cere sa se realizeze un algoritm si pe baza acestuia un program, care sa decidace 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 contine numarul de module N (1 ≤ N ≤ 100). Urmeazadescrierea modulelor. Prima linie a descrierii contine numele modulului. A doua linie

151

Page 152: CursuriAG2014

Algoritm 55 Algoritmul lui Gabow pentru determinarea componentelor tare conexe

1: procedure Gabow(n, V ecin)2: for i← 1, n do

3: vizitati ← 04: end for

5: counter ← 06: S ← ∅, P ← ∅7: for i← 1, n do

8: if (vizitati = 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: vizitatk ← 115: S ⇐ k, P ⇐ k16: counter ← counter + 117: prenumk ← counter18: for i← 1, n do

19: if (vecink,i = 1) then

20: if (vizitati = 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 conexe24: while (prenumi < prenumpeek(P )) do

25: P ⇒ u26: end while

27: end if

28: end if

29: end if

30: end for

31: if (k = peek(P )) then

32: P ⇒ u33: repeat

34: S ⇒ u35: Output ”u”36: until (u = k)37: end if

38: end procedure

contine numarul liniilor din codul sursa. A treia linie contine numarul M (0 ≤ M < N)de module de care depinde modulul actual. Linia urmatoare contine numele acestormodule, separate printr–un spatiu. Numele unui modul nu depaseste 20 de caractere.

Descrierea modulelor este urmata de mai multe blocuri, cate unul pentru fiecare versiunea programului. Prima linie a fiecarui bloc contine numarul k (1 ≤ k ≤ N) de modulece au suferit modificari de la recompilarea versiunii precedente.

Linia urmatoare contine numele modulelor, separate prin spatiu, ın care au survenitmodificari. Dupa ultimul bloc exista o singura linie ce contine doar numarul 0.

Pentru fiecare versiune a programului se scrie o linie ce contine numarul liniilor codului

152

Page 153: CursuriAG2014

sursa care au trebuit sa fie recompilate.

Intrare Iesire3 127

MATH200

MAIN100

2MATH IO

IO703

MATH IO MAIN0

(Propusa la CEOI 1997)

2. Se da un numar de k (k < 1000) reguli, numerotate de la 1 la k. O regula are formax → y unde x si y sunt propozitii cu urmatoarea semnificatie: daca propozitia x esteadevarata, atunci proprozitia 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. Demonstratia 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 demonstratie corecta, ce contine ın plus regula 1(1)→ 2. Profesorul ar fi fost

multumit cu demonstratia 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 (propozitia care seconsidera adevarata), y (propozitia ce trebuie demonstrata), sirul celor k reguli cat sisirul numerelor de ordine ale regulilor ce constituie demonstratia elevului.

Algoritmul verifica daca sirul numerelor de ordine ale regulilor constituie o demonstratie.In caz negativ va afisa ′NU ′, iar ın caz afirmativ va afisa ′DA′, urmat pe linia urmatoarede demonstratia elevului din care au fost eliminate afirmatiile inutile. Se considera caun sir de reguli fara reguli ın plus constituie o demonstratie corecta a propozitiei ypornind de la propozitia x, daca renuntarea la orice regula ar conduce la o secventaprin 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 cheltuiescfoarte multi bani pentru a convinge oamenii ca ofera cele mai bune servicii la cel maiscazut 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 careconstituie cercul sau de prieteni). Daca acesta suna pe cineva inclus ın aceasta lista,si persoana respectiva este, de asemenea, abonata la aceeasi companie, va beneficia deun discount mai mare decat pentru o convorbire telefonica cu cineva din afara listei.

O alta companie a aflat de aceasta initiativa si se ofera sa determine ea lista decunostinte cu care un abonat vorbeste cel mai frecvent la telefon.

153

Page 154: CursuriAG2014

LibertyBellPhone este o companie noua de telefoane ce se gandeste sa ofere un plande apeluri mult mai avantajos decat alte companii. Ea ofera 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 fiecare apel telefonic.In afara unui abonat, cercul sau de apel consta din toate persoanele pe care le suna sicare ıl suna, direct sau indirect.

De exemplu, daca Ben ıl suna pe Alexander, Alexander o suna pe Dolly si Dolly ılsuna pe Ben, atunci ei toti fac parte din acelasi cerc. Daca Dolly ıl mai suna si peBenedict iar Benedict o suna pe Dolly, atunci Benedict este ın acelasi cerc cu Dolly,Ben si Alexander. In fine, daca Alexander ıl suna pe Aron dar Aaron nu ıl suna peAlexander, Ben, Dolly sau Benedict, atunci Aaron nu este ın cerc.

Sa se realizeze un algoritm ce determina cercurile de apel, cunoscandu–se lista apelurilortelefonice dintre abonati.

(Finala ACM 1995, Calling Circles)

4. La facultatea X exista doua alternative pentru ca studentii sa aiba timp sa asimilezecunostintele:

(a) Marirea zilei la 30 de ore, si

(b) Reducerea programei scolare.

Optand pentru a doua varianta, Liga Studentilor 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 ”TeorieEconomica” 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 nuservesc (direct sau indirect) la ınvatarea unor materii folositoare.

(d) Cere sa se indice care dintre materii nu pot fi predate ın nici o ordine. De ex-emplu, cursul ”Mecanica” se bazeaza pe cursul ”Ecuatii Diferentiale”, dar cursulde ”Ecuatii Diferentiale” ısi preia exemplele din ”Mecanica”. Prin urmare nu ex-ista nici o ordine ın care aceste materii sa fie predate fara a introduce cunostintenedemonstrate.

5. Distribuirea cartilor cerute de catre cititorii de la sala de lectura a unei biblioteci estefacuta de catre un robot ce are posibilitatea sa ajunga la orice carte ce poate fi solicitata.Din pacate, rafturile unde sunt depozitate cartile sunt dispuse astfel ıncat robotul nupoate lua cartile ıntr–un singur drum. Dupa receptionarea comenzilor de la mai multicititori, robotul cunoaste pozitia cartilor ın rafturi si drumurile catre acestea. Dinpacate, de la pozitia unei carti, robotul nu se poate deplasa decat spre anumite carti.Acesta porneste si culege cartile ce sunt accesibile ıntr–un drum, apoi porneste de lao alta pozitie de carte si culege acele carti ce sunt accesibile din acel punct si asa maideparte.

154

Page 155: CursuriAG2014

Datele de intrare constau din numarul de carti n precum si numarul m de legaturidintre pozitiile acestora (1 ≤ n ≤ 100, 11 ≤ m ≤ 10000), urmate de m perechi denumere naturale, ce semnifica legaturile directe ıntre pozitiile cartilor.

Datele de iesire constau din drumurile pe care le face robotul pentru a culege cartilecerute.

Fig. 7.9: Pozitiile cartilor ıntr–o biblioteca precum si posibilitatile de deplasare ale robotului

6. Se considera o multime de n elevi dintr–o clasa. Fiecare elev are cunostinte mai avansateıntr–un anumit domeniu. Pentru ridicarea nivelului clasei, dirigintele vrea sa–i aranjezeın grupuri astfel ıncat toti elevii dintr–un grup sa ajunga sa cunoasca, ıntr–o anumitaperioada de timp, toate cunostintele tuturor celorlalti colegi din acelasi grup.

Grupurile de elevi nu ısi vor schimba cunostintele ıntre ele. Se stie ca un elev nu sepoate face ınteles de catre oricine. El are o lista de preferinte fata de care el le vaımpartasi cunostintele sale. Relatia de preferinta nu este simetrica.

Sa se determine numarul minim de grupuri ın care va fi ımpartita clasa precum sicomponenta acestora.

155

Page 156: CursuriAG2014

Capitolul 8

Distante ın grafuri

Reteaua de drumuri europene, nationale si judetene dintr–o tara, reteaua feroviara reprezentandinfrastructura cailor ferate absolut necesara pentru realizarea transportului de marfuri sicalatori cu trenul, reteaua de fibra optica folosita pentru traficul de date ın Internet, reteauade transport a energiei electrice folosita pentru alimentarea cu energie electrica a consumato-rilor casnici si a celor industriali, reteaua de canalizare dintr–un oras folosita pentru evacuareadeseurilor, reteaua CATV a unui operator de televiziune prin cablu, reteaua de linii de auto-buz ce face parte din sistemul public de transport al unui oras sunt exemple tipice de grafuricu care interactionam ın viata de zi cu zi.

Putem spune ca retelele de transport si cele de comunicatii de date ne influenteaza ınmod direct modul de viata, devenind elemente indispensabile ale omului modern, si astfel,problemele referitoare la studiul cailor de comunicatie, drumurilor, conexiunilor, capata uninteres special.

De obicei suntem interesati 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 maisigur. Teoria grafurilor ne pune la dispozitie mijloacele pentru aflarea raspunsului la multeastfel de ıntrebari.

Definitiile pentru drum, lant, ciclu, circuit au fost prezentate ın capitolele anterioare,ımpreuna cu multe alte concepte teoretice. Lungimea unui lant este determinata de numarulmuchiilor sale. In mod analog, lungimea unui drum este egala cu numarul arcelor sale.

Intr–un graf G se introduce o functie de cost ce asocieaza o valoare reala fiecarei muchiisau arc, dupa caz:

c : E −→ R sau c : V × V −→ R

Notam costul unui drum ca fiind suma costurilor arcelor componente. Astfel pentru undrum D = [v0, v1, . . . , vm] de lungime m, costul acestuia va fi dat de urmatoarea formula:

c(D) =m−1∑

i=0

c((vi, vi+1))

Notam cuMs,t multimea drumurilor dintre nodul xs si nodul xt, xs, xt ∈ V . Pentru douanoduri oarecare xs si xt, se doreste sa se determine un drum δs,t de la xs la xt a carui valoaresa fie optima (minima sau maxima):

c(δopts,t ) = min

δs,t∈Ms,t

c(δs,t)

156

Page 157: CursuriAG2014

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 = x1, x2, . . . , xn este multimea nodurilor si E estemultimea arcelor (E ⊆ V ×V ). Pentru reprezentarea grafului vom utiliza listele de adiacenta(listele cu vecini).

Fie u un varf al grafului numit sursa. Dorim sa determinam pentru fiecare varf w ∈V, w 6= u, daca exista, un drum de lungime minima de la u la w. Lungimea unui drum sedefineste ca fiind numarul arcelor ce ıl compun.

Algoritmul lui Moore (algoritmul 56) se bazeaza pe structura algoritmului de parcurgereın latime al unui graf (breadth first search – vezi algoritmul 20). In lucrarea [98], Moore ısiprezinta algoritmul astfel:

Write 0 on the source. Then look at all the neighbors of the source and write1 on them. Then look at all the neighbors of nodes with 1 on them and write 2on them. And so on.

Vom nota cu dk – costul drumului minim de la varful u la varful xk, iar tatak – varful anteriorlui xk, pe drumul de cost minim de la u la xk.

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 contine capetele listelor de vecini

Output:

d - vectorul distantelor de la nodul sursa la celelalte noduri

tata - vector ce contine pentru fiecare nod k, predecesorul acestuia pe drumul

de cost minim de la nodul sursa la nodul k2: for i← 1, n do

3: di ← +∞4: end for

5: dk ← 0 ⊲ distanta de la un nod la el ınsusi este 06: Q⇐ k ⊲ inserarea nodului curent k ın coada7: while (Q 6= ∅) do ⊲ cat timp coada nu este vida8: Q⇒ k ⊲ extrage nodul curent din coada9: v ← vecink ⊲ se pleaca cu primul vecin din lista de vecini

10: while (v 6= NULL) do

11: if (dv.nodeIndex = +∞) then ⊲ v.nodeIndex este indicele nodului vecin12: dv.nodeIndex ← dk + 1, tatav.nodeIndex ← k13: Q⇐ v.nodeIndex ⊲ inserarea nodului v.nodeIndex ın coada14: end if

15: v ← v.next ⊲ se trece la urmatorul vecin16: end while

17: end while

18: end procedure

Exemplul 8.1 Fie un graf orientat definit de catre urmatoarele liste de vecini:

157

Page 158: CursuriAG2014

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 obtin 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 afisate, putem spune ca drumul de lungime minima de la nodul 1 lanodul 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 nodurileaccesibile din acesta, ın cazul ın care lungimea unui drum se defineste ca fiind suma costurilorasociate 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 costurilor2: for i← 1, n do

3: di ← +∞4: end for

5: dk ← 0 ⊲ distanta de la un nod la el ınsusi este 06: Q⇐ k ⊲ inserarea nodului curent k ın coada7: while (Q 6= ∅) do ⊲ cat timp coada nu este vida8: Q⇒ k ⊲ extrage nodul curent din coada9: for fiecare vecin (v = xi) al lui xk do

10: if (dk + ck,i < di) then

11: di ← dk + ck,i, tatai ← k12: Q⇐ i ⊲ inserarea nodului i ın coada13: 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 multimea nodurilor si E estemultimea arcelor (E ⊆ V ×V ). Pentru reprezentarea grafului se utilizeaza matricea costurilorC:

ci,j =

0 , daca i = j

∞ , daca (i, j) /∈ E, i 6= j

d > 0 , daca (i, j) ∈ E

158

Page 159: CursuriAG2014

Fie u un varf al grafului numit sursa. Dorim sa determinam pentru fiecare varf j ∈ V, j 6=u, daca exista, un drum de lungime minima de la u la j. Lungimea unui drum se definesteca fiind suma costurilor asociate arcelor ce-l compun.

Algoritmul lui Dijkstra [38] utilizeaza metoda generala de elaborare a algoritmilor Greedy,drumurile de lungime minima fiind generate ın ordinea crescatoare a lungimii lor. Vom notacu S multimea nodurilor grafului G pentru care se cunoaste (s-a calculat) drumul de lungimeminima de la sursa. La ınceput multimea S este formata doar din nodul sursa. La fiecarepas, se adauga la multimea S un nod k ∈ V \ S cu proprietatea ca drumul de la sursa laacel nod este cel mai mic dintre toate drumurile posibile de la sursa la noduri din multimeaV \ S, cu proprietatea ca un astfel de drum are drept noduri intermediare numai elementedin multimea S, cu exceptia extremitatii finale. Vom utiliza un tablou D ce va pastra pentrufiecare nod k, lungimea drumului cel mai scurt de la sursa ce trece numai prin noduri dinmultimea S (vezi algoritmul 58).

Dupa ce am identificat un astfel de nod k, multimea S se modifica astfel: S = S ∪ k.Este posibil ca lungimea unui drum de la sursa la un nod j ∈ V \ S, ce are drept noduriintermediare noduri din multimea S, sa se modifice datorita faptului ca, mai ınainte, nodul knu fusese luat ın considerare, deoarece nu apartinea multimii S. Astfel, se poate ca un drumde la sursa la nodul j, ce trece prin nodul k, sa fie mai mic decat drumul anterior de la sursala nodul j: dk + ck,j < dj.

Algoritm 58 Algoritmul lui Dijkstra (schema generala)

1: procedure Dijkstra1(n,C, u)2: S ← u3: for i← 1, n do

4: di ← cu,i

5: end for

6: for i← 1, n − 1 do

7: k ← mindk|k ∈ V \ S8: S ← S ∪ k9: for each j ∈ V \ S do

10: dj ← min(dj, dk + ck,j)11: end for

12: end for

13: end procedure

Vom utiliza trei vectori (vezi algoritmul 59):

• vizitat - vector caracteristic

vizitatk =

1 , daca nodul k ∈ S

0 , daca nodul k ∈ V \ S

• d - vectorul distantelor de la nodul u la celelalte noduri ale grafului. In momentulinitial dj = cu,j. Fie k nodul ales la un moment dat. Atunci dj se modifica numai dacadk + ck,j < dj, fiind actualizat astfel: dj = dk + ck,j.

• tatak - contine pentru fiecare nod k nodul anterior j (j ∈ S) pe drumul de cost minimde la u la k. La ınceput,

tatak =

0 , daca nodul k = u sau cu,k =∞u , ın rest (k 6= u si cu,k 6=∞)

159

Page 160: CursuriAG2014

Un element al acestui vector se poate modifica atunci cand se modifica dj, caz ın caretataj = k.

Algoritm 59 Algoritmul lui Dijkstra

1: function DistantaMinima(n, vizitat, d)2: min←∞3: for j ← 1, n do

4: if (vizitatj 6= 1) ∧ (dj < min) then

5: min← dj

6: j0 ← j7: end if

8: end for

9: if (min =∞) then

10: return −111: else

12: return j0

13: end if

14: end function

15: procedure Dijkstra2(n,C, u)16: vizitatu ← 117: du ← 0, tatau ← 018: for i← 1, n do

19: if (i 6= u) then

20: vizitati ← 021: di ← cu,i, tatai ← u22: 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 ciclare28: else

29: vizitatk ← 130: for i← 1, n do

31: if (vizitati 6= 1) ∧ (dk + ck,i < di) then

32: tatai ← k33: di ← dk + ck,i

34: end if

35: end for

36: end if

37: end while

38: end procedure

Observatia 8.2 Algoritmul lui Dijkstra prezinta asemanari cu algoritmul de cautare ınlatime, la final, vectorul tata pastrand un arbore al drumurilor minime ce are drept radacinanodul sursa.

160

Page 161: CursuriAG2014

uk

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 acelnod este cel mai mic dintre toate drumurile posibile de la sursa la noduri din multimea V \S,ce trec numai prin noduri din multimea S, cu exceptia extremitatii finale, acel drum este celmai mic drum de la sursa la k dintre toate drumurile posibile. Denumim drum special undrum de la sursa la un nod k ce are drept noduri intermediare numai elemente din multimeaS, cu exceptia extremitatii finale.

Sa presupunem prin reducere la absurd, ca exista un drum de lungime mai mica de lanodul sursa la nodul k, ce nu are toate nodurile intermediare din multimea S. Fie j ∈ V \S,primul nod pe drumul de la nodul sursa la nodul k, ce nu apartine multimii S. Atunci drumulde la nodul sursa u la nodul k se compune dintr-un drum de la u la j, si un drum de la j lak. Datorita modului de alegere al lui j, drumul de la u la j are drept noduri intermediarenumai elemente din multimea S (j este primul nod pe drumul de la nodul sursa la nodulk, care nu apartine multimii S), deci este un drum special si are o lungime mai mica decatdrumul special de la sursa la nodul k. Prin urmare am gasit un alt drum special de lungimemai mica, ceea ce contrazice modul de alegere al nodului k.

Trebuie sa demonstram ca ın orice moment, dk pastreaza lungimea celui mai scurt drumspecial de la nodul sursa u la nodul k ∈ V \ S. In momentul ın care nodul k este adaugatmultimii S, avem grija sa verificam daca nu exista un drum special de la nodul u la un nodj ∈ V \ S care sa aiba o lungime mai mica. Sa presupunem ca pentru un nod j fixat existaun nod x ∈ S astfel ıncat drumul special u k + k x + (x, j) sa aiba o lungime maimica (vezi figura 8.1). Deoarece nodul x a fost adaugat multimii S ınaintea nodului k avemdx ≤ dk. Prin urmare dx + cx,j ≤ dk + cx,j < dk + costk j + cx,j, adica drumul special de lasursa la nodul j ce trece prin nodul x are lungimea mai mica decat drumul special compusdin 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 figura 8.2. Dupaetapa de initializare 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

Page 162: CursuriAG2014

Fig. 8.2: Un exemplu de graf orientat ponderat

Dupa prima iteratie avem:

d2 + c2,3 < d3 ⇔ 1 + 8 < +∞d2 + c2,4 < d4 ⇔ 1 +∞ < 21

d2 + c2,5 < d5 ⇔ 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 iteratii se calculeaza:

d5 + c5,3 < d3 ⇔ 5 + 3 < 9

d5 + c5,4 < d4 ⇔ 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:

d3 + c3,4 < d4 ⇔ 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 iteratii vom obtine: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

Page 163: CursuriAG2014

#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

Page 164: CursuriAG2014

/**

* 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

Page 165: CursuriAG2014

Utilizarea structurii coada cu prioritate ın algoritmul lui Dijkstra

Complexitatea–timp al algoritmului lui Dijkstra poate fi ımbunatatita 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: di ←∞4: tatai ← NULL5: call Insert(Q, i, di) ⊲ insereaza ın coada elementul i cu prioritatea di

6: end for

7: du ← 08: call DecreaseKey(Q,u, du) ⊲ actualizeaza prioritatea varfului u la du

9: S ← ∅10: for i← 1, n − 1 do

11: k ← DeleteMin(Q) ⊲ sterge elementul de prioritate minima din coada12: S ← S ∪ k13: for fiecare j ∈ V \ S, astfel ıncat (k, j) ∈ E do

14: if (dj > dk + ck,j) then

15: dj ← dk + ck,j

16: tataj ← k17: call DecreaseKey(Q, j, dj) ⊲ actualizeaza prioritatea varfului j la dj

18: end if

19: end for

20: end for

21: end procedure

Analizand algoritmul 60 obtinem ca timpul de lucru al acestuia depinde de formula:

T (n, m) = O(n · TInsert + n · TDeleteMin + m · TDecreaseKey) (8.1)

unde n = numarul de noduri ale grafului G iar m = numarul de muchii ale aceluiasi graf.Cele trei operatii ıntalnite ın cadrul algoritmlui sunt (vezi si capitolul ??):

1. DeleteMin(Q) - sterge nodul ce contine cheia de valoare minima si reorganizeaza struc-tura prin refacerea proprietatii de coada cu prioritate.

2. Insert(Q, p, x) - insereaza nodul p ın coada cu prioritate Q.

3. DecreaseKey(Q, p, v) - modifica valoarea prioritatii nodului p din coada cu prioritateQ, atribuindu–i valoarea v si reorganizeaza aceasta structura.

Astfel pentru diferite implementari ale cozii cu prioritate Q, complexitatea algoritmuluiva fi [30]:

1. Lista liniara dublu ınlantuita neordonata:

T (n, m) = O(n · 1 + n · n + m · 1) = O(n2)

165

Page 166: CursuriAG2014

2. Arbore 2− 3:T (n, m) = O(n · 1 + n · n + m · 1) = O(n2)

3. Heap-uri Fibonacci:

T (n, m) = O(n · 1 + n · n + m · 1) = O(n2)

8.2 Drumuri minime ıntre toate perechile de varfuri

Fie G = (V, E) un graf orientat unde V = x1, x2, . . . , xn reprezinta multimea nodurilorsi E reprezinta multimea arcelor (E ⊆ V × V ). Fiecarui arc din E i se asociaza o valoarepozitiva ci,j (ci,j ≥ 0) ce reprezinta lungimea arcului. Se doreste calcularea drumurilor delungime minima pentru oricare pereche de noduri xi, xj .

Pentru a determina drumurile minime ıntre toate perechile de varfuri, putem alege unalgoritm ce determina drumurile minime de sursa unica (drumurile minime de la acel varf latoate celelalte), si pe care sa–l aplicam pentru fiecare varf al grafului.

Un astfel de algoritm este algoritmul lui Dijkstra, algoritm ce a cunoscut multiple ımbunata-tiri fata de varianta orginala, ce se bazeaza pe utilizarea unor structuri de date avansate (de e-xemplu heap-uri Fibonacci), menite sa–i optimizeze timpul de executie. Astfel complexitatea–timp ın cazul cel mai defavorabil pentru calculul celor mai scurte drumuri pornind dintr–unvarf al unui graf cu n noduri si m arce este O(m + n log n). Daca aplicam acest algoritmpentru toate cele n varfuri vom obtine un timp de lucru de O(mn + n2 log n).

Algoritmul 61 prezinta o varianta a algoritmului lui Dijkstra ın care drumurile de lungimeminima ıntre oricare doua varfuri sunt calculate incremental si intercalat [35]. Matricea Dva pastra pentru fiecare pereche [xi, xj] lungimea di,j a drumului minim dintre cele exploratepana la momentul curent. Coada de prioritati C pastreaza toate perechile (i, j), ordonatecrescator ın functie de prioritatea di,j a fiecaruia. La fiecare pas, se extrage din coada perechea(i, j) avand prioritatea cea mai mica si se ıncearca extinderea drumului [xi, xj ] cu exact unarc la fiecare extremitate a drumului. Tehnica utilizata este cea a relaxarii, ıntalnita si ıncadrul algoritmului lui Bellman, cu scopul de a micsora costul drumului de la xi la xj , prinparcurgerea tuturor arcelor ce parasesc varful xj si a celor ce sosesc ın varful xi.

8.2.1 Algoritmul lui Roy-Floyd-Warshall

Fie p = [x1, x2, . . . , xk] un drum elementar. Definim un varf intermediar orice varf u ∈x2, . . . , xk−1 (u 6= x1, u 6= xk – varful intermediar este diferit de extremitatile drumului p).

Fie U = x1, x2, . . . , xk o multime de noduri. Notam cu MUi,j multimea drumurilor de

la xi la xj ce au drept noduri intermediare elemente din multimea U . Fie p drumul de costminim de la xi la xj (p ∈MU

i,j). Un astfel de drum este elementar deoarece am presupus canu exista cicluri al caror cost sa fie negativ.

Notam dki,j costul drumului minim de la xi la xj ce are noduri intermediare numai din

multimea x1, x2, . . . , xk. Daca xk /∈ p (xk nu apartine drumului p) atunci drumul decost minim de la xi la xj avand toate nodurile intermediare din multimea x1, x2, . . . , xk−1va fi si drum de cost minim de la xi la xj cu toate nodurile intermediare din multimeax1, x2, . . . , xk:

dki,j = dk−1

i,j

Daca xk este un varf intermediar al drumului p, fie p1 si p2 subdrumuri ale lui p, p = p1 ⊕ p2

(p1 drumul de la xi la xk avand nodurile intermediare din multimea x1, x2, . . . , xk si p2

166

Page 167: CursuriAG2014

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 (ci,j > 0) ∧ (ci,j <∞)5: di,j ← ci,j

6: else

7: di,j ←∞8: end if

9: C ⇐ (i, j) cu prioritatea di,j

10: end for

11: end for

12: while (C 6= ∅) do

13: C ⇒ (i, j)14: for k ← 1, n do

15: if (di,j + cj,k < di,k) then

16: di,k ← di,j + cj,k

17: actualizeaza prioritatea lui (i, k) din C la di,k

18: end if

19: end for

20: for k ← 1, n do

21: if (ck,i + di,j < dk,j) then

22: dk,j ← ck,i + di,j

23: actualizeaza prioritatea lui (k, j) din C la dk,j

24: end if

25: end for

26: end while

27: end procedure

drumul de la xk la xj avand nodurile intermediare din multimea x1, x2, . . . , xk). Deoarecep1 si p2 sunt drumuri de cost minim si xk /∈ x1, x2, . . . , xk−1 avem: dk−1

i,k = dki,k, dk−1

k,j = dkk,j.

c(p) = c(p1) + c(p2)⇒ dki,j = dk−1

i,k + dk−1k,j

Algoritmul va construi un sir de matrici D0, D1, . . . , Dk, . . . , Dn. Pentru fiecare k (1 ≤k ≤ n), dk

i,j va contine lungimea drumului minim de la nodul xi la nodul xj ce are dreptnoduri intermediare numai noduri din multimea x1, x2, . . . , xk.

Matricea D0 se va initializa astfel:

d0i,j =

0 , daca i = j

+∞ , daca (xi, xj) /∈ E, i 6= j

d > 0 , daca (xi, xj) ∈ E

(8.2)

(un drum ce nu are nici un varf intermediar este determinat de costul legaturii directe dintrexi si xj).

Drumul de lungime minima de la xi la xj ce trece numai prin nodurile x1, x2, . . . , xk fienu contine nodul xk caz ın care dk

i,j = dk−1i,j , fie ıl contine, si atunci dk

i,j = dk−1i,k + dk−1

k,j . Prin

urmare dki,j = mindk−1

i,j , dk−1i,k + dk−1

k,j .Desi aceasta ultima relatie sugereaza un algoritm recursiv, o abordare iterativa este mai

eficienta atat ın ceea ce priveste complexitatea timp cat si din punctul de vedere al necesarului

167

Page 168: CursuriAG2014

de memorie. Se observa ca matricea Dk nu mai este necesara de ındata ce matricea Dk+1 afost calculata.

Dn = (dni,j), dn

i,j = δi,j , ∀xi, xj ∈ V.

Algoritm 62 Algoritmul Floyd–Warshall

1: procedure FloydWarshall1(n,C;Dn)2: for i← 1, n do

3: for j ← 1, n do

4: d0i,j ← ci,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: dki,j ← min dk−1

i,j , dk−1i,k + dk−1

k,j 11: end for

12: end for

13: end for

14: end procedure

In algoritmul 62 se poate renunta la indicii superiori, obtinandu–se astfel o economie despatiu de la Θ(n3) la Θ(n2) (vezi algoritmul 63).

Algoritm 63 Algoritmul Floyd–Warshall (varianta optimizata)

1: procedure FloydWarshall2(n,C;D)2: for i← 1, n do

3: for j ← 1, n do

4: di,j ← ci,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: di,j ← min di,j , di,k + dk,j11: end for

12: end for

13: end for

14: end procedure

Exemplul 8.4 Fie graful din figura 8.2. Matricea costurilor asociata acestui graf este:

C =

0 1 +∞ 21 +∞+∞ 0 8 +∞ 43 +∞ 0 12 +∞

+∞ +∞ 9 0 +∞+∞ +∞ 3 +∞ 0

168

Page 169: CursuriAG2014

Sirul de matrice Dk, rezultat al aplicarii algoritmului Roy-Floyd-Warshall pentru acestgraf, este:

D0 =

0 1 ∞ 21 ∞∞ 0 8 ∞ 43 ∞ 0 12 ∞∞ ∞ 9 0 ∞∞ ∞ 3 ∞ 0

D1 =

0 1 ∞ 21 ∞∞ 0 8 ∞ 43 4 0 12 ∞∞ ∞ 9 0 ∞∞ ∞ 3 ∞ 0

D2 =

0 1 9 21 5∞ 0 8 ∞ 43 4 0 12 8∞ ∞ 9 0 ∞∞ ∞ 3 ∞ 0

D3 =

0 1 9 21 511 0 8 20 43 4 0 12 8

12 13 9 0 176 7 3 15 0

D4 =

0 1 9 21 511 0 8 20 43 4 0 12 8

12 13 9 0 176 7 3 15 0

D5 =

0 1 8 20 510 0 7 19 43 4 0 12 8

12 13 9 0 176 7 3 15 0

Inchiderea tranzitiva

Definitia 8.1 Fie G = (V, E) un graf orientat, simplu si finit, V = x1, x2, . . . , xn.Inchiderea tranzitiva a grafului G este un graf G+ = (V, E+), unde E+ = (xi, xj)|∃ un drum de la xi la xj ın G.

Inchiderea tranzitiva a unui graf orientat prezinta multiple aplicatii drept subproblema ıncazul unor probleme computationale cum ar fi: construirea unui automat de parsare utilizatla realizarea unui compilator, evaluarea interogarilor recursive realizate asupra unei baze dedate sau analiza elementelor accesibile ıntr–o retea de tranzitie asociata unui sistem paralelsau distribuit.

Prima varianta de a determina ınchiderea tranzitiva presupune atribuirea unui cost unitar(= 1) arcelor din E urmata de aplicarea algoritmului Roy–Floyd–Warshall. Vom obtine omatrice ın care, di,j = +∞ daca nu exista un drum de la xi la xj sau di,j = c < n daca exista.

In cadrul celei de-a doua variante de calcul (vezi algoritmul 64), se ınlocuiesc operatiilemin cu ∨ (sau logic) si respectiv + cu ∧ (si logic).

dki,j = 1 daca exista un drum de la xi la xj ın graful G avand varfurile intermediare numai

din multimea x1, . . . , xk.

dki,j =

1 , daca i = j sau (xi, xj) ∈ E

0 , daca i 6= j si (xi, xj) /∈ E(8.3)

dki,j = dk−1

i,j ∨ (dk−1i,k ∧ dk−1

k,j )

Exemplul 8.5 Fie graful din figura 8.2, din care am eliminat arcul (1, 2). Matricea cos-turilor asociata acestui graf modificat este:

C =

0 ∞ ∞ 21 ∞∞ 0 8 ∞ 43 ∞ 0 12 ∞∞ ∞ 9 0 ∞∞ ∞ 3 ∞ 0

169

Page 170: CursuriAG2014

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 (xi = xj) ∨ (ci,j 6= +∞) then

5: d0i,j ← 1

6: else

7: d0i,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: dki,j ← dk−1

i,j ∨ (dk−1i,k ∧ dk−1

k,j )15: end for

16: end for

17: end for

18: end procedure

D0 =

1 0 0 1 00 1 1 0 11 0 1 1 00 0 1 1 00 0 1 0 1

D1 =

1 0 0 1 00 1 1 0 11 0 1 1 00 0 1 1 00 0 1 0 1

D2 =

1 0 0 1 00 1 1 0 11 0 1 1 00 0 1 1 00 0 1 0 1

D3 =

1 0 0 1 01 1 1 1 11 0 1 1 01 0 1 1 01 0 1 1 1

D4 =

1 0 1 1 01 1 1 1 11 0 1 1 01 0 1 1 01 0 1 1 1

D5 =

1 0 1 1 01 1 1 1 11 0 1 1 01 0 1 1 01 0 1 1 1

8.3 Exercitii

1. Cutii n–dimensionale Sa consideram o cutie n–dimensionala, data prin lungimea fiecareilaturi (o cutie bidimensionala este un dreptunghi, o cutie tridimensionala este un par-alelipiped, etc.).

Problema cere analizarea unui grup de k cutii n–dimensionale: trebuie gasita o secventade lungime maxima (b1, b2, . . .) din grupul de k cutii astfel ıncat fiecare cutie bi sa poatafi introdusa ın cutia bi+1.

Cutia D = (d1, d2, . . . , dn) poate fi introdusa ın cutia E = (e1, e2, . . . , en) numai dacalaturile cutiei D pot fi combinate ın asa fel cu laturile cutiei E, astfel ıncat lungimea

170

Page 171: CursuriAG2014

fiecarei laturi a cutiei D sa nu depaseasca lungimea laturii corespunzatoare din cutiaE. De exemplu cutia (2, 6) poate fi introdusa ın cutia (7, 3).

Cutiile egale pot fi introduse una ıntr–alta. Masurile laturilor sunt numere reale maimici sau egale cu 1000. Numarul de cutii nu depaseste 100, iar numarul de dimensiuninu depaseste 20.

(Tuymaada, 1997)

2. Sunteti angajat la o companie ce asigura servicii de transport marfuri en-gross. Clientiiau magazine ın orase din toata tara si ei sunt aprovizionati din depozitele locale alecompaniei.

Pentru o aprovizionare optima, compania vrea sa investeasca ın construirea unui depozitcentral din care sa se aprovizioneze toate zonele; va fi deci necesar ca acest depozit safie plasat ıntr-unul din orase ın asa fel ıncat timpul total de livrare din acest depozitın toate orasele sa fie minim. Camioanele companiei transporta marfa la depozitelelocale si se ıntorc la depozitul central. Timpul de livrare este format din timpul necesarparcurgerii drumului de la depozitul central la oras si ınapoi (se presupune ca soferulva urma de fiecare data calea cea mai rapida, iar ın fiecare oras depozitul local se aflaamplasat la intrare) si timpul de descarcare al camionului la destinatie, ce este de exact30 minute. Drumurile ce leaga orasele sunt de aceeasi calitate, dar pot exista drumurice iau mai mult timp ıntr-un sens decat ın sens invers. Pot fi, de asemenea, drumuricu sens unic.

Pentru a simplifica modelul, s-a stabilit pentru fiecare oras o lista cu toate drumurilece pleaca din oras spre celelalte orase si cat timp ia parcurgerea fiecarui drum.

(Concurs ACM Zona Pacificul de Sud)

3. Se da reteaua hidrografica a unei tari constituita din multimea raurilor si afluentii lor.Cele N rauri (2 ≤ n ≤ 1000) sunt numerotate de la 1 la N . Legatura dintre un rau vsi un afluent al sau u este specificata prin perechea (u, v).

Pentru a se putea face estimari cu privire la potentialul risc de inundaie pe cursul unuirau trebuie sa se calculeze debitul fiecarui rau ın parte.

Debitul unui izvor se defineste ca fiind cantitatea de apa ce trece prin sectiunea izvoruluiın unitatea de timp. Debitul raului u la varsare va fi egal cu debitul izvorului raului uplus suma debitelor afluentilor la varsare ın raul u.

Se cere sa se realizeze un algoritm care sa calculeze debitul la varsare al fiecarui rau.

4. Sa se determine drumul de lungime minima necesar deplasarii unui cal pe o tabla desah (avand dimensiunile 8× 8) de la un punct de plecare la unui de sosire, stiind ca petabla exista si gauri. Calul poate fi mutat numai ın casutele fara gauri.

(ACM, Eastern Europe, 1994)

5. Un traducator gaseste o carte scrisa cu litere latine, ın care ınsa ordinea literelor dinalfabet este schimbata. La sfarsitul cartii se afla 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 Sudpe care le–a descoperit ın timpul unei expeditii ın jungla Amazonului. Mierea produsa

171

Page 172: CursuriAG2014

de aceste albine este superioara din punct de vedere calitativ mierii produse de albineledin Europa sau din America de Nord. Din pacate, aceste albine nu se ınmultesc ıncaptivitate. Profesorul Heiff crede ca pozitiile larvelor (albine lucratoare, regina) dinfagure depind de conditiile de mediu, care sunt diferite ın laborator fata de padureatropicala.

Ca un prim pas pentru a-si verifica teoria, profesorul Heiff doreste sa calculeze diferentadintre pozitiile larvelor. Pentru aceasta el masoara distanta dintre celulele fagureluiın care sunt plasate larvele. El a numerotat celulele alegand ın mod arbitrat una sinumerotand–o cu 1, apoi celelalte celule ramase sunt numerotate circular, ın sensulacelor de ceas, ca ın figura.

__ __ __ __

__/ \__/ \__/ \__/ \__

__/ \__/ \__/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 pozitionate ın celulele 19 si 30 se afla la distanta 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 distanta minima dintre oricare doua celule.

Datele de intrare constau din doua numere naturale u si v (u, v ≤ 10.000) reprezentandnumarul celulelor ıntre care se doreste sa se determine distanta minima.

(ACM Final, 1999)

7. In fiecare noapte un print intra ın subsolurile unui castel unde locuieste o printesa.Drumul catre printesa este ca un labirint. Sarcina printului este sa se grabeasca si sagaseasca drumul prin labirint catre printesa, deoarece trebuie sa se ıntoarca ın zori.Acesta are unelte potrivite cu ajutorul carora poate sa sparga numai un singur peretepentru a–si scurta drumul catre destinatie.

(a) gasiti lungimea celui mai scurt drum din labirint din locul ın care printul intra ınlabirint pana ın locul ın care traieste printesa;

172

Page 173: CursuriAG2014

(b) gasiti lungimea celui mai scurt drum daca se sparge un perete.

Castelul este de forma dreptunghiulara cu m × n camere (1 ≤ n, m ≤ 100). Fiecarecamera poate avea pereti spre E, S, V si N codificati 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 saaiba pereti ın toate directiile (codul < 15).

Lungimea celui mai scurt drum se defineste ca fiind numarul de camere dintre sursa sidestinatie inclusiv.

Datele de intrare constau din M linii ce contin fiecare N numere ıntregi reprezentandcodificarea peretilor din fiecare camera, urmate se coordonatele printului si ale printesei.

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

Page 174: CursuriAG2014

Capitolul 9

Fluxuri ın retele de transport

Problema studierii fluxului ın retele de transport ısi are originea ın analiza unor probleme detransport [108]. Un graf orientat poate modela procesul de transport dintre un producator siun consumator prin intermediul unei retele de transport. Ceea ce se trimite pe un drum nupoate depasi capacitatea sa de transport. La destinatie nu poate sa ajunga o cantitate maimare decat cea care a fost realizata de catre producator.

In jurul nostru exista foarte multe retele cum ar fi reteaua electrica, reteaua de apa,reteaua de drumuri, reteaua de legaturi telefonice, ce au devenit elemente indispensabile alemodului de viata actual. O retea de transport poate modela curgerea unui lichid ıntr-o reteade conducte, deplasarea curentului prin retele electrice, transportul de marfuri de-a lungulunei retele de drumuri, etc.

Doua dintre lucrarile considerate a avea un caracter de pionierat ın acest domeniu ısibazeaza studiul de caz pe reteaua feroviara existenta ın fosta U.R.S.S. [108]. Asa cum obervasi autorii lui [63] o abordare a acestei probleme folosea algoritmi avand la baza programarealiniara, mai exact metoda simplex [33], ınsa algoritmii dezvoltati independent de aceastametoda au condus la rezultate mai bune ın ceea ce priveste complexitatea timp.

Prima formulare a problemei determinarii fluxului maxim ıntr-o retea de transport a fostfacuta de T. E. Harris ın [70]:

Consider a rail network connecting two cities by way of a number of intermediatecities, where each link of the network has a number assigned to it representing itscapacity. Assuming a steady state condition, find a maximal flow from one givencity to the other. 1

Exista doua probleme celebre care s-a demonstrat matematic a fi duale una alteia: prob-lema fluxului maxim ıntr-o retea de transport si problema determinarii taieturii de capacitateminima.

9.1 Retea de transport. Flux. Taietura

Definitia 9.1 Se numeste retea de transport o secventa < G, c, s, t > ce prezinta urmatoareleproprietati:

1Luati ın considerare o retea de cale ferata ce leaga doua orase prin intermediul unui numar de oraseintermediare, unde fiecare legatura are atribuit un numar ce reprezinta capacitatea acesteia. Presupunandca sistemul se afla ıntr-o stare de echilibru, se cere sa se determine un flux maxim de la un oras specificat laaltul.

174

Page 175: CursuriAG2014

1. G = (V, E) este un graf orientat, unde fiecarui arc (u, v) ∈ E ıi este asociata o valoarepozitiva denumita capacitate, c(u, v) ≥ 0;

2. exista doua noduri speciale, s, t ∈ V (s - sursa, t - destinatie);

3. ∀u ∈ V \ s, t, nodul u se gaseste pe cel putin un drum de la sursa la destinatie.

Observatia 9.11. Daca (u, v) /∈ E vom considera ca valoarea capacitatii arcului este 0 (c(u, v) =0).

2. Graful este conex si |E| ≥ |V | − 1.

Definitia 9.2 Pentru o retea de transport < G, c, s, t > definim fluxul asociat retelei detransport drept o functie f : V × V → R ce satisface urmatoarele conditii:

1. ∀u, v ∈ V , avem 0 ≤ f(u, v) ≤ c(u, v) (restrictie de capacitate);

2. ∀u, v ∈ V , avem f(u, v) = −f(v, u) (antisimetrie);

3. ∀u ∈ V \ s, t avem∑

v∈V f(u, v) = 0 (conservarea fluxului).

Definitia 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 fluxul paraseste nodul u, iar daca pentru arcul (u, v) avemf(u, v) < 0 (echivalent cu f(v, u) > 0) spunem ca fluxul intra ın nodul u.

Observatia 9.2 f(u, u) = 0, ∀u ∈ V .

Observatia 9.3 Pentru doua submultimi oarecare A, B (A, B ⊆ V ), se defineste f(A, B)astfel:

f(A, B) =∑

u∈A

v∈B

f(u, v).

Conditia de conservare a fluxului ıntr-un nod poate fi descrisa astfel: f(v, V ) = 0.

Propozitia 9.41. ∀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

Page 176: CursuriAG2014

Definim valoarea fluxului f astfel: |f | =∑

v∈V

f(s, v) . Drept urmare, valoarea fluxului

ın exces ce paraseste nodul sursa s este:

|f | =∑

v∈V,f(s,v)>0

f(s, v)−∑

u∈V,f(u,s)>0

f(u, s) (9.3)

Se poate demonstra ca |f | = ∑

u∈V,f(u,t)>0 f(u, t)−∑

v∈V,f(t,v)>0 f(t, v) (valoarea fluxuluif este diferenta dintre suma fluxurilor ce intra ın destinatie minus suma fluxurilor ce parasescdestinatia).

Din regula de conservare a fluxului rezulta ca:

v∈V,f(u,v)>0

f(u, v) =∑

v∈V,f(v,u)>0

f(v, u), ∀u ∈ V \ s, t (9.4)

Cu alte cuvinte, suma fluxurilor ce intra ıntr-un nod u este egala cu suma fluxurilor ceparasesc acelasi nod u.

Intr-o retea de transport avem urmatoarea relatie:

u∈V

(∑

v∈V,f(u,v)>0

f(u, v)−∑

w∈V,f(w,u)>0

f(w, u)) = 0. (9.5)

Pe de alta parte

u∈V

(∑

v∈V,f(u,v)>0

f(u, v)−∑

w∈V,f(w,u)>0

f(w, u)) = (∑

v∈V,f(s,v)>0 f(s, v)−∑

u∈V,f(u,s)>0 f(u, s)) +

(∑

v∈V,f(t,v)>0 f(t, v)−∑

u∈V,f(u,t)>0 f(u, t))

= |f |+ (∑

v∈V,f(t,v)>0 f(t, v)−∑

u∈V,f(u,t)>0 f(u, t))

Astfel rezulta ca|f | =

u∈V,f(u,t)>0

f(u, t)−∑

v∈V,f(t,v)>0

f(t, v). (9.6)

Definitia 9.4 O < s, t > - taietura este o pereche de multimi disjuncte (A, B) din V (A∩B =∅, A ∪B = V , A, B ⊆ V ) cu proprietatea ca s ∈ A si t ∈ B.

Capacitatea unei < s, t > - taieturi este suma capacitatilor arcelor ce au o extremitate ınmultimea A si cealalta extremitate ın multimea B:

c(A, B) =∑

u∈A,v∈B

c(u, v) (9.7)

Se defineste fluxul de-a lungul taieturii (A, B) ca fiind:

f(A, B) =∑

u∈A

v∈V

f(u, v) (9.8)

|f | not= f(s, V \ s) =

v∈V

f(s, v) (fluxul net ce paraseste nodul sursa) (9.9)

Problema fluxului maxim presupune determinarea unui flux de valoare maxima de la s lat pentru reteaua de transport < G, c, s, t > [47], [48].

176

Page 177: CursuriAG2014

Lema 9.5 Pentru < G, c, s, t > retea de transport, (A, B) o < s, t >-taietura si f un flux

ın reteaua de transport, avem |f | = f(A, B) (valoarea fluxului ın reteaua de transport este

egala cu valoarea fluxului de-a lungul taieturii).

Demonstratie: Sa ne reamintim ca daca (A, B) este o < s, t >-taietura avem A ∩ B =∅, A ∪B = V . Atunci din propozitia 9.4 obtinem

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 avemf(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 relatii 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 flux f oarecare ın reteaua de transport < G, c, s, t > avem inegal-

itatea: |f | ≤ c(A, B)

Demonstratie: Din Lema 9.5 avem:

|f | L9.5= f(A, B)

def=

u∈A

v∈B

f(u, v)def

≤∑

u∈A

v∈B

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

Taietura minima reprezinta modalitatea cea mai eficienta / simpla de a ıntrerupe fluxul(curgerea) de la s la t.

Problema taieturii minime se refera la a determina o < s, t > - taietura a carei capacitatesa fie maxima.

Exemplul 9.7 In figura 9.1 este prezentat un exemplu de retea de transport si un flux f .Ca o ilustrare a celor discutate vom calcula suma fluxurilor pentru nodul 1:

v∈V

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∑

v∈V

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

Page 178: CursuriAG2014

Fig. 9.1: Un exemplu de retea de transport

9.2 Graf rezidual. Drum de ameliorare. Flux maxim–

taietura minima

Definitia 9.5 Definim capacitatea reziduala a unui arc (u, v) apartinand grafului G ast-fel:

cR(u, v) = c(u, v)− f(u, v) . (9.17)

Definitia 9.6 Graful rezidual[47] asociat cu graful G = (V, E) si capacitatea c, este grafulGR = (V, ER) si capacitate cR, unde ER se defineste astfel: ER = (u, v) ∈ V × V |cR(u, v) >0.

Observatia 9.8 Intre doua noduri u si v din graful G vom avea cel mult doua arce ın grafulrezidual GR:

1. daca (u, v) ∈ E si f(u, v) < c(u, v) atunci exista arcul (u, v) ın graful rezidual ((u, v) ∈ ER)si cR(u, v) = c(u, v)− f(u, v) (cR(u, v) > 0);

2. daca (u, v) ∈ E si f(u, v) > 0 atunci exista arcul (v, u) ın graful rezidual ((v, u) ∈ ER) sicR(v, u) = f(u, v).

Altfel spus, ın graful rezidual GR pot sa apara arce noi, care nu existau ın graful initialG. Un alt element ce merita subliniat se refera la faptul ca daca ıntre doua noduri nu existanici un arc ın graful initial G, atunci nu va exista nici un arc ıntre cele doua noduri nici ıngraful rezidual GR. Prin urmare, numarul total de arce din graful rezidual GR este cel multde doua ori mai mare decat numarul arcelor din graful G.

Lema 9.9 Fie < G, c, s, t > o retea de transport si f un flux ın aceasta retea de transport.Daca fR este un flux ın reteaua de transport < GR, cR, s, t > (GR este graful rezidual asociatcu G), atunci f + fR este un flux ın < G, c, s, t >, iar |f + fR| = |f |+ |fR|.

Demonstratie: Pentru a arata ca f + fR este un flux ın reteaua de transport < G, c, s, t >trebuie sa verificam daca conditiile din definitia 9.2 sunt ındeplinite:

1. restrictie de capacitateAvem fR(u, v) ≤ cR(u, v), ∀u, v ∈ V .

(f + fR)(u, v) = f(u, v) + fR(u, v) ≤ f(u, v) + cR(u, v)= f(u, v) + (c(u, v)− f(u, v)) = c(u, v)(9.18)

178

Page 179: CursuriAG2014

2. antisimetrie

(f + fR)(u, v) = f(u, v) + fR(u, v) = −f(v, u)− fR(v, u)= −(f(v, u) + fR(v, u)) = −(f + fR)(v, u) (9.19)

3. conservarea fluxului

v∈V

(f + fR)(u, v) =∑

v∈V

(f(u, v) + fR(u, v))

=∑

v∈V

f(u, v) +∑

v∈V

fR(u, v) = 0 + 0 = 0 (9.20)

Sa demonstram ca |f + fR| = |f |+ |fR|:

|f + fR| =∑

v∈V

(f + fR)(s, v) =∑

v∈V

(f(s, v) + fR(s, v))

=∑

v∈V

f(s, v) +∑

v∈V

fR(s, v) = |f |+ |fR|. (9.21)

Corolarul 9.10 Daca f ′ not= f+fR, unde fR este un flux ın reteaua de transport < GR, cR, s, t >

a grafului rezidual, atunci f ′ este un flux ın < G, c, s, t > si |f ′| = |f |+ |fR| > |f |.

Demonstratia acestui corolar rezulta imediat din lema 9.9.

Lema 9.11 Fie f un flux ın < G, c, s, t > si GR graful rezidual asociat cu G. Atunci avem:

1. functia fR este un flux maxim ın < GR, cR, s, t > daca f + fR este un flux maxim ın <G, c, s, t >;

2. valoarea functiei este aditiva: |f + fR| = |f |+ |fR|, |f − fR| = |f | − |fR|;3. daca f este un flux oarecare si f ∗ este fluxul maxim ın < G, c, s, t >, atunci valoarea fluxului

maxim ın < GR, cR, s, t > este |f ∗| − |f |.

Definitia 9.7 Fiind data o retea de transport < G, c, s, t > si un flux f ın aceasta retea,atunci o cale de crestere d (drum de ameliorare, drum de augmentare) este un drum de las la t ın graful rezidual GR.

Numim capacitate reziduala a lui d, cantitatea maxima a fluxului ce poate fi transportatde-a lungul drumului de ameliorare d:

cR(d) = mincR(u, v)|(u, v) arc pe drumul d (9.22)

Observatia 9.12 Unui drum de ameliorare ın graful rezidual GR ıi corespunde un lant ıngraful G.

Definitia 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 deameliorare (c(u, v) = cR(d)).

Teorema 9.13 (flux maxim - taietura minima) [46], [48], [49] Fie o retea de transport< G, c, s, t > si f un flux ın aceasta retea. Urmatoarele afirmatii sunt echivalente:

179

Page 180: CursuriAG2014

1. f este un flux maxim ın reteaua de transport;

2. nu exista nici o cale de crestere (drum de ameliorare) ın reteaua 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 pentrucare valoarea fluxului maxim este egala cu capacitatea taieturii).

Demonstratie: Vom demonstra aceasta teorema abordand urmatoarea serie de implicatii:1)⇒ 2)⇒ 3)⇒ 1).

1)⇒ 2)Sa presupunem prin reducere la absurd ca exista un drum de ameliorare ın reteaua de trans-port < G, c, s, t > pentru un flux maxim |f |.

Daca exista un drum de ameliorare atunci exista un flux nenul fp ın reteaua < GR, cR, s, t >.Fie f ′ fluxul construit astfel: f ′ = f + fp. Din corolarul 9.10 obtinem ca f ′ este un flux

ın reteaua de transport < G, c, s, t > si |f ′| > |f |.Am determinat astfel un flux f ′ ın < G, c, s, t > a carui valoare este mai mare decat

cea a fluxului f . Contradictie cu faptul ca f este un flux maximal ın reteaua 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 dela s la t ın graful rezidual GR (GR = (V, ER)).

Sa notam S = v ∈ V |∃ un drum de la s la t ın GR si T = V \ S.Deoarece nu exista nici un drum de la s la t ın GR ⇒ 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 GR ⇒ nu exista arce

ın GRcare 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 obtinem 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 fluxul maxim ce se poate obtine ın reteaua de

transport < G, c, s, t >.

Valoarea maxima a unui flux ıntr–o retea de transport < G, c, s, t > este egala cu valoareacapacitatii taieturii minime pentru aceeasi retea de transport.

Corolarul 9.14 Fie f un flux ıntr-o retea de transport < G, c, s, t >. Notam cu Af multimeanodurilor ce apartin unui drum de ameliorare. Fie Bf = V \ Af . Atunci f este un fluxmaximal daca si numai daca t ∈ Bf .

Mai mult, Af , Bf reprezinta o < s, t >-taietura minima (de cost minim): |f | = c(Af , Bf).

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 reteaua de transport din figura 9.1 construim reteaua reziduala dinfigura 9.2:

cR(s, 1) = c(s, 1)− f(s, 1) = 16− 11 = 5

cR(1, s) = c(1, s)− f(1, s) = 0− (−11) = 11

180

Page 181: CursuriAG2014

Algoritm 65 Algoritmul Ford–Fulkerson (varianta simplificata)

1: se initializeaza fluxul cu valoarea 02: while (∃ un drum de ameliorare d ın GR) do

3: mareste fluxul f de-a lungul drumului de ameliorare d4: end while

5: return |f |

Fig. 9.2: Reteaua reziduala corespunzatoare retelei de transport din figura 9.1

cR(1, 3) = c(1, 3)− f(1, 3) = 12− 12 = 0

cR(3, 1) = c(3, 1)− f(3, 1) = 0− (−f(1, 3)) = 12

cR(4, 3) = c(4, 3)− f(4, 3) = 7− 7 = 0

cR(3, 4) = c(3, 4)− f(3, 4) = 0− (−f(4, 3)) = f(4, 3) = 7

cR(2, 3) = c(2, 3)− f(2, 3) = 0− (−f(3, 2)) = f(3, 2) = 4

cR(3, 2) = c(3, 2)− f(3, 2) = 9− 4 = 5

cR(2, 1) = c(2, 1)− f(2, 1) = 4− 1 = 3

cR(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 figura 9.2. Capacitateareziduala a acestui drum este:

cR(d) = min5, 4, 5 = 4

Vom mari fluxul f pentru arcele din G ce sunt ıntalnite de–a lungul drumului de ameliorared. Avem doua tipuri de arce:

• arc ınainte - arc al carui sens corespunde cu sensul parcurgerii de la s la t; pentru unastfel de arc, (u, v) ∈ E, f(u, v) = f(u, v) + cR(d);

• arc ınapoi - arcul are sens contrar sensului de parcurgere de la s la t: (u, v) ∈ E,f(u, v) = f(u, v)− cR(d).

Astfel noul flux corespunzator grafului din figura 9.1 si drumului de augmentare d =(s, 2, 3, t) poate fi urmarit ın figura 9.3.

Vom prezenta o varianta mai elaborata a algoritmului Ford–Fulkerson.

181

Page 182: CursuriAG2014

Fig. 9.3: Flux ıntr-o retea de transport dupa o crestere pe baza unui drum de ameliorare

Algoritm 66 Algoritmul Ford–Fulkerson (varianta a doua)

1: for (fiecare arc (u, v) ∈ E) do

2: f(u, v)← 0, f(v, u)← 03: end for

4: while (∃ un drum d de la s la t ın reteaua reziduala < GR, cR, s, t >) do

5: cR(d)← mincR(u, v)|(u, v) arc pe drumul d6: for fiecare arc (u, v) ∈ E corespunzator lantului d do

7: f(u, v)←

f(u, v) + cR(d) , daca (u, v) este arc de ınaintare pentru d

f(u, v)− cR(d) , daca (u, v) este arc de ıntoarcere pentru d8: end for

9: end while

10: return |f |

Observatia 9.16 Determinarea fluxului maxim ıntr-o retea de transport avand capacitatilearcelor numere rationale, precum si valorile fluxului tot numere rationale, se reduce la de-terminarea unui flux maxim avand componentele fluxului cat si capacitatile arcelor numerenaturale (aceasta reducere este posibila deoarece valorile rationale pot fi amplificate cu o val-oare pozitiva, cel mai mic multiplu comun al numitorilor acestor numere).

Complexitatea algoritmului

In tabelul 9.1 [127] sunt prezentati principalii algoritmi pentru determinarea fluxului maximıntr-o retea de transport, anul ın care au aparut precum si complexitatea lor. Astfel acestia sepot compara din punct de vedere al complexitatii teoretice si se poate alege varianta potrivitarezolvarii unor probleme concrete.

9.3.1 Algoritmul Ford-Fulkerson (varianta)

Prezentam ın continuare o varianta a algoritmului Ford-Fulkerson:

Pas 1. Se considera un flux initial f0. De obicei se alege drept flux initial fluxul nul (f0(u, v) =0, ∀u, v ∈ V, (u, v) ∈ E).

Pas 2. Se construieste un flux maxim:

Pas 2.1. Se marcheaza nodul s cu semnul ’+’.

182

Page 183: CursuriAG2014

Table 9.1: Principalii algoritmi pentru determinarea fluxului maxim ıntr-o retea de transport

Autor(i) Anul aparitiei ComplexitateFord & Fulkerson 1956 [48] O(V EU)Dinic 1970 [39] O(V 2E)Edmonds & Karp 1972 [42] O(V E2)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(V5

3 E2

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 2E)

)

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 seeticheteaza v cu [+u];

ii. daca (v, u) ∈ E, v este neetichetat iar fluxul 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 nodult sau se mai pot eticheta noduri noi).

Pas 2.3. Daca t nu a fost etichetat, atunci fluxul construit pana la momentul actual estemaxim si procesul se opreste.

Pas 2.4. Daca t a fost etichetat, atunci se identifica un drum d de la s la t. Notam cu U+

multimea arcelor (u, v) ∈ d unde v a fost etichetat cu ’+’ si U− multimea 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 fluxului de-a lungul fiecarui arc din d, devine f + ε∗ daca arcul apartinelui U+ sau f − ε∗ daca arcul apartine lui U−.

Exemplul 9.17 Fie reteaua de transport din figura 9.4 ın care a fost considerat la ınceputfluxul nul.

183

Page 184: CursuriAG2014

Fig. 9.4: Flux ıntr-o retea de transport

Se eticheteaza varful s cu [+]. Deoarece arcele (s, 1) si (s, 2) sunt nesaturate, varfurile 1si 2 pot fi etichetate cu [+s]. In continuare, deoarece arcele (1, 3) si (2, 4) sunt nesaturate vorfi etichetate nodurile 3 si 4 cu [+1] respectiv [+2]. Arcul (3, 2) are fluxul nul si astfel nodul3 nu poate fi etichetat cu [−2]. Analog, se eticheteaza nodul t cu [+3] (vezi figura 9.4).

Deoarece nodul destinatie t a fost etichetat, se poate trage concluzia ca fluxul curent nueste maxim.

Trebuie subliniat faptul ca etichetarea nodurilor nu este unica, aceasta depinzand de modulde parcurgerea al nodurilor grafului. Spre exemplu, nodul 3 poate fi 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 secventa de etichetare, se identifica un drumde la s la t, d1 = (s, 1, 3, t).

ε∗ = min(u,v)∈U+

c(u, v)− f(u, v)= minc(s, 1)− f(s, 1), c(1, 3)− f(1, 3), c(3, t)− f(3, t) = min16, 12, 20 = 12

Pe acest drum avem arcele (s, 1), (1, 3), (3, t) ∈ U+. Prin urmare valoarea fluxului de-alungul acestor arce devine (vezi figura 9.5):

f(s, 1) = f(s, 1) + ε∗ = 0 + 12 = 12, f(1, 3) = 0 + 12 = 12, f(3, t) = 0 + 12 = 12

In figura 9.5 poate fi urmarita o noua etichetare a nodurilor grafului. Se marcheaza noduls cu [+]. Din nodul s prin intermediul arcelor nesaturate (s, 1) si (s, 2) pot fi etichetatenodurile 1 si 2 cu [+s]. Arcul (1, 3) nu mai poate fi utilizat ın procesul de etichetare deoareceeste 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 intermediularcului (2, 4) vom eticheta nodul 4 cu [+2]. Arcul (3, 2) nu poate fi utilizat pentru etichetareanodului 3 cu [−2] deoarece fluxul 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 secventa de etichetare, se identifica un drum

de la s la t, d2 = (s, 2, 4, t).

ε∗ = min(u,v)∈U+

c(u, v)− f(u, v)= minc(s, 2)− f(s, 2), c(2, 4)− f(2, 4), c(4, t)− f(4, t) = min13, 14, 4 = 4

184

Page 185: CursuriAG2014

Fig. 9.5: Flux ıntr-o retea de transport

Arcele ıntalnite de-a lungul drumului d2, (s, 1), (1, 3), (3, t), apartin multimii U+. Prinurmare valoarea fluxului de-a lungul acestor arce devine (vezi figura 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 retea de transport

Cea de-a treia etapa de etichetare este ilustrata ın figura 9.6: nodul s se eticheteaza cu[+]. Urmeaza apoi nodurile 1 si 2 cu [+s] fiecare, si nodul 4 cu [+2]. De aici mai departenodul 3 se eticheteaza cu [+4] iar t cu [+3].

Pentru aceasta etichetare se identifica drumul d3 de la s la t: d3 = (s, 2, 4, 3, t).

ε∗ = min(u,v)∈U+

c(u, v)− f(u, v)= minc(s, 2)− f(s, 2), c(2, 4)− f(2, 4), c(4, 3)− f(4, 3), c(3, t)− f(3, t)= min13− 4, 14− 4, 7− 0, 20− 12 = 7

Toate arcele din care este alcatuit drumul d3 apartin multmii U+. Valoarea fluxul calculatpentru fiecare arc ın parte este (vezi figura 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

Page 186: CursuriAG2014

Fig. 9.7: Flux maxim ıntr-o retea de transport

Analizand reteaua de transport si fluxul din figura 9.7 se observa ca nu se mai poateeticheta nodul t pornind din s datorita prezentei arcelor saturate (1, 3), (4, 3), (4, t) precumsi a arcului (3, 2) ce are ınsa valoarea fluxului nula.

In aceasta situatie procesul iterativ de etichetare se opreste conform Pasului 2.3 din algo-ritmul anterior.

Fluxul maxim determinat ın reteaua 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 Exercitii

1. Aplicadu-se algoritmul Ford-Fulkerson sa se determine fluxul maxim ın retelele de trans-port din figura 9.1. Nodul 0 este nodul sursa iar nodul 5 respectiv nodul 6 este noduldestinatie.

186

Page 187: CursuriAG2014

0

1

2

3

4

5

10

4

10

9

6

10 10

82 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 retele de transport

187

Page 188: CursuriAG2014

Appendix A

Probleme. Algoritmi. Complexitate

Vom considera o problema computationala ca fiind o aplicatie

P : I −→ O (A.1)

unde I reprezinta multimea intrarilor problemei, multimea instantelor problemei, iar O reprezintamultimea iesirilor, raspunsurilor, solutiilor. Aceasta problema P pentru fiecare intrare i ∈ Iofera o iesire P(i) ∈ O.

Definitia A.1 Daca O = da, nu atunci P se va numi problema de decizie, P(i) ∈da, nu va fi raspunsul la ıntrebarea pusa de P, iar forma uzuala de prezentare a pro-ble-mei va fi: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: multimea O continepentru fiecare i ∈ I macar o solutie acceptabila ın raport cu un anumit criteriu precizat, iarproblema cere gasirea unei astfel de solutii.

O clasa speciala de astfel de probleme este cea a problemelor de optimizare, si care pot fiprobleme 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 ∃).sauDrumMin Intrare: G un graf, a, b doua varfuri ale lui G, o functie 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.sauMaxCut Intrare: G graf, o functie de lungime a muchiilor lui G.

Iesire: O bipartitie (S, T ) a multimii varfurilor grafului Gcu suma lungimilor muchiilor dintre cele doua clase maxima.

188

Page 189: CursuriAG2014

Oricarei probleme de optimizare i se poate asocia o problema de decizie (care ne va dainformatii asupra dificultatii ei computationale). Pentru cele doua probleme de optimizarede mai sus, avem:

DrumMin–D Intrare: G un graf, a, b varfuri ale lui G, k ∈ N

o functie de lungime a muchiilor lui G.

Intrebare: Exista P drum ın G de la a la b cu suma lungimilormuchiilor ≤ k?

sauMaxCut–D Intrare: G un graf, k ∈ N, o functie de lungime a muchiilor lui G.

Intrebare: Exista (S, T ) bipartitie a multimii varfurilor grafului Gcu suma lungimilor muchiilor dintre cele doua clase ≥ k?

Vom considera ın continuare doar probleme de decizie.Pentru a fi rezolvate cu ajutorul calculatorului problemele sunt codificate. Fie Σ o multime

finita, fixata, numita alfabet, iar Σ∗ multimea tuturor cuvintelor peste Σ.

Definitia A.2 Obiectele care apar ın descrierea unei probleme (numere rationale, grafuri,functii, matrici etc.) vor fi reprezentate cu ajutorul unor cuvinte w ∈ Σ∗. Lungimeacuvantului w se va nota cu |w|. Orice multime de cuvinte peste Σ, adica orice submultime alui Σ∗ se numeste limbaj (peste Σ).

Problemele de decizie au urmatoarea forma: Fiind dat un anumit obiect, are el o anumitaproprietate?. Deoarece obiectele le reprezentam cu ajutorul cuvintelor ınseamna ca problemase reduce la ıntrebarea: Fiind dat un cuvant, prezinta el o anumita proprietate?

Definitia A.3 Vom considera problema de decizie o functie

P : Σ∗ −→ da, nu (A.2)

Definitia A.4 Limbajul asociat problemei P este

P−1(da) = w|w ∈ Σ∗ si P (w) = da (A.3)

Definitia A.5 Vom considera ca un algoritm este o functie

A : Σ∗ −→ da, nu, nedecidabil (A.4)

Definitia A.6 Limbajul L ⊆ Σ∗ este acceptat de algoritmul A daca L = w|w ∈Σ∗ si A(w) = da.

Definitia A.7 Limbajul L ⊆ Σ∗ este decis de algoritmul A daca ∀w ∈ L : A(w) = da si∀w /∈ L : A(w) = nu.

Definitia A.8 Limbajul L ⊆ Σ∗ este acceptat de algoritmul A ın timp polinomialdaca L este acceptat de A si ∃k ∈ N astfel ıncat pentru orice w ∈ L algoritmul A evalueazaA(w) = da ın timpul O(|w|k).

Definitia 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 siA(w) = nu, daca w /∈ Σ, ın timpul O(|w|k).

Definitia A.10 Clasa de complexitate P:

P = L ⊂ Σ∗|∃A alg. a.ı. L e decis de A ın timp polinomial. (A.5)

189

Page 190: CursuriAG2014

Daca P este o problema de decizie, atunci ea este rezolvabila ın timp polinomial dacalimbajul L = P−1(da) satisface L ∈ P. Se noteaza aceasta P ∈ P.

De exemplu, problema DrumMIN −D este rezolvabila ın timp polinomial daca functiade lungime (specificata ın intrarea ei) prezinta numai valori nenegative. Daca se permit sivalori negative, atunci nu se cunoaste nici o demonstratie a apartenentei DrumMin−D ∈ P(si nici nu se crede ca ar exista una). De asemenea, NrCompus ∈ P s-a demonstrat destulde recent, ın 2002.

Observatia A.31. Daca notam

P’ = L ⊂ Σ∗|∃A alg. a.ı. L este acceptat de A ın timp polinomial,

se observa imediat ca P ⊆ P′ si nu este dificil sa se arate si incluziunea inversa. Prin urmareavem P = P′.

2. Se verifica usor ca daca P ∈ P atunci si Σ∗ \ P ∈ P.

A.0.1 Verificare ın timp polinomial

Un algoritm de verificare este o functie

A : Σ∗ × Σ∗ −→ da, nu, nedecidabil.

Pentru A(x, y), x reprezinta intrarea iar y este certificatul.Limbajul L ⊆ Σ∗ este verificat de algoritmul de verificare A daca

L = w|w ∈ Σ∗ si ∃y ∈ Σ∗ a.ı. A(w, y) = da.

Definitia A.11 Clasa de complexitate NP:

NP = L ⊆ Σ∗|∃A algoritm de verificare 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 limbajulL = P−1(da) satisface L ∈ NP.

NP este mnemonic pentru Nedeterminist Polinomial.Nu este bine sa asimilam NP cu nepolinomial deoarece

textP ⊆ NP. Justificarea este imediata: Daca L ∈ P, atunci exista A : Σ∗ −→ da, nu, nedecidabilalgoritm ce decide L ın timp polinomial. Consideram A′ : Σ∗×Σ∗ −→ da, nu, nedecidabil,satisfacand A′(x, x) = A(x) pentru orice x ∈ Σ∗. Se vede usor ca L este verificat de A′ ıntimp polinomial.

Din definitiile de mai sus ar fi fost mai normal sa folosim notatia VP (verificabil poli-nomial). Sintagma Nedeterminist Polinomial se justifica daca am considera algoritmi nede-terministi ın care, dupa fiecare pas, este posibil sa se execute unul dintre pasii specificatidintr–o multime finita de pasi succesori. Un astfel de algoritm accepta un cuvant de intraredaca este posibila o executie care sa conduca la rezultatul ’da’. Se poate arata ca aceastadefinitie a acceptarii nedeterministe este echivalenta cu cea de verificare data mai sus, ıncare certificatul este utilizat pentru efectuarea alegerilor corecte ale passilor urmatori ai uneiexecutii a algoritmului nedeterminist.

NP noteaza clasa problemelor de decizie pentru care raspunsurile afirmative au certificatecare pot fi folosite pentru a demonstra succint (ın timp polinomial) corectitudinea lor.

190

Page 191: CursuriAG2014

Intuitiv, NP este clasa tuturor problemelor de decizie pentru care se poate verifica unraspuns pozitiv (’da’) rapid daca ni se da o solutie.

De exemplu, pentru problema MaxCut − D un raspuns afirmativ are drept certificat opartitie (S∗, T ∗) a multimii varfurilor grafului (iar proprietatea ca suma lungimilor muchiilorcu 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 justifica un raspuns ’da’ la o problema UnDrum? Daca prezentam un

drum anume drept certificat, el nu ne asigura ca nu mai exista s altele. O demonstratiesuccinta pare a nu exista. Prin urmare nu se cunoaste daca UnDrum ∈ NP.

Definitia A.12 Clasa de complexitate co–NP:

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 circuitcare sa treaca exact o data prin fiecare varf al sau?

Observatia A.4 P ⊆ NP ∩ co−NP.

A.0.2 Reduceri polinomiale

Definitia A.13 Fie L1, L2 ⊆ Σ∗. Spunem ca L1 se reduce polinomial la L2, si notamaceasta prin L1 ∝ L2, daca exista f : Σ∗ −→ Σ∗ o functie polinomial calculabila astfel ıncat∀w ∈ Σ∗ : w ∈ L1 daca si numai daca f(w) ∈ L2.

f se numeste functie de reducere si algoritmul polinomial F ce calculeaza f se numestealgoritm de reducere polinomiala.

Observatia A.51. 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 multimea polinoameloreste ınchisa la operatia de compunere).

2. Relatia ∝ este tranzitiva: L1 ∝ L2, L2 ∝ L3 ⇒ L1 ∝ L3.

Definitia A.14 Limbajul L ⊂ Σ∗ este NP–dificil (engl. NP-hard) daca ∀L′ ∈ NP are locL′ ∝ L.

Definitia A.15 Limbajul L ⊆ Σ∗ este NP–complet daca L ∈ NP si L este NP–dificil.

Terminologia se transfera pentru probleme de decizie.Spunem ca problema de decizie P1 se reduce polinomial la problema de decizie P2, si

notam P1 ∝ P2, daca L1 = P−11 (da) ∝ L2 = P−1

2 (da).

191

Page 192: CursuriAG2014

Definitia A.16 Problema de decizie P este NP–dificila daca

∀P ′ ∈ NP are loc P ′ ∝ P.

Definitia A.17 Problema de decizie P este NP–completa daca

P ∈ NP si P este NP–dificila.

Folosind observatia anterioara si faptul ca P ⊆ NP rezulta urmatoarea teorema.

Teorema A.6 Daca P o problema oarecare NP–completa satisface P ∈ P atunci P = NP.

Rezulta ca problemele NP–complete formeaza o submultime a lui NP ce contine cele maidificile probleme. Daca gasim un algoritm polinomial pentru una dintre ele, putem construiun algoritm polinomial pentru oricare alta problema din NP. Din pacate, desi nu exista odemonstratie, oamenii cred ca, de fapt, aceste probleme nu admit algoritmi polinomiali derezolvare.

Se obisnuieste sa se spuna ca o problema de optimizare este NP–dificila, daca problemade decizie asociata este asa. Pentru a fi consistenti fata de definitiile precedente, vom spuneca o problema oarecare P (nu neaparat de decizie) este NP–dificila daca existenta unuialgoritm polinomial pentru P implica P = NP.

Sa prezentam un exemplu pentru clasa de complexitate a problemelor NP–complete.Primul om care a demonstrat existenta unei astfel de probleme este Cook, care ın 1971 aaratat ca SAT ∈ NP, unde

SAT Intrare: U = u1, . . . , un o multime finita de variabile booleene.C = C1 ∧ C2 ∧ . . . ∧ Cm o formula ın forma conjunctiva peste U :Ci = vi1 ∨ vi2 ∨ . . . ∨ viki

, ∀i = 1, m unde

∀ij ∃α ∈ 1, . . . , n astfel ıncat vij = uα sau vij = 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 restrictia lui SAT ın care fiecare clauza Ci are exact trei literali (ki = 3), un

literal vij fiind, asa cum este descris mai sus, o variabila sau negatia ei.Se poate arata usor ca SAT ∝ 3SAT si astfel se obtine faptul ca 3SAT este NP–

completa (apartenenta la NP este clara fiind o restrictie a lui SAT care apartine lui NP, iartranzitivitatea relatiei ∝ ımpreuna cu teorema lui Cook termina demonstratia).

In concluzie, pentru a arata ca o problema de decizie P este NP–completa se procedeazaastfel:

1. Se arata ca L = P−1(da) satisface L ∈ NP.

2. Se selecteaza un limbaj L′ despre care stim ca este NP–complet.

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

Page 193: CursuriAG2014

Appendix B

Metoda Backtracking

Metoda Backtracking este una dintre cele mai cunoscute metode de elaborare a algoritmilor.Metoda se aplica numai ın situatia ın care nu exista nici o alta modalitate de rezolvare aproblemei propuse deoarece timpul de executie depinde exponential de dimensiunea datelorde intrare. Se utilizeaza o structura de tip stiva iar metoda poate fi implementata atatiterativ cat si recursiv. Metoda se aplica acelor probleme ın care solutia se poate reprezentasub forma unui vector x = (x1, x2, . . . , xn) ∈ A1×A2× . . .×An, unde multimile Ai, (i = 1, n)sunt finite si nevide (|Ai| = ni > 0). In plus, pentru fiecare problema ın parte este necesar casolutia x1, x2, . . . , xn sa satisfaca anumite conditii interne ρ(x1, x2, . . . , xn) (vezi algoritmul67).

Algoritm 67 Algoritm Backtracking (varianta generala)

1: procedure Backtracking(n,A)2: k ← 13: xk ← prima valoare din afara domeniului de valori4: while (k > 0) do

5: gasit← false6: while (∃ valori neverificate pentru xk) ∧ (gasit 6= true) do

7: xk ← urmatoarea valoare neverificata8: if (ρk(x1, x2, . . . , xk) = true) then

9: gasit← true10: end if

11: end while

12: if (gasit = true) then

13: if (k = n) then

14: call Afis Solutie(x1, . . . , xn)15: else

16: k ← k + 117: xk ← prima valoare din afara domeniului de valori18: end if

19: else

20: k ← k − 121: end if

22: end while

23: end procedure

De exemplu, sa consideram doua multimi, S1 = a, b, c si S2 = m, n. Se doreste sa sedetermine perechile (x1, x2), cu x1 ∈ A1 si x2 ∈ A2, cu proprietatea ca daca x1 este a sau b

193

Page 194: CursuriAG2014

atunci x2 nu poate fi n. Rezolvarea conduce la urmatoarele variantele: (a, m), (b, m), (c, m), (c, n).Din cele sase solutii posibile (a, m), (a, n), (b, m), (b, n), (c, m), (c, n), numai acestea patruındeplinesc conditiile interne.

Multimea A = A1 × A2 × ... × An se numeste spatiul solutiilor posibile, iar elementelex ∈ A ce satisfac conditiile interne se numesc solutii rezultat. Ne propunem determinareatuturor solutiilor rezultat, eventual pentru a alege dintre ele pe aceea ce minimizeaza saumaximizeaza o functie obiectiv.

Metoda Backtracking evita generarea tuturor solutiilor posibile (toate elementele pro-dusului cartezian A1 × A2 × ... × An). Construirea unei solutii se face ın mai multi pasi,elementele vectorului X primind valori pe rand: elementului xk ∈ Ak, k = 1, n, i se atribuieo valoare numai dupa ce au fost atribuite valori pentru componentele x1 ∈ A1, x2 ∈ A2,. . ., xk−1 ∈ Ak−1. Metoda trece la atribuirea unei valori pentru xk+1 ∈ Ak+1 doar dacaxk ımpreuna cu x1, x2, . . . , xk−1 verifica conditiile de continuare, notate cu ρk(x1, x2, . . . , xk).Daca aceste conditii ρk(x1, x2, . . . , xk) sunt ındeplinite se trece la cautarea unei valori pentruelementul xk+1 ∈ Ak+1 al solutiei.

Neındeplinirea conditiilor are urmatoarea semnificatie: pentru orice alegere xk+1 ∈ Ak+1,. . . , xn ∈ An, nu vom putea ajunge la o solutie rezultat ın care conditiile interne sa fieındeplinite. In aceasta situatie va trebui sa ıncercam o alta alegere pentru xk, acest lucru fiindposibil doar daca nu am epuizat toate valorile disponibile din multimea Ak. Daca multimeaAk a fost epuizata va trebui sa micsoram valoarea variabilei k cu o unitate (k ← k− 1), si satrecem la alegerea unei alte valori pentru elementul xk−1 ∈ Ak−1. Micsorarea valorii curentea variabilei k cu o unitate da numele metodei si semnifica faptul ca atunci cand nu putemavansa, vom urmari ınapoi secventa curenta din solutie. Faptul ca valorile v1, v2, . . . , vk−1,ale componentelor x1, x2, . . . , xk−1, satisfac conditiile de continuare, nu este suficient pentrua garanta obtinerea unei solutii ale carei prime k − 1 componente coincid cu aceste valori.

O alegere buna a conditiilor de continuare conduce la reducerea numarului de calcule,fiind de dorit ca aceste conditii de continuare sa fie nu numai necesare, dar si suficientepentru obtinerea unei solutii. Conditiile interne devin chiar conditii de continuare pentruk = n. Orice vector solutie se obtine progresiv ıncepand cu prima componenta si deplasandu-ne catre ultima, cu eventuale reveniri asupra valorilor atribuite anterior. Anumite valori suntconsumate ın urma unor atribuiri sau ıncercari de atribuire esuate din cauza neındepliniriiconditiilor de continuare.

Exista doua variante fata de metoda standard:

• solutiile pot avea numar variabil de componente;

• dintre solutii se alege cea care minimizeaza sau maximizeaza o functie cost sau o functieobiectiv data.

Exemplul B.1 Enuntul problemei: Se cere sa se genereze permutari de n elemente.Rezolvare: Spatiul solutiilor este A = ×n

i=1Ai, Ai = 1, 2, . . . , n, |Ai| = n. Solutia vafi obtinuta ın vectorul x = (x1, x2, . . . , xn) ∈ A1 × A2 × . . . An.

La pasul k se ıncearca atribuirea unui alt element din multimea Ak lui xk. Vom trece lapasul k + 1 doar daca sunt ındeplinite conditiile de continuare: (x1, x2, . . . , xk) nu contineelemente care se repeta. Deoarece aceasta verificare se face la fiecare pas, este suficient saverificam daca valoarea elementului xk nu se regaseste printre valorile x1, x2, . . . , xk−1 (vezifunctia CanContinue() din algoritmul 68).

Exemplul B.2 Fie n = 4. Atunci Ai va fi compus din elementele Ai = 1, 2, 3, 4.Pentru k = 1, x1 va primi valuarea 1 (vezi linia 15): 1

194

Page 195: CursuriAG2014

Pentru k = 2, se verifica x2 = 1, ınsa nu se respecta conditiile de continuare (linia 16).Astfel se trece la urmatoarea valoare, x2 = x1 + 1 = 2 (linia 15). Pentru aceasta configuratieconditiile de continuare sunt ındeplinite, si se trece la pasul urmator, k = k + 1 = 3 (linia24): 1 2

Se verifica valorile 1, 2 si 3 pentru x3 (linia 16), dintre care, numai ultima satisfaceconditiile de continuare: 1 2 3

Ajunsi la ultimul pas, k = 4, se verifica valorile 1, 2, 3 si 4 pentru x4. In urma verificariiconditiilor de continuare pentru x4 = 4, se urmareste trecerea la pasul k = k+1 = 5. Deoarecesuntem la ultimul element al vectorului x (linia 21), se obtine prima solutie, ce se si afiseaza:1 2 3 4

Mai departe, nu mai exista valori netestate pentru x4 (linia 14), si revenim la nivelulanterior k = k−1 = 3 (linia 28). Aici urmatoarea valoare din domeniul de valori neverificataeste x3 = 4 (linia 15). Solutia partiala respecta conditiile de continuare (linia 16), astfel ıncatse trece la nivelul urmator (linia 24), k = k + 1 = 4: 1 2 4

Pentru x4 sunt verificate valorile, 1, 2, 3, 4 (liniile 15–16), dintre acestea numai valoarea3, conducand la o solutie finala (linia 21): 1 2 4 3 Algoritmul se continua ın acelasimod pana se obtin toate solutiile:

(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

Page 196: CursuriAG2014

Algoritm 68 Algoritm pentru generare permutari (varianta backtracking)

Input: n - numarul de elemente din multimea initiala1: function CanContinue(A, k)2: for i← 1, k − 1 do

3: if (ai = ak) then

4: return false5: end if

6: end for

7: return true8: end function

9: procedure Permutari(n)10: k ← 111: xk ← 012: while (k > 0) do

13: gasit← false14: while (xk + 1 ≤ n) ∧ (gasit 6= true) do

15: xk ← xk + 116: if ((CanContinue(X, k)) = true) then

17: gasit← true18: end if

19: end while

20: if (gasit = true) then

21: if (k = n) then

22: Output x1, . . . , xn23: else

24: k ← k + 125: xk ← 026: end if

27: else

28: k ← k − 129: 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

Page 197: CursuriAG2014

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 Enuntul problemei: Sa se genereze combinari de n luate cate m (0 ≤

197

Page 198: CursuriAG2014

m ≤ n).Rezolvare: Spatiul solutiilor este A = ×m

i=1Ai, Ai = 1, 2, . . . , n, |Ai| = n. Solutia vafi obtinuta ın vectorul x = (x1, x2, . . . , xm) ∈ A1 × A2 × . . . Am (vezi algoritmul 69).

La pasul k se ıncearca atribuirea unui alt element din multimea Ak lui xk. Conditia decontinuare se refera la proprietatea ca elementele vectorului solutie trebuie sa respecte relatiax1 < x2 < . . . < xk. Acest lucru se obtine foarte usor prin urmatorul procedeu: la trecerea lapasul k +1, variabila xk+1 va primi, ca valoare initiala, valoarea curenta a variabilei xk (vezilinia 15 din algorimul 69).

Pentru n = 5 si m = 3 avem: A = ×3i=1Ai = A1 × A2 × A3, unde A1 = A2 = A3 =

1, 2, 3, 4, 5. Solutiile obtinute 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 ← 13: xk ← 04: while (k > 0) do

5: gasit← false6: while (xk + 1 ≤ n) ∧ (gasit 6= true) do

7: xk ← xk + 18: gasit← true9: end while

10: if (gasit = true) then

11: if (k = m) then

12: Output x1, . . . , xm13: else

14: k ← k + 115: xk ← xk−1

16: end if

17: else

18: k ← k − 119: end if

20: end while

21: end procedure

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

198

Page 199: CursuriAG2014

#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

Page 200: CursuriAG2014

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 damelorEnuntul problemei: Pe o tabla de sah cu n linii si n coloane (n × n patrate), sa se

pozitioneze n dame astfel ıncat sa nu se atace reciproc.Rezolvare: Tabla de sah va fi reprezentata prin matricea A = (aij), i, j = 1, n. Doua

dame aflate ın pozitiile aij si akl se vor ataca reciproc daca:

i = k sau j = l sau |i− k| = |j − l|

Prima observatie care se poate deduce se refera la faptul ca doua dame nu trebuie sa seafle pe aceeasi linie sau pe aceeasi coloana.

Notam cu V = 1, 2, . . . , n multimea celor n coloane ale tablei de sah. Vectorul solutieirezultat X = (x1, x2, . . . , xn) ∈ V × ... × V are urmatoarea semnificatie: componenta i avectorului (i = 1, n) reprezinta linia i de pe tabla de sah. Valoarea xi a acestei componentereprezinta 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 xi = 0, i = 1, n.La pasul k vom ıncerca asezarea damei k (de pe linia k) pe coloana urmatoare (xk + 1).

Initial dama a k-a este pozitionata ın afara tablei (xk = 0 /∈ V ). O dama poate fi asezata peo alta coloana daca vechea pozitie satisface conditia xk < n. Noua pozitie (xk + 1) trebuie sasatisfaca conditiile interne ρk:

• ∀i, 1 ≤ i < k, xi 6= xk + 1 (nu sunt pe aceeasi coloana);

• |i− k| 6= |xi − (xk + 1)| (nu sunt pe aceeasi diagonala).

Daca xk < n si ρk sunt adevarate, dama de pe linia k va fi pozitionata pe coloana xk + 1si se trece la pasul k + 1, corespunzator pozitionarii damei k + 1. In caz contrar, dama k nupoate fi asezata pe tabla si va trebui sa reluam pozitionarea damei k − 1.

Exemplul B.5 Problema colorarii hartilorEnuntul problemei: Sa se coloreze o harta reprezentand n tari folosind m culori

etichetate 1, . . . , m.Rezolvare: Datele necesare pentru descrierea hartii vor fi reprezentate de o matrice

A = (aij), i, j = 1, n, ale carei elemente au urmatoarea semnificatie:

aij =

1 , daca tara i are frontiera comuna cu tara j

0 , ın caz contrar

Matricea A ∈ Mn×n este simetrica si elementele de pe diagonala principala sunt nule:aij = aji si aii = 0.

200

Page 201: CursuriAG2014

Algoritm 70 Algoritm Problema damelor

Input: n - numarul de linii/coloane de pe tabla de sah1: function CanContinue(A, k)2: for j ← 1, k − 1 do

3: if (aj = ak) ∨ ((k − j) = |ak − aj|) then

4: return false5: end if

6: end for

7: return true8: end function

9: procedure DameBacktracking(n)10: i← 111: xi ← 012: while (i > 1) do

13: gasit← false14: while (xi + 1 ≤ n) ∧ (gasit 6= true) do

15: xi ← xi + 116: if (CanContinue(X, i) = true) then

17: gasit← true18: end if

19: end while

20: if (gasit = true) then

21: if (i = n) then

22: call Afis Solutie(x1, . . . , xn)23: else

24: i← i + 125: xi ← 026: end if

27: else

28: i← i− 129: end if

30: end while

31: end procedure

Fie C = c1, c2, . . . , cm multimea culorilor.Vectorul solutiei rezultat X = (x1, x2, . . . , xn) ∈ C × ...×C, are urmatoarea semnificatie:

tara i are repartizata culoarea xi ∈ C, i = 1, n. La ınceput, fiecarei tari i se va atribui valoarea0.

La pasul k ıncercam sa atribuim o noua culoare (xk + 1) pentru tara k, k = 1, n, dacasunt ındeplinite conditiile:

1. xk < m (daca mai exista alte culori neatribuite pentru tara k);

2. pentru ∀i, 1 ≤ i < k cu ai,k = 1 avem xi 6= xk + 1.

Daca cele doua conditii anterioare sunt ındeplinite, atunci noua culoare pentru tara k vafi xk +1, si se va trece la pasul k +1 (stabilirea unei culori pentru tara k +1). In caz contrar,tarii k nu i se mai poate atribui o alta culoare si ne ıntoarcem la pasul k − 1, corespunzatoralegerii unei noi culori pentru tara k − 1. Algoritmul se termina atunci cand nu mai existanici o culoare neverificata pentru tara 1 (vezi algoritmul 71).

201

Page 202: CursuriAG2014

Algoritm 71 Algoritm Problema colorarii hartilor

Input:

A - matricea de adiacenta/de vecinatate a tarilor

n - numarul de tari

m - numarul de culori disponibile

1: function CanContinue(A, X, k)2: for j ← 1, k − 1 do

3: if (xj = xk) ∧ (aj,k = 1) then

4: return false5: end if

6: end for

7: return true8: end function

9: procedure ColorBacktracking(A,n,m)10: k ← 111: xk ← 012: while (k > 0) do

13: gasit← false14: while (xk + 1 ≤ m) ∧ (gasit 6= true) do

15: xk ← xk + 116: gasit← CanContinue(A,X, k)17: end while

18: if (gasit = true) then

19: if (k = n) then

20: call Afis Solutie(x1, . . . , xn)21: else

22: k ← k + 123: xk ← 024: end if

25: else

26: k ← k − 127: end if

28: end while

29: end procedure

Exemplul B.6 Enuntul problemei: Se da o suma s si n tipuri de monede avand valorilea1, a2, . . . , an lei. Realizati un algoritm care sa determine o modalitate de plata a sumei sutilizand 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

Page 203: CursuriAG2014

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

Page 204: CursuriAG2014

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

Page 205: CursuriAG2014

else

//altfel revenim la un element anterior si alegem o alta valoare

i--;

void main(void)

readInput();

run();

print();

205

Page 206: CursuriAG2014

Bibliografie

[1] A. Aho, J. Hopcroft, J. Ullman, On finding lowest common ancestors in trees, Proc. 5thACM 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. 748–759, 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 onFoundations of Computer Science, pp. 540–546, 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 generalizedpriority queues, Programming techniques and Data structures. Comm. ACM, vol. 29(10),pp. 996-1000, 1986.

[10] M. Augenstein, A. Tenenbaum, Program efficiency and data structures, Proceedings ofthe eighth SIGCSE technical symposium on Computer science education, pp. 21–27,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 4thLatin 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, Proceedingsof the 8th Annual ACM-SIAM Symposium on Discrete Algorithms, 1997.

206

Page 207: CursuriAG2014

[16] J. Bentley, R. Sedgewick, Ternary Search Trees, Dr. Dobb’s 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 parallelizableproblems, 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 onComputing, vol.22(2), pp.221-242, 1993.

[21] O. Boruvka, O jistem problemu minimalnım (About a certain minimal problem), ActaSociet. 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. 176–184, 1980.

[23] D. D. Burdescu, Analiza complexitatii algoritmilor, Editura Albastra, Cluj–Napoca,1998.

[24] D. D. Burdescu, M. Brezovan, M. Cosulschi, Structuri de date arborescente cu aplicatiiın Pascal si C, Reprografia Universitatii 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 randomaccess computer, Algorithmica, vol. 15, pp. 521-549, 1996.

[29] B. V. Cherkassky, Algorithm for construction of maximal flows in networks with com-plexity of O(V 2

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

7, pp. 112–125, 1977.

[30] T. H. Cormen, C. E. Leiserson, R. L. Rivest, Introducere ın Algoritmi, Computer LibrisAgora, Cluj–Napoca, 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, McGraw–Hill, 2006.

[35] C. Demetrescu, G. F. Italiano, Engineering Shortest Path Algorithms, WEA, Springer,LNCS 3059, pp. 191–198, 2004.

207

Page 208: CursuriAG2014

[36] R. B. Dial, Algorithm 360: shortest-path forest with topological ordering [H], Communi-cations of the ACM, vol. 12:11, pp. 632–633, 1969.

[37] Dictionarul explicativ al limbii romane, Academia Romana, Institutul de LingvisticaIorgu 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 flow in a network with powerestimation, Doklady Akademii nauk SSSR, vol. 11, pp. 1277-1280, 1970.

[40] Y. Dinitz, Dinitz’ Algorithm: The Original Version and Even’s Version, in Oded Goldre-ich, Arnold L. Rosenberg, and Alan L. Selman, Theoretical Computer Science: Essaysin 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 efficiency for networkflow problems, Journal of the ACM, vol. 19(2), pp. 248-264, 1972.

[43] J. Egervary, Matrixok kombinatorius tulajdonsagairol, (in Hungarian), Matematikai esFizikai Lapok, vol. 38 pp. 16-28, 1931.

[44] J. Farey, On a Curious Property of Vulgar Fractions, London, Edinburgh and DublinPhil. Mag. 47, 385, 1816.

[45] J. Feng, G. Li, J. Wang, L. Zhou, Finding and ranking compact connected trees foreffective keyword proximity search in XML documents, Information Systems, vol. 35(2),pp. 186–203, 2010.

[46] L. R. Ford, Network flow theory, Technical Report P-923, RAND, Santa Monica, CA,1956.

[47] L. R. Ford, Jr., D. R. Fulkerson, Maximal Flow Through a Network, Canadian Journalof Mathematics, 8, pp. 399–404, 1956.

[48] L. R. Ford, Jr., D. R. Fulkerson, A Simple Algorithm for Finding Maximal NetworkFlows and an Application to the Hitchcock Problem, Canadian Journal of Mathematics,9, pp. 210–218, 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 ofself-adjusting heap, Algorithmica, 1, pp. 111–129, 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

Page 209: CursuriAG2014

[55] H. N. Gabow, R. E. Tarjan, A linear-time algorithm for a special case of disjoint setunion, Proceedings of the 15th ACM Symposium on Theory of Computing (STOC), pp.246-251, 1983.

[56] H. N. Gabow, Path-based depth-first 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, AmericanMathematical Monthly, vol. 69, pp. 9–14, 1962.

[58] Z. Galil, An O(V5

3 Efrac23) algorithm for the maximal flow problem, Acta Informatica,vol. 14, pp. 221–242, 1980.

[59] Z. Galil, A. Naamad, An O(EV (log V )2) algorithm for the maximal flow problem, Jour-nal of Computer and System Sciences, vol. 21(2), pp. 203–217, 1980.

[60] C. Giumale, Introducere ın analiza algoritmilor, Editura Polirom, Iasi, 2004.

[61] A. V. Goldberg, A new max-flow 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 flow problem, in Pro-ceedings of the 18th ACM Symposium on Theory of Computing, ACM, pp. 136–146,1986.

[63] A. V. Goldberg, E. Tardos, R. E. Tarjan, Network flow algorithms, Algorithms andCombinatorics, 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 forComputer Science, 2nd Edition, Addison-Wesley, 1994.

[65] D. Gries, The Science of Programming, Springer Verlag, Heidelberg, New–York, 1981.

[66] L. Guo, F. Shao, C. Botev, J. Shanmugasundaram, XRANK: ranked keyword search overXML documents, in Proceedings of the 2003 ACM SIGMOD International Conferenceon Management of Data, pp. 16–27, 2003.

[67] D. Gusfield, 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 finding nearest common ancestors, SIAMJournal 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 PublishingCompany, 1978.

209

Page 210: CursuriAG2014

[72] J. E. Hopcroft, R. Karp, An n5

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 ProximitySearch in XML Trees, IEEE Transactions on Knowledge and Data Engineering, vol.18(4), pp. 525–539, 2006.

[74] D. A. Huffman, 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. Jarnık, O jistem problemu minimalnım (About a certain minimal problem), PraceMoravske Prırodovedecke Spolecnosti, 6, pp. 57–63, 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 find minimumspanning trees, Journal of ACM, 42, pp. 321328, 1995.

[80] A. V. Karzanov, Determining the maximum flow in the network by the method of pre-flows, Doklady Akademii nauk SSSR 15, pp. 434-437, 1974.

[81] B. W. Kernigham, D. M. Ritchie, The C Programming Language, 2nd Edition, PrenticeHall, 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 finiteand infinite 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 salesmanproblem, 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

Page 211: CursuriAG2014

[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 ResearchLogistics Quarterly, vol. 3, pp. 253-258, 1956.

[92] Y. Li , C. Yu , H. V. Jagadish, Schema-free XQuery, in Proceedings of the ThirtiethInternational Conference on Very Large Databases (VLDB), pp. 72–83, 2004.

[93] L. Livovschi, H. Georgescu, Analiza si sinteza algoritmilor, Ed. Stiintifica si Enciclope-dica, Bucuresti, 1986.

[94] V. M. Malhotra, M. P. Kumar, S. N. Maheshwari, An O(|V |3) algorithm for findingmaximum flows in networks, Information Processing Letters, 7(6), pp.277–278, 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 finding maximum matchingin 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 laUniversitatea 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 ofthe 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. 135–140, 2004.

[102] I. Odagescu, F. Furtuna, Metode si tehnici de programare, Computer Libris Agora,Cluj–Napoca, 1998.

[103] S. Pettie, A faster all-pairs shortest path algorithm for real-weighted sparse graphs, inProceedings 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 ofACM, 49:1634, 2002.

[106] R. C. Prim, Shortest connection networks and some generalizations, Bell System Tech-nical Journal, 36, pp. 1389-1401, 1957.

211

Page 212: CursuriAG2014

[107] B. Schieber, U. Vishkin, On finding lowest common ancestors: Simplification and par-allelization, SIAM J. Comput., vol. 17, pp. 1253-1262, 1988.

[108] A. Schrijver, On the history of the transportation and maximum flowproblems, Mathe-matical Programming, vol. 91, issue 3, pp. 437-445, 2002.

[109] R. Seidel, C. Aragon, Randomized Search Trees, Algorithmica, vol. 16, pp. 464–497,1996.

[110] M. Sharir, A strong-connectivity algorithm and its applications in data fow analysis,Computers and Mathematics with Applications, vol. 7(1), pp. 67–72, 1981.

[111] Y. Shiloach, U. Vishkin, An O(n2 log n) parallel max-flow 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 flow, Technical Report,STAN-CS-80-831, 1980.

[114] D. D. Sleator, R. E. Tarjan, A data structure for dynamic trees, Journal of ComputerSciences, vol. 26, pp. 362–391, 1983.

[115] J. Stasko, J. Vitter, Pairing heaps: Experiments and analysis, Communications of theACM, 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 (COCOON’99), pp. 115–128, 2003.

[117] R. Tarjan, Depth–first search and linear graph algorithms, SIAM Journal on Computing,vol. 1(2), pp. 146–160, 1972.

[118] R. E. Tarjan, Edge-disjoint spanning trees and depth-first 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 Karzanov’s blocking flow algorithm, Operation Re-search Letters, vol. 2, pp.265–268, 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, Reprografia Universitatii din Craiova, 1993.

[124] I. Tutunea, S. Pescarus, Algoritmi si programe Pascal. (Culegere de probleme), Repro-grafia Universitatii din Craiova, 1994.

[125] J. Vuillemin, A data structure for manipulating priority queues, Communications ofthe ACM, vol. 21:4, pp. 309–315, 1978.

212

Page 213: CursuriAG2014

[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(n3) max-flow algorithm, Mathematical and Com-puter Modelling, vol. 16(2), pp.65–72, 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, Efficient keyword search for smallest LCAs in XMLdatabases, in Proceedings of the 2005 ACM SIGMOD International Conference on Man-agement of Data, pp. 527–538, 2005.

[131] D. Zaharie, Introducere ın proiectarea si analiza algoritmilor, Eubeea, Timisoara, 2008.

213