Sunteți pe pagina 1din 201

INTRODUCERE

IN
ALGORITMIC

A
Paul Iacob
September 28, 2005
2
Cuprins
Prefat a 7
Cuvant nainte 9
1 Introducere 11
Scopul cart ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Generalitat i . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Limbajul pseudocod 15
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Limbajul pseudocod . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3 Analiza algoritmilor 21
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Analiza algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Algoritmi parametrizat i (subalgoritmi) . . . . . . . . . . . . . . . . 25
Notat ia asimptotica . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4 Structuri elementare de date 33
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Structuri liniare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Stiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
Alocarea secvent iala a stivei . . . . . . . . . . . . . . . . . . . 35
Alocarea nlant uita a stivei . . . . . . . . . . . . . . . . . . . . 35
Coada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
Alocarea secvent iala a cozii . . . . . . . . . . . . . . . . . . . 37
Alocarea nlant uita a cozii . . . . . . . . . . . . . . . . . . . . 38
Arbori binari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3
Alocarea secvent iala a unui arbore binar . . . . . . . . . . . . 39
Alocarea nlant uita a unui arbore binar . . . . . . . . . . . . . 40
Alocarea mixta a unui arbore binar . . . . . . . . . . . . . . . 40
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
5 Recursivitate 45
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Calculul lui n! . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Sirul lui Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . 49
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
6 Metoda Backtracking 53
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Exemplu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7 Generarea submult imilor 59
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Schema generala de lucru . . . . . . . . . . . . . . . . . . . . . . . 59
Generarea elementelor unui produs cartezian . . . . . . . . . . . . . 61
Generarea tuturor submult imilor unei mult imi . . . . . . . . . . . . 62
Generarea mult imii combinarilor . . . . . . . . . . . . . . . . . . . 63
Generarea mult imii permutarilor . . . . . . . . . . . . . . . . . . . 66
Generarea mult imii aranjamentelor . . . . . . . . . . . . . . . . . . 69
Submult imi de suma data . . . . . . . . . . . . . . . . . . . . . . . 71
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8 Metoda Divide et Impera 75
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
Problema turnurilor din Hanoi . . . . . . . . . . . . . . . . . . . . . 76
Metoda I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Metoda a IIa . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Metoda a IIIa . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4
Algoritmul de sortare QuickSort . . . . . . . . . . . . . . . . . . . . 80
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
9 Sortare si statistici de ordine 87
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Exemplicari, generalitat i . . . . . . . . . . . . . . . . . . . . . . . 87
Determinarea simultana a minimului si a maximului . . . . . . . . . 88
G asirea celor mai mici doua elemente dintrun sir . . . . . . . . . . 89
Problema select iei . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
Select ie n timp mediu liniar . . . . . . . . . . . . . . . . . . . 91
Select ia n timp liniar n cazul cel mai defavorabil . . . . . . . 92
Heapsort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Algoritmi de sortare n timp liniar . . . . . . . . . . . . . . . . . . . 95
Algoritmul sortarii prin numarare (CountSort) . . . . . . . . . 95
Sortare pe baza cifrelor . . . . . . . . . . . . . . . . . . . . . . 96
Sortare pe grupe . . . . . . . . . . . . . . . . . . . . . . . . . 97
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
10 Metoda Greedy 101
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
Problema submult imilor de suma maxima . . . . . . . . . . . . . . 102
Arborele Human . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Interclasare optimala . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
11 Programare dinamica 113
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

Inmult irea unui sir de matrici . . . . . . . . . . . . . . . . . . . . . 114


Cel mai lung subsir crescator . . . . . . . . . . . . . . . . . . . . . 120
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
12 Algoritmi euristici 125
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
O problema de taiere cu doua criterii de optimizare. . . . . . . . . . 125
5
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
13 Algoritmi n algebra liniara. 131
Obiective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Algoritmul lui Strassen. . . . . . . . . . . . . . . . . . . . . . . . . 131
Metoda LUP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Rezumat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
Exercit ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
14 Teste de autoevaluare 143
A Metode utile n calculul complexitat ii 149
Sume des ntalnite . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
Delimitarea sumelor . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Induct ia matematica . . . . . . . . . . . . . . . . . . . . . . . 150
Aproximarea prin integrale . . . . . . . . . . . . . . . . . . . . 151
Analiza algoritmilor recursivi . . . . . . . . . . . . . . . . . . . . . 152
Metoda iterat iei . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Recurent e liniare omogene . . . . . . . . . . . . . . . . . . . . 153
Recurent e liniare neomogene . . . . . . . . . . . . . . . . . . . 154
B Rezolvari 157
Rezolvari pentru capitolul 3 . . . . . . . . . . . . . . . . . . . . . . 157
Rezolvari pentru capitolul 4 . . . . . . . . . . . . . . . . . . . . . . 167
Rezolvari pentru capitolul 5 . . . . . . . . . . . . . . . . . . . . . . 172
Rezolvari pentru capitolul 6 . . . . . . . . . . . . . . . . . . . . . . 175
Rezolvari pentru capitolul 7 . . . . . . . . . . . . . . . . . . . . . . 182
Rezolvari pentru capitolul 8 . . . . . . . . . . . . . . . . . . . . . . 184
Rezolvari pentru capitolul 9 . . . . . . . . . . . . . . . . . . . . . . 186
Rezolvari pentru capitolul 10 . . . . . . . . . . . . . . . . . . . . . 190
Rezolvari pentru capitolul 11 . . . . . . . . . . . . . . . . . . . . . 196
6
Prefat a

In ultimii ani asistam la o dezvoltare n ritm sust inut a utilizarii cal-


culatoarelor electronice, spectrul aplicat iilor creste continuu, numarul uti-
lizatorilor se mareste simt itor. A aparut astfel necesitatea elaborarii unei
metodologii a programarii.

In acest context, ne permitem sa apreciem ca ind gresita opinia (din


pacate nca raspandita) ca a sti sa programezi echivaleaza cu a cunoaste
unul sau mai multe limbaje de programare. Adevarul este altul: a sti sa pro-
gramezi nseamna a stapani tehnici de elaborare a algoritmilor si metode de
elaborare a programelor, unele dintre ele ind prezentate n aceasta lucrare.
Cea mai mare parte a materialului prezentat se refera la subiecte ce g-
ureaza n mai toate manualele si tratatele actuale si anume: analiza algo-
ritmilor, structuri elementare de date, recursivitate, metode de elborare a
algoritmilor, algoritmi euristici, algoritmi n algebra liniara. Se au n vedere
atat aspectele teoretice ale problemelor, cat si cele practice, majoritatea capi-
tolelor cont inand probleme rezolvate si probleme propuse.
Pentru redactarea algoritmilor se foloseste un limbaj algoritmic (pseudocod
n limba romana), foarte naural si accesibil. Acest limbaj are avantajul ca
permite elaboraream mai usoara a algoritmilor si evita, n mare parte, efortul
de memorare a nenumaratelor detalii ale unui limbaj de programare.
Iata de ce aceasta lucare este bine venita; ea ne face sa gandim. Ne face
sa gandim algoritmic si despre algoritmi.
Structurarea lucrarii si modul de prezentare a not iunilor sunt ingenios
realizate, acestea ind principalele repere care o deosebesc de alte lucrari din
domeniu.
Lucrarea se adreseazan primul rand student ilor dinnvat amantul univer-
sitar de informatica, dar si din nvat amantul universitar tehnic, matematic
si economic.
Problemele constitue un fond reprezentativ atat pentrunvat area not iunilor
din carte cat si pentru pregatirea unor concursuri, olimpiade scolare, la di-
verse nivele. De asemenea, ea vine n sprijinul profesorilor de liceu pentru
pregatirea orelor de informatica n concordant a cu cerint ele programelor de
7
specialitate actuale.
Prof. Dr.
Ciurea Eleonor
8
Cuvant nainte
Se cuvine sa spunem cate ceva despre stradania depusa pentru aceasta
carte.
Materialul sa strans pe parcursul a 14 ani de predare a materiei algo-
ritmic a la Facultatea de Matematica si Informatica a universitat ii Transil-
vania din Brasov. Redactarea lui s a facut n mai multe etape cu jutorul
nepret uit al sot iei mele, Mirela si al domnului Sasu Lucian, studentul si
apoi asistentul nostru mai mult i ani. Trebuie sa mai spun ca majoritatea
solut iilor problemelor propuse au fost scrise tot de Sasu Lucian, tot el a avut
ideea de introduce, n apendix, metode utile n calculul complexitat ii si tot
la init iativa lui a fost introdus capitolul de recursivitate. La capitolul de-
spre metoda Greedy sia adus o conrtribut ie importanta doamna Tabarca
Tatiana.
Mult umesc, pe aceasta cale, profesorului Ciurea Eleonor pentru prefat a,
pe care probabil at i citito deja, si pentru desele discut ii anterioare care au
contribuit la completarea materialului.
Autorul
9
10
Capitolul 1
Introducere
Scopul cart ii
Lucrarea de fat a si propune sa e o introducere n teoria algoritmilor. Se
vor introduce not iunile de algoritm, subalgoritm, complexitatea algoritmilor,
diferite metode de elaborare a algoritmilor, probleme clasice. Cartea este
detinata tuturor celor ce vor sa scrie un program si nu stiu cu ce sa nceapa.
Generalitat i
Pentru rezolvarea unei probleme pe calculator, se parcurg urmatorii pasi:
1. se detecteaza problema;
2. se adauga restrict iile impuse de domeniul care a creat problema;
3. se creeaza un model matematic;
4. se concepe un algoritm (un mod) de rezolvare a problemei;
5. se scrie un program;
6. se interpreteza rezultatele de la calculator n termeni specici domeni-
ului problemei.
Pasii 1, 2, 3 sunt n general reunit i sub numele de analiza. Pasul 4
constituie programarea. Pasul 6 face parte din implementare.
Deci algoritmul reprezinta un pas intermediar ntre modelul matematic
si programul realizat ntr-un limbaj conceput pentru calculator. Originea
cuvantului algoritm este legata de numele Abu Jafar Mohammed Ibn M usa
11
al Khowarizm, autor arab al unei cart i de matematica. Not iunea de algoritm
este fundamentala, deci nu se poate deni; n general, ea este explicata ca o
succesiune nita de pasi computat ionali care transforma date de intrare n
date de iesire.
Proprietat ile pe care trebuie sa le aibe un algoritm sunt:
1. Fiecare pas trebuie sa cont ina o operat ie bine denita (de exemplu
urmatoarele operat ii nu sunt bine denite: 4/0 sau scade 10 sau 20
din 30);
2. Pasul care urmeaza ecarui pas trebuie sa e unic denit;
3. Fiecare pas trebuie sa e efectuabil, adica sa poata executat cu
creionul pe hartie: operat ii cu numere ntregi - da, dar operat ii cu
numere reale n general - nu.
4. Trebuie sa se termine n timp nit. Se poate spune ca timpul trebuie
sa e rezonabil de scurt si totusi vor considerat i algoritmi care pe
masinile actuale necesita zeci de ani pentru ca se presupune ca viitoarele
masini vor mult mai rapide.
Ce vom studia n legatura cu algoritmii?
1. Cum sa concepem un algoritm? Crearea unui algoritm nu va nicio-
data pe deplin automatizata, va ramane o problema a omului n primul
rand si abia apoi a masinii.

In aceasta ordine de idei vom studia n
acest curs metode de elaborare a algoritmilor.
2. Exprimarea noastra va restransa, din necesitatea de a scrie usor pro-
grame corecte, la algoritmi structurat i, adica algoritmi care folosesc
anumite structuri specice care vor expuse la nceputul cursului.
3. Vom nvat a sa vericam corectitudinea algoritmilor conceput i. Un al-
goritm corect trebuie sa rezolve problema propusa pentru orice date
de intrare. Nu se pune problema vericarii cu anumite date (acest lu-
cru t ine de vericarea programului), ci problema unei demonstrat ii a
corectitudinii programului (n general ca o teorema).
4. Nu ajunge sa construim algoritmi corect i! Trebuie sa cunoastem si
performant ele algoritmilor creat i. Pot exista mai mult i algoritmi care
sa rezolve aceeasi problema, unii mai greu sau mai usor de nteles (de
urmarit), unii mai lungi n numarul de pasi descrisi, dar cu performant a
urmarita prin analiza (numarul de pasi elementari executat i, n legatura
12
cu dimensiunea intrarii). O alta problema este cea legata de dimensi-
unea memoriei necesare execut iei programului realizat dupa un anumit
algoritm.
13
14
Capitolul 2
Limbajul pseudocod si structuri
fundamentale
Obiective

In acest capitol se va prezenta lexicul limbajului pseudocod, care va


folosit n restul lucrarii pentru reprezentarea algoritmilor. Se introduc
instruct iunile de atribuire, decizie, ciclare, citire, scriere. Not iunile prezen-
tate sunt nsot ite de exemple simple care sa ajute la nsusirea temeinica a
limbajului pseudocod.
Limbajul pseudocod
Limbajul n care este descris algoritmul trebuie sa e un intermediar ntre
limbajul matematic si cel de programare.
Limbajul schemei logice are avantaje de explicat ie graca, dar si dezavan-
taje legate de structurare si translatare, asa ca vom folosi pseudocodul. Acest
limbaj foloseste cuvinte cheie (subliniate), cuvinte care denesc variabile si
constante si text explicativ (ntre acolade).
Putem distinge urmatoarea structura generala:
Start Numele programului
citeste( date de intrare )
prelucreaza datele
scrie( rezultate )
Stop
Putem specica:
15
Liste de date (a, b, x)
Vectori (a(i), i = 1, n)
Matrici ((x(i, j), j = 1, n), i = 1, m)
Constante (Viteza=, v)
Operat ia cea mai des folosita este atribuirea.
a = 1
Figura 2.1: Atribuirea a = 1.

In acest mod, numele a este legat de o zona de memorie n care se intro-


duce valoarea 1. Pentru
a = b +c
efectul este dat n gura 2.2:
Figura 2.2: Atribuirea a = b +c.
Se calculeaza rezultatul operat iei de adunare b + c, acesta depunandu-
se ntr-o zona intermediara. Rezultatul adunarii se copiaza apoi n zona de
memorie alocata variabilei a. Chiar si pentru o atribuire de genul:
a = a + 1
rezultatul adunarii lui a cu 1 se depune ntr-o zona intermediara, dupa care
se copiaza n locat ia lui a, analog cu gura 2.2.
Atunci cand pasul urmator depinde de o anumita situat ie cucerita pana
atunci, el este rezultatul unei decizii care va scris astfel:
daca condit ie logica atunci
(grup de pasi 1)
altfel
(grup de pasi 2)
sfarsit daca
Exemplul 1.
Start Algoritm 1
citeste( i, a )
16
daca i 1 atunci
a = a +i
altfel
a = a i
sfarsit daca
scrie( a=, a )
Stop
Acest algoritm scrie a = 10 daca intrarea este 0, 10, iar pentru intrarea 2, 10
scrie a = 8.
Exemplul 2. Urmatorul algoritm gaseste cel mai mare dintre trei nu-
mere:
Start Algoritm 2
citeste( a, b, c )
max = a
daca max < b atunci
max = b
sfarsit daca
daca max < c atunci
max = c
sfarsit daca
scrie( Maximul este , max )
Stop
Urmarit i algoritmul pentru valorile de intrare (10, 1, 3), (2, 2, 5), (1, 12, 2).
Exista grupuri de instruct iuni care se executa n mod repetat. Aceste
structuri se numesc cicluri si apar des n elaborarea algoritmilor.
Prima forma de ciclare se numeste ciclu cu numarator si se foloseste atunci
cand se stie de cate ori se executa un grup de instruct iuni. Are forma:
pentru ind = vi, vf, pas
grup de pasi
sfarsit pentru
Daca pas = 1, atunci el se poate omite. Grupul de pasi din interiorul ciclului
poate sa nu se execute niciodata, daca vi > vf (pentru pas > 0), respectiv
daca vi < vf (pentru pas < 0). De exemplu, ciclul de mai jos nu se executa
daca n < 1:
pentru ind = 1, n
grup de pasi
sfarsit pentru
17
Exemplul 3. Algoritmul de mai jos calculeaza suma componentelor unui
vector a(i), i = 1, n:
Start Algoritm 3
citeste( n, (a(i), i = 1, n) )
s = 00 este element neutru pentru adunare
pentru i = 1, n, 1
s = s +a(i)
sfarsit pentru
scrie( suma este , s )
Stop
Exemplul 4. Pentru a numara componentele pozitive (np), negative (nn)
si cele nule (nz) ale unui vector vom avea urmatorul algoritm:
Start Algoritm 4
citeste( n, (a(i), i = 1, n) )
np = 0
nn = 0
nz = 0
pentru i = 1, n
daca a(i) > 0 atunci
np = np + 1
altfel
daca a(i) < 0 atunci
nn = nn + 1
altfel
nz = nz + 1
sfarsit daca
sfarsit daca
sfarsit pentru
scrie( Pozitive= , np, Negative= , np, Nule= , nz )
Stop
Acest tip de cicluri se numesc cicluri cu numarator. Mai avem si cicluri cu
condit ie, care poate nainte sau dupa corpul ciclului (grupul de pasi ce se
executa de ecare data).
Ciclul cu test anterior are forma:
cat timp (condit ie logica)
grup de pasi
sfarsit cat timp
Corpul ciclului poate sa nu se execute niciodata, daca codit ia logica este de
la nceput falsa.
18
Exemplul 5. Algoritmul urmator (algoritmul lui Euclid) serveste la deter-
minarea celui mai mare divizor comun a doua numere:
Start Euclid
citeste( a, b )
m = a
n = b
c at timp n ,= 0
r = rest(m/n)
m=n
n=r
sf arsit cat timp
scrie( CMMDC dintre , a, si , b, este , m )
Stop
Urmarit i algoritmul pentru intrarile (10, 3) si (258, 12).
Ciclul cu test posterior are forma:
repeta
grup de pasi
pana cand condit ie logica
Grupul de pasi se executa cel put in o data.
Exemplul 6. Se cere listarea combinarilor din 1, 2, 3, 4, 5 luate cate
3:
Start Combinari
pentru i = 1, 3
j = i
repeta
j = j + 1
k = j
repeta
k = k + 1
scrie( i,-,j,-,k )aseaza o combinat ie
pana cand k = 5
pana cand j = 4
sf arsit pentru
Stop
19
Rezumat
Un algoritm are o structura bine denita. Instruct iunile prezentate, m-
preuna cu not iunea de subalgoritm din capitolul 3 formeaza un vocabular
sucient pentru scrierea algoritmilor. Sau prezentat: forma generala a
unui algoritm, citirea si scrierea datelor, atribuirea, instruct iunea de de-
cizie, cele trei forme de ciclare.
20
Capitolul 3
Analiza algoritmilor.
Subalgoritmi. Notat ia
asimptotica
Obiective
Acest capitol prezinta modalitatea de comparare a performant ei algorit-
milor, folosind not iunea de complexitate. Se introduc cele trei notat ii asimp-
totice mpreuna cu relat iile dintre ele, formule de calcul general, proprietat i.
Exemplicarea se face prin compararea a doi algoritmi care rezolva aceeasi
problema: sortarea unui vector de numere (problema de larg interes, care nu
are o rezolvare triviala).
Se introduce de asemenea not iunea de subalgoritm, absolut necesara n
scrierea algoritmilor recursivi sau ca forma de abstractizare. Capitolul se
ncheie cu o suita de probleme propuse spre rezolvare, a caror solut ionare
este data la sfarsitul lucrarii.
Analiza algoritmilor
Putem usor sa ne dam seama ca pentru a rezolva o anumita problema
pot exista mai mult i algoritmi. De exemplu, se stie deja ca pentru aarea
celui mai mare divizor comun a doua numere se poate folosi e algoritmul
lui Euclid, e un algoritm bazat pe descompunerea numerelelor n produse
de factori primi.
Se pune ntrebarea: care din acesti algoritmi este mai bun? si n general:
cum putem compara doi algoritmi care rezolva aceeasi problema?
Cu raspunsul la aceasta ntrebare se ocupa analiza algoritmilor.
21
A analiza un algoritmnseamna a preciza ce resurse (de memorie si timp)
o s a aiba nevoie atunci cand va translatat n program care rezolva pe
calculator problema respectiva.
Vom parcurge treptele spre not iunile de baza ale analizei algoritmilor
studiind doi algoritmi de sortare. Primul de care ne ocupam este sortarea
prin insert ie.
Pentru problema sortarii avem: la intrare un sir de n valori numerice
(a
1
, a
2
, . . . , a
n
) si vrem la iesire un sir (a

1
, a

2
, . . . , a

n
), obt inut prin per-
mutarea valorilor init iale, astfel ncat a

1
a

2
a

n
. Ideile algoritmului
descris mai jos (sortare prin insert ie) pot nt elese daca ne gandim la aran-
jarea cart ilor de joc: avem pe masa, cu fat a n jos, o serie de cart i pe care le
putem lua una cate una n mana, deplasandu-le pana la locul pe care trebuie
sa l ocupe.
Exemplu: Fie sirul A = 4 1 6 3 8 5 . Acest sir va parcurs de un
cursor i (se ia cate o carte) si mutat n cadrul sirului cu ajutorul unui cursor
j care parcurge pe A

pana la locul potrivit:


pentru i = 1:
A

= 4
pentru i = 2, elementul A(2) = 1 este mai mic decat 3, deci trebuie
pus n fat a lui:
A

= 1 4
pentru i = 3:
A

= 1 4 6
pentru i = 4:
A

= 1 3 4 6
pentru i = 5:
A

= 1 3 4 6 8
pentru i = 6:
A

= 1 3 4 5 6 8
Sa observam ca nu avem nevoie de un spat iu suplimentar pentru rezultat
si putem face ceea ce se numeste sortare in place (pe loc) (i.e. n afara
sirului nu se t in decat cel mult un numar constant de elemente ale sirului).

In pseudocod algoritmul poate scris astfel:


Start Sortins
1 citeste( n, (A(i), i = 1, n) )
22
2 pentru i = 2, n
3 k = A(i)
insereaza A(i) n sirul sortat A(1), . . . , A(i 1)
4 j = i 1
5 cat timp j > 0 si A(j) > k
6 A(j + 1) = A(j)
7 j = j 1
sfarsit cat timp
8 A(j + 1) = k
a terminat inserarea
sfarsit pentru
9 scrie( A(i), i = 1, n )
Stop
Dintre resursele consumate ne va interesa n primul rand timpul de rulare.
Timpul de rulare al unui algoritm pentru o anumita intrare (instant a) este
exprimat prin numarul de pasi elementari executat i. Pentru nceput vom
considera ca pas elementar ecare linie parcursa din algoritmul n pseudocod
si timpul pentru un astfel de pas o constanta diferita pentru ecare linie
(desi este evident ca unele din aceste constante sunt egale).

Incepem prin
a prezenta algoritmul Sortins cu timpul ecarei instruct iuni si numarul de
execut ii ale liniei respective. Vom nota cu t
i
numarul de execut ii ale ciclului
de la linia 5 (evident ca el este diferit pentru ecare valoare a lui i).
Urmarind tabelul de mai jos, putem calcula timpul total de execut ie:
Numar linie Instruct iune Timp Numar de operat ii
Start Sortins
1 citeste ( n, (A(i), i = 1, n) ) c
1
n + 1
2 pentru i = 2, n c
2
n 1
3 k = A(i) c
3
n 1
4 j = i 1 c
4
n 1
5 cat timp j > 0 si A(j) > k c
5
n

i=2
t
i
6 A(j + 1) = A(j) c
6
n

i=2
(t
i
1)
7 j = j 1 c
7
n

i=2
(t
i
1)
sfarsit cat timp
8 A(j + 1) = k c
8
n 1
sfarsit pentru
9 scrie ( A(i), i = 1, n ) c
9
n
Stop
23
T(n) = c
1
(n + 1) +c
2
(n 1) +c
3
(n 1) +c
4
(n 1) +
+ c
5

i=2
t
i
+ (c
6
+c
7
)
n

i=2
(t
i
1) + (c
6
+c
7
)
n

i=2
(t
i
1) +
+ c
8
(n 1) +c
9
n
Cum putem sa-l aam pe t
i
? O sa ne punem, de fapt, problema interval-
ului n care se plimba, studiind cele doua cazuri care corespund limitelor
intervalului.
Cel mai rapid caz se obt ine cand sirul este gata sortat si deci n linia 5 vom
avea A(j) k pentru orice j = 2, . . . , n deci n acest caz t
i
= 1, iar
T(n) = a n +b, unde a, b constante, deci T funct ie liniara de n.
Cel mai rau caz se obt ine cand sirul dat este sortat descrescator, ceea ce
nseamna ca pe linia 5 vom avea A(j) > k pentru orice j de la i 1 la 1, deci
t
i
= i 1 ; atunci
n

i=2
(i 1) =
n(n1)
2
si
n

i=2
(i 2) =
(n2)(n1)
2
, deci
T(n) = a n
2
+b n +c, funct ie patratica de n.
Analiza se face, n general, pentru cel mai rau caz .
Sa vedem acum daca sortarea se poate face altfel, eventual mai repede.
Pentru aceasta vom adopta o alta metoda, divide et impera. Aceasta
metoda porneste de la ideea ca problema pusa pentru o intrare mare (numar
mare de date) este mai greu de rezolvat decat o problema cu un numar redus
de date, de exemplu un sir format dintr-un singur element. Principiul divide
et impera funct ioneaza astfel:
- se mparte problema n mai multe subprobleme
- se rezolva ecare din subprobleme (n general recursiv)
- se combina solut iile pat iale ntr-o solut ie nala
Vom reveni cu amanunte despre aceasta metoda n capitolul 8.
Algoritmul sortarii prin interclasare (mergesort) se bazeaza pe metoda
divide et impera. Sa vedem ce nseamna interclasarea: din doua siruri
sortate crescator sa se creeze sirul sortat tot crescator care cont ine toate
elementele celor doua siruri init iale.
Aceasta da urmatorul algoritm:
Start Interclasare
24
citeste( n, (A(i), i = 1, n) )
citeste( m, (B(j), j = 1, m) )
k = 0
i = 1
j = 1
repeta
k = k + 1
daca A(i) < B(j) atunci
C(k) = A(i)
i = i + 1
altfel
C(k) = B(j)
j = j + 1
sfarsit daca
pana cand i > n sau j > m
Ciclul de mai jos poate sa nu se execute nici o data
pentru il = i, n
k = k + 1
C(k) = A(il)
sfarsit pentru
Ciclul de mai jos poate sa nu se execute nici o data
pentru jl = j, m
k = k + 1
C(k) = B(jl)
sf arsit pentru
Din cele doua cicluri pentru de mai sus, se executa exact unul singur
scrie( C(kl), kl = 1, m+n )
Stop
Se observa ca timpul total de execut ie pentru algoritmul de interclasare
este T(n, m) = c (n + m) unde c este timpul maxim necesar execut iei
instruct iunilor din interiorul ciclurilor repeta si pentru (c nu depinde de m, n).
Pentru algoritmul de sortare prin interclasare prezentam not iunea de sub-
algoritm.
Algoritmi parametrizat i (subalgoritmi)
Rareori un algoritm, ca aceia prezentat i pana acum, constituie probleme
independente; n general, algoritmii pentru rezolvarea unor probleme com-
plexe au part i care se combina ntre ele.
Pentru punerea n evident a a unei astfel de structuri modulare vom folosi
25
algoritmi parametrizat i numit i si subalgoritmi.
Parametrii vor variabile ale caror valori vin din algoritmul care cheama
si se ntorc napoi n acesta, deci efectele produse asupra parametrilor de
intrare vor exista si dupa ce subalgoritmul se termina
1
.
Algoritmul Interclas parametrizat ar : Interclas(A, n, B, m, C) ceea ce
nseamna: interclaseaza A (avand n componente) cu B (avand m compo-
nente) si obt ine C.

Intr-un algoritm parametrizat nu mai au ce cauta instruct iunile de intrare


si nici instruct iunea Stop; n locul acesteia din urma vom folosi Return care
nseamna ntoarce-te n (sub)algoritmul chemator.
Exemplu: Interclas(A

, n

, B

, m

, C

).
Corespondent a dintre parametrii de chemare si cei din subalgoritm se face
pozit ional.
Pentru usurarea exprimarii, vom considera si subalgoritmi de tip funct ie
care returneaza o valoare.

In acest caz, valoarea care se determina de catre
subalgoritm este atribuita numelui funct iei.
Exemplu:
ArieCerc(r)
ArieCerc = r r
Return
Apelul unui astfel de subalgoritm se face la fel ca mai nainte.

In plus, val-
oarea returnata poate folosita ntro expresie sau ntro atribuire:
STotal = ArieCerc(10) 5

In continuare vom folosi o varianta speciala a interclasarii numita Inter-


clas(A, p, q, r). Acest algoritm interclaseaza elementele A(p), . . . , A(q) cu
elementele A(q + 1), . . . , A(r) si pune rezultatul n locul A(p), . . . , A(r).
Interclas(A, p, q, r)
k = 0
i = p
j = q + 1
repeta
k = k + 1
daca A(i) < A(j) atunci
C(k) = A(i)
i = i + 1
altfel
C(k) = A(j)
1
Corespunde n limbaje de programare la cazul n care transmiterea parametrilor se
face prin adresa.
26
j = j + 1
sf arsit daca
pana cand i > q sau j > r
Ciclul de mai jos poate sa nu se execute nici o data
pentru il = i, q
k = k + 1
C(k) = A(il)
sfarsit pentru
Ciclul de mai jos poate sa nu se execute nici o data
pentru jl = j, r
k = k + 1
C(k) = A(jl)
sfarsit pentru
Din cele doua cicluri pentru de mai sus, se executa exact unul singur
Aici se reface bucata din A de la A(p) la A(r)
k = 0
pentru i = p, r
k = k + 1
A(i) = C(k)
sfarsit pentru
Return
Asa cum am precizat la nceputul acestui capitol algoritmul sortarii prin
interclasare Intersort se bazeaza pe metoda divide et impera, ai carei pasi
au fost deja prezentat i. Evident iem n continuare pasii acestui algoritm:
1.

Imparte sirul init ial n doua siruri
2. Rezolva (recursiv) ecare din cele doua subprobleme
3. Combina (interclaseaza) cele doua subsiruri sortate pentru a obt ine
sirul sortat
Exemplu: e sirul: 10 2 7 3
1. mpart ire: 10 2 7 3
2. sortare (recursiv)
(a) mpat ire: 10 2
(b) Sortarea este evidenta, ecare parte avand cate un element
(c) interclasare 2 10
27
(a) mpat ire: 7 3
(b) Sortarea este evidenta, ecare parte avand cate un element
(c) interclasare 3 7
3. interclasare: 2 3 7 10
Algoritmul va :
Intersort(A, p, r)
daca p < r atunci
q =
_
p+r
2

partea ntreaga
q este indicele elementului de la jumatatea sirului
cheama Intersort(A, p, q)
cheama Intersort(A, q + 1, r)
cheama Interclas(A, p, q, r)
sfarsit daca
Return
Acest algoritm poate folosit de exemplu astfel:
Start Sortare
citeste( n, (A(i), i = 1, n) )
cheama Intersort(A, 1, n)
scrie( Sirul sortat este: , (A(i), i = 1, n) )
Stop
Observat ii:
1. Sortarea consta de fapt din interclasarea perechilor de siruri de un
element, de doua elemente, . . . , pana cand interclasam o pereche de
siruri de
n
2
elemente, obt inand sirul sortat.
2. Daca la un moment dat un sir are un numar impar de elemente, atunci
se vampart i n doua subsiruri de dimeniuni care difera printr-o unitate
(subsirurile sunt cat mai echilibrate ca numar de elemente).
Vericat i execut ia algoritmului pentru sirul 3 2 5 6 4 1 0 7
Notat ia asimptotica
Pentru a vedea cum se comporta timpul de execut ie al unui algoritm
pentru intrari mari vom deni funct iile , , O.
Spunem ca T(n) = (f(n)) daca N, c
1
, c
2
> 0 astfel ncat:
0 < c
1
f(n) < T(n) < c
2
f(n), n > N (3.1)
28
Spunem ca T(n) = (f(n)) daca N, c
1
> 0 astfel ncat:
0 < c
1
f(n) < T(n), n > N (3.2)
Spunem ca T(n) = O(f(n)) daca N, c
1
> 0 astfel ncat:
T(n) < c
1
f(n), n > N (3.3)
Lasam n seama cititorului sa demonstreze proprietat ile de mai jos.
Fie F , , O. Atunci:
1. Tranzitivitate:
T(n) = F(f(n)) si f(n) = F(g(n)) T(n) = F(g(n))
2. Reexivitate:
T(n) = F(T(n))
3. Simetrie:
f(n) = (g(n)) g(n) = (f(n))
4. Bisimetrie:
f(n) = O(g(n)) g(n) = (f(n))
f(n) = (g(n)) g(n) = O(f(n))
5. Daca
M astfel ncat g(n) > f(n), n > M
atunci
(f(n) +g(n)) = (g(n))
6. T(n) = (f(n)) T(n) = O(f(n)) si T(n) = (f(n))
7. (cf(n)) = (f(n)), c constanta > 0
Aplic and proprietat ile 1-7 se demonstreaza imediat urmatoarele:
1. T(n) = a n
2
+b n +c T(n) = (n
2
)
2. T(n) = c
1
n log n +c
2
n +c
3
T(n) = (n log n)
29
Din cele de mai sus, precum si analiza facuta la algoritmul de sortare prin
insert ie rezulta ca complexitatea acestuia este T(n) = O(n
2
) si T(n) = (n).
Calculul complexitat ii algoritmului de sortare prin interclasare se efectueaza
mai jos.
Cand un algoritm cont ine o apelare a lui nsusi se numeste recursiv.

In
acest caz timpul de execut ie se descrie printr-o ecuat ie recursiva. Pentru
rezolvarea unei asemenea ecuat ii vom folosi metode matematice care vor
descrise n capitolul dedicat metodei Divide et impera.
Ne vom limita acum la a scrie recurent a pentru sortare prin interclasare.
Daca timpul pentru un sir cu n elemente este T(n), atunci timpul pentru
sirul cu
n
2
elemente va T
_
n
2
_
, deci:
T(n) =
_
a , daca n = 1
2 T
_
n
2
_
+c n , daca n > 1

In capitolul 8 vom demonstra ca T(n) = (nlog


2
n). Deci complexitatea
algoritmului Mergesort este (nlog
2
n).

In nal, deducem ca complexitatea algoritmului de sortare prin insert ie


(O(n
2
)) este mai mare decat cea a algoritmului Mergesort ((nlog
2
n)), altfel
spus Mergesort este mai performant decat sortarea prin insert ie.
Rezumat
Pentru compararea a doi algoritmi, cel mai utilizat criteriu este cel al
timpului de execut ie relativ la dimensiunea datelor de intrare. Calculul com-
plexitat ii unui algoritm este o etapa obligatorie a solut iei acestuia. Pentru
exprimarea complexitat ii se folosesc notat iile O(), (), () care sunt legate
de viteza de variat ie a timpului cerut pentru rezolvarea unei instant e, n
funct ie de dimensiunea intrarii si care sunt cu atat mai corecte cu cat n este
mai mare.
Subalgoritmii sunt o modalitate de a concepe blocuri de cod parame-
trizate, apelabile prin intermediul unei interfet e (liste de parametri de apel).
Ele efectueaza prelucrari asupra datelor transmise, rezultatul returnat ind
folosit mai apoi de algoritmul apelant. De asemenea, reprezinta o forma de
abstractizare, utilizata n toate paradigmele de programare.
Exercit ii (rezolvarile la pagina 157)
1. Determinat i complexitatea algoritmilor din capitolul 2.
30
2. Se deneste produsul scalar a doi vectori A si B, de aceeasi dimensiune
n cu formula PS =
n

i=1
A(i) B(i). Sa se scrie algoritmul pentru calculul
produsului scalar.
3. Se da n, vectorul A(i), i = 1, n si un numar x. Sa se scrie un algoritm
care gaseste indicele j pentru care A(j) = x (problema cautarii).
4. Cum se modica algoritmul de mai sus daca stim ca vectorul este sortat
crescator?
5. Se dau n si vectorul A(i), i = 1, n. Sa se gaseasca cel mai mic element.
6. Reluat i problema anterioara n situat ia n care trebuie sa aat i cate el-
emente minime sunt.

Incercat i sa rezolvat i problema folosind o singura
parcurgere a sirului.
7. Se dau n si vectorul A(i), i = 1, n. Ce numar apare cel mai des si de
cate ori?
8. Cum se modica algoritmul de mai sus daca vectorul este sortat crescator?
9. Se dau n, ((A(i, j), j = 1, n), i = 1, n) (A este o matrice patratica, cu
n linii si n coloane). Sa se calculeze produsul elementelor diferite de 0:
(a) din toata matricea;
(b) de pe diagonala principala;
(c) de sub diagonala principala.
31
32
Capitolul 4
Structuri elementare de date
Obiective
Am folosit, pana acum, structuri de date foarte simple cum ar :
variabile simple (dintre care unele aveau domeniul de valori format doar
din doua valori)
vectori cu componente sortate sau nesortate (asa cum sunt folosit i n
matematica)
matrici considerate ca vectori de vectori sau ca masive biortogonale
Vom studia acum alte structuri de date necesare n algoritmii ulteriori: lista,
stiva, coada, arborii binari, mpreuna cu diferite forme de reprezentare a
acestora.
Structuri liniare
O structura liniara este o mult ime de n 0 componente x(1), x(2), . . . x(n)
cu proprietat ile:
1. cand n = 0 spunem ca structura este vida;
2. daca n > 0 atunci x(1) este primul element iar x(n) este ultimul ele-
ment;
3. oricare ar x(k) unde k 2, . . . , n1 exista un predecesor x(k 1)
si un succesor x(k + 1).
Ne va interesa sa executam cu aceste structuri urmatoarele operat ii:
33
- adaugarea unui element;
- extragerea unui element;
- accesarea unui element x(k) din structura;
- combinarea a doua sau mai multe structuri ntr-una singura;
- ruperea unei structuri n mai multe structuri;
- sortarea elementelor unei structuri;
- cautarea unui element al structurii care are anumite proprietat i;
- operat ii specice
Stiva
Una din cele mai cunoscute structuri liniare este stiva. O stiva este car-
acterizata prin disciplina de intrare si de iesire. Sa consideram o mult ime
de cart i puse una peste alta ntr-o cutie stramta; exista o prima carte care
se poate lua foarte usor (TOP) si o carte carte care se poate lua numai daca
se nlatura toate celelate cart i (BOTTOM).
Disciplina unei stive este ultimul intrat, primul iesit (disciplina care nu
v-ar place sa e respectata cand stat i la rand la lapte!), prescurtat LIFO
(Last In, First Out).
Diferent ele fat a de un vector sunt:
- un vector are o lungime xa, nonzero, cunoscuta aprioric;
- o stiva poate vida;
- stiva are un numar variabil de elemente n timpul execut iei unui algo-
ritm
Se pune problema reprezentarii concrete a unei stive n memoria unui calcu-
lator. Putem aloca o stiva n doua moduri:
1. Secvent ial
2.

Inlant uit
34
Alocarea secvent iala a stivei
Folosim vectorul ca ind structura cea mai apropiata de structura reala
a memoriei.

In vectorul (x(i), i = 1, n) consideram:
x(1) x(2) x(3) . . . x(k) . . . x(n)

BOTTOM TOP
adica din cele n componente ale unui vector doar primele k elemente fac parte
din stiva.
Algoritmul de intrare n stiva este:
a Stiva
daca k = n atunci
Depasire
altfel
k = k + 1
x(k) = a
sfarsit daca
Return
Algoritmul de iesire (scoatere) din stiva este:
a Stiva
daca k = 0 atunci
Stiva vida
altfel
a = x(k)
k = k 1
sfarsit daca
Return
Alocarea nlant uita a stivei

In alocarea nlant uita ecare element al structurii este nsot it de adresa


de memorie la care se aa precedentul element. Vom folosi semnul * cu sensul
nici o adresa de memorie. Vom avea varful stivei pus n evident a (ancorat)
n INC si elementul de la baza stivei va cont ine n campul LEG adresa *
(adica nici o adresa), ca n gura:
INFO LEG
INC x(k) x(k 1) . . . x(2) x(1) *
35
(ordinea 1, 2, . . . k este ordinea intrarii n stiva).

In acest caz intrarea n stiva va folosi stiva de locuri libere


1
(aceasta stiva
se numeste LIBERE), pentru a obt ine noi locuri la introducerea n stiva.
Vom prezenta n continuare algoritmii de intrare/iesire dintr-o stiva n
cazul n care alocarea ei a fost nlant uita.
Algoritmul de intrare n stiva este:
a Stiva
a este informat ia introdusa n stivca
y LIBEREalocare de memorie pentru elementul nou
INFO(y) = a
LEG(y) = INC
INC = y
Return
La nceput, INC =*, stiva necont inand nici un element.
Algoritmul de iesire din stiva este:
a Stiva
a este informat ia extrasa din varful stivei nevide
daca INC =* atunci
Stiva este vida
altfel
a = INFO(INC)
aux = INC
INC = LEG(INC)
aux LIBEREEliberarea spat iului de memorie
sfarsit daca
Return
Coada
O alta structura de date folosita n conceperea algoritmilor este coada.
O coada este caracterizata si ea de o disciplina de intrare/iesire, binent eles
diferita de cea a stivei. De data aceasta putet i sa va gandit i la coada la lapte:
primul care s-a asezat la coada va primul servit, adica primul care iese din
coada.
Disciplina unei cozi este deci primul venit, primul plecat (rst in, rst
out - FIFO).
1
Cunoscuta n cadrul limbajelor de programare drept heap; obt inerea de memorie se
face prin alocare dinamica, eliberarea ei prin dealocare.
36
O coada poate vida si are si ea un numar variabil de elemente n timpul
execut iei unui algoritm.
Alocarea secvent iala a cozii
Coada alocata secvent ial si va gasi locul tot ntr-un vector (x(i), i = 1, n):
x(1) x(2) . . . x(F) . . . x(S) . . . x(n)

FAT

A SF

ARSIT
Din cele n componente ale vectorului, doar componentele x(F), . . . , x(S)
fac parte din coada.
Algoritmul de intrare n coada este:
a Coada
daca S = n atunci
Depasire
altfel
S = S + 1
x(S) = a
sfarsit daca
Return
Algoritmul de iesire din coada este:
a Coada
daca F > S atunci
Coada este vida
altfel
a = x(F)
F = F + 1
sfarsit daca
Return
Se poate imagina usor ca procedand n acest mod (scot and din fat a si in-
troducand la sfarsit), coada migreaza spre dreapta si poate sa ajunga n
situat ia de depasire cand de fapt mai exista mult loc gol (n vectorul x) pe
primele pozit ii. Apare astfel ideea de a folosi elementele vectorului ca si cum
ar dispuse circular, precum n gura 4.1, pagina 38.
Lasam n seama cititorului sa scrie algoritmii de intrare/iesire din coada
circulara.
37
Figura 4.1: Coada circulara
Alocarea nlant uita a cozii
Alocareanlant uita se face similar cu alocareanlant uita a stivei n noduri
de tipul:
INFO LEG
x(F) . . . x(S) *

FAT

A SF

ARSIT
Algoritmul de intrare n coada este:
a Coada
y LIBERE
INFO(y) = a
LEG(y) =
daca FAT

A=* atunci
Coada este vida
FATA=y
altfel
LEG(SF

ARSIT)=y
sfarsit daca
SF

ARSIT=y
Return
Init ial, coada este vida, i.e. FAT

A=SF

ARSIT=*.
Algoritmul de iesire din coada este:
a Coada
daca FATA=* atunci
Coada este vida
altfel
a = INFO(FATA)
aux =FATA
FATALEG(FATA)
aux LIBERE
sfarsit daca
Return
38
Arbori binari
Un arbore n care orice varf (nod) are 0, 1 sau 2 descendent i se numeste
arbore binar. Un arbore binar care are varfuri cu 0 sau 2 descendent i se
numeste arbore binar strict. Un astfel de arbore se poate folosi, de exemplu,
la reprezentarea n memorie a unei expresii aritmetice.
Exemplu: expresia
(a +b) c
2
c
3
se va reprezenta astfel:
Figura 4.2: Arborele binar atasat expresiei aritmetice (a+b) c
2
c
3
. Semnul
este reprezentare pentru operatorul de ridicare la putere.
Frunzele acestui arbore (nodurile fara descendent i) cont in operanzii, iar
celelalte noduri cont in operatorii. Deoarece nu toate operat iile sunt comu-
tative, este foarte important daca un nod este descendent pe stanga sau pe
dreapta. Radacina unui arbore este nodul care nu este descendentul nimanui.
Alocarea unui arbore binar se poate face:
- secvent ial
- nlant uit
- mixt
Alocarea secvent iala a unui arbore binar

In vectorul (x(i), i = 1, n) vom avea urmatoarele reguli:


- radacina este n x(1);
- pentru ecare nod x(i), descendentul sau din stanga este x(2 i) iar cel
din dreapta este x(2 i + 1);
- daca nu exista descendent, se pune *.
Reprezentarea secvent iala a arborelui din gura 4.2 este:
- / + c 2 a b * * * * c 3 * * . . . *
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 . . . 31
39
Observat ie: Pozit iile x(10), . . . x(13), x(16), . . . x(31) cont in *.
Vom volosi aceasta alocare n capitolul destinat sortarii pentru a construi
o structura de date asemanatoare, numita HEAP
2
.
Alocarea nlant uita a unui arbore binar

In acest caz se folosesc noduri de forma INFO LS LD , unde LS


si LD cont in adresele de memorie ale nodurilor descendent stang, respectiv
descendent drept. Reprezentarea nlant uita a arborelui din gura 4.2 este
data n gura 4.3.
Figura 4.3: Alocarea nlant uita pentru arborele din gura 4.2.
Alocarea mixta a unui arbore binar
La acest tip de alocare se folosesc trei vectori INFO, LS, LD unde LS(i)
si LD(i) cont in indicii unde se aa memorat i descendentul stang, respectiv
descendentul drept ai nodului i.
Reprezentarea mixta a arborelui din gura 4.2 este data n gura 4.4.
INFO LS LD
1 - 2 3
2 4 5
3 / 6 7
4 + 8 9
5 c * *
6 2 * *
7 10 11
8 a * *
9 b * *
10 c * *
11 3 * *
Figura 4.4: Alocarea mixta pentru arborele din gura 4.2.
La arborii binari ne intereseaza problema parcurgerii lor. T inem cont de
faptul ca:
2
A nu se confunda cu heapul pomenit n nota de subsol de la pagina 36
40
- arborele binar se deneste recursiv ca: radacina, subarbore stang, sub-
arbore drept (ecare subarbore este la randul lui un arbore binar, posi-
bil vid);
- la parcurgere mai ntai va subarborele stang naintea celui drept.
Dupa pozit ia radacinii (R) relativ la subarborele stang (S) si subarborele
drept (D), avem urmatoarele trei tipuri de parcurgeri ale unui arbore binar:
1. postordine (SRD);
2. preordine (RSD)
3. inordine (SRD)
Exemple de parcurgeri:
1. Parcurgerea arborelui din gura 4.2 n preordine:
- + a b c / 2 c 3
Acesta scriere se numeste scriere poloneza prexata a unei expresii ar-
itmetice.
2. Parcurgerea arborelui din gura 4.2 n inordine:
a + b c - 2 / c 3
3. Parcurgerea arborelui din gura 4.2 n postordine:
a b + c 2 c 3 / -
Acesta scriere se numeste scriere poloneza postxata a unei expresii
aritmetice.
Dam n continuare algoritmul iterativ pentru parcurgerea n preordine a
unui arbore binar. Vom avea nevoie de o STIV

A care va cont ine nodurile


succesive parcurse pe stanga care urmeaza sa e parcurse si pe dreapta;
radacina arborelui se aa n rad.
Preordine iterativ(rad)
STIV A = STIVA este vida
nodCurent = rad
maiAmNoduri = adevarat
repeta
41
parcurgPeStanga = adevarat
repeta
daca nodCurent ,= atunci
scrie( INFO(nodCurent) )
parcurgere pe stanga
nodCurent STIV A
nodCurent = LS(nodcurent)
altfel
parcurgPeStanga = fals
sfarsit daca
pana cand parcurgPeStanga = fals
parcurgere pe dreapta
daca STIV A = atunci
maiAmNoduri = fals
altfel
nodCurent STIV A
nodCurent = LD(nodCurent)
sfarsit daca
pana cand maiAmNoduri = adevarat
Return
Se pot da algoritmi iterativi si pentru celelalte doua parcurgeri (vezi prob-
lema 2 de la exercit ii). De asemenea se pot da algoritmi recursivi pentru
parcurgeri, mai usor de nt eles, dar ceva mai inecient i (a se vedea capitolul
5, problema 6).
Rezumat
Pentru prelucrarea datelor se folosesc diferite structuri adecvate: liste,
stive, cozi, arbori (sunt cele mai des utilizate, dar mai multe vor stu-
diate ntrun curs dedicat de structuri de date). Exista diferite tipuri de
reprezentari ale acestor structuri: pe baza de tablouri, folosind alocarea di-
namica, sau o varianta mixta (la arbori). Stiva si coada au politici specice
de acces, iar arborele poate parcurs n moduri diferite pentru procesarea
datelor.
Exercit ii (rezolvarile la pagina 167)
1. Scriet i algoritmii de intrare/iesire din coada circulara.
42
2. Scriet i algoritmii iterativi pentru parcurgerea arborilor binari n inor-
dine si postordine.
3. Se da o stiva alocata nlant uit si o valoare x. Sa se extraga din stiva,
daca exista, elementul cu INFO = x.
4. Se da o stiva si o valoare x. Sa se introduca n stiva dupa elementul cu
INFO = x un element cu INFO = y.
5. Sa se implementeze o coada folosind doua stive. Sa se analizeze com-
plexitatea.
6. Sa se implementeze o stiva prin doua cozi. Sa se analizeze complexi-
tatea.
43
44
Capitolul 5
Recursivitate
Obiective
Capitolul detaliaza modul de lucru al unui subalgoritm recursiv. Este
dat un exemplu simplu de algoritm recursiv, pentru care se descriu toate
informat iile care se depun pe stiva la execut ia lui. Explicat iile date sunt
aplicabile pentru orice caz de recursivitate.
Prezentare generala
Recursivitatea reprezinta un mod de elaborare a algoritmilor, caracterizat
prin faptul ca un subalgoritm se apeleaza pe el nsusi (direct sau indirect).
Ea a aparut din necesitat i practice, permit and implementarea unei funct ii
matematice recursive. Nu reprezinta o modalitate mai puternica sau mai
slaba din punct de vedere al rezultatelor ce se pot obt ine comparativ cu
metodele iterative; sa demonstrat ca aceste doua abordari sunt egale ca si
putere de calcul. Algoritmii recursivi nu sunt mai rapizi decat algoritmii
iterativi echivalent i, dar uneori sunt mai expresivi si mai usor de ntret inut
(modicat).
Pentru nt elegerea algoritmilor recursivi, este esent iala nt elegerea lucru-
lui cu stiva.

Inainte de a se efectua un apel de subalgoritm (recursiv sau nu),
se salveaza pe stiva adresa de memorie a instruct iunii de la care se va con-
tinua execut ia dupa ntoarcerea din apel. La intrarea ntrun subalgoritm se
rezerva spat iu pe stiva pentru parametrii transmisi si pentru variabilele care
au fost declarate n subalgoritm (variabile locale). La iesirea din apel, stiva
se elibereaza de informat ia depusa la intrarea n apel, iar adresa urmatoarei
instruct iuni ce se va executa se preia de pe varful stivei (si de asemenea
aceast a informat ie va scoasa de pe stiva).
45
Exemplu: urmatorul program nu are o utilitate zdrobitoare, dar ilustreaza
cele spuse mai nainte. Pentru a simplica expunerea, vom considera ca
transmiterea parametrilor se face prin valoare (pe stiva se copiaza valorile
parametrilor) si nu prin adresa (cand pe stiva se copiaza adresa de memorie
a parametrilor efectivi) - a se vedea convent ia de la pagina 26.

In cazul
exemplului de mai jos, ntrucat n corpul subalgoritmului nu se modica
valoarea lui n, rezultatul ar acelasi indiferent de convent ia de apel.
Start Exemplu
citeste( n )
Recursiv(n)

scrie( Sfarsit )
Stop
Recursiv(n)
i = 2 ni este variabila locala, alocata n subalgoritmul Recursiv
daca n = 0 atunci
Return
altfel
Recursiv(n 1)

i = i + 1
scrie( i )
sfarsit daca
Return
Ca si comentarii sunt trecute niste adrese la care se presupune a se aa
instruct iunile corespunzatoare. Sa presupunem ca se va citi n = 2. Evolut ia
stivei programului este:


Inainte de apelul Recursiv(2) din algoritmul Exemplu se scrie pe stiva
adresa de memorie a instruct iunii care se va executa dupa ce se va
reveni din acest apel (n cazul nostru instruct iunea de scriere cu adresa
):
adr = n = 2
Se apeleaza Recursiv(2);
Se calculeaza i = 2 n = 4,
Se face testarea n = 0; deoarece este condit ia nu este ndeplinita, se
intra pe ramura altfel.
Avem din nou apel: nainte de acesta se salveaza adresa de memorie
46
a instruct iunii de la care se va continua execut ia (incrementarea de la
adresa ):
adr = n=2 i=4
adr = n = 2
Se intra n Recursiv(1);
Se calculeaza i = 2 n = 2
Se face testarea n = 0; deoarece este condit ia nu este ndeplinita, se
intra pe ramura altfel.
Avem din nou apel: nainte de acesta se salveaza adresa de memorie
a instruct iunii de la care se va continua execut ia (incrementarea de la
adresa ):
adr = n = 1 i = 2
adr = n=2 i=4
adr = n = 2
Se intra n apelul Recursiv(0);
Se calculeaza i = 2 n = 0
Se face testarea n = 0; deoarece este condit ia ndeplinita, se intra pe
ramura atunci, care reprezinta ntoarcere la metoda Recursiv(1).
La ntoarcerea din Recursiv(0) n Recursiv(1), se scoate de pe stiva
informat ia care a fost depusa datorita apelului Recursiv(0), revenindu
se la forma de dinainte de efectuarea acestui apel:
adr = n = 2 i = 4
adr = n = 2
S-au scos din stiva adr = , n = 1, i = 2.
Deci instruct iunea de la care se va continua execut ia este de la adresa
, care a fost scoasa de pe stiva.
Suntem n Recursiv(1).
Execut ia se continua de la instruct iunea cu adresa (conform punctului
precedent), deci i ia valoarea 2+1 (valoareal 2 din suma ind datorata
informat iei i = 2 de pe stiva), care se aseaza.
Datorita instruct iunii de retur nale din subalgoritmul Recursiv, avem o
ntoarcere de la Recursiv(1) la Recursiv(2). Se scot din stiva informat iile
47
i = 2, n = 1, adr = si se continua execut ia de la instruct iunea cu
adresa : Stiva ramane:
adr = n = 2
Suntem n Recursiv(2). Execut ia se continua de la instruct iunea cu
adresa , deci i ia valoarea 4 + 1 (valoarea 4 din suma ind datorata
informat iei i = 4 de pe stiva), care se aseaza.
Datorita instruct iunii de retur nale din subalgoritmul Recursiv, avem
o ntoarcere de la Recursiv(2) la Exemplu. Se scot din stiva informat iile
n = 2, adr = si continuarea execut iei se va face de la instruct iunea
cu adresa . Stiva va vida.
Se executa instruct iunea cu adresa : Scrie(Sfarsit).
Se termina algoritmul Exemplu, iar stiva este vida.

In cazul unei im-
plementari, controlul ar preluat de catre sistemul de operare.
Algoritmul a asat valorile 3, 5. Evident, acest lucru se putea face mult mai
simplu printro iterat ie; dar exemplul de fat a a dorit sa ilustreze funct ionarea
unui apel recursiv. Datorita operat iilor de curat are a stivei (care se efectueaza
printro simpla incrementare sau decrementare a valorii dintrun registru al
microprocesorului), precum si datorita informat iilor repetate care se salveaza
pe stiva (n, i, adr), timpul si spat iul de memorie necesar sunt mai mari decat
pentru variantele iterative. Totusi, n destul de multe cazuri implementarile
recursive sunt mult mai usor de urmarit si de nt eles decat cele iterative.
O observat ie importanta: programatorul este singurul raspunzator de
faptul ca programul lui se termina. Altfel spus, trebuie mare atent ie la
impunerea unei condit ii de terminare a recursivitat ii (n cazul nostru, testarea
pentru n = 0).

In caz contrar, un astfel de algoritm implementat va epuiza
spat iul disponibil pentru stiva si se va opri fara a rezolva problema (apel
recursiv la innit).
Daca revenim la convent ia ca transferul parametrilor sa se faca prin
adresa, atunci pe stiva, n cadul ecarui subalgoritm apelat, n loc de valoarea
lui n sar depus adresa de memorie rezervata n cadrul algoritmului (la noi:
adresa bazei stivei).

In acest fel, orice modicare care sar face asupra para-
metrului n din subalgoritmul Recursiv s-ar face de fapt (via aceasta adresa
pusa pe stiva) asupra valorii lui n din algoritmul Exemplu. Majoritatea lim-
bajelor (Pascal, C/C++, C#, PL/SQL) au mecanisme prin care se poate
stabili daca pe stiva se depune o valoare (copia valorii parametrului efectiv)
sau o adresa de memorie (adresa la care este stocat parametrul efectiv).
48
Exemple
Calculul lui n!
Pentru un n natural, denim valoarea n! n mod recursiv astfel:
n! =
_
1, pentru n = 0
n (n 1)!, pentru n > 0
(5.1)
Algoritmul recursiv este urmatoarea:
Start FactRec
citeste( n )
scrie( Fact(n) )
Stop
unde subalgoritmul Fact are forma:
Fact(n)
daca n = 0 atunci
Fact = 1
altfel
Fact = n Fact(n 1)
sfarsit daca
Return
Complexitatea algoritmului este data de ecuat ia recursiva T(n) = T(n
1) + c, c ind o constanta datorata apelului recursiv (operat iei cu stiva) si
nmult irii, pentru care solut ia este T(n) = (n) (pentru rezolvarea recurent ei
anterioare, a se vedea anexa A). Varianta iterativa este de aceeasi complex-
itate teoretica, dar mai rapida n practica.
Sirul lui Fibonacci
Sirul lui Fibonacci se deneste astfel:
f(n) =
_
_
_
0, n = 0
1, n = 1
f(n 1) +f(n 2), n 2
(5.2)
Vom implementa recursiv acest algoritm:
Start FiboRec
citeste( n )
scrie( Fibo(n) )
Stop
unde algoritmul recursiv Fibo este:
49
Fibo(n)
daca n = 0 sau n = 1 atunci
Fibo = n
altfel
Fibo = Fibo(n 1) +Fibo(n 2)
sfarsit daca
Return
Complexitatea teoretica este data de ecuat ia recursiva T(n) = T(n 1) +
T(n 2) + c, care duce la T(n) = (
n
), unde =
1+

5
2
(taietura de
aur)(a se vedea Anexa A) . Complexitatea exponent iala mare este datorata
faptului ca se calculeaza de mai multe ori aceleasi valori: de exemplu, n
f(n) = f(n 1) + f(n 2), f(n 2) este apelat atat pentru calculul lui
f(n 1), cat si pentru cel de al doilea membru al part ii drepte a ecuat iei
anterioare. Redundant a de calcul devine tot mai accentuata pentru valori
mici ale argumentului.
Sa vedem o implementare iterativa:
Start FiboIter
citeste( n )
f(0) = 0
f(1) = 1
pentru i = 2, n
f(i) = f(i 1) +f(i 2)
sfarsit pentru
scrie( f(n) )
Stop
Complexitatea algoritmului anterior este evident (n). Acest fapt se da-
toreaza memorarii valorilor lui f si evitarii calculului repetat (can algoritmul
precedent).
Rezumat
Scrierea recursiva a algoritmilor este deseori mai usoara decat cea it-
erativa.

In esent a, orice apel de subalgoritm (recursiv sau nu) determina
depunerea unor informat ii pe o stiva gestionata automat. Codul rezultat
este mai scurt si mai usor de depanat; nsa o implementare recursiva poate
duce la o complexitate crescuta, datorita rezolvarii n mod repetat a acelorasi
probleme, deci este necesara de ecare data o analiza pertinenta a com-
plexitat ii (un exemplu relevant este dat n cele doua implementari pentru
calculul sirului lui Fibonacci de mai sus).
50
Exercit ii (rezolvarile la pagina 172)
1. Sa se calculeze recursiv maximul unui sir.
2. Sa se calculeze recursiv suma elementelor dintrun sir.
3. Sa se calculeze puterea a na a unui numar real a, cu o complexitate
mai buna decat (n).
4. Sa se dea un contraexemplu pentru care algoritmul de la 3 nu da
numarul optim de nmult iri.
5. Sa se scrie un algoritm care calculeaza termenul fibo(n) al sirului Fi-
bonacci n timp mai bun de (n) (a se veda si problema 3).
6. Sa se dea algoritmi recursivi pentru parcurgerea n preordine, postor-
dine, inordine a unui arbore binar.
51
52
Capitolul 6
Metoda Backtracking
Obiective
Acest capitol introduce una din cele mai generale modalitat i de rezolvare
a problemelor: metoda Backtracking. Ea duce la scrierea unor algoritmi care
evita generarea tuturor combinat iilor posibile si apoi la validarea rezultatelor.
Este prezentata schema generala de algoritm backtracking si probleme clasice
pentru a caror rezolvare se foloseste aceasta abordare.
Prezentare generala
Metoda Backtracking se poate aplica algoritmilor care trebuie sa constru-
iasca o solut ie de forma
x = (x(1), x(2), . . . , x(n)) (6.1)
unde pentru orice i 1, 2, . . . , n, x(i) A
i
, A
i
ind o mult ime data ca
informat ie de intrare si unde, n plus, componentele lui x trebuie sa mai
satisfaca niste condit ii interne.
Exemplu: sa consideram:
A
1
= A, B, E
A
2
= A, C
A
3
= U, S, E, C
Cerint e:
1. Sa se construiasca cuvintele care au prima litera din A
1
, a doua litera
din A
2
, a treia litera din A
3
si care respecta condit iile interne de la 2;
53
2.

In plus, se cere respectarea urmatoarelor condit ii interne:
(a) Nu sunt doua litere consecutive egale;
(b) Nu sunt formate numai din consoane sau numai din vocale.
Daca luam n considerare numai cerint a de la 1, obt inem solut iile admisi-
bile ale problemei, de exemplu (AAU), (ACS), (EAU), (BAU), (BCC), . . . .
Dar (AAU), (BCC) nu respecta condit iile interne 2a, iar (EAU) nu respecta
condit ia 2b.
O metoda de rezolvare a acestei probleme ar sa construim mai ntai
toate solut iile admisibile si apoi sa vericam care dintre ele respecta condit iile
interne. Acest mod de a aborda problema duce, n exemplul nostru, la 324 =
24 de solut ii din care evident cele carencep cu AA, de exemplu, nu sunt bune.
Daca mult imile A
1
, A
2
, . . . , A
n
au respectiv k
1
, k
2
, . . . , k
n
elemente, atunci
am avea n total k
1
k
2
. . . k
n
solut ii admisibile. Pentru k
1
= k
2
= = k
n
=
m avem m
n
solut ii admisibile, deci un algoritm de tip brute force care ia n
considerare toate posibilitat ile ar avea o complexitate exponent iala.
Algoritmul de tip backtracking urmareste micsorarea numarului de ope-
rat ii, dar trebuie sa spunem ca ramane de complexitate exponent iala. Acest
algoritm urmareste sa genereze cate o componenta x(k) A
k
cat timp mai
are o componenta netestata din A
k
; daca nu mai are componente netestate,
se revine la alegerea elementului de pe pozit ia anterioara x(k 1), altfel se
merge la componenta x(k + 1). In felul acesta s-ar genera toata mult imea
solut iilor admisibile; dar daca dupa ce am gasit o componenta x(k) testam
daca bucata de vector (x(1), x(2), . . . , x(k)) generata pana atunci satisface
condit iile de continuare derivate din condit iile interne, atunci vom putea sa
nu permitem generarea inutila a unor solut ii care oricum nu ar bune (n
exemplul nostru (AA )).
Trebuie sa mai subliniem ca simplul fapt ca bucata (x(1), x(2), . . . x(k))
din vectorul x satisface condit iile de continuare nu nseamna ca o sa gasim,
obligatoriu, o solut ie a problemei (exista, totusi, o metoda care gaseste solut ia
pas cu pas, fara revenire, numita Greedy; ea va prezentata mai tarziu).
Schema algoritmului general va :
Backtracking(A, n)
k = 1
c at timp k > 0
daca k = n + 1 atunci
scrie( (x(i)), i = 1, n )s-a generat o solut ie
k = k 1
altfel
daca mai exista valori netestate a A
k
atunci
54
x(k) = a
daca (x(1), x(2), . . . , x(k)) satisface condit iile de continuare atunci
k = k + 1
sfarsit daca
altfel
k = k 1
sfarsit daca
sfarsit daca
sfarsit cat timp
Return
Exemplu
Vom utiliza acest model la construirea unui algoritm pentru problema
asezarii damelor pe tabla de sah astfel ncat oricare doua dame sa nu se
atace (2 dame se ataca daca sunt pe aceesi linie, coloana, diagonala).
Vom considera mult imile (A
i
)
i=1,n
ca ind pozit iile (de la 1 la n) pe care
le poate ocupa o dama pe linia i. Evident ca de data aceasta toate mult imile
A
i
sunt egale.
Deci o congurat ie pe o tabla de n = 5 precum mai jos va simbolizata
de vectorul solut ie x = (1, 3, 5, 2, 4) si se poate vedea can acest caz condit iile
interne sunt respectate (oricare doua dame nu se bat).


Algoritmul pentru n > 4 este:
Dame(n)
pentru i = 1, n
x(i) = 0init ial pe nici o linie nu avem pozit ionata nici o regina
sfarsit pentru
k = 1
cat timp k > 0
daca k = n + 1 atunci
scrie( (x(i)), i = 1, n )
k = k 1
altfel
x(k) = x(k) + 1
55
daca x(k) n atunci
daca DispunereCorecta(x, k)=adevarat atunci
k = k + 1
sfarsit daca
altfel
x(k) = 0 Nu avem nici o regina pe aceasta linie
k = k 1 Ne ntoarcem la regina de pe pozit ia anterioara
sfarsit dacax(k) n
sfarsit daca k = n + 1
sfarsit cat timp
Return
DipunereCorecta(x, k) testeaza daca condit iile de continuare pentru bucata
x(1), . . . , x(k) sunt ndeplinite; returnaza adevarat daca nu avem regine care
se ataca, fals n caz contrar.
DispunereCorecta(x, k)
corect = adevarat presupunem init ial ca nu avem nici un atac ntre regina
k si cele dispuse anterior
pentru i = 1, k 1
daca x(k) = x(i) sau [x(k) x(i)[ = k i atunci
sunt pe aceeasi coloana sau pe aceeasi diagonala
corect = fals
sfarsit daca
sfarsit pentru
DispunereCorecta = corect
Return
Rezumat
Multe probleme cer generarea uneia/mai multora/tuturor solut iilor care
respecta anumita cerint e. O abordare de tipul genereaza toate combinat iile,
apoi ret inele pe cele valide (bruteforce) este posibila, dar si inecienta.
Metoda backtracking urmareste depistarea cat mai devreme cu putint a a
solut iilor care sunt invalide (pe masura ce componentele lor se genereaza).
Desi algoritmii care rezulta sunt de complexitate exponent iala, multe solut ii
admisibile, dar invalide sunt evitate.
56
Exercit ii (Rezolvarile la pagina 175)
1. Scriet i un algoritm pentru parcurgerea tablei de sah cu un cal (calul
sare pe diagonala unui dreptunghi cu laturile de un patrat si doua
patrate). Fiecare patrat al tablei trebui sa e vizitat exact o singura
data.
2. Avand 4 culori si o harta cu n t ari (data printr-o matrice de adiacent a:
a
ij
= 1 daca t ara i este vecina cu t ara j, 0 altfel), sa se coloreze
harta astfel ca doua t ari vecine sa nu aiba aceeasi culoare (doua t ari se
considera a vecine daca au o frontiera comuna).
3. O organizat ie are n component a sa n barbat i si m femei. Sa se scrie
un algoritm care listeaza toate modalitat ile n care se poate alcatui o
delegat ie care sa cont ina cel put in k femei, k < m.
4. Cum poate platita o suma de x lei, n bancnote de valoare v(i),
i = 1, n din care avem cate b(i) bucat i? Sa se dea toate solut iile posibile.
Pentru alte probleme cum ar : generarea patratelor magice vezi [1].
57
58
Capitolul 7
Generarea submult imilor
Obiective
De multe ori solut iile care se cer pentru rezolvarea unei (sub)probleme
sunt de o forma particulara: produse carteziene, familia submult imilor, a
combinat iilor, aranjamentelor, permutarilor, submult imilor de suma data.
Acest capitol cont ine rezolvari clasice pentru aceste probleme, n mai multe
variante.
Schema generala de lucru
O aplicat ie imediata a metodei Backtracking este generarea submult imilor.
Vom considera sumbult imi ale mult imii A = a(1), a(2), . . . , a(n) cu n el-
emente. Evident ca avem biject ie ntre mult imea indicilor 1, 2, . . . , n si
elementele mult imii A. Exemplu:
1, 3, 4, 5 a(1), a(3), a(4), a(5)
Ca atare, vom presupune pentru simplicarea algoritmilor ca a(i) = i, i
1, . . . , n.
Avem la dispozit ie urmatoarele modalitat i de reprezentare a unei submult imi
X cu i elemente ale lui A:
1. Printrun vector x cu i componente care cont ine elementele submult imii,
precizanduse valoarea lui i sau completand componentele lui x cu o
valoare neutilizata (de exemplu 0);
2. Analog cu metoda 1, dar plasand elemetele submult imii la sfarsitul
vectorului x;
59
3. Prin vectorul caracteristic al submult imii: un vector c cu n componente
unde c(i) = 1 arata ca a(i) apart ine submult imii, iar c(i) = 0 arata ca
a(i) nu apart ine submult imii.
Exemplu: pentru A = 1, 2, 3, 4, 5, 6, 7, submult imea X = 1, 3, 4, 5 poate
reprezentata astfel:
1. x = (1, 3, 4, 5, 0, 0, 0): elementele din submult imea X la nceput, restul
pana la n pozit ii ind completate cu o valoare care nu se gaseste n A,
de exemplu 0 (care nu este indice valid);
2. x = (0, 0, 0, 1, 3, 4, 5): elementele din submult imea X la sfarsit, primele
pozit ii ind completate cu o valoare care nu se gaseste n A;
3. c = (1, 0, 1, 1, 1, 0, 0): c este vectorul caracteristic:
c(i) =
_
1, daca i X
0, daca i , X
Toate generarile prezentate n continuare au un caracter iterativ ecare
nou element (i.e. submult ime) al mult imii ind gasit pe baza elementului
anterior.
Algoritmul general pe care l vom prezenta n continuare foloseste, pe
langa un vector de dimensiune n (n care apar succesiv elementele submult imii)
si un indicator de generare. Acest indicator de generare are init ial valoarea
0; apoi are valoarea 1 cat timp se mai poate genera o submult ime X si din
nou valoarea 0 cand s-a terminat generarea.
Generare(x, n, ig)
daca ig = 0 atunci
x = valoarea (submult imea) init iala
ig = 1
Returniese n (sub)algoritmul apelant
sfarsit daca
daca exista un succesor al lui x atunci
x =succesorul lui xig ramane 1
altfel
ig = 0nu s-a mai putut genera submult imea X
sfarsit daca
Return
Un mod de utilizare a acestui algoritm pentru generari este urmatorul:
ig = 0
60
repeta
cheama Generare(x, n, ig)
daca ig = 0 atunci
exitIesi din ciclare
altfel
cheama Prelucrare(x, n)prelucreaza elementul proaspat obt inut al
submult imii
sfarsit daca
pana cand fals

In majoritatea algoritmilor pe care i vom prezenta, vectorii vor generat i


n ordine lexicograca
1
, ceea ce corespunde strategiei generale Backtracking.
Generarea elementelor unui produs cartezian
Fiind date mult imile A
1
, A
2
, . . . A
m
, unde A
i
= 1, 2, . . . , n(i), dorim sa
gener am elementele produsului cartezian A
1
A
2
A
m
. Vom avea n
total
m

i=1
n(i) elemente.

In algoritmul urmator elementele produsului cartezian vor generate suc-


cesivn vectorul x cu melemente, unde o congurat ie x = (x(1), x(2), . . . , x(m))
va desemna elementul (A
1
(x(1)), A
2
(x(2)), . . . , A
m
(x(m))) al produsului cartezian.
Vom porni deci cu un element init ial x = (1, 1, . . . , 1) care nseamna ca
din ecare mult ime A
i
luam primul element.

In continuare vom determina
cel mai mare indice i cu proprietatea ca x(i) < n(i) si vom alege ca succesor
al lui x = (x(1), x(2), . . . , x(m)) elementul x = (x(1), x(2), . . . , x(i1), x(i)+
1, 1, . . . , 1).
Daca pentru ecare i 1, . . . , m avem x(i) = n(i) nseamna ca aceasta
a fost ultima componenta a produsului cartezian si generarea s-a terminat.
Algoritmul pentru generarea produsului cartezian este:
ProdusCartezian(x, m, n, ig)
daca ig = 0 atunci
pentru i = 1, m
1
Doua siruri x = (x(1), . . . , x(n)) si y = (y(1), . . . , y(n)) sunt n ordine lexicograca
strict crescatoare daca exista k 1, k < n astfel ncat x(i) = y(i) pentru orice i k si
x(k +1) < y(k +1). Exemplu: (1, 1, 2) < (1, 2, 1) n sens lexicograc. Pentru cazul n care
x si y au forma generala x = (x(1), . . . , x(m)) si y = (y(1), . . . , y(n)), daca exista k m, n
astfel ncat (x(1), . . . , x(k)) < (y(1), . . . , y(k)) atunci x este mai mic (lexicograc) decat y.
Daca un astfel de k nu exista (adica x(1) = y(1), . . . , x(p) = y(p) unde p este min(m, n)),
atunci cel mai scurt dintre vectori este considerat cel mai mic. Exemplu: (1, 2) < (1, 3, 4),
(1, 2) < (1, 2, 3).
61
x(i) = 1
sfarsit pentru
ig = 1
Return
sfarsit daca
pentru i = m, 1, 1
daca x(i) < n(i) atunci
x(i) = x(i) + 1
Return
altfel
x(i) = 1
sfarsit daca
sfarsit pentru
ig = 0
Return
Generarea tuturor submult imilor unei mult imi
O prima metoda ar sa generam elementele produsului cartezian al
mult imilor A
1
= A
2
= = A
n
= 0, 1. Vectorul x care se obt ine, interpre-
tat ca vector caracteristic, va element al mult imii part ilor lui 1, 2, . . . , n
O a doua metoda va genera submult imile unei mult imi n ordinea crescatoare
a numarului de elemente utlizand modalitatea (2) de reprezentare a mult imilor.
Specicam ca vectorii x vor generat i si de aceasta data n ordine lexi-
cograca strict crescatoare.
Fie x = (x(1), x(2), . . . , x(n)); atunci succesorul lui se va determina n
modul urmator: se va determina indicele i cu proprietatea ca x(i) < i si
pentru n j > i avem x(j) = j. Este evident ca urmatorul element x

n
ordine lexicograca este cel n care x

(i) = x(i) + 1 iar celelalte componente


cresc cu cate 1, adica: x

(i + 1) = x(i) + 2, . . . , x

(n) = x(i) +n i + 1.
Se ncepe cu x = (0, 0, . . . , 0) care reprezinta mult imea vida, iar atunci
cand x = (1, 2, . . . , n) nseamna ca am generat ultimul element.
Algoritmul pentru generarea submult imilor unei mult imi este:
Submultimi(x, m, ig)
daca ig = 0 atunci
pentru i = 1, n
x(i) = 0
sfarsit pentru
ig = 1
Return
62
sfarsit daca
pentru i = n, 1, 1
daca x(i) < i atunci
x(i) = x(i) + 1
pentru j = i + 1, n
x(j) = x(j 1) + 1
sfarsit pentru
Return
sfarsit dacax(i) < i
sfarsit pentru
ig = 0
Return
Generarea mult imii combinarilor
Fie A = 1, 2, . . . n si m n. Vom construi n continuare algoritmi de
generare a tuturor celor C
m
n
combinari din mult imea A cu proprietatea ca
oricare doua elemente difera ntre ele prin natura lor, nu si prin ordine.
O prima metoda se bazeaza pe metoda de reprezentare 1. Si de aceasta
data vectorii vor generat i n ordine lexicogracancepand cu x = (1, 2, . . . , m)
2
.
Fiind dat x = (x(1), x(2), . . . , x(m)), urmatorul element x

va determinat
astfel:
1. se determina indicele i cu proprietatea: x(i) < n m + i, x(i + 1) =
n m +i + 1, . . . , x(m) = n
2. se trece la x

prin:
- x

(j) = x(j) daca j < i


- x

(i) = x(i) + 1
- x

(j) = x(j 1) + 1 pentru j de la i + 1 la m


3. cand nu gasim i cu proprietatea de mai sus nseamna ca x = (n m+
1, n m + 2, . . . , n) si deci s-a generat ultimul element.
Algoritmul va urmatorul:
Combin1(x, n, m, ig)
daca ig = 0 atunci
pentru i = 1, m
2
Restul componentelor vectorului x ind permanent 0, nu vor mai reprezentate, deci
vom lucra efectiv doar cu m componente n loc de n.
63
x(i) = i
sfarsit pentru
ig = 1
Return
sfarsit daca
pentru i = m, 1, 1
daca x(i) < n m +i atunci
x(i) = x(i) + 1
pentru j = i + 1, m
x(j) = x(j 1) + 1
sfarsit pentru
Return
sfarsit daca
sfarsit pentru
ig = 0
Return
A doua metoda foloseste reprezentarea elementelor prin vectorul carac-
teristic, generat n ordine lexicograca crescatoare. Primul element va :
x = (0, 0, . . . , 0, 1, 1, . . . , 1) vectorul cu ultimele m pozit ii egale cu 1 si 0 n
rest.
Fie acum vectorul x caruia vrem sa i determinam succesorul x

; pentru
aceasta vom pune n evident a ultima secvent a de cifre 1:
X =(. . . , 0, 1, . . . 1, 0, . . . , 0)
a b
unde a este indicele unde ncepe aceasta secvent a iar b indicele ultimului
element egal cu 1.
Trecerea la x

depinde de faptul ca ultima secvent a cont ine un singur


element (a = b) sau mai multe elemente (a < b).
Daca a = b atunci x

(a 1) = 1, x

(a) = 0 si n rest x

(i) = x(i) va
determina congurat ia urmatoare.
Daca a < b atunci rezulta ca x(a 1) = 0. Sa notam cu l
1
lungimea
secvent ei de elemente 1, deci l
1
= b a + 1 si cu l
0
lungimea secvent ei de
zerouri de la sfarsitul lui x, deci l
0
= n b. Rezulta ca l
1
2 si l
0
0.
Trecerea de la x la x

se poate vedea usor n urmatoarea schema:


l
1
l
0
x = (. . . , 0, 1, . . . , 1, 0, . . . , 0)
a b
64
l
1
1
x = (. . . , 1, 0, . . . , 1, . . . , 1)
a n l
1
+ 2
Deci x

(a 1) va deveni 1, urmeaza apoi un sir de l


0
+ 1 zerouri, urmat,
n nal de un sir de l
1
1 elemente egale cu 1. Algoritmul pentru generarea
combinarilor este urmatorul:
Combinari2(x, n, m, ig, a, b)
daca ig = 0 atunci
pentru i = 1, n m
x(i) = 0
sfarsit pentru
pentru i = n m + 1, n
x(i) = 1
sfarsit pentru
ig = 1
a = n m + 1
b = n
Return
sfarsit daca
daca a = 1 atunci
ig = 0
Return
sfarsit daca
daca a < b atunci
l
1
= b a + 1
x(a 1) = 1
pentru i = a, n l
1
+ 1
x(i) = 0
sfarsit pentru
pentru i = n l
1
+ 2, n
x(i) = 1
sfarsit pentru
a = n l
1
+ 2
b = n
Return
altfel
x(a 1) = 1
x(a) = 0
b = a 1
pentru i = a 1, 1, 1
65
daca x(i) = 0 atunci
a = i + 1
Return
sfarsit daca
a = 1
sfarsit pentru
sfarsit dacaa < b
Return
Generarea mult imii permutarilor
Complexitatea oricarui algoritm care rezolva aceasta problema este de
(n!), deoarece trebuie generat i n! vectori. Vectorul p cu n elemente va
cont ine permutarea mult imii A = 1, 2, . . . , n. Exista mult i algoritmi pen-
tru rezolvarea acestei probleme, dar noi prezentam aici numai doi dintre ei.
Pentru mai multe detalii, a se consulta lucrarea [5].
Prima metoda este: urmareste generarea vectorului x n ordine lexi-
cograca crescatoare. Pentru construct ia lui p

succesorul lui p vom


pune n evident a ultima secvent a descrescatoare:
p(i) < p(i + 1) > p(i + 2) > > p(n) (7.1)
si n consecint a componenta care trebuie modicata este p(i).

In locul lui
p(i) trebuie pusa o componenta p(j) cu j > i, cu condit ia ca p(j) > p(i), dar
pentru ca p

este succesorul lui p, trebuie ales j astfel ncat p(j) sa e cel mai
mic cu proprietatea p(j) > p(i); e acest indice k; atunci prin interschimbarea
lui p(i) cu p(k) se ajunge la:
(p(1), . . . , p(i 1), p(k), p(i + 1), . . . , p(k 1), p(i), p(k + 1), . . . , p(n))
unde p(i +1) > p(i +2) > > p(k 1) din ecuat ia (7.1). Daca p(i) nu ar
mai mare decat p(k+1), atunci am avea (datorita inegalitat ii p(k) > p(k+1))
ca p(k) nu ar cel mai mic din secvent a p(i +1), . . . , p(n) care este mai mare
dec at p(i), contradict ie cu alegerea lui k; deci avem ca p(i) > p(k + 1),
deci p(i) > p(k + 1) > > p(n). Usor se demonstreaza ca p(k 1) > p(i).
Rezulta ca secvent a de la p(i+1) la p(n) este descrescatoare si pentru a obt ine
p

nu avem decat sa inversam aceasta secvent a, interschimband termenii de la


nceput cu cei de la sfarsit pana la mijlocul secvent ei. Algoritmul este:
Perm1p, n, ig
daca ig = 0 atunci
pentru i = 1, n
66
p(i) = i
sfarsit pentru
ig = 1
Return
sfarsit daca
i = n 1
cat timp p(i) > p(i + 1)
i = i 1
daca i = 0 atunci
ig = 0
Return
sfarsit daca
sfarsit cat timp
k = n cautarea lui k
cat timp p(i) > p(k)
k = k 1
sfarsit cat timp
schimba p(i) cu p(k)
p(i) p(k)
3
calculeaza mijlocul secvent ei
m =
_
ni
2

[x] este partea ntreaga a lui x


pentru j = 1, m
p(i +j) p(n + 1 j)
sfarsit pentru
Return
Metoda pe care o prezentamn continuare se bazeaza pe generarea recursiva
a permutarilor. Daca avem S
k
mult imea permutarilor de k elemente de forma
p = (p(1), . . . , p(k)) S
k
, atunci S
k+1
va cont ine pe baza ecarei permutari p
cate k+1 permutari P

: (p(1), . . . , p(k), k+1), (p(1), . . . , p(k1), k+1, p(k)),


. . . , (p(1), k + 1, p(2), . . . , p(k)), (k + 1, p(1), . . . , p(k)). Deci permutarile S
n
vor frunzele unui arbore construit astfel:
- radacina cont ine 1;
- descendent ii unei permutari p = (p(1), . . . , p(k)) sunt cele k + 1 per-
mutari descrise mai sus
Putem atasa acestui arbore unul n care toate permutarile sunt de n ele-
mente, prin completarea permutarii de k elemente cu componentele (k +
1, k + 2, . . . , n).
3
Notat ia a b nseamna interschimba valoarea lui a cu valoarea lui b, care se
efectueaza prin urmatoarea secvent a: aux = a, a = b, b = aux.
67
Exemplu: pentru n = 3 se obt ine arborele din Figura 7.1 si arborele
atasat din Figura 7.2.
Figura 7.1: Arborele atasat unei permutari de 3 elemente
Figura 7.2: Arbore cu noduri completate pana la n
Arborele atasat are, evident, aceleasi varfuri terminale. Trecerea de la o
permutare p la urmatoarea permutare p

nseamna o parcurgere a frunzelor


acestui arbore.
Fie p = (p(1), . . . , p(n)); atunci p

se construieste astfel:
Daca n apare pe o pozit ie m > 1, atunci se face interschimbarea p(m)
p(m 1) si s-a obt inut noua permutare. Daca p(1) = n, atunci se permuta
circular spre stanga cele n elemente, obt inanduse tatal permutarii p.

In
continuare, daca n 1 apare pe o pozit ie m ,= 1, atunci se efectueaza inter-
schimbarea p(m) p(m1) si sa obt inut noua permutare; n caz contrar,
se permuta circular ultimele n1 pozit ii si se ncearca deplasarea spre stanga
a lui n 2, etc. Algoritmul este:
Perm2(p, n, ig)
daca ig = 0 atunci
pentru i = 1, n
p(i) = i
sfarsit pentru
ig = 1
Return
sfarsit daca
pentru i = n, 2, 1
m = 1
cat timp p(m) ,= i
m = m + 1
sfarsit cat timp
daca m ,= 1 atunci
p(m1) p(m)
Return
sfarsit daca
cheama PermCircStanga(p, n, i) se permuta circular primele i compo-
nente ale lui P
68
Return
sfarsit pentru
ig = 0
Return
unde PermCircStanga(p, n, i) este urmatorul algoritm:
PermCirc(p, n, i)
x = p(1)
pentru j = 1, i 1
p(j) = p(j + 1)
sfarsit pentru
p(i) = x
Return
Generarea mult imii aranjamentelor
O prima metoda consta n generarea tuturor combinarilor de n luate cate
m si pentru ecare din acestea realizarea tuturor permutarilor. Aceasta idee
duce la urmatorul algoritm:
Aranj1(x, n, m, ig, c, p, ig1)
daca ig = 0 atunci
pentru i = 1, m
x(i) = i
c(i) = i
p(i) = i
sfarsit pentru
ig = 1
ig1 = 1
Return
sfarsit daca
cheama Perm(p, m, ig1)
daca ig1 ,= 0 atunci
pentru i = 1, m
x(i) = c(p(i))
sf arsit pentru
altfel
cheama Combin(c, m, ig)
daca ig = 1 atunci
pentru i = 1, m
p(i) = i
x(i) = c(i)
69
sfarsit pentru
ig1 = 1
Return
sfarsit daca
sfarsit daca
Return
Sa observam ca metoda nu genereaza aranjamentelen ordine lexicograca
crescatoare. Urmatoarea metoda urmareste sa pastreze aceasta ordine, con-
form strategiei generale Backtracking.
Fie x = (x(1), . . . , x(m)) un aranjament oarecare. Pentru determinarea
lui x

, aranjamentul succesor, n ordine lexicograca, vom determina mai ntai


indicele i, cel mai mare indice care poate marit. Un x(i) nu poate marit
daca valorile x(i)+1, x(i)+2, . . . , n nu sunt disponibile. Vom folosi un vector
disp cu n componente care sunt 0 sau 1. disp(k) = 0 arata ca valoarea k este
disponibila iar disp(k) = 1 arata ca valoarea x(k) nu este disponibila (este
deja folosita n x). Cand se gaseste valoarea x cu proprietatea ment ionata,
x(i), x(i + 1), . . . , x(m) vor primi cele mai mici valori disponibile, n ordine
crescatoare. Rezulta de aici ca pana la gasirea lui i toate valorile cercetate
regresiv vor facute disponibile.
Obt inem n acest fel urmatorul algoritm:
Aranj2(x, n, m, ig, disp)
daca ig = 0 atunci
pentru i = 1, m
x(i) = i
disp(i) = 1
sfarsit pentru
pentru i = m + 1, n
disp(i) = 0
sfarsit pentru
ig = 1
Return
sfarsit daca
pentru i = m, 1, 1
disp(x(i)) = 0
pentru j = x(i) + 1, n
daca disp(j) = 0 atunci
x(i) = j
disp(j) = 1
k = 0
pentru l = i + 1, m
70
repeta
k = k + 1
pana cand disp(k) = 0
x(l) = k;
disp(k) = 1
sfarsit pentru
Return
sfarsit daca
sfarsit pentru
sfarsit pentru
ig = 0
Return
Generarea submult imilor de suma data
Fie A = (a(1), . . . , a(n)) un vector cu componente strict pozitive si M > 0
un numar pozitiv dat. Se cer submult imile B = i
1
, i
2
, . . . , i
l
1, 2, . . . , n
astfel ncat

iB
a(i) = M (7.2)
Vom folosi pentru reprezentarea mult imilor B modalitatea 3, deci daca x este
vectorul caracteristic al lui B atunci (7.2) se rescrie ca:
n

i=1
x(i) a(i) = M (7.3)
Componentele lui x vor generate succesiv dupa metoda generala back-
tracking: daca am stabilit deja n x componentele x(1), x(2), . . . , x(k 1),

k1
i=1
x(i) a(i) M, atunci componenta x(k) trebuie sa satisfaca condit iile:
k

i=1
x(i) a(i) M (7.4)
si
k

i=1
x(i) a(i) +
n

i=k+1
a(i) M (7.5)
Vom considera
S =
k

i=1
x(i) a(i) (7.6)
71
si
R =
n

i=k+1
a(i) (7.7)
Vom presupune ca elementele mult imii A sunt sortate crescator (se face
o sortare n prealabil). Algoritmul va :
SumbultimiSuma(a, x, n, M, k, S, R, ig)
daca ig = 0 atunci
pentru i = 0, n
x(i) = 1
k = 1
S = 0
R =
n

i=1
a(i)
sfarsit pentru
altfel
S = S x(k) a(k)
R = R +a(k)
x(k) = 1
k = k 1
sfarsit daca
cat timp k > 0
daca x(k) < 1 atunci
x(k) = x(k) + 1
S = S +x(k) a(k)
daca S = M atunci
ig = 1
Return
sfarsit daca
daca S < M si S +R M atunci
R = R x(k)
k = k + 1
sfarsit daca
daca S +R < M atunci
S = S +x(k) a(k)
R = R +a(k)
x(k) = 1
k = k 1
sfarsit daca
altfel
S = S a(k)
72
R = R +a(k)
x(k) = 1
k = k 1
sfarsit daca
sfarsit cat timp
ig = 0
Varianta recursiva, mult mai usor de urmarit este data mai jos. Variabila
ramas este egala cu M S din algoritmul precedent.
SubmultimiRecursiv(a, x, n, k, ramas)
daca ramas = 0 atunci
cheama Prelucrare(a, x, k 1)
Return
sfarsit daca
daca k > n sau ramas < 0 atunci
Return
sfarsit daca
pentru x[k] = 0, 1
cheama SubmultimiRecursiv(a, x, n, k + 1, ramas x[k] a[k])
sfarsit pentru
Return
Rezumat
Pentru determinarea unor submult imi (de o natura particulara) a unei
mult imi exista algoritmi specializat i. Se pot da, evident, mai mult i algoritmi
pentru generarea unei solut ii. Aceste tipuri de probleme se ntalnesc adeseori
sub o forma mascata n enunt ul altor probleme, sau ca etapa intermediara
ntrun caz mai mare.
Exercit ii (rezolvarile la pagina 182)
1. Sa se scrie algoritmi recursivi pentru generarea tipurilor de submult imi
din acest capitol.
73
74
Capitolul 8
Metoda Divide et Impera
Obiective
Capitolul prezinta metoda Divide et Impera, ce se poate utiliza atunci
cand rezolvarea unei probleme se face prin spargerea ei n cazuri de dimen-
siune mai mica (dar de aceeasi natura cu problema init iala), iar apoi prin
recombinarea solut iilor obt inute. Determinarea complexitat ii se reduce la
rezolvarea unei recurent e, pentru care o unealta utila este Teorema centrala.
Este dat cel mai ecient algoritm de sortare (Quicksort) si se demonstreaza
o limita inferioara pentru algoritmii de sortate bazat i pe comparat ii.
Prezentare generala
Aceasta metoda nu este ceva nou pentru noi. Am rezolvat cu ea prob-
lema sortarii prin interclasare n capitolul 3, pagina 24. Metoda consta n
urmatoarele etape:
1. Partit ionarea problemei init iale n mai multe probleme mai mici;
2. Rezolvarea (de obicei recursiva) a ecarei subprobleme; daca o subprob-
lema este de dimensiune sucient de mica, atunci ea se poate rezolva
printro metoda ad-hoc, care poate mai put in performanta pentru
cazuri de dimensiune mare;
3. Combinarea rezultatelor part iale pentru a obt ine rezultatul problemei
init iale.
Daca o problema a fost divizata n a subprobleme care au dimensiunea
n
b
si sunt rezolvate recursiv, atunci complexitatea este data de formula:
T(n) = aT
_
n
b
_
+f(n) (8.1)
75
unde f(n) este costul combinarii solut iilor subproblemelor.
Aarea formei lui T(n) este o problema de algebra care se poate aborda
prin induct ie sau folosind rezultatele teoremei principale din [2]:
Teorema 1. (Teorema centrala.) Fie a 1 si b > 1 constante, e f(n) o
funct ie si T(n) denita pe ntregii nenegativi prin recurent a:
T(n) = aT
_
n
b
_
+f(n) (8.2)
unde interpretam pe
n
b
e ca pe
_
n
b
_
, e ca pe
_
n
b
_
. Atunci T(n) poate
delimitata asimptotic dupa cum urmeaza:
1. Daca f(n) = O(n
log
b
a
) pentru o anumita constanta > 0, atunci
T(n) = (n
log
b
a
)
2. Daca f(n) = (n
log
b
a
) atunci T(n) = (n
log
b
a
log n)
3. Daca f(n) = (n
log
b
a+
) pentru o anumita constanta > 0 si daca
af
_
n
b
_
cf(n) pentru o anumita constanta c < 1 si tot i n sucient i
de mari, atunci T(n) = (f(n)).
Demonstrat ia se poate gasi n [2].
Am folosit divide et impera la sortarea unui sir (sortarea prin interclasare,
algoritmul Mergesort); se vede ca se ajunge la complexitatea:
T(n) = (nlog
2
n)
(care se deduce din cazul 2 al Teoremei centrale), complexitate mai buna
decat cea de la sortarea prin insert ie, care era
T(n) = O(n
2
)
Problema turnurilor din Hanoi
Prima problema pe care o prezentam este Problema turnurilor din Hanoi,
problema care nu are nici o legatura cu Hanoi-ul, ci este un joc logic inventat
n secolul trecut de matematicianul francez Eduard Lucas. El a fost cel care
a vandut pentru prima oara aceasta problema drept joc, cu opt discuri si trei
baghete.
Dupa o straveche legenda hindusa, zeul Brahma ar xat pe masa tem-
plului sau din Benares trei bastonase verticale de diamant si ar nsirat pe
acesta 64 de discuri de marimi descrescatoare (de la baza la varf), formand
76
astfel un trunchi de con. A dispus apoi ca discurile sa e mutate pe un al
doilea, folosind si al treilea bastonas; zi si noapte trebuia mutat cate unul
din discurile aate n varful unuia din bastonase n varful altui bastonas,
respectand n ecare moment ordinea descrescatoare a marimii discurilor
aate pe ecare bastonas. Legenda spune ca, dand aceasta porunca, Brahma
a sust inut ca atunci cand se va termina asezarea celor 64 de dicuri pe cel de-al
doilea bastonas, atunci se va sfarsi si viat a pe Pamant. O versiune destul
de optimista deoarece presupunand ca mutarea unui disc ar dura o secunda,
cele 64 de discuri vor ajunge pe al doilea bastonas n circa 584.942.416.729
de ani.
Enunt ul formalizat al problemei este: e trei tije si n discuri perforate
de diametre diferite. Discurile sunt asezate init ial pe tija 1 n ordinea de-
scresc atoare a diametrelor acestora considerand sensul de la baza la varf.
Problema consta n a muta turnul de n discuri de pe tija 1 pe tija 2 ntr-
un numar minim de mutari, t inand cont de urmatoarele reguli:
1. La ecare mutare se muta un singur disc
2.

In permanet a, pe ecare tija, deasupra oricarui disc pot mutate numai
discuri de diametre mai mici.
Calcularea numarului minim de pasi: observam ca pentru 2, 3, 4 si 5 discuri,
problema se rezolva efectuand un numar de mutari egal cu 3, 7, 15 si respectiv
31, de unde putem formula ipoteza ca pentru problema cu n discuri vom
efectua 2
n
1 mutari.
Sa demonstram valabilitatea acestui rezultat prin induct ie matematica
completa dupa n. Am aratat ca armat ia este adevarata pentru n = 2, 3, 4, 5
discuri. Presupunem ca ea este adevarata pentru n discuri, deci sunt necesare
2
n
1 mutari. Vom demonstra ca pentru n+1 discuri sunt necesare 2
n+1
1
mutari.
Putem rezolva problema mutarii celor n + 1 discuri n trei etape:
1. Mutam primele n discuri pe tija a treia
2. Mutam al n + 1-lea disc pe a doua tija
3. Mutam cele n discuri de pe a treia tija pe cea de-a doua tija.
Folosind acest procedeu, sunt necesare:
1. 2
n
1 mutari pentru realizarea primei etape
2. o mutare pentru realizarea celei de a doua etape
77
3. 2
n
1 mutari pentru realizarea celei de a treia etape

In total sunt suciente 2


n+1
1 mutari.

In continuare vom prezenta mai
mult i algoritmi, ecare bazanduse pe cate o observat ie importanta.
Metoda I
O mutare poate scrisa ca o pereche (i, j) cu i 1, 2, 3 si i ,= j,
semnicand ca se muta discul cel mai mic de pe tija i pe tija j. Mai notam
cu H(m, i, j) sirul mutarilor necesare pentru a muta primele m discuri (cele
mai de sus) de pe tija i pe tija j.

In aceste ipoteze, problema se reduce la a
determina sirul de mutari H(m, i, j). Observam ca putem scrie:
H(m, i, j) =
_
(i,j), pentru m = 1
H(m-1, i, k),(i,j),H(m-1, k, j) pentru m ,= 1
(8.3)
unde k = 6 i j este tija diferita de tijele i si j.
Cu aceasta reducem rezolvarea problemei cu n discuri la rezolvarea a
doua probleme cu n 1 discuri. Algoritmul se bazeaza pe ideea ca n loc
de H(m, i, j) putem scrie H(i, j), memorand valoarea lui m separat. Se
mai poate observa ca H(i, j) se transforma n H(i, k), (i, j), H(k, j) cu
k = 6 i j. Avand n mijloc tot perechea (i, j), rezulta ca imediat ce
o pereche este generata, ea poate nscrisa direct pe locul ei. Algoritmul
obt ine cele 2
n
1 mutari folosind n acest scop o matrice M cu 2 linii si
2
n
1 coloane, ecare coloana memorand o mutare.

Incepem prin a nscrie
perechea (1,2) pe coloana 2
n1
. Perechile ce vor lua nastere din ea vor
nscrise pe coloanele 2
n2
si 2
n1
+ 2
n2
. Se observa ca acest algoritm face
parte din clasa algoritmilor Divide et Impera.
Mai general, pentru ecare valoare a lui m n, n 1, . . . , 2 se ex-
pandeaza perechile din coloanele c de forma (c = /2
m
+ 2
m1
)
1
, perechile
care rezulta din cea din coloana c indnscrise pe coloanele c2
m2
, c+2
m2
.
Hanoi1(M, n, N)N = 2
n
1
k1 = N + 1
k2 = k1/2
k3 = k2/2
M(1, k2) = 1
M(2, k2) = 2
pentru m = n, 2, 1
pentru l = k2, N, k1
i = M(1, l)
1
/p este notat ie pentru multiplu de p.
78
j = M(2, l)
k = 6 i j
M(1, l k3) = i
M(2, l k3) = k
M(1, l +k3) = k
M(2, l +k3) = j
sfarsit pentru
k1 = k2
k2 = k3
k3 = k3/2
sfarsit pentru
Metoda a IIa
Varianta recursiva este bazata tot pe metoda Divide et Impera. Aceasta
metoda este eleganta din punct de vedere al redactarii, dar inecienta din
cauza spat iului ocupat n stiva si antarzierilor datorate apelurilor n cascada
a procedurii.
Hanoi2(n, i, j)
daca n = 1 atunci
muta discul superior de pe tija i pe tija j
altfel
cheama Hanoi2(n 1, i, 6 i j)
muta discul superior de pe tija i pe tija j
cheama Hanoi2(n 1, 6 i j, j)
sfarsit daca
Return
Figura 8.1: Arborele apelurilor recursive pentru Hanoi2(4, 1, 2)
Metoda a IIIa
Vom porni de la algoritmul precedent, pe care l vom transforma ntr
unul iterativ. Apelul Hanoi2(4,1,2) va duce la arborele de apeluri recursive
din gura 8.1, unde n ecare nod este memorat un triplet de forma (n, i, j).
Prin parcurgerea n inordine a acestui arbore binar si asarea pentru
ecare nod a ultimelor doua numere memorate n el, se ajunge la deter-
minarea solut iei cerute. Pentru parcurgere se va folosi o stiva S n care se
79
vor memora triplete de forma (a, b, c). Arborele nu este construit n mod
explicit.
Hanoi3(n)
i = 1
j = 2
gata = fals
niv = 1pornim de la radacina, care se aa pe nivelul 1
S = S este stiva
con = 0
repeta
cat timp niv < n 1
niv = niv + 1
(i, j, niv) S
j = 6 i j
sfarsit cat timp
scrie( i, 6 i j )
scrie( i, j )
scrie( 6 i j, j )
daca S = atunci
gata = adevarat
altfel
(i, j, niv) S
scrie( i, j )
i = 6 i j
sfarsit daca
pana cand gata = adevarat
Return
Observat ie: Pentru implementarea stivei se poate folosi o matrice cu n 2
linii si 3 coloane.
Algoritmul de sortare QuickSort
Fie sirul x = (x(1), x(2), . . . , x(n)). Dorim sa sortam acest sir, adica i
1, . . . , n 1, x(i) x(i +1). Dupa cum stim, algoritmii sunt caracterizat i
de timpul de execut ie si spat iul de memorie ocupat.
Sortarea unui sir cu metoda bulelor sau cea a insert iei s-a facut cu algo-
ritmi in place (n afara sirului sau ment inut cel mult un numar constant
de elemente din sir), iar prin metoda interclasarii se ocupa un alt sir (nu este
un algoritm in place) si n plus timpul de execut ie ascunde o constanta
multiplicativa mare.
80
Ne dorim sa realizam un algoritm de sortare prin metoda Divide et
Impera, fara a folosi un sir intermediar, deci in place. Profesorul C.A.R.
Hoare de la Universitatea Oxford a propus mpart irea sirului n part i nu
neaparat egale avand proprietatea ca toate elemetele primei part i sa e mai
mici sau egale decat un x(k) xat (determinat de algoritmul de partit ionare
care va prezentat mai jos), iar componentele celei de a doua part i sa e
mai mari decat x(k). Faza de combinare lipseste (este o metoda Divide et
Impera schioapa).
Algoritmul QuickSort (sortare rapida) este:
QuickSort(x, p, r)
daca p < r atunci
cheama Part(x, p, r, k)
cheama QuickSort(x, p, k)
cheama QuickSort(x, k + 1, r)
sfarsit daca
Return
Algoritmul care realizeaza partit ionarea este:
Part(x, p, r, k)
pivot = x(p)
i = p 1
j = r + 1
terminat = fals
repeta
repeta
j = j 1
pana cand x(j) pivot
repeta
i = i + 1
pana cand x(i) pivot
daca i < j atunci
x(i) x(j)
altfel
k = j
terminat = adevarat
sfarsit daca
pana cand terminat = adevarat
Return
Exemplu: e sirul:
6 3 2 6 3 1 2 8
i j
81
Avem: pivot = 6, p = 1, r = 8. Primul element al sirului mai mic sau egal
decat pivotul 6 este 2 (n cautarea de la dreapta la stanga) si primul element
al sirului mai mare sau egal decat pivorul 6 este 6 (cautare de la stanga spre
dreapta). Dupa gasirea lor le interschimbam, ajungand la congurat ia:
2 3 2 6 3 1 6 8
i j
Apoi, succesiv:
2 3 2 1 3 6 6 8
i j
2 3 2 1 3 6 6 8
j i
Deoarece j a devenit mai mic decat i, se iese din procedura de partit ionare
cu valoarea lui k = 5.

In acest moment sa terminat partit ionarea dupa
pivot = 6.

In continuare se face partit ionarea sirului din partea stanga
pentru pivot = 2:
2 3 2 1 3
i j
1 3 2 2 3
i j
1 2 3 2 3
i j
1 2 3 2 3
j i
Deoarece avem j i, procedura se termina valoarea lui k = 2. Analog se
procedeaza pentru ecare subcaz, pana cand se ajunge la vectori de lungime
1, care sunt (evident) sortat i.
Observat ie: Daca sirul este deja ordonat crescator, se face partit ionare
dupa ecare element.
Complexitatea partit ionarii este data de T
P
(n) = c n, c constanta. Com-
plexitatea QuickSort n cazul sirului care este deja sortat este:
82
T
Q
(n) = T
Q
(1) +T
Q
(n 1) +T
P
(n) =
= T
Q
(n 1) +T
P
(n) +c =
= T
Q
(1) +T
Q
(n 2) +T
P
(n 1) +T
P
(n) +c =
= T
Q
(n 2) +T
P
(n 1) +T
P
(n) + 2c =
= =
= T
Q
(2) +
n

k=3
T
P
(k) + (n 2)c =
= T
Q
(1) +T
Q
(1) +
n

k=2
T
P
(k) + (n 2)c =
=
n

k=2
T
P
(k) +cn =
n

k=2
c k +c n = (n
2
)
unde am considerat n mod convenabil ca T
Q
(1) este marginit de acceasi
constanta c care apare n expresia lui T
P
(n).

In cel mai bun caz, cand sirul semparten jumatate, T


Q
(n) = 2T
Q
(n/2)+
(n) = (nlog n) (conform teoremei centrale). Se poate demonstra ca tim-
pul mediu al QuickSortului este (nlog n).

In practica se dovedeste ca
QuickSort este cel mai rapid algoritm de sortare!!
Ne punem ntrebarea daca exista algoritmi de sortare cu complexitatea
mai mica decat nlog n? Se poate demonstra ca daca algoritmul se bazeaza
doar pe comparat ii ntre elemente, nu se poate cobor sub bariera de (nlog n).
Pentru a demonstra, alegem a
1
, a
2
, a
3
elemente pe care le comparam (Figura
8.2). Se obt ine un arbore binar care are drept frunze permutarile indicilor
elementelor init iale, adica 3! frunze.
Figura 8.2: Arborele de decizie pentru 3 elemente

In cazul a n valori, obt inem un arbore binar cu n! frunze. Prin nat imea
unui arbore nt elegem lungimea drumului maxim de la radacina la orice
frunz a si se noteaza cu h. h reprezinta numarul de comparat ii n cazul cel
mai defavorabil. Este evident ca numarul maxim de frunze pentru un arbore
binar de adancime h este 2
h
. Deci n cazul nostru pentru compararea a n
elemente vom avea un arbore cu o adancime h astfel ncat n! 2
h
. Rezulta
83
ca h log
2
(n!) si folosind aproximat ia lui Stirling:
n!

2n
_
n
e
_
n
2
obt inem ca:
h log
2
n! > nlog
2
n nlog
2
e = (nlog
2
n)
Se obt ine ca T(n) = (nlog
2
n). Am demonstrat deci ca pentru algorit-
mii care se bazeaza doar pe comparat ii complexitatea nu poate sa scada
sub nlog
2
n. Pentru cazuri speciale ale sirului ce trebuie sortat, a se vedea
capitolul 9.
Rezumat
Metoda Divide et Impera se foloseste atunci cand rezolvarea unei prob-
leme se poate face prin descompunerea ei n cazuri de dimensiune mai mica,
rezolvarea acestora dupa acelasi principiu, apoi combinarea rezultatelor lor.
Deseori algoritmii de acest tip se scriu recursiv (datorita naturii lor), iar de-
terminarea complexitat ii se face prin rezolvarea unei ecuat ii recursive, a carei
solut ii se poate da de multe ori pe baza Teoremei centrale.
Un exemplu important de algoritm de tip divide et Impera este Quicksort.
Problemele de la sfarsitul capitolului dau si alte exemple ale utilitat ii metodei.
Exercit ii (rezolvarile la pagina 184)
1. Bazanduva pe observat ia ca mutarea din mijloc se stie, scriet i un
algoritm iterativ pentru problema turnurilor din Hanoi, punand mereu
mijloacele intervalelor obt inute prinnjumatat irentr-un sir cu numarul
cunoscut de mutari.
2. Avand la intrare un sir ordonat crescator, sa se scrie un algoritm de
tip Divide et Impera pentru gasirea pozit iei unui element de valoare
data x, daca el exista. Se va folosi metodanjumatat irii intervalului dat
de numarul de elemente al sirului. Care este complexitatea cautarii?
3. Rezolvat i aceeasi problema prin cautare secvent iala (testarea pe rand
a elementelor). Care este n acest caz complexitatea?
2
Se poate arata ca:

2n
n+
1
2
e
n
e
(12n+1)
1
< n! <

2n
n+
1
2
e
n
e
(12n)
1
84
4. Demonstrat i ca timpul de execut ie al algoritmului QuickSort, n cazul
unui vector cu toate elementele egale, este (nlog n).
5. Complexitatea algoritmului QuickSort este mare din cauza ca n cazuri
defavorabile, partit ionarea se face cu un singur element ntr-una din
partit ii. Rescriet i algoritmul de partit ionare, luand ca element de sep-
arare nu primul element, ci valoarea din mijloc ntre primul element,
ultimul si cel aat pe pozit ia din mijloc.
Pentru alte probleme cum ar : transformata Fourier, vezi [1].
85
86
Capitolul 9
Sortare si statistici de ordine
Obiective

In acest capitol ne propunem sa rezolvam urmatoarele probleme, relative


la un sir cu n elemente:
1. sa se gaseasca a i-a componenta n ordine statistica a sirului
2. sa se gaseasca mediana (componenta din mijloc) unui sir
3. sa se gaseasca cele mai mici doua elemente dintrun sir
4. determinarea simultana a minimului si maximului
Observat ie: Vom considera ca sirul este cu elemente distincten rezolvarea
tuturor problemelor enunt ate, urmand apoi sa extindem rezultatele obt inute
si pentru situat ia n care elementele se repeta.
Vor considerat i mai mult i algoritmi care rezolva aceasta problema.
Capitolul cont ine si prezentari ale altor algoritmi de sortare (heapsort, cu
care ocazie se introduce si structura de date numita heap, sortari n timp
liniar).
Exemplicari, generalitat i
Exemple: Fie x = (5, 4, 2, 8, 9, 1, 7). Ce se nt elege prin a i-a componenta
n ordine statistica? Avem n = 7 si n mod evident 1 i 7. Daca l
consider pe i = 3, vom nt elege prin a i-a componenta n ordine statistica a
sirului x elementul al treilea din sirul x sortat n ordine crescatoare.
x = (1, 2, 4, 5, 7, 8, 9), x(3) = 4
87
Mediana depinde de paritatea numarului de elemente din sirul dat. Daca
n este impar atunci mediana este unica si se gaseste n sirul sortat pe pozit ia
i = (n + 1)/2. Altfel avem dea face cu doua mediane, una dintre ele pe
pozit ia i = n/2, cealalta pe pozit ia i = n/2 + 1.

In general, pentru un sir
de lungime n vom considera mediana elementul de pe pozit ia
_
n+1
2

din sirul
sortat.

In cazul nostru mediana este 5.
Ce reprezinta minimul si maximul din perspectiva statisticilor de ordine?
Minimul este prima componenta n ordine statistica a unui sir. Maximul este
a n-a componenta n ordine statistica.
Determinarea simultana a minimului si a max-
imului
MinMax(x, n)
min = x(1)
max = x(1)
pentru i = 2, n, 1
daca x(i) < min atunci
min = x(i)
altfel
daca x(i) > max atunci
max = x(i)
sfarsit daca
sfarsit daca
sfarsit pentru
scrie( minimul este , min )
scrie( maximul este , max )
Return
Numarul de comparat ii ntre elemente necesare n determinarea indepen-
denta a min si max este 2(n1) (prin doua parcurgeri ale sirului), n schimb
pentru determinarea simultana a min si max avem nevoie de 3 n/2| 2
comparat ii (demonstrat i acest lucru). Sugeram cititorului sa verice algorit-
mul pentru intrarea x = (1, 2, 3, 4, 5, 6, 85, 2).
88
Gasirea celor mai mici doua elemente dintrun
sir
Ideea algoritmului prezentat mai jos este urmatoarea: se compara ele-
mentele 1 cu 2, 3 cu 4, etc; pentru ecare pereche comparata se determina
cel mai mic. Aceste elemente castigatoare se vor compara la randul lor pe
perechi adiacente, ca mai sus. Cand ramane un singur element, acesta este
minimul sirului. Atasam acestor operat ii un arbore binar (posibil nestrict)
echilibrat, construit n felul urmator: exista n noduri terminale (frunze),
ecare cont inand drept informat ie cate un element din sir; un nod netermi-
nal are drept valoare minimul din cei doi i (gura 9).
(a)
Ar-
borele
de
comparat ii
pen-
tru
vec-
torul
(7, 6, 4, 5, 2, 3, 1)
(b)
Ar-
borele
de
comparat ii
pen-
tru
vec-
torul
(7, 6, 4, 5, 2, 1, 3)
Figura 9.1: Exemple de arbori construit i conform strategiei de mai sus.
Evident ca pentru ecare nod neterminal, informat ia sa coincide cu a unui
descendent al sau.

In cadrul acestui algoritm vom folosi termenul nvins
n exprimarea x este nvins de y daca x > y (deoarece se cauta min-
imul). Pentru determinarea celui de al doilea minim trebuie sa determinam
cel mai mic element din vectorul init ial nvins de minim: n exemplele
date este 2, nvins de 1. Pentru aceasta vom considera informat ia din
cei doi descendent i ai radacinii, n ambele exemple date ind 4 si 1. 4 este
cel mai mic element din jumatatea stanga a sirului (este descendent stang
al radacinii) si va trebui sa cautam n jumatatea dreapta a sirului cel mai
mic numar, nvins de radacina; acest lucru se face (n exemplele date) co-
borand n subarborele drept spre frunze. Se compara toate elementele pe
care informat ia din radacina lea depasit cu minimul din jumatatea stanga
(n cazul nostru 4); coborarea se termina atunci cand e se ajunge la frunze
(cazul 9.1(b)), e este evident ca nu mai are sens coborarea (cazul 9.1(a)).

In algoritmul de mai jos nu se va construi explicit arborele. Se vor folosi


linii succesive ntro matrice pentru ment inerea pentru ecare element din
sirul anterior a elementelor nvinse de acestea.
89
MinMin(x, n, min1, min2)
pentru i = 1, n
A(1, i) = X(i)Prima linie a matricii cont ine sirul init ial
sfarsit pentru
k = n
j = 1
cat timp (k > 1)
k ne arata cate elemente mai avem pe linia curenta
j = j + 1j este linia din matrice unde pun nvingatorii
l = 0l este indicele pe linia j unde se vor pune elementele nvingatoare
pentru i = 1, k, 2
l = l + 1
daca a(j 1, i) < a(j 1, i + 1) atunci
a(j, l) = a(j 1, i)
altfel
a(j, l) = a(j 1, i + 1)
sfarsit daca
sfarsit pentru
daca mod(k/2) = 1 atunci
Daca k este impar
l = l + 1
a(j, l) = a(j, k)
sfarsit daca
k = l
sfarsit cat timp
min1 = a(j, 1)
daca a(j 1, 1) = min1 atunci
c = 1c va indicele minimului pe linia anterioara
min2 = a(j 1, 2)
altfel
c = 2
min2 = a(j 1, 1)
sfarsit daca
pentru i = j 2, 1, 1
ciclu care parcurge liniile matricii de jos n sus
daca a(i, 2 c 1) = min1 atunci
elco = a(l 1, 2 c)
c = 2 c 1
altfel
elco = a(l 1, 2 c 1)
90
c = 2 celco cont ine elementul cu care sa comparat min1, iar c va
cont ine indicele lui min1 de pe coloana anterioara
sfarsit daca
daca elco < min2 atunci
min2 = elco
sfarsit daca
sfarsit pentru
Return
Numarul de comparat ii se determina dupa cum urmeaza: n 1 pentru
determinarea minimului (terminarea ciclului cat timp), dupa care numarul
de comparat ii pentru determinarea lui min2 care face o comparat ie pe ecare
linie si avem log
2
(n) linii. Deci n total avem n +log
2
n| 2 comparat ii.
Problema select iei
Select ie n timp mediu liniar

In general determinarea celei de a ia componente este o problema avand


ca date de intrare un sir a cu n elemente distincte si un numar i cu propri-
etatea 1 i n, iar ca data de iesire un element rez al sirului a care are
proprietatea ca exista exact i 1 elemente ale sirului mai mici decat rez.
Sel(A, p, r, i, rez)
dac a p = r atunci
rez = a(p)
Return
sfarsit daca
Part(A, p, r, k)Part este algoritmul de partit ionare din QuickSort
daca i k atunci
Sel(a, p, k, i, rez)
altfel
Sel(a, k + 1, r, i k, rez)
sfarsit daca
Return
Algoritmul Sel aplicat unui sir deja sortat are (cel mai rau caz) complex-
itatea O(n
2
). Se poate arata (vezi lucrarile [5], [2]) ca pentru cazul mediu
complexitatea este de O(n).
91
Select ia n timp liniar n cazul cel mai defavorabil
Ideea algoritmului urmator este de a obt ine o part itionare mai buna decat
n versiunea precedenta a algoritmului. Vom folosi algoritmul Part modicat
astfel ncat sa preia ca parametru de intrare elementul n jurul caruia este
efectuata partajarea.
Algoritmul Selectie modicat determina al ilea cel mai mic element al
unui tablou de intrare de n elemente, efectuand urmatorii pasi (oprirea algo-
ritmului se face atunci cand subsirul pe care se face cautarea are un element,
caz n care se returneaaza aceasta unica valoare).
1. Se mpart cele n elemente ale tabloului de intrare n
n
5
| grupe de cate
5 elemente ecare si cel mult un grup sa cont ina restul de n mod 5
elemente.
2. Se determina mediana ecareia din cele
n
5
| grupe cu sortarea prin
insert ie, ordonand elementele ecarui grup (cu cel mult 5 elemente),
apoi se aleg medianele din listele sortate, corespunzatoare grupelor.
Daca n ultimul grup avem numar par de elemente, se va considera cel
mai mare din cele doua mediane.
3. Se utilizeaza recursiv Selectie pentru a gasi mediana x din cele
n
5
|
mediane gasite la pasul precedent.
4. Se partit ioneaza tabloul n jurul medianei medianelor x, utilizand o
versiune modicata a algoritmului Partitie. Fie k elemente din prima
parte a partit ionarii.
5. Se utilizeaza recursiv select ie pentru a gasi al ilea cel mai mic element
din partea inferioara (daca i k), sau al (ik)lea cel mai mic element
din partea a doua a partit iei (pentru i > k).

In [2] se arata ca se ajunge la o complexitate T(n) = O(n).


Heapsort
Fie vectorul:
v = 17 13 9 8 7 9 3 2 4 1
1 2 3 4 5 6 7 8 9 10
Arborele atasat este cel din Figura 9.2 (a se revedea sect iunea 4, pagina
40). Acest arbore are adancimea de log
2
n|.
92
Figura 9.2: Arborele atasat vectorului v
O structura careia i se poate pune n corespondent a un arbore binar
echilibrat se numeste HeapMax, daca oricare nod are o valoare mai mare
decat oricare din ii sai. Daca orice nod are valoarea mai mica decat oricare
dintre i, atunci structura se numeste HeapMin.
Algoritmul de heapicare a unui vector cu n elemente ncepand de la a
i-a componenta este:
Heapify(a, n, i)
imax = i
repeta
i = imax
l = 2 i
r = l + 1
daca l n si a(l) > a(i) atunci
imax = l
sfarsit daca
daca r n si a(r) > a(imax) atunci
imax = r
sfarsit daca
daca i ,= imax atunci
a(i) a(imax)
sfarsit daca
pana cand i = imax
Return
Algoritmul pentru costruct ia unui heap este urmatorul:
ConstruiesteHeap(a, n)
pentru i = [n/2], 1, 1
Heapify(a, n, i)
sfarsit pentru
Return
Fie sirul:
a = 5 3 2 1 10 4 15 11 9 6
1 2 3 4 5 6 7 8 9 10
Evolut ia arborelui la apelul ConstruiesteHeap(a, 10) este aratata n Figura
9.3.
93
Figura 9.3: Obt inerea unui maxheap din sirul (5, 3, 2, 1, 10, 4, 15, 11, 9, 6).
Complexitatea: pentru un nod de nalt ime h, complexitatea algoritmului
Heapify este de (h). Se poate arata ca pentru un heap cu n noduri ex-
ista cel mult
n
2
h+1
| noduri de nalt ime h. Deci timpul de execut ie pentru
ConstruiesteHeap este:
T(n) =
log
2
n

h=0
_
n
2
h+1
_
O(h) = O
_
_
n
log
2
n

h=0
h
2
h
_
_
Dar
log
2
n

h=0
h
2
h

h=0
h
2
h
=
1/2
(1 1/2)
2
= 2
Deci timpul de execut ie pentru algoritmul ConstruiesteHeap este O(n).
Folosim cei doi algoritmi de mai sus pentru sortare n modul urmator:
HeapSort(a, n)
ConstruiesteHeap(a, n)
pentru i = n, 2, 1
a(1) a(i)
Heapify(a, i 1, 1)
sfarsit pentru
Return
Sortarea cu HeapSort se face cu complexitatea O(n) + nO(log
2
n) =
O(nlog
2
n). Deoarece sortatea folosind comparat ii are complexitatea infe-
rioara (nlog
2
n) (sect iunea 8), rezulta ca algoritmul Heapsort are complex-
itatea (nlog n).
Exemplu: e sirul: a = (5, 3, 2, 1, 10, 4, 15, 11, 9, 6). Dupa apelul proce-
durii ConstruiesteHeap(a, 10) se obt ine heap-ul din Figura 9.4(a). Pentru
apelurile Heapify(a, i 1, 1) (i = n, n 1, . . . , 2) evolut ia este data n Fig-
urile 9.4(b)-9.4(j) (sau pus n evident a prin detasare elementele care nu vor
mai face parte din heap).
Rezultatul sortarii sirului a este: a = (1, 2, 3, 4, 5, 6, 9, 10, 11, 15).
Heapsort este un excelent algoritm de sortare, dar o implementare buna
a QuickSortului duce la sortari mai rapide. Heapul este nsa foarte util n
t inerea n evident a dinamica a cozilor de prioritat i unde o complexitate de
n care sar putea obt ine printrun algoritm cu insert ie este nlocuita cu o
complexitate de log n pastrand coada ntrun heap.
94
(a)
Dupa
apelul
pro-
ce-
durii
Heapify
(b)
i =
10
(c)
i =
9
(d)
i =
8
(e)
i =
7
(f)
i =
6
(g)
i =
5
(h)
i =
4
(i)
i =
3
(j)
i =
2
Figura 9.4: Evolut ia sirului si a heapului n subalgoritmul Heapsort.
Algoritmi de sortare n timp liniar
Exista algoritmi de sortare a caror complexitate este mai mica decat cea
teoretica de (nlog
2
n), dar pentru situat ii speciale ale sirului. Astfel, daca
sirul este constituit din numere ntregi pozitive (sau macar ntregi), sau daca
ele sunt numere distribuite uniformntrun interval, sau lund n considerare
cifrele numerelor din sir se pot da diferit i algoritmi de complexitate liniara
pentru sortare.
Algoritmul sortarii prin numarare (CountSort)
Un astfel de algoritm este algoritmul de sortare prin numarare numit
CountSort. Fie (x(i))
i=1,n
un sir de numere naturale strict pozitive si k
maximul acestui sir. Sortarea prin numarare constan gasirea a cate elemente
sunt mai mici decat x(i) (pentru ecare i); n acest fel vom sti pe ce pozit ie
trebuie sa se ae x(i) n sirul sortat (daca sunt m elemente mai mici decat
x(i), atunci el ar trebui sa se ae pe pozit ia m + 1 n sirul sortat).
Consideramsirul init ial x = (x(1), x(2), . . . , x(n)); y = (y(1), y(2), . . . , y(n))
va sirul sortat, iar c = (c(1), c(2), . . . c(k)) este un sir ajutator.
CountSort(x, n, y, k)
pentru i = 1, k
c(i) = 0
sfarsit pentru
pentru j = 1, n
c(x(j)) = c(x(j)) + 1
sfarsit pentru
pentru i = 2, k
95
c(i) = c(i) +c(i 1)
sfarsit pentru
pentru j = n, 1, 1
y(c(x(j))) = x(j)
c(x(j)) = c(x(j)) 1
sfarsit pentru
Return
Exemplu: x = (2, 7, 4, 1, 2, 4, 1, 4), k = 7.
- elementele lui c sunt init ializate cu 0:
c = (0, 0, 0, 0, 0, 0, 0)
- pentru i de la 1 la k, pe pozit ia i din c obt inem numarul de elemente
egale cu i n sirul x:
c = (2, 2, 0, 3, 0, 0, 1)
- pentru i = 2, k, pe pozit ia i a sirului c se obt ine cate elemente mai mici
sau egale cu i sunt n sirul x:
c = (2, 4, 4, 7, 7, 7, 8)
- pentru j = n, 1, cu pasul -1, se aa componentele sirului y sortat:
y = (1, 1, 2, 2, 4, 4, 4, 7)
Complexitatea algoritmului CountSort este (n+k). Daca k = O(n) (adica
exista o constanta c astfel ncat pentru orice n sucient de mare, sa avem
k < cn), atunci complexitatea algoritmului de sortare prin numarare este
(n).
Sortare pe baza cifrelor
Sa presupunem ca avem un sir de numere naturale, avand toate acelasi
numar d de cifre (daca nu, atunci un numar se poate completa cu zerouri
nesemnicative pana cand atinge numarul maxim de cifre din sir). Se poate
face ordonarea sirului de numere n felul urmator: se porneste de la cifra cea
mai put in semnicativa (ultima cifra) si se sorteaza elementele pe baza aces-
tei informat ii, obt inanduse o alta ordine (un alt sir). Se porneste de la acest
ultim sir generat si se sorteaza elementele dupa urmatoarea cifra mai put in
semnicativa (penultima cifra), pentru care se face sortarea elementelor; si
asa mai departe, n nal facanduse sortarea dupa cea mai semnicativa cifra
96
(prima cifra). Esent ial este ca daca sortarea se face dupa cifra i (numerotarea
cifrelor o consideram de la stanga spre dreapta, de la cifra cea mai semni-
cativ a la cea cea mai put in semnicativa), atunci se pleaca de la ordinea
obt inuta anterior pentru cifra i + 1 (1 i < d); n al doilea rand, algoritmul
care este folosit pentru sortarea cifrelor trebuie sa aiba urmatoarea propri-
etate: daca ntrun sir x = (x(1), . . . , x(n)) avem ca x(i) = x(j) si i < j, prin
sortare se ajunge ca x(i) sa e repartizat pe pozit ia i

, x(j) sa e repartizat
pe pozit ia j

, iar i

< j

(spunem ca algoritmul de sortare este stabil ).

In pseudocod, algoritmul este:


OrdonarePeBazaCifrelor(a, d)
pentru i = d, 1, 1
sorteaza stabil tabloul a dupa cifra i
sfarsit pentru
Return
Analiza algoritmului depinde n mod evident de complexitatea algoritmului
prin care se face sortarea pe baza unei cifre. De exemplu, daca numerele sunt
n baza b, se poate folosi sortarea prin numarare din sect iunea precedenta
(care este stabil). Pentru ecare cifra dupa care se face sortarea avem timpul
(n + b), iar pentru sortarea completa (ciclul pentru) complexitatea este
(d(n + b)). Daca d este constant si b = O(n), atunci complexitatea este
liniar a.
Sortare pe grupe
Pentru algoritmul prezentat aici, n ipotezan care numerele sunt uniform
distribuite (daca consideram intervalul dat de minimul si maximul din sir si
daca mpart im acest interval n k subintervale de lungime egala, atunci sansa
ca un numar oarecare din sir sa se gaseasca n oricare din cele k subintervale
este aceeasi; altfel spus, nu exsite zone n care numerele sa se concentreze n
numar mult mai mare decat n alte regiuni de aceeasi dimensiune), se poate
da un algoritm care n medie are complexitatea (n).
Vom considera fara a restrange generalitatea ca numerele sunt n inter-
valul [0, 1) (daca nu sunt, atunci putem proceda astfel: determinam min =
min x(i), i = 1, n si max = max x(i), i = 1, n; se efectueaza x(i) = x(i)min,
pentru i = 1, n - n acest fel se aduc numerele n intervalul [0, max min];
apoi se face mpart irea x(i) = x(i)/(max min + 1), prin care se aduc nu-
merele la intervalul [0, 1); dupa sortare se fac operat iile inverse, n ordinea
nmult ire, adunare). principiul algoritmului consta n a mpart i intervalul
[0, 1] n n intervale egale si sa introducem cele n numere n cele n grupe.
Daca numerele sunt uniform distribuite, nu ar trebui sa apara diferent e mari
97
ntre grupe, din punct de vedere a cate numere cont in. Se sorteaza numerele
din ecare grupa, dupa care se trece prin ecare grupa si se obt ine ordinea
crescatoare.
Algoritmul de mai jos considera ca ecare grupa este implementata ca o
list a nlant uita. Pentru subintervalul (k
1
n
, (k + 1)
1
n
), 0 k < n vom avea
lista nlant uita b(k).
SortarePeGrupe(a, n)
pentru i = 1, n
insereaza a(i) n lista b (n a(i)|)
sfarsit pentru
pentru i = 0, n 1
Sorteaza lista b(i) folosind sortarea prin insert ie
sfarsit pentru
Concateneaza listele b(0), b(1), . . . , b(n)
Return
Plecand de la proprietatea ca numerele sunt uniform distribuite, se arata n
[2] ca timpul mediu pentru sortarea pe grupe este O(n).
Rezumat
Not iunea de statistica de ordine generalizeaza pe cele de minim, maxim,
mediana. Selectarea celei de a i-a statistici de ordine se poate realiza n timp
liniar. Pentru cazuri particulare ale vectorilor care se sorteaza, se pot folosi
algoritmi liniari (se depaseste deci bariera de (nlog n) demonstrata pentru
algoritmi care lucreaza exclusiv pe baza comparat iilor).
Exercit ii (rezolvarile la pagina 186)
1. Descriet i un algoritm care, ind data o mult ime S de n numere ntregi
si distincte si un ntreg pozitiv k n, determina cele k numere care
sunt cele mai apropiate de mediana lui S.
2. Fie a[1 . . . n], b[1 . . . n] doua siruri sortate. Scriet i un algoritm perfor-
mant care gaseste mediana celor 2n numere.
3. Fiind data o mult ime de n numere, dorim sa gasim cele mai mari i
numere n ordinea sortata, folosind un algoritm bazat pe comparat ii.
Sa se scrie mai multe variante si sa se compare din punct de vedere al
complexitat ii.
98
4. Sa se modice algoritmul CountSort astfel ncat sa sorteze si siruri
cont inand numere ntregi negative.
99
100
Capitolul 10
Metoda Greedy
Obiective
Capitolul introduce o noua metoda de rezolvare a problemelor. Metoda
aceasta va arata cum se abordeaza problemele pentru care solut ia se poate
construi prin alegeri ale componentelor, alegeri asupra carora nu se revine.
Va trebui sa demonstram corectitudinea algoritmilor (fara de care acesta ar
doar un algoritm euristic vezi capitolul 12). Probleme clasice, ale caror
rezultate se pot folosi n cazuri mai generale sunt enunt ate si rezolvate (sau
sunt facute trimiteri bibliograce).
Prezentare generala
Metoda Greedy este o metoda de elaborare a algoritmilor ce determina
solut ia unei probleme de optimizare (sau pusa sub aceasta forma) nghit ind
(de aici greedy = lacom) cate o componenta n solut ia nala. Procedeul este
fara a reveniri cu alegere pe baza unui criteriu local folosind, eventual, o
pregatire prealabila a datelor.
Modul de rezolvare al problemelor dat de aceasta strategie este de a con-
strui solut ia componenta cu componenta. Se pleaca de la solut ia vida si la
ecare pas al algoritmului se selecteaza o valoare pentru o componenta; daca
aceasta valoare convine, atunci aceasta este pusa n solut ie pe componenta
respectiva. Metoda seamana cu metoda backtracking, dar, spre deosebire de
aceasta, nu revine sa nlocuiasca componente o data xate.
Strategia descrisa anterior are un posibil inconvenient dat de modul de
select ie. Daca la ecare pas alegem cea mai buna valoare n spiritul unui
criteriu local nu este sigur ca n nal vom obt ine solut ia optima cautata.
Metoda trebuie completata cu o demonstrat ie ca optimul obt inut prin pasi
101
de optim local , este un optim global. Altfel, daca solut ia gasita se aproapie
de solut ia optima spunem ca avem o solut ie Greedy eurisitca (vezi capitolul
12).
Procedura Greedy are deci urmatoarea forma:
Greedy(x)
x =
cat timp solut ia nu este completa
selecteaza o valoare a
daca valoarea a convine atunci
x = x a
sfarsit daca
sfarsit cat timp
Return
Pentru a elabora un algoritm prin metoda greedy vom parcurge etapele:
1. Pregatirea datelor ( de obicei sortari)
2. Elaborarea unui criteriu local de alegere
3. Elaborarea algoritmului dupa schema de mai sus
4. Demonstrarea corectitudinii alegerii facute aratand ca solut ia x

re-
specta criteriul global. Altfel se ncearca sa se determine cat de departe
este solut ia gasita de algoritm fat a de solut ia cautata.
Complexitatea solut iei Greedy este data de complexitatea pregatirii datelor,
de complexitatea select iei valorii la ecare pas si de numarul de select ii facute
de catre algoritm.

In general, metodele de tip Greedy sunt metode de com-
plexitate polinomiala, ceea ce ne face sa catam o solut ie de acest tip, n prima
instant a.
Dam, n continuare cateva exemple clasice:
Problema submult imilor de suma maxima
Avand la intrare x = (x(i), i = 1, n) o mult ime de elemente sa se deter-
mine submult imea y = (y(i), i = 1, k) de suma maxima.
Problema este o problema de optimizare care se rezolva prin Greedy.
Modelul matematic este:
max
_

yY
y[ , = Y X
_
Gasim usor un criteriu de selet ie foarte simplu bazat pe observat iile:
102
1. dacan mult imea x sunt numere pozitive, adaugarea unuia la submult imea
y conduce la cresterea sumei; deci submult imea y va formata din toate
elementele pozitive;
2. Daca toate elementele sunt negative sau nule, submult imea y este for-
mata cu cel mai mare element.
Deci la ecare pas vom alege n y cate un element pozitiv. Daca nu sunt,
atunci alegem n y elementul maximal.
SumaMax(n, x, k, y)
k = 0
pentru i = 1, n
daca x(i) 0 atunci
k = k + 1
y(k) = x(i)
sfarsit daca
sfarsit pentru
daca k = 0 atunci
max = x(1)
pentru i = 2, n
daca x(i) > max atunci
max = x(i)
sfarsit daca
sfarsit pentru
k = 1
y(k) = max
sfarsit daca
Return
Se vede ca ecare din cele n select ii are complexitate (1), si n nal vom
avea o complexitate (n).
Teorema 2 (Corectitudine). Submult imea y determinata de acest algoritm
are suma elementelor maxima fat a de toate submult imile lui x.
Demonstrat ie. Notam sum(x) suma elementelor din x. Fie Sm submult imea
de suma maxima. Vom arata ca n ambele cazuri y = Sm.
1. Sa presupunem ca n x nu sunt elemente pozitive. Atunci sum(Sm)
Sm(j) max x(i), i = 1, n = sum(y) sum(Sm); deci y = Sm
unde j este un indice oarecare.
2. Daca n x sunt elemente pozitive atunci:
103
(a) Sm nu va cont ine elemente negative pentru ca daca z ar cont ine
elementul x(i) negativ, atunci sum(Sm) = sum(Sm x(i)) +
x(i) < sum(Smx(i)) cea ce contrazice faptul ca Sm este de
suma maximala;
(b) Daca Sm cont ine toate elementele pozitive atunci daca Sm nu
cont ine elementul strict pozitiv x(i) atunci sum(Sm) < sum(Sm

x(i))
cea ce este fals.
Arborele Human
Una din cele mai interesante probleme este urmatoarea:
Fie S = s
1
, s
2
, . . . , s
n
este o mult ime de semnale si p = (p(i), i = 1, n)
probabilitat ile asociate lui S. Sa se determine codul de lugime optima asociat
lui S.
De exemplu alfabetul Morse este un astfel de cod. O caracteristica a
acestui cod este aceea ca simbolurile cele mai probabile sunt codicate cu mai
put ine caractere, astfel ncat, la tramsmiterea unui mesaj, costul transmisiei
sa e minim. Mai ntai cateva not iuni de teoria codurilor.
Un cod binar este o aplicat ie injectiva : S 0, 1
+
. Lungimea medie
a codului cu sistemul de probabilitat i dat mai sus este denita de L() =

n
i=1
[(s
i
)[p(i) (unde [(s
i
)[ este numarul de caractere a lui (s
i
)). Vom
spune ca un cod este optim daca minimizeaza lungimea medie L() . Asociem
unui cod instantaneu : S 0, 1
+
arborele T

care are urmatoarele


proprietat i:
- numarul de frunze este egal cu numarul de semnale ale lui S;
- drumul, n arbore, de la radacina la orice frunza s S este o codicarea
(s) prin concatenarea marcajelor muchiilor.
Lungimea medie a unui cod este data de lungimea medie a arborelui asociat,
adica:
L() =
n

i=1
[(s
i
)[p(i) =
n

i=1
niv
T

(s
i
)p(i) = L(T

)
unde niv
T

(s
i
) este nivelu n arborele T

a lui (s
i
).
Un arbore Human asociat sistemului de numere reale p = (p(i), i = 1, n)
este un arbore care minimizeaza L(T) =

n
i=1
niv
T
(s
i
)p(i).
104
Vom memora o structura arborescenta prinnlant uire (vezi capitolul 4) n
care n campul de informat ie avem probabilitatea sau frecvent a simbolului.
Algoritmul lui Human construieste codul optim prelucrand o padure
dupa urm oarele reguli:
- init ial padurea este formata din varfuri izolate reprezentand semnalele.
- se repeta :
1. selecteaza arborii padurii avand informat ia cea mai mica;
2. se conecteaza cei doi arbori alesi ntrunul singur printro radacina
comuna avand informat ia suma informat iilor din arbori
Proceura Human pentru determinarea arborelui minim va :
Human(n, s, p, rad)
pentru i = 1, n
s(i) LIBERELIBERE este zona din care se fac alocari de memorie
LS(s(i)) =
LD(s(i)) =
INFO(s(i)) = p(i)
sfarsit pentru
Sort(n, s)
pentru i = n, 2, 1
x LIBERE
LS(x) = s(i)
LD(x) = s(i 1)
INFO(x) = p(i) +p(i 1)
j = i 1
pentru j > 0 si INFO(x) > INFO(s(j))
s(j + 1) = s(j)
j = j 1
sfarsit pentru
s(j + 1) = x
sfarsit pentru
rad = s(1)
Return

In algoritmul precedent procedura Sort face sortarea semnalelor s(i), i =


1, n descrescatoare dupa p(i).
Teorema 3 (Complexitate). Algoritmul Human are complexitatea (n
2
).
Demonstrat ie. Complexitatea algoritmului depinde de complexitatea sortarii
si de complexitatea select iilor. Minimul pentru complexitatea sortarii prin
105
comparat ii este (nlog n) (vezi 8). Select iile ce se fac utilizeaza principiul
inserarii directe a semnalului p n structura (s(j), j = 1, i 1) si facem cel
mult i1 comparat ii deci, n nal, vom avea

n
i=1
i1 = n(n1)/2 = (n
2
)
comparat ii.
Teorema 4 (Corectitudine). Algoritmul Human genereaza un cod optim n
raport cu probabilitat ile p = (p(i), i = 1, n).
Demonstrat ie. Folosim, n demonstrat ie, notat iile:
H = H(p
1
, . . . , p
n
) - arborele dat de algoritmul lui Human
T = T(p
1
, . . . , p
n
) - arborele optim, unde p(i) = p
i
, i = 1, n.
Pentru arborele optim putem arata ca:
p
i
< p
j
rezulta niv
T
(s
i
) > niv
T
(s
j
)
exista un arbore optim n care semnalele cele mai put in probabile sunt
frat i.
Daca s
i
si s
j
sunt semnalele cu probbabilitatea cea mai mica atunci, prin
unirea celor doua semnale, se creeaza un nou semnal notat s
i,j
.
Algoritmul nosrtu construieste un arbore binar dupa regula exemplicata
de gura 10.1. Calculul lungimii este:
Figura 10.1: Crearea unui nod pe baza semnalelor cele mai put in probabile
L(H) =
n

i=1
niv(s
i
) =
n2

i=1
niv(s
i
)p(i) +niv(s
n1
)p(n 1) +niv(s
n
)p(n)
si pentru ca niv(s
n1
) = niv(s
n
) rezulta ca:
L(H) =
n2

i=1
niv(s
i
)p(i) + (p(n 1) +p(n))niv(s
n1
) 1 +
+ p(n 1) +p(n) =
=
n2

i=1
niv(s
i
))p(i) +p(n 1, n)niv(s
n,n1
) +p(n 1) +p(n)
n nal vom avea:
L(H(p(1), . . . , p(n))) = L(H(p(1), . . . , p(n 1) +p(n))) +p(n 1) +p(n)
106
Analog se arata ca si arborele optim, care i are pe s
n1
si s
n
ca frat i,
veric a:
L(T(p(1), . . . , p(n))) = L(T(p(1), . . . , p(n 1) +p(n))) +p(n 1) +p(n).
Vom face demonstrat ia optimalitat ii prin induct ie dupa n.
Pentru n = 2 algoritmul ne ofera H(p(1), p(2)) care codica pe s
1
cu 0 si
pe s
2
cu 1, ceea ce nseamna ca este un cod optim.
Presupunem ca avem proprietatea adevarata pentru n semnale si anume
codul Human asociat semnalelor s
1
, . . . , s
n
este optim.
Demonstram proprietatea pentru n + 1:
Fie p = (p(i), i = 1, n + 1) un cod cu n + 1 probabilitat i n care p(n 1)
si p(n 2) sunt cele mai mici doua numere din sirul p. Aplicand formulele
anterioare vom avea:
L(H(p(1), . . . , p(n), p(n + 1))) = L(H(p(1), . . . , p(n) +p(n + 1)) +p(n) +p(n + 1))
L(T(p(1), . . . , p(n), p(n + 1))) = L(T(p(1), . . . , p(n) +p(n + 1)) +p(n) +p(n + 1))
Deoarece arborele Human codica n semnale n mod optim avem:
L(T(p(1), . . . , p(n) +p(n + 1))) L(H(p(1), . . . , p(n) +p(n + 1)))
Deunde rezulta:
L(T(p(1), . . . , p(n) +p(n + 1))) +p(n) +p(n + 1) L(H(p(1), . . . , p(n)
+p(n + 1))) +p(n) +p(n + 1)
si deci L(T(p(1), . . . , p(n), p(n + 1))) L(H(p(1), . . . , p(n), p(n + 1))) Daca
T este optim atunci:
L(T(p(1), . . . , p(n), p(n + 1))) = L(H(p(1), . . . , p(n), p(n + 1)))
deci si H va un arbore optim.
Interclasare optimala
Avand la intrare o mult ime de vectori sortat i crescator se cere algoritmul
care arata ordinea interclasarii acestora cu numarul minim de comparat ii.
Avem deci la intrare: n - numarul de vectori, nr = (nr(i), i = 1, n) -
numarul de elemente din ecare vector, x(i) = (x(i, j), j = 1, nr(i)) sirul de
vectori.
107
Daca interclasarea a doi vectori o facem prin algoritmul Interclasare din
capitolul 3 dimensiunile vectorilor ind m, respectiv n atunci numarul de
comparat ii este cel mult m + n.

In funct ie de ordinea de interclasare al
vectorilor se obt ine un numar diferit de comparat ii. Trebuie deci sa gasim o
ordine care conduce la un numar minim de comparat ii.
Vom nota x+y vectorul obt inut prin interclasarea lui x cu y. Daca avem
4 vectori x, y, z, t cu respectiv 10, 200, 40 si 60 de elemente atunci:
interclasarea ((x+y)+z)+t se face cu (10+200)+(210+40)+(250+60)=770
comparat ii
inteclasarea ((z+y)+t)+x se face cu (40+200)+(240+60)+(300+10)=850
comparat ii
deci prima strategie este mai buna decat a doua (si, de fapt, nu este cea
optima).
Va propunem sa o cautat i acum pe cea mai buna.
Din acest exemplu, a doua ncercare, se observa ca lungimea maxima
de 200 se regaseste n toate interclasarile ce se efectueaza conducand la un
numar mare de comparat ii. Ar bine ca vectorii cu dimensiuni mici sa se
se interclaseze prima data astfel ncat aceste valori mici sa apara n sumele
succesive de interclasare si valorile mari sa apara de mai put ine ori. Strategia
greedy va ca la ecare pas sa selectam vectorii de dimensiune minima.
Pregatirea, la ecare pas, va sa pastram n matricea x vectorii de-
screscator dupa nr. Vom selecta ultimii 2 vectori din matricea x. Dupa
realizarea interclasarii noul vector se insereaza n matrice folosind, de ex-
emplu, insert ia directa. Procedeul se repeta pana cand ramane un singur
vector.
InterOpt(n, nr, x, z)
Sortare(n, nr, x)
pentru i = n 1, 1, 1
Inter(nr(i + 1), x(i + 1), nr(i), x(i), y)
n1 = nr(i)
n2 = nr(i + 1)
j = i 1
cat timp j > 0 si n(j) > n1 +n2
pentru k = 1, nr(j)
x(j + 1, k) = x(j, k)
sfarsit pentru
nr(j + 1) = nr(j)
j = j 1
sfarsit cat timp
108
pentru k = 1, n1 +n2
x(j + 1, k) = y(k)
sfarsit pentru
nr(j + 1) = n1 +n2
sfarsit pentru
Return

In algoritmul de mai sus procedura Sortare face rearanjarea elementelor (lini-


ilor) matricii x descrescator n funct ie de vectorul nr iar Inter face inter-
clasare directa a doi vectori.
Pentru a analiza corectitudinea algoritmului denim arborele asociat unei
ordini de interclasare:
1. Unui vector i asociem un nod care are ca informat ie numarul de ele-
mente ale vectorului;
2. pentru interclasarea a doi vectori x(1) si x(2), arborele asociat este
reprezentat grac n gura 10.2;
3. Daca avem T
1
arborele asociat sirului de vectori x(i
1
), . . . , x(i
k
) si T
2

arborele asociat sirului de vectori x(i
k+1
), . . . , x(i
n
) atunci T din gura
10.3 va arborele asociat prin strategie sirului de vectori x(i
1
), . . . , x(i
n
).
Figura 10.2: Arbore construit pe baza a doi vectori
Figura 10.3: Arbore construit pe baza a doua subsecvent e de vectori.
Avem urmatoarel proprietat i pentru arborele asociat unui sir de vectori:
- arborele are atatea frunze cat i vectori sunt n sirul de vectori;
- informat ia atasata unui nod o vom calcula ca suma dimensiunilor vec-
torilor din subarborii nodului;
- daca un vector apare pe nivelul p atunci termenii sirului vor apare n
exact p interclasari;
- numarul total de comparat ii dat de ordinea dicata de arbore este L(T) =

n
i=1
nr(i) niv(i) n + 1 unde niv(i) este nivelul n T al vectorului
x(i)
109
Teorema 5 (Corectitudine). Algoritmul InterOpt determina interclasarea
vectorilor x(i), i = 1, n cu numar minim de comparat ii.
Demonstrat ie. Sa observam ca arborele asociat unei strategii de interclasare
ete arborele Human asociat numerelor nr(1), . . . , , nr(n). Algoritmul are
acelasi mod de construct ie ca si arborele Human deci suma

n
i=1
nr(i)
niv(i) este minima si L(T) este minim.
Teorema 6 (Complexitate). Notam cu L numarul de comparat ii rezultat din
interclasarile directe. Algoritmul InterOpt are complexitatea (L +n
2
).
Demonstrat ie. Complexitatea algoritmului este data de numarul de comparat ii
facut de interclasarile directe n si de numarul de comparat ii dat de pastrarea
structurii x. Pentru acesta se observa ca inserarea directa foloseste cel mult
i 1 comparat ii pentru ounerea sirului y n structura x. Deci numar total
este
n

i=2
(i 1) = (n
2
) comparat ii.
Rezumat
Metoda Greedy nseamna construirea pas cu pas a solut iei, prin alegerea
componentelor pe baza unei strategii deduse din enunt ul problemei. Spre
deosebire de metoda Backtracking, nu se revine asupra unei decizii. Metoda
greedy poate folosita si pentru elaborarea unor algoritmi euristici (care nu
determina optimul, sau pentru care o demonstrat ie de corectitudine nu este
data). Pentru ecare rezolvare greedy trebuie sa se ncerce justicarea prin
metode matematice a optimalitat ii solut iei.
Exercit ii (rezolvarile la pagina 190)
1. Daca x = (x(i), i = 1, m), y = (y(i), i = 1, n) reprezinta doua mult imi
de elemente, atunci sa se determine mult imea intersect ie z = (z(i), i =
1, k).
2. Danduse n obiecte de cost c = (c(i), i = 1, n) cu greutatea g =
(g(i), i = 1, n) si un rucsac de capacitate maxima G, sa se elaboreze un
algoritm de umplere a rucsacului de cost maxim. Un obiect poate pus
n rucsac ntrun anumit procent (problema continua a rucsacului).
110
3.

Intro sala, ntro zi trebuie planicate n spectacole. Pentru ecare
spectacol se cunoaste intervalul n care se desfasoara: [st, sf). Se cere
sa se planice un numar maxim de spectacole astfel ncat sa nu se
suprapuna..
4. Se dau n numere ntregi nenule b
1
, . . . , b
n
si m numere ntregi nenule
a
1
, . . . a
m
, n m. Sa se determine o submult ime a mult imii B =
b
1
, . . . , b
n
care sa maximizeze valoarea expresiei:
E = a
1
x
1
+a
2
x
2
+ +a
m
x
m
unde x
i
B..
5. O stat ie de servire trebuie sa satisfaca cererile a n client i. Timpul de
servire pentru ecare client este cunoscut: pentru clientul i timpul este
t
i
. Sa se minimizeze timpul total de asteptare
T =
n

i=1
(timpul de asteptare pentru clientul i)
6. Se da un sir n, (A(i), i = 1, n) si un numar S. Se cere algoritmul care
gaseste minimul de elemente din A a caror suma este mai mare sau
egala cu S.
111
112
Capitolul 11
Programare dinamica
Obiective

In acest capitol se prezinta metoda programarii dinamice. Denumirea de


programare nu vine de la un program scris ntrun limbaj oarecare pentru
calculator; denumirea vine de la utilizarea a unor tabele care se completeaza
sistematic. La fel ca la metoda Divide et impera problema init iala este
mpart ita n subprobleme si rezultatul se obt ine din combinaarea solut iilor
subproblemelor, dar de data aceasta subproblemele nu mai sunt disjuncte, ci
se suprapun part ial. Dupa parcurgerea materialului, cititorul ar trebui sa e
familiarizat cu trasaturile generale ale unei probleme pentru care se apeleaza
la programarea dinamica si sa si nsuseasca strategia generala de rezolvare
a unei probleme folosind aceasta metoda.
Prezentare generala
Programarea dinamica se aplica problemelor de optimizare sau prob-
lemelor care pot puse sub aceasta forma.
O problema de optimizare nseamna optimul (maximul sau minimul) un-
eia sau mai multor funct ii pe un anumit domeniu (numit al solut iilor admis-
ibile). Solut ia unei astfel de probleme are, deci, un dublu aspect. Valoarea
funct iei (sau funct iilor) obiectiv solut ia n spat iul obiectivelor, si punctul
din domeniu pe care se obt ine aceasta valoare solut ia n spat iul deciziilor.
Pentru realizarea uniu algoritm prin metoda programarii dinamice trebuie
sa parcurgem urmatorii patru pasi:
1. Caracterizarea structurii unei solut ii optime ca avand subsolut ii optime
2. Denirea recursiva a valorii unei solut ii optime
113
3. Calculul valorii unei solut ii optime (n spat iul obiectivelor) plecand de
la subprobleme de dimensiune mica si, trecand prin unele de dimensiuni
din ce n ce mai, mariajungand la solut ia problemei init iale
4. Memorarea unor informat ii care sa permita construirea solut iei optime
din spat iul deciziilor.
Al patrulea pas poate cateodata omis cum se poate vedea n problema 4.

Inmult irea unui sir de matrici


Este foarte usor, pentru cititorul ajuns n acest punct, sa scrie algoritmul
de nmult ire a doua mtrici:
Inmultire(A, n, m, B, p, q, C)
daca m ,= p atunci
scrie( dimensiuni incompatibile! )
altfel
pentru i = 1, n
pentru j = 1, q
C(i, j) = 0
pentru k = 1, m
C(i, j) = C(i, j) +A(i, k) B(k, j)
sfarsit pentru
sfarsit pentru
sfarsit pentru
sfarsit daca
Return
Matricile A de n linii si m coloane se poate nmult i si B de p linii si
q coloane daca numarul de coloane al lui A este egal cu numarul de linii
al lui B adica m = p. Produsul, C, va o matrice cu n linii si q coloane.
Din imbricarea celor trei cicluri pentru rezulta imediat complexitatea acestui
subalgoritm data de numarul de nmult iri de numere:
T(n) = n mq
Ne punem urmatoarea problema: Se da un sir A
1
, A
2
, . . . , A
n
de n ma-
trici care trebuie nmult ite n aceasta ordine. T inand cont de asociativitatea
nmult irii matricilor acest produs se poate face n mai multe moduri fxand
ordinea cu ajutorul parantezelor. Daca produsul A
1
A
n
este parantezat
(aceasta rezulta din faptul ca nmult irea matricilor este operat ie binara). Un
114
produs de matrici este complet parantezat daca este format dintro sigura
matrice sau daca este format din factori complet parantezat i.
De exemplu produsul A
1
A
2
A
3
A
4
poate parantezat astfel:
(A
1
(A
2
(A
3
A
4
)))
(A
1
((A
2
A
3
) A
4
))
((A
1
A
2
) (A
3
A
4
))
((A
1
(A
2
A
3
)) A
4
)
(((A
1
A
2
) A
3
) A
4
)
adica n cinci moduri.
Modul n care punem parantezele poate sa dea diferent e mari la numarul
de nmult iri de numere. Spunemn mod special cand este vorba de nmult iri
de numere pentru a ne dierent ia de nmult irile de matrici.
Pentru a vedea modul n care apar numere diferite de nmult iri de numere,
la parantezari diferite ale produsului de matrici, sa consideram problema
sirului A
1
, A
2
, A
3
.Fixam dimensiunile matricilor la 10 50, 50 5, 5 100.
Daca efectuamnmult irile pentru ((A
1
A
2
) A
3
), atunci vom avea 10 50
5 = 2500 nmult iri scalare pentru a efectua (A
1
A
2
), care va o matrice
de dimensiune 10 5, plus alte 10 5 100 = 5000 nmult iri pentru a
efectua (A
1
A
2
) A
3
, deci n total rezulta 7500 nmult iri de numere. Pentru
parantezarea (A
1
(A
2
A
3
)) vom avea 505100 = 25000nmult iri de numere
pentru a efectua A
2
A
3
, care va o matrice de dimensiune 50 100, plus
alte 1050100 = 50000 nmult iri de numere pentru a efectua A
1
(A
2
A
3
).
Deci rezulta un numar de 75000 nmult iri de numere; a doua varianta este
de 10 ori mai proasta.
Cum ar sa calculam numarul denmult iri de numere pentru toate paran-
tezarile posibile?
Sa notam cu P(n), numarul de parantezari distincte al unui sir de n
matrici. Un sir de n matrici se poate mpat i printro paranteza pusa ntre
matricile k si k + 1 pentru orice k = 1, . . . , n 1 si apoi putem descompune
n paranteze, n mod independent, ecare din siruri. Obt inem, n acest mod,
ecuat ia de recurent a:
P(n) =
_
_
_
1 daca n = 1
n1

k=1
P(k)P(n k) daca n 2
(11.1)
Numerele dente de (11.1) se numesc numerele lui Catalan si se arata ca
P(n) =
1
n
C
n1
2n2
, de unde P(n) = (
4
n
n
2
). Numarul de solut ii este exponent ial,
deci ar o strategie slaba.
Conform cu schema prezentata mai sus, vom cauta caracterizarea solut iei
optime. Notam matricea obt inuta n urma evaluaarii a produsului A
i
A
i+1

115
. . . A
j
cu A
i...j
. O parantezare optima a produsului A
1
. . . A
n
va pune o
paranteza ntre A
k
si A
k+1
pentru un anumit k din intervalul 1 . . . n. Adica
pentru o valoare a lui k, mai ntai calculam matricele A
1...k
si A
k+1...n
si apoi
le nmult im pentru a obt ine rezultatul nal A
1...n
. Numarul de nmult iri
de numere al parantezarii optime este dat de numarul de nmult iri pentru
matricea A
1...k
plus cel pentru A
k+1...n
si plus numarul de nmult iri pentru a
obt ine matricea nala A
1...n
. Sa observam ca parantezarea subsirului A
1
. . .
A
k
n cadrul parantezarii optime a produslui A
1
. . . A
n
este o parantezare
optima pentru A
1
. . . A
k
, pentru ca altfel, daca am presupune ca mai exista
o metoda de parantezare mai put in costisitoare a lui A
1
. . . A
k
ar contrazice
faptul ca parantezarea pentru A
1
. . . A
n
este optima. La fel se tampla
si pentru parantezara lui A
k+1
. . . A
n
. Deci, o solut ie optima a problemei
cont ine solut ii optime pentru subprobleme.
Pentru doilea pas sa denim valoarea solut iei optime n mod recursiv, n
funct ie de solut iile optime ale subproblemelor.

In cazul problemei nmult irii
sirului de matrice, o subproblema consta n determinarea costului minim al
unei parantezari a sirului A
i
A
i+1
A
j
, pentru 1 i j n. Notam
cu m(i, j) numarul minim de nmult iri de numere necesar pentru a calcula
matricea A
i...j
; numarul optim de calcul al lui A
1...n
va m(1, n). Formula
pentru m(i, j) este (11.2):
m(i, j) =
_
0 daca i = j
min
ik<j
m(i, k) +m(k + 1, j) +p
i1
p
k
p
j
daca i < j
(11.2)
Valorile m(i, j) sunt costul solut iilor optime ale subproblemelor. Pentru
a putea construi solut ia optima n spat iul deciziilor denim s(i, j) care va
cont ine valoarea k pentru care mpart irea produsului A
i
. . . A
j
produce o
parantezare optima. Adica s(i, j) este egal cu valoarea lui k pentru care
m(i, j) = m(i, k) +m(k + 1, j) +p
i1
p
k
p
j
.
Algoritmul recursiv dat de recurent a (11.2), care sa calculeze costul minim
m(1, n) pentru produsul A
1
. . . A
n
necesita timp exponent ial la fel ca si
cautarea completa a parantezarilor. Un algoritm recursiv ar ntalni ecare
subproblema de mai multe ori pe ramuri diferite ale arborelui sau de recurent a.
Aceasta este o proprietate specica programarii dinamice.
T inand cont de pasul al treilea din schema programarii dinamice, prezen-
tata la nceput, vom calcula costul optimal cu o abordare bottomup.
Algoritmul pe care l prezentam presupune ca matricele A
i
au dimensiunile
p
i1
p
i
pentru orice i = 1, . . . , n. Avem, la intrare, secvent a (p
0
, . . . , p
n
) de
n+1 elemente. Folosim un tablou auxiliar m(1 . . . n, 1 . . . n) pentru costurile
m(i, j) si un tablou auxiliar s(1 . . . n, 1 . . . n) care nregistreaza acea valoare
a lui k pentru care sa obt inut costul optim n calculul lui m(i, j), conform
116
(11.2). Obt inem, n acest fel, urmatorul algoritm:
InmultireMatrici(p, m, s, n)
pentru i = 1, n
m(i, i) = 0
sfarsit pentru
pentru l = 2, n
pentru i = 1, n l + 1
j = i +l 1
m(i, j) =
pentru k = i, j 1
q = m(i, k) +m(k + 1, j) +p
i1
p
k
p
j
daca q < m(i, j) atunci
m(i, j) = q
s(i, j) = k
sfarsit daca
sfarsit pentru
sfarsit pentru
sfarsit pentru
Return
Algoritmul completeaza tabloul m corespunzator rezolvarii problemei paran-
tezarii unor siruri de la 2,3,... matrici. Formula (11.2) arata ca costul de
calcul al sirului de j i + 1 matrici m(i, j) depinde doar de costurile cal-
cularii produselor sirurilor de mai put in de j i + 1 matrici. Adica pentru
k = i, i + 1, . . . , j 1, matricea A
i...k
este un produs de k i + 1 < j i + 1
matrici, iar matricea A
k+1...j
este un produs de j k < j i + 1 matrici.

In ciclul pentru i = 1, n algoritmul init ializeaza m(i, i) = 0 (costul minim


al sirurilor de lungime 1). La prima execut ie a ciclului pentru l = 2.n se
calculeaza, cu formula (11.2), m(i, i + 1) pentru i = 1, 2, . . . , n 1 (costul
minim al sirurilor de lungime 2 produse de doua matrici). La a doua trecere
prin ciclul pentru l = 2, n se calculeaza m(i, i + 2), pentru i = 1, 2 . . . , n 2
(costul minim al sirurilor de lungime 3),... etc. La ecare pas, costul m(i, j)
calculat n ciclul pentru k = i, j 1 depinde doar de celulele deja calculate
ale tabloului m(i, k) si m(k + 1, j).

In tabelul 11.2 de mai jos este descris mersul algoritmului pentru un sir
de n = 7 matrici avand dimensiunile date n tabelul 11.1.
Observat i ca se completeaza mai ntai diagonala principala cu 0, apoi di-
agonala de deasupra ei si n continuare matricile sunt completate pe diagonale
succesiv paralele cu diagonala principala.
Valorile n matricea s se completeaza n paralel cu valorile n matricea m
si n aceeasi ordine.
117
Matrice Dimensiune
A
1
25 35
A
2
35 15
A
3
15 5
A
4
5 10
A
5
10 20
A
6
20 10
A
7
10 20
Tabelul 11.1: Dimensiunile matricelor care se nmult esc
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 0 0 0 0 0 0 1 0 0 0 0 0
0 0 2625 0 0 0 0 0 0 2 0 0 0 0
0 0 0 750 0 0 0 0 0 0 3 0 0 0
0 0 0 0 1000 0 0 0 0 0 0 4 0 0
0 0 0 0 0 2000 0 0 0 0 0 0 5 0
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 7000 0 0 0 0 0 1 1 0 0 0 0
0 0 2625 4375 0 0 0 0 0 2 3 0 0 0
0 0 0 750 2500 0 0 0 0 0 3 3 0 0
0 0 0 0 1000 2000 0 0 0 0 0 4 5 0
0 0 0 0 0 2000 4000 0 0 0 0 0 5 6
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0

In tablourile m, s sunt utilizate doar elementele de desupra diagonalei


principale. Numarul minim de nmult iri scalare necesare nmult irii acestor
sapte matrici este m(1, 7) = 12500. Pentru a calcula cu formula q = m(i, k)+
m(k + 1, j) +p
i1
p
k
p
j
pe m(2, 5), procedam ca mai jos:
m(2, 5) =
_
_
_
m(2, 2) +m(3, 5) +p
1
p
2
p
5
= 0 + 2500 + 35 15 20 = 13000
m(2, 3) +m(4, 5) +p
1
p
3
p
5
= 7125
m(2, 4) +m(5, 5) +p
1
p
4
p
5
= 11375
_
_
_
= 7125
118
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 7000 8250 0 0 0 0 1 1 3 0 0 0
0 0 2625 4375 7125 0 0 0 0 2 3 3 0 0
0 0 0 750 2500 2750 0 0 0 0 3 3 3 0
0 0 0 0 1000 2000 3000 0 0 0 0 4 5 6
0 0 0 0 0 2000 4000 0 0 0 0 0 5 6
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 7000 8250 10500 0 0 0 1 1 3 3 0 0
0 0 2625 4375 7125 6375 0 0 0 2 3 3 3 0
0 0 0 750 2500 2750 4500 0 0 0 3 3 3 3
0 0 0 0 1000 2000 3000 0 0 0 0 4 5 6
0 0 0 0 0 2000 4000 0 0 0 0 0 5 6
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 7000 8250 10500 10250 0 0 1 1 3 3 3 0
0 0 2625 4375 7125 6375 9125 0 0 2 3 3 3 3
0 0 0 750 2500 2750 4500 0 0 0 3 3 3 3
0 0 0 0 1000 2000 3000 0 0 0 0 4 5 6
0 0 0 0 0 2000 4000 0 0 0 0 0 5 6
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0
Tot din tabel deducem ca avem o paranteza dupa A
3
(s(1, 7)), apoi ntre
A
1
si A
3
dupa cum spune s(1, 3) paranteza este dupa A
1
, iar ntre A
4
si
A
7
paranteza este dupa A
5
(vezi s(4, 7)) si ntre A
6
si A
7
, dupa cum spune
s(6, 7) = 6, paranteza este dupa A
6
. Deci parantezarea va arata astfel:
(A
1
(A
2
A
3
))(((A
4
A
5
)A
6
)A
7
).
Constatam usor ca timpul de execut ie este (n
3
).
119
1 2 3 4 5 6 7 1 2 3 4 5 6 7
0 13125 7000 8250 10500 10250 12500 0 1 1 3 3 3 3
0 0 2625 4375 7125 6375 9125 0 0 2 3 3 3 3
0 0 0 750 2500 2750 4500 0 0 0 3 3 3 3
0 0 0 0 1000 2000 3000 0 0 0 0 4 5 6
0 0 0 0 0 2000 4000 0 0 0 0 0 5 6
0 0 0 0 0 0 4000 0 0 0 0 0 0 6
0 0 0 0 0 0 0 0 0 0 0 0 0 0
Tabelul 11.2: Evolut ia algoritmului pentru matricile din tabelul 11.1.

In
partea stanga apare matricea m, n partea dreapta matricea s.
Cel mai lung subsir crescator
Problema se enunt an felul urmator: se da un sir de numere a = (a(i), i =
1, n). Sa se determine cel mai lung subsir crescator. Prin subsir se nt elege
un sir a(i
1
), a(i
2
), . . . , a(i
k
), unde 1 i
1
< i
2
< < i
k
n (elementele
subsirului nu sunt neaparat adiacente n sirul init ial).
Daca am considera toate subsirurile de elemente, atunci acestea ar
n numar de 2
n
1. Chiar daca am genera prin backtracking subsirurile
crescatoare ale lui a, tot la complexitate exponent iala sar ajunge.
Ideea este de a calcula, pentru ecare element al sirului a cel mai lung
subsir crescator care ncepe cu elementul respectiv.

In nal, se alege cel
mai mare subsir crescator din cele determinate pentru ecare element. Sa
presupunem ca cel mai lung subsir crescator care cont ine elementul a(p) este
a(i
1
), . . . , a(p), . . . , a(i
k
) (1). Facem armat ia ca subsirul a(p), . . . , a(i
k
) este
cel mai lung subsir crescator care se formeaza ncepand cu a(p). Daca prin
absurd nu ar asa, atunci ar nsemna ca am avea un alt subsir crescator
care sa nceapa cu a(p): a(p), . . . a(i
k
)(2). Ori, daca am considera subsirul
a(i
1
), . . . , a(p), . . . a(i
k
) (partea nala a lui (1) este nlocuita cu subsirul (2)),
atunci am avea un subsir crescator care sal cont ina pe a(p) mai lung decat n
cazul (1), ceea ce contrazice faptul ca am presupus (1) maximal. Deci optimul
total implica optimul local, o caracteristica a problemelor de programare
dinamica. Armat iile de mai sus reprezinta suportul pentru strategia de
rezolvare aleasa.
Vom considera un sir auxiliar L = (L(i), i = 1, n), care va avea pe pozit ia i
lungimea celui mai lung subsir crescator care ncepe cu valoarea a(i). Relat ia
120
pe care o respecta elementele acestui sir este:
L(i) =
_
1, daca i = n
1 + maxL(j)[j > i, a(j) a(i), daca i < n
(11.3)
unde pentru cazul mult imii vide de la a doua varianta maximul se ia 0.
Valorile lui L se vor calcula iterativ (implementarea recursiva ar extrem de
inecienta, datorita calculului repetat care sar face pentru aceleasi valori),
n ordinea L(n), L(n1), . . . , L(1). Pentru a determina mai usor subsirul de
lungime maxima, se construieste un sir sol = (sol(i), i = 1, n) care va cont ine
pentru valoarea i acel j care da minimul pentru 11.3, sau chiar valoarea i
daca un asemenea j nu exista. Determinarea lungimii maxime a unui subsir
se face apoi calculand max
i=1,n
(L(i)), iar determinarea efectiva a acestui sir se
face pe baza informat iei din sol.
Exemplu: a = (3, 2, 8, 6, 9, 7), n = 6. Atunci:
L(6) = 1, sol(6) = 6
L(5) = 1 + max = 1, sol(5) = 5
L(4) = 1 + maxL(5), L(6) = 2, sol(4) = 5
L(3) = 1 + maxL(5) = 2, sol(3) = 5
L(2) = 1 + maxL(3), L(4), L(5), L(6) = 3, sol(2) = 3
L(1) = 1 + maxL(3), L(4), L(5), L(6) = 3, sol(1) = 3
Valoarea maxima din vectorul L este 3, obt inuta pentru L(1) (si altele). Pe
baza vectorului sol obt inem si sirul crescator maximal: 2, urmat de elementul
de indice sol(1) = 3, adica a(3) = 8, care este urmat de elementul de indice
sol(3) = 5, adica a(5) = 9, pentru care avem sol(5) = 5, adica nu are
succesor.
Start SubsirCrescator
citeste( n, (a(i), i = 1, n) )
pentru i = n, 1, 1
L(i) = 1
sol(i) = i
pentru j = i + 1, n
Acest ciclu nu se executa niciodata pentru i = n
daca a(j) a(i) si 1 +L(j) > L(i) atunci
L(i) = 1 +L(j)
sol(i) = j
121
sfarsit daca
sfarsit pentru
sfarsit pentru
LMax = L(1)
pozLMax = 1
pentru i = 2, n
daca L(i) > LMax atunci
LMax = L(i)
pozLMax = i
sfarsit daca
sfarsit pentru
scrie( Lungimea maxima a unui subsir crescator este:, LMax )
scrie( a(LMax) )
i = pozLMax
cat timp sol(i) ,= i
i = sol(i)
scrie( a(i) )
sfarsit cat timp
Stop
Complexitatea acestui algoritm este (n
2
), datorita celor doua cicluri pentru
imbricate. Ment inam ca nu este absolut necesar vectorul sol, dar deter-
minarea solut iei se face mai usor pe baza lui.
Rezumat
Programarea dinamica este o metoda care se folosesste n cazurile n care
optimul general implica optimul part ial; n astfel de cazuri, demonstrat ia se
face de cele mai multe ori prin reducere la absurd. Pentru evitarea calcularii
acelorasi rezultate de mai multe ori, se apeleaza la tabelare rezultatele
pentru cazurile luate n considerare sunt memorate ntro structura de tip
matricial. Pe baza acestor informat ii, se poate determina solut ia atat n
spat iul oboectivelor cat si n spat iul deciziilor.
Exercit ii (rezolvarile la pagina 196)
1. Gasit i o parantezare optima a produsului unui sir de matrici al carui
sir de dimensiuni este (5, 10, 3, 12, 5, 50, 6) (adica 5 10, 10 3, etc).
2. Aratat i ca o parantezare completa a unei expresii cu n elemente are
exact n 1 perechi de paranteze.
122
3. Fie R(i, j) numarul de accesari ale elementului m(i, j) din tabloul
m, de catre algoritmul InmultireMatrici, pentru calcularea elementelor
tabloului. Aratat i ca:
n

i=1
n

j=i
R(i, j) =
n
3
n
3
. (Indicat ie:
n

i=1
i
2
=
n(n+1)(2n+1)
6
).
4. Se da o matrice subdiagonala. Se considera toate sumele n care se
aduna elementele de pe ecare linie aate sub elementul adunat anterior
sau sub-si-la-dreapta. Se cere un algoritm care gaseste suma maxima.
Exemplu:
5
2 3
8 1 2
5 9 3 4
Suma maxima este S = 5 + 2 + 8 + 9.
5. Folosind rezultatele lui InmultireMatrici sa se descrie un algoritm care
realizeaza nmult irea matricilor n ordine optima.
Pentru alte probleme cum ar : drumuri minime n grafuri, vezi [1].
123
124
Capitolul 12
Algoritmi euristici
Obiective

In acest capitol prezentam, printr-un exemplu, algoritmii euristici.


Prezentare generala
Un algoritm euristic da o solui e unei probleme de optimizare pentru
care nu avem o demonstrat ie a optimalitat ii, dar exista motive sa credem
ca nu este prea departe de optim. Un astfel de algoritm seamana cu metoda
Greedy, adica construieste solut ia pe baza unui criteriu de optim local , dar
lipseste demonstrat ia optimalitat ii.
O problema de taiere cu doua criterii de opti-
mizare.
Avem de a face cu o problema practica: avand de acoperit o camera
dreptunghiulara cu linoleum sau mocheta; materialul se aa n rulou care are
lat ime xa si care poate taiat tot numai ca un dreptunghi (la o anumita
lungime care trebuie determinata). Cautam o solut ie de acoperire a camerei
cu un numar minim de bucat i si cu o pierdere minima de material (pierderea
este diferent a dintre materialul cumparat si suprafat a camerei).
Pentru nceput vom arata ca cele doua criterii sunt contrarii, apoi vom
construi algoritmul care gaseste puncte de optim Pareto, adica puncte fat a
de care nu putem gasi altele cu ambele criterii satisfacute mai bine , adica si
mai mica pierdere si mai put ine bucat i.
125
Sa presupunem ca avem de acoperit o camera de 2m6m cu mocheta de
lat ime 3m. Putem sa facem asta cu o singura bucata de 3m 6m pierzand
18mp 12mp = 6mp, sau cu doua bucat i de 3m2m si pierdere zero.
Mai ntai sa vedem cum se poate acoeri o camera de dimensiuni a b cu
mocheta de lat ime x si lungime y unde avem, fara pierdere: a b = x y
Este evident ca daca x = a sau x = b atunci avem cele doua dreptunghiuri
egale si nu vom avea nici o taiere. Vom presupune, n continuare, fara a
restrange generalitatea, ca: x < a < b < y si , ca si n practica, putem
considera ca lucram numai cu numere ntregi.
Fie m = c.m.m.d.c.(a, b, x, y, ) (cel mai mare divizor comun). Putem
considera ca cele doua dreptunghiuri sunt mpart ite n patrate de dimensiune
m si de la mocheta la camera facem o permutare a acestor patrate. Este un
numar nit, dar inacceptabil de mare.
Algoritmul pe care l dam n continuare este bazat pe urmatoarele pro-
prietat i:
1. Punem mocheta pe podea acoperind doua laturi adiacente ale camerei
cu alte doua laturi corespunzatoare ale mochetei si taiem materialul
care este n plus; se obt ine, n acest fel, o noua bucata dreptunghiulara
de camera care trebuie acoperita cu restul de mocheta tot dreptunghi-
ular.
2. Mocheta poate pusa pe podea n doua direct ii ( vezi exemplul).
Fie a = 6, b = 10, x = 4, y = 15 (observat i ca a b = x y = 60)
Figura 12.1: Dreptunghiurile pot suprapuse n cele doua moduri.
Putem pune mocheta si n celalalt sens ca n gura 12.2
Figura 12.2: Dreptunghiurile pot suprapuse n cele doua moduri.

In orice caz ramane aceeasi situat ie adica de a acoperi un dreptunghi de


camera cu alt dreptunghi de mocheta.
Algoritmul pe carel propunem genereaza recursiv un arbore binar. Fiecare
nod are 6 campuri:
- a,b dimensiunile camerei
- x,y dimensiunile mochetei
126
- d este codul pozit iei 0 pentru asezare directa 1 pentru celalalt sens
- l nivelul n arbore
Un nod al acestui arbore binar va avea urmatoarea structura:
Figura 12.3: Structura nodului
Se construieste mai ntai radacina:
Radacina(z)
LIBERE z
citeste( a,b,x )
y = a b/x
z.a = a; z.b = b; z.x = x; z.y = y; d = 0; l = 0
cheama Arbores(z)
cheama Arbored(z)
cheama listare(z)
Return
Arbores(z)
LIBERE nou;
nou.d = 0; nou.l = z.l + 1
z.LS = nou
daca z.a > z.x atunci
nou.a = z.a z; nou.b = z.b; nou.x = z.x; nou.y = z.y b
altfel
nou.a = z.a; nou.b = z.b z.y; nou.x = z.x z.a; nou.y = z.y
sfarsit daca
daca x ,= 0

y ,= 0 atunci
exit
altfel
cheama Arbores(y)
cheama Arbored(y)
sfarsit daca
Return
Arbored(z)
LIBERE nou;
nou.d = 1; nou.l = z.l + 1
z.LD = nou
daca z.a > z.y atunci
127
nou.a = z.a z.y; nou.b = z.b; nou.x = z.x z.b; nou.y = z.y
altfel
nou.a = z.a; nou.b = z.b z.x; nou.x = z.x; nou.y = z.y z.a
sfarsit daca
daca x ,= 0

y ,= 0 atunci
exit
altfel
cheama Arbores(y)
cheama Arbored(y)
sfarsit daca
Return
Unde listare(z) este listarea frunzelor grafului ntrun mod convenabil.
Rezumat
Sunt cazuri n care, sau nu exista demonstrat ia, sau chiar nu se poate
demonstra ca solut ia unui algoritm este cea cautata. Dar, macar din practica,
se vede ca solut ia nu este departe de optim. Avem de a face atunci cu un
algoritm euristic. Acesti algoritmi sunt cateodata preferat i chiar cand exista
algoritmi exact i, pentru viteza lor superioara.
Exercit ii
1. Sa se studieze complexitatea algoritmului de mai sus
2. Sa se transforme algoritmul de mai sus astfel ncat sa se opreasca dupa
un numar stabilit de pasi.
3. Sa se realizeze un algoritm care pastreaza din arborele binar numai
ultimul nivel si cel urmator, care se construieste.
4. Sa se modice algoritmul astfel ca el sa dea si solut iile n care exista
acoperire dar ramane un rest de material.
Pentru solut ii rugam cititorul sa consulte [3] si [4].
128
129
130
Capitolul 13
Algoritmi n algebra liniara.
Obiective

In acest capitol prezentam o foarte interesanta aplicat ie a metodei divide


et impera la nmult irea matricilor si o metoda de rezolvare a sistemelor de
ecuat ii liniare.
Algoritmul lui Strassen.
Pentru a aplica metoda divide et impera lanmult irea a doua matrici vom
descompune matricile astfel:
A =
_
A1 A2
A3 A4
_
(13.1)
B =
_
B1 B2
B3 B4
_
(13.2)
Unde A si B sunt de dimensiune n n, iar Ai si Bi sunt de dimensiune
[n/2].
Produsul va :
A B =
_
A1B1 +A2B3 A1B2 +A2B4
A3B1 +A4B4 A3B2 +A4B4
_
(13.3)

In aceasta forma, complexitatea va data de ecuat ia funct ionala:


T(n) = 8T(n/2) + (n
2
) (13.4)
131
care, conform teoremei centrale din capitolul 8 da: T(n) = (n
3
) adica
nam facut nici o mbunatat ire. Strassen a descoperit ca se pot face doar 7
nmult iri de matrici dupa cum urmeaza:
m1 = (A2 A4) (B3 B4) (13.5)
m2 = (A1 +A4) (B1 +B4) (13.6)
m3 = (A1 A3) (B1 +B2) (13.7)
m4 = (A1 +A2) B4 (13.8)
m5 = A1 (B2 B4) (13.9)
m6 = A4 (B3 B1) (13.10)
m7 = (A3 +A4) B1 (13.11)
Cu aceste 7 produse se poate calcula:
C1 = m1 +m2 m4 +m6 (13.12)
C2 = m4 +m5 (13.13)
C3 = m7 +m6 (13.14)
C4 = m2 m3 +m5 m7 (13.15)
Deci vom avea:
C =
_
C1 C2
C3 C4
_
(13.16)
Algoritmul n cazul n = 2
k
va :
Strassen(x,y,n,z)
daca n > 1 atunci
descompune matricile x si y n x1,x2,x3,x4,y1,y2,y3,y4
n1 = [n/2]
Strassen( x2 x4,y3 y4,n1,m1)
Strassen( x1 +x4,y1 +y4,n1,m2)
Strassen( x1 x3,y1 +y2,n1,m3)
Strassen( x1 +x2,y4,n1,m4)
Strassen( x1,y2 y4,n1,m5)
Strassen( x4,y3 y1,n1,m6)
Strassen( x3 +x4,y1,n1,m7)
z1 = m1 +m2 m4 +m6
z2 = m4 +m5
132
z3 = m6 +m7
z2 = m2 m3 +m5 m7
recompune matricea z
sfarsit daca
Return
Ecuat ia funct ionala pentru calculul complexitat ii va :
T(n) = 7T(n/2) + (n
2
)
Ceea ce da :
T(n) = (n
log
7
2
)
Metoda LUP
Sa consideram sistemul:
_

_
a
11
x
1
+a
12
x
2
+... +a
1n
x
n
= b
1
a
21
x
1
+a
22
x
2
+... +a
2n
x
n
= b
2
...
a
n1
x
1
+a
n2
x
2
+... +a
nn
x
n
= b
n
(13.17)
unde:
A =
_
_
_
_
a
11
a
12
... a
1n
a
21
a
22
... a
2n
...
a
n1
a
n2
... a
nn
_
_
_
_
(13.18)
B =
_
_
_
_
b
1
b
2
...
b
n
_
_
_
_
(13.19)
X =
_
_
_
_
x
1
x
2
...
x
n
_
_
_
_
(13.20)
Atunci sistemul se poate scrie:
AX = B
Daca determinantul lui A este diferit de 0 (din teorema lui Cramer) solut ia
este:
X = A
1
B
133
Ideea metodei LUP porneste de la descompunerea matricii A:
A = LUP
unde L este o matrice subdiagonala:
L =
_
_
_
_
_
_
l
11
0 0 ... 0
l
21
l
22
0 ... 0
l
31
l
32
l
33
... 0
...
l
n1
l
n2
l
n3
... l
nn
_
_
_
_
_
_
(13.21)
Care are toate elementele de deasupra diagonalei principale egale cu 0,
iar U este o matrice supradiagonala
U =
_
_
_
_
_
_
u
11
u
12
u
13
... u
1n
0 u
22
u
23
... u
2n
0 0 u
33
... u
3n
...
0 0 0 ... u
nn
_
_
_
_
_
_
(13.22)
care are elementele de sub diagonala principala egale cu 0, iar P este o
matrice de permutari adica o matrice cu elemente 0 si cate un singur element
1 pe linie si coloana.
Atunci sistemul se scrie:
LUX = B

unde B

= BP.
Rezolvam mai ntai sistemul:
LY = B

adica:
_

_
11
y
1
+ 0y
2
+... + 0y
n
= b

1
l
21
y
1
+l
22
y
2
+... + 0y
n
= b

2
...
l
n1
y
1
+l
n2
y
2
+... +l
nn
y
n
= b

n
(13.23)
care se rezolva prin nlocuire progresiva:
_

_
y
1
= b

1
/l
11
y
i
= 1/l
ii
(b

i1

j=1
(l
ij
y
j
)
pentrui = 2, n
(13.24)
134
Apoi rezolvam sistemul:
UX = B
Adica:
_

_
u
11
x
1
+u
12
x
2
+... +u
1n
x
n
= y
1
0x
1
+u
22
x
2
+... +u
2n
x
n
= y
2
...
0x
1
+ 0x
2
+... +u
nn
x
n
= y
n
(13.25)
prin nlocuire regresiva tot n complexitate
T(n) = (n
2
)
.
_

_
x
n
= y
n
/u
nn
y
i
= 1/u
ii
(y
i

j=i+1
(u
ij
x
j
)
pentrui = n 1, 1
(13.26)
Ar atam, n continuare, cum poate descompusa matricea, nesingulara
A.
A =
_
_
_
_
a
11
a
12
... a
1n
a
21
a
22
... a
2n
...
a
n1
a
n2
... a
nn
_
_
_
_
=
_
a
11
r
t
l A

_
(13.27)
unde A este o matrice de ordinul (n 1) (n 1), iar r si l sunt vectori
coloana (r
t
este r transpus, adica un vector linie).
Atunci A se descompune:
A =
_
a
11
r
t
l A

_
=
_
1 0
l/a
11
I
n1
_

_
a
11
r
t
0 A

lr
t
/a
11
_
(13.28)
unde 0 si 1 este, dupa nevoi, vector linie sau coloana cu toate elementele
egale cu 0 sau 1, de ordinul n-1 si matricea
A

lr
t
/a
11
este complementul Schurr al matricii A cu pivotul a
11
.
Prin induct ie, sa presupunem ca orice matrice de ordin < n se poate
descompune n produs de matrici LU atunci:
A

lr
t
/a
11
= L

135
rezulta ca:
A =
_
1 0
l/a
11
I
n1
_

_
a
11
r
t
0 A

lr
t
/a
11
_
=
_
1 0
l/a
11
I
n1
_

_
a
11
r
t
0 L

_
(13.29)
=
_
1 0
l/a
11
L

_
a
11
r
t
0 U

_
= LU (13.30)
Deducem, de aici, regula de descompunere: La pasul i pivotul este a
ii
.
Daca a
ii
= 0 atunci se interschimba linia i cu o linie de sub aceasta linie
( Atent ie, schimbarea se va face si n B B

). Linia i se scrie asa cum


este, coloana i se mparte la a
ii
, iar restul matricii se calculeaza dupa regula
dreptunghiului:
Avand bucata de matrice:
a
ii
... a
ik
a
ji
... a
jk
(13.31)
urmatorul a
jk
va :
a

jk
=
a
ii
a
jk
a
ik
a
ji
a
ii
(13.32)
Transformarile se fac pe matrici din ce n ce mai mici, (n-1) pasi, ca n
exemplul urmator, n care pivotul este scris cu caractere mai mari:
A =
_
_
_
_
1 1 2 1
1 1 1 1
2 1 2 2
1 0 1 0
_
_
_
_

_
_
_
_
1 1 2 1
1 0 1 2
2 1 6 0
1 1 1 1
_
_
_
_
(13.33)
Pentru ca a
22
= 0 schimbam liniile 2 si 3 ntre ele.
_
_
_
_
1 1 2 1
2 -1 6 0
1 0 1 2
1 1 1 1
_
_
_
_

_
_
_
_
1 1 2 1
2 1 6 0
1 0 -1 2
1 1 5 1
_
_
_
_
(13.34)
Deci vom avea descompunerea:
A =
_
_
_
_
1 0 0 0
2 1 0 0
1 0 1 0
1 1 5 1
_
_
_
_

_
_
_
_
1 1 2 1
0 1 6 0
0 0 1 2
0 0 0 -11
_
_
_
_
(13.35)
136
Atunci, pentru a rezolva sistemul,:
_

_
x
1
+x
2
+ 2x
3
+x
4
= 5
x
1
+x
2
+x
3
+x
4
= 2
2x
1
+x
2
2x
3
+ 2x
4
= 3
x
1
+ 0x
2
+x
3
+ 0x
4
= 2
(13.36)
aplicam permutarea termenilor liberi pe liniile 2 si 3 si rezolvam sistemul
subdiagonal Ly = B

:
_

_
y
1
+ 0y
2
+ 0y
3
+ 0y
4
= 5
2y
1
+y
2
+ 0y
3
+ 0y
4
= 3
y
1
+ 0y
2
+y
3
+ 0y
4
= 2
y
1
+y
2
5y
3
+y
4
= 2
(13.37)
care da:
_

_
y
1
= 5
y
2
= 7
y
3
= 3
y
4
= 11
(13.38)
Apoi rezolvam sistemul Ux = y, adica:
_

_
x
1
+x
2
+ 2x
3
+x
4
= 5
0x
1
x
2
6x
3
+ 0x
4
= 7
0x
1
+ 0x
2
x
3
2x
4
= 3
0x
1
+ 0x
2
+ 0y
3
11x
4
= 11
(13.39)
care da:
_

_
x
1
= 1
x
2
= 1
x
3
= 1
x
4
= 1
(13.40)
De fapt, n algoritm vom cauta, pentru pivot, cea mai mare valoare n
valoare absoluta.
Algoritmul de descompunere va :
LUPDESC(A, n, P, IE)
IE = 0
pentru i = 1, n
pentru j = 1, n
P
i,j
= 0
sfarsit pentru
137
sfarsit pentruP va matricea identitate de ordinul n
pentru i = 1, n
P
ii
= 1
sfarsit pentru
pentru i = 1, n 1
n 1 transformari
EP = 0 EP este valoarea elementului pivot
pentru k = i, n
Cauta pivotul sub linia i
daca [a
ki
[ > EP atunci
EP = a
ki
;i

= k
sfarsit daca
sfarsit pentru
daca EP = 0 atunci
IE = 1eroare matrice singulara
sfarsit dacaaici schimba ntre ele liniile i si i
pentru k = 1, n
a
ik
a
i

k
P
ik
P
i

k
sfarsit pentru
pentru k = i + 1, n
a
ki
= a
ki
/a
ii
se mparte linia la pivot
pentru j = i + 1, n
a
kj
= a
kj
a
ki
a
ij
regula dreptunghiului
sfarsit pentru
sfarsit pentru
sfarsit pentru
Return
Rezolvarea prin nlocuire progresiva va :
L-REZ(A, n, P, B, y)
pentru i = 1, n
a
ii
= 1
pentru j = 1, i 1
l
ij
= a
ij
sfarsit pentru
sfarsit pentru
pentru i = 1, n
b

i
= 0
pentru j = 1, n
b

i
= b
i
p
ij
138
sfarsit pentru
sfarsit pentru
y
1
= b

1
pentru i = 2, n
y
i
= b

i
pentru j = 1, i 1
y
i
= y
i
l
ij
y
j
sfarsit pentru
sfarsit pentru
Return
Rezolvarea prin nlocuire regresiva va :
U-REZ(A,n,y,x)
pentru i = 1, n
pentru j = i, n
u
ij
= a
ij
sfarsit pentru
sfarsit pentru
x
1
= y
1
/u
11
pentru i = n 1, 1, 1
x
i
= y
i
/u
ii
pentru j = 1, i 1
x
i
= x
i
y
i
u
ij
/u
ii
sf arsit pentru
sfarsit pentru
Return
Rezolvarea sistemului va :
Start REZ-SIST-EC-LIN
citeste( n, ((a
ij
, j = 1, n), i = 1, n) )
citeste( (b
i
, = 1, n) )
LUP-DESC(A, n, P, IE)
daca IE = 1 atunci
scrie( sistem necramerian )
Return
sfarsit daca
L-REZ(A, n, P, B, y)
U-REZ(A, n, y, x)
scrie( (x
i
, i = 1, n) )
Stop

In [2] se poate vedea demonstrat ia faptului ca, cu condit ii foarte des


ndeplinite, inversarea matricilor si produsul matricilor au aceeasi complexi-
139
tate.
Pentru complexitatea algoritmului LUP sa observam ca complexitatea
este:
T(n) = (n
3
) + (n
2
) = (n
3
)
Pentru inversarea matricilor, algoritmul se poate folosi n felul urmator:
_
AX = E
i
i = 1, n
(13.41)
unde e
i
este vectorul
E
i
=
_
_
_
_
e
i
1
e
i
2
...
e
i
n
_
_
_
_
(13.42)
si unde:
_
e
ij
= 0j ,= i
e
ij
= 1j = i
(13.43)
Descompunem o singura data sistemul n A = LUP si apoi rezolvam n
sisteme:
_
_
_
LY
i
= e
i
UX = Y
i
i = 1, n
(13.44)
Complexitatea inversarii va :
T(n) = (n
3
+n (n
2
= (n
3
)
Rezumat

In acest capitol at i vazut cum se poate face nmult irea matricilor n com-
plexitate mai mica decat n
3
. Apoi at i nvat at o metoda de rezolvare a sis-
temelor de ecuat ii liniare, crameriene, cu complexitatea n
3
, metoda care se
poate aplica si la inversarea matricilor.
Exercit ii
1. Scriet i un algoritm care, folosind subalgoritmii de mai sus , inverseaza
o matrice.
140
2. Sa se inverseze matricea:
A =
_
_
_
_
1 1 2 1
1 1 1 1
2 1 2 2
1 0 1 0
_
_
_
_
(13.45)
3. Sa se rezolve sistemul AX = B unde:
A =
_
_
_
_
1 1 2 1
1 1 1 1
2 2 2 1
1 2 1 2
_
_
_
_
(13.46)
B =
_
_
_
_
1
1
3
2
_
_
_
_
(13.47)
141
142
Capitolul 14
Teste de autoevaluare
1. Algoritmi de sortare prin metoda Divide et impera.
2. Folosind un subalgoritm pentru nmult irea matricilor sa se scrie algo-
ritmul care ridica la puterea k o matrice patratica de ordinul n.
3. Dandu-se parcurgerile n preordine A, B, C, D, E, F, G si n inordine
C, B, E, D, A, G, F sa se deseneze arborele binar corespunzator.
Solut ii
1. (Din ociu: 1p)
Metoda presupune parcurgerea a trei pasi:
a) mpart irea datelor n mai multe part i;
b) rezolvarea (de obicei recursiva) a problemei pe ecare bucata
de date;
c) combinarea rezultatelor part iale n rezultatul nal.
(1p)
Sortarea prin interclasare presupune:
a) mpart irea sirului init ial n doua part i;
b) sortarea ecarei jumatat i;
c) interclasarea bucat ilor sortate.
MergeSort(a, p, q)
daca p q atunci
Return
sfarsit daca
143
r =
_
p+q
2

MERGESORT(a, p, r)
MERGESORT(a, r + 1, q)
Interclasare(a, p, r, q)
Return
(1p)
Interclasare(a, p, r, q)
i = p
j = r + 1
k = 0
repeta
k = k + 1
daca a(i) < a(j) atunci
b(k) = a(i)
i = i + 1
altfel
b(k) = a(j)
j = j + 1
sfarsit daca
pana cand i > r sau j > q
pentru il = i, r
k = k + 1
b(k) = a(il)
sfarsit pentru
pentru jl = j, q
k = k + 1
b(k) = a(jl)
sfarsit pentru
k = 0
pentru i = p, q
k = k + 1
a(i) = b(k)
sfarsit pentru
Return
(2p)
Apelarea se face:
Start Sortare1
citeste( n, (a(i), i = 1, n) )
MERGESORT(a, 1, n)
144
scrie( (a(i), i = 1, n) )
Stop
Complexitatea rezulta din:
T(n) = 2T
_
n
2
_
+a n
unde a este o constanta. Din teorema centrala (pagina 76) onbt inem
T(n) = (nlog n). (1p)
Alta metoda este Quicksort (n practica, cel mai bun algoritm de sortare):
Quicksort(a, p, q)
daca p < q atunci
Partitionare(a, p, q, r)
Quicksort(a, p, r)
Quicksort(a, r + 1, q)
sfarsit daca
Return
(1p)
unde
Partitionare(a, p, q, r)
el = a(p)
i = p 1
j = q + 1
repeta
repeta
i = i + 1
pana cand a(i) el
repeta
j = j 1
pana cand a(j) el
daca i < j atunci
a(i) a(j)
altfel
r = j
sfarsit daca
pana cand i j
Return
(2p)
145
Se apeleaza ca si celalalt.
Complexitatea este (n
2
), dar n cazul (frecvent) al mpart irii propor-
t ionale a sirului avem (nlog n). Se pot face mbunatat iri prin alegerea
aleatoare al lui el (elementul pivot). (1p)
2. Vom scrie doi subalgoritmi: unul pentru nmult irea a doua matrice
patratice si altul pentru ridicarea la putere a unei matrici.
Din ociu (1p).
InmultireMatrici(a, b, c, n)
pentru i = 1, n
pentru j = 1, n
c(i, j) = 0
pentru k = 1, n
c(i, j) = c(i, j) +a(i, k) b(k, j)
sfarsit pentru
sfarsit pentru
sfarsit pentru
Return
(3p)
PutereMatrice(a, n, k, c)
pentru i = 1, n
pentru j = 1, n
b(i, j) = a(i, j)
sfarsit pentru
sfarsit pentru
pentru p = 2, k
InmultireMatrici(a, n, b, c)
pentru i = 1, n
pentru j = 1, n
b(i, j) = c(i, j)
sfarsit pentru
sfarsit pentru
sfarsit pentru
Return
(4p)
Subalgoritmul PutereMatrice se apeleaza n felul urmator:
Start RidicareLaPutere
citeste( k, n, ((a(i, j), j = 1, n), i = 1, n) )
PutereMatrice(a, n, k, c)
146
scrie( ((c(i, j), j = 1, n), i = 1, n) )
Stop
(1p)
Complexitatea este (n
3
k). (1p)
Observat ie: Prin algoritmul ridicarii la putere prezentat n capitolul
5, problema 3, se poate scrie un algoritm de complexitate (n
3
log k).
Utilizand un subalgoritm care sa efectueze nmult irea a doua matrici n
timp (n
log
2
7
) (algoritmul lui Strassen, vezi [2]), se ajunge la un algo-
ritm de complexitate
_
n
log
2
7
log k
_
(sau chiar (n
2.376
log k), conform
aceleiasi surse bibliograce).
3. Din ociu (1p). Arborele este dat n gura 14.1. Rat ionamentul prin
care se construieste arborele se poate face dupa o strategie de tip di-
vide et impera: A ind primul nod care apare n parcurgerea n pre-
ordine, rezulta ca el este radacina arborelui. Ceea ce se aa la stanga
lui A n sirul dat n parcurgerea n inordine este subarborele stang al
radacinii (la noi: parcurgerea n inordine a subarborelui stang al lui
A este C, B, E, D, iar la parcurgerea n preordine aceleasi 4 simboluri
apar n ordinea B, C, D, E; analog, pentru partea dreapta inordine:
G, F, preordine: F, G). La ecare pas se detecteaza la fel ca mai sus
radacina ecarui subarbore, dupa care descendent ii sai stang si drept.
Cand se ajunge la o secvent a formata dintrun singur nod, nu mai avem
ce sa determinam: arborele este complet construit.
Figura 14.1: Arborele care corespunde celor doua secvent e: preordine
A, B, C, D, E, F, G si inordine C, B, E, D, A, G, F
Explicat ii: 4 puncte
Pasii efectuat i pana la sfarsit: 3p
Reprezentare arbore: 1p
Este posibil ca sa se determine prin alta metoda un arbore care respecta
doar una din secvent ele date. De exemplu, arborele din gura 14.2
produce doar parcurgerea n preordine conform secvent ei date, dar nu
si inordinea. (4p).
147
Figura 14.2: Arbore care produce la parcurgere n preordine
A, B, C, D, E, F, G, dar nu da rezultat corect pentru inordine:
C, B, E, D, A, G, F, pe cand la noi se obt ine: D, C, E, B, A, F, G.
148
Anexa A
Metode utile n calculul
complexitat ii
Sume des ntalnite
1. Progresia aritmetica:
a
k
= a
k1
+r, k = 2, a
1
si r dat i (A.1)
S =
n

k=1
a
k
=
(a
1
+a
n
)n
2
(A.2)
2. Sume particulare:
n

k=1
k =
n(n + 1)
2
= (n
2
) (A.3)
n

k=1
k
2
=
n(n + 1)(2n + 1)
6
= (n
3
) (A.4)
n

k=1
k
3
=
_
n(n + 1)
2
_
2
= (n
4
) (A.5)
si n general:
n

k=1
k
p
= (n
p+1
) (A.6)
3. Progresii geometrice:
149
a
k
= a
k1
r, k = 1, a
1
, r ,= 1 dat i
S =
n

k=1
a
k
=
n

k=1
a
1
r
k
= a
1
r
n1

k=0
r
k
= a
1
r
r
n
1
r 1
(A.7)
Daca r < 1, atunci
S =
n

k=1
a
k

k=1
a
k
= a
1

1
1 r
(A.8)
Delimitarea sumelor
De multe ori, sumele nu se regasesc n formele simple date mai sus. Ex-
ista diferite tehnici de determinare a unei majorari si minorari a acestora.
Prezentam cateva din ele mai jos.
Induct ia matematica
Una din modalitat ile usor de abordat pentru delimitarea unei sume este
bazata pe induct ia matematica. De exemplu, sa demonstram ca seria arit-
metica
n

k=1
k are valoarea
1
2
n(n+1). Putem verica usor pentru n = 1, n = 2
asa ca facem ipoteza de induct ie ca formula este adevarata pentru orice n si
demonstram ca are loc pentru n + 1. Avem
n+1

k=1
k =
n

k=1
k + (n + 1) =
1
2
n(n + 1) + (n + 1) =
1
2
(n + 1)(n + 2). (A.9)
Nu ntotdeauna putem determina valoarea exacta a unei sume. Pe noi
oricum ne intereseaza ordinul sumei (deci constantele multiplicative si ter-
menii mici nu sunt ntotdeauna esent iali
1
). De exemplu, sa demonstram ca
n

k=0
2
k
c2
n
pentru o anumita constanta c, de la un rang nncolo (saun alta
notat ie:
n

k=0
2
k
=O(2
n
)). Pentru condit ia init iala n = 0 avem
0

k=0
2
k
= 1 c1,
cat timp c 1. Presupunand proprietatea de marginire are loc pentru n sa
demonstram ca are loc si pentru n + 1. Avem:
n+1

k=0
2
k
=
n

k=0
2
k
+ 2
n+1
c 2
n
+ 2
n+1
=
_
1
2
+
1
c
_
c 2
n+1
c 2
n+1
(A.10)
1
Dar: (2
3n
) ,= (2
n
); n acest caz constanta 3 nu poate neglijata
150
cat timp (1/2 + 1/c) 1 sau, echivalent, c 2. Astfel,
n

k=0
2
k
= O(2
n
), ceea
ce am dorit sa aratam.
Atent ionam cititorul asupra unui viciu de procedura n cazul utilizarii
acestui instrument matematic, care se regaseste n urmatoarea demonstrat ie
corecta: aratam ca
n

k=1
k = O(n). Desigur,
1

k=1
k = O(1). Acceptand
delimitarea pentru n, o demonstram acum pentru n + 1:
n+1

k=1
k =
n

k=1
k + (n + 1)
= O(n) + (n + 1) gresit !
= O(n + 1).
Greseala n argumentat ie este aceea ca O ascunde o constanta care
creste n funct ie de n si deci nu este constanta. Ar trebui sa aratam ca exista
o constanta care se ascunde n notat ia O() si care este deci valabila pentru
tot i n.
Aproximarea prin integrale
Cand o suma poate exprimata ca
n

k=m
f(k), unde f(k) este o funct ie
monoton crescatoare, o putem margini prin integrale:
_
n
m1
f(x)dx
n

k=m
f(k)
_
n+1
m
f(x)dx. (A.11)
Justicarea (geometrica, intuitiva) pentru aceasta aproximare este aratata
n gura A.1. Suma este reprezentata prin aria dreptunghiului din gura,
iar integrala este regiunea hasurata de sub curba. Cand f(k) este o funct ie
monoton descrescatoare, putem utiliza o metoda similara pentru a obt ine
marginile
_
n+1
m
f(x)dx
n

k=m
f(k)
_
n
m1
f(x)dx. (A.12)
Aproximat ia integrala (A.12) da o estimare stransa pentru al n - lea
numar armonic. Pentru o limita inferioara, obt inem
n

k=1
1
k

_
n+1
1
dx
x
= ln(n + 1). (A.13)
151
(a)
Marginire
in-
fe-
rioara
(b)
Marginire
su-
pe-
rioara
Figura A.1: Marginire prin integrale.
Pentru limita superioara, deducem inegalitatea
n

k=2
1
k

_
n
1
dx
x
= ln n, (A.14)
care da limita
n

k=1
1
k
ln n + 1. (A.15)
Avantajul acestei tehnici este ca permite atat determinarea unei marginiri
inferioare, cat si a unei marginiri superioare, care pot duce la o exprimare a
complexitat ii cu notat ia (mai exacta decat O sau ).
Propunem cititorului sa aplice aceasta tehnica pentru sumele prezentate
anterior
Analiza algoritmilor recursivi
Analiza unui algoritm recursiv implica rezolvarea unui sistem de recurent e.
Vom vedea n continuare cum pot rezolvate astfel de recurent e.

Incepem
cu tehnica cea mai banala.
Metoda iterat iei
Tehnica urmatoare cere ceva mai multa tehnica matematica, dar rezul-
tatele sunt destul de expresive. Traiectoria ar : se executa cat iva pasi,
se intuieste forma generala, iar apoi se demonstreaza prin induct ie matem-
atica ca aceasta forma este corecta. Sa consideram, de exemplu, recurent a
problemei turnurilor din Hanoi. Pentru un n > 1 obt inem succesiv
t(n) = 2t(n1) +(1) = 2
2
t(n2) +(2) +(1) = . . . = 2
n1
t(1) +
n2

i=0
2
i
.
(A.16)
Rezulta t(n) = 2
n
1. Prin induct ie matematica se demonstreaza acum
cu usurint a ca aceasta formula este corecta.
152
Recurent e liniare omogene
Vom prezenta modul de rezolvare al unor ecuat ii recurente liniare omo-
gene, adica de forma:
a
0
t
n
+a
1
t
n1
+. . . +a
k
t
nk
= 0 (A.17)
unde t
i
sunt valorile pe care le cautam, iar coecient ii a
i
sunt constante.
Vom atasa recurent ei (A.17) ecuat ia:
a
0
x
n
+a
1
x
n1
+. . . +a
k
x
nk
= 0 (A.18)
Solut iile acestei ecuat ii sunt e solut ia triviala x = 0, care nu ne intereseaza,
e solut iile ecuat iei de grad k
a
0
x
k
+a
1
x
k1
+. . . +a
k
= 0 (A.19)
care este ecuat ia caracteristica a recurent ei (A.17).
Presupunand deocamdata ca cele k radacini r
1
, r
2
, . . . , r
k
ale acestei ecuat ii
caracteristice sunt distincte, orice combinat ie liniara
t
n
=
k

i=1
c
i
r
n
i
(A.20)
este o solut ie a recurent ei (A.17), unde constantele c
1
, c
2
, . . . , c
k
sunt deter-
minate de condit iile init iale.
Sa exemplicam prin recurent a care deneste sirul lui Fibonacci:
t
n
= t
n1
+t
n2
, n 2 (A.21)
iar t
0
= 0, t
1
= 1. Putem sa rescriem aceasta recurent a sub forma
t
n
t
n1
t
n2
= 0 (A.22)
care are ecuat ia caracteristica
x
2
x 1 = 0 (A.23)
cu radacinile r
1,2
= (1

5)/2. Solut ia generala are forma


t
n
= c
1
r
n
1
+c
2
r
n
2
. (A.24)
Impunand condit iile init iale, obt inem
c
1
+c
2
= 0, n = 0
r
1
c
1
+r
2
c
2
= 1, n = 1
153
de unde determinam
c
1,2
= 1/

5.
Deci, t
n
= 1/

5(r
n
1
r
n
2
). Observam ca r
1
= = (1 +

5)/2, r
2
=
1
si
obt inem
t
n
= 1/

5(
n
()
n
)
Ca atare, implementarea recursiva pentru determinarea celui de-al nlea ter-
men al sirului lui Fibonacci duce la o complexitate exponent iala
2
.
Daca radacinile ecuat iei caracteristice nu sunt distincte, se procedeaza
dupa cum urmeaza: daca r este o radacina de multiplicitate m a ecuat iei
caracteristice, atunci t
n
= r
n
, t
n
= nr
n
, t
n
= n
2
r
n
, . . . , t
n
= n
m1
r
n
sunt
solut ii pentru (A.17). Solut ia generala pentru o astfel de recurent a este o
combinat ie liniara a acestor termeni si a termenilor provenit i de la celelalte
rad acini ale ecuat iei caracteristice. Ca mai sus, trebuie determinate exact k
constante din condit iile init iale.
Vom da din nou un exemplu. Fie recurent a
t
n
= 5t
n1
8t
n2
+ 4t
n3
, n 3 (A.25)
iar t
0
= 0, t
1
= 1, t
2
= 2. Ecuat ia caracteristica are radacinile 1 (de multi-
plicitate 1) si 2 (de multiplicitate 2). Solut ia generala este:
t
n
= c
1
1
n
+c
2
2
n
+c
3
n2
n
.
Din condit iile init iale, obt inem c
1
= 2, c
2
= 2, c
3
= 1/2.
Recurent e liniare neomogene
Consideram acum recurent e de urmatoarea forma:
a
0
t
n
+a
1
t
n1
+. . . +a
k
t
nk
= b
n
p(n) (A.26)
unde b este o constanta, iar p(n) este un polinom n n de grad d
Pentru a rezolva (A.26), este sucient sa luam urmatoarea ecuat ie carac-
teristica:
(a
0
x
k
+a
1
x
k1
+. . . +a
k
)(x b)
d+1
= 0. (A.27)
Odata ce s-a obt inut aceasta ecuat ie, se procedeaza ca n cazul omogen.
Vom rezolva acum recurent a corespunzatoare problemei turnurilor din
Hanoi:
t
n
= 2t
n1
+ 1, n 1
2
Pentru o complexitatea logaritmica, a se vedea capitolul 5.
154
iar t
0
= 0. rescriem recurent a astfel
t
n
2t
n1
= 1
care este de forma (A.26 ) cu b = 1 si p(n) = 1, un polinom de gradul 0.
Ecuat ia caracteristica este atunci (x2)(x1) = 0, cu solut iile 1, 2. Solut ia
generala a recurent ei este
t
n
= c
1
1
n
+c
2
2
n
.
Avem nevoie de doua condit ii init iale. Stim ca t
0
= 0; pentru a gasi cea de-a
doua condit ie calculam
t
1
= 2t
0
+ 1.
Din condit iile init iale, obt inem
t
n
= 2
n
1.
din care se deduce ca t
n
= (2
n
).
155
156
Anexa B
Rezolvari
Rezolvari pentru capitolul 3
1. Problema 1.
(a) Exemplul 1. acest program cont ine doar instruct iuni elementare
care cer un timp constant de execut ie. Ca atare, timpul total este
marginit superior de o constanta, fapt gurat prin notat ia (1).
(b) Exemplul 2: justicarea este aceeasi cu cea de la punctul prece-
dent, deci complexitatea este (1).
(c) Exemplul 3: citirea datelor de intrare are un cost de t
1
(n) = c
1

(n+1), unde c
1
este o constanta reprezentand timpul necesar citirii
unei valori. Atribuirea s = 0 se executa ntr-un timp constant
t
2
= c
2
, independent de dimensiunea datelor de intrare. Ciclarea
nseamna t
3
= c
3
n, unde c
3
este timpul necesar pentru calculul
sumei si efectuarea atribuirii; de asemenea, c
3
nu depinde de n.
Asarea se face n timpul t
4
= c
4
(constant).
Ca atare,
T(n) = t
1
(n) +t
2
(n) +t
3
(n) +t
4
(n) = c
1
(n +1) +c
2
+c
3
n +c
4
Conform proprietat ii 5, pagina 29, avem ca:
T(n) = (c
1
(n + 1) +c
2
+c
3
n +c
4
)
= (max(c
1
(n + 1) +c
3
n), c
2
+c
4
)
= (c
1
(n + 1) +c
2
n) = ((c
1
+c
3
)n +c
1
)
= ((c
1
+c
2
)n) = (n),
ultima egalitate avand loc datorita proprietat ii 7, pagina 29.
157
(d) Exemplul 4: citirea datelor este t
1
(n) = c
1
(n + 1); atribuirile
nseamna t
2
(n) = 3 c
2
, unde c
2
este timpul necesar unei atribuiri.
Ciclul cu numarator nseamna t
2
(n) = c
3
n, timpul c
3
ind con-
stant din cauza ca se fac evaluari de expresii logice si atribuiri,
costul ecarei operat ii n parte ind independent de n.
Deci
T(n) = t
1
(n)+t
2
(n)+t
3
(n) = (c
1
(n + 1) + 3 c
2
+c
3
n) = (n)
O alta justicare: sirul este parcurs o singura data, pentru ecare
element al sau efectuanduse operat ii cu cost (1); n total com-
plexitatea este (n).
(e) Exemplul 5: analiza algoritmului lui Euclid este destul de dicila.
Complexitatea algoritmului este (log (min(a, b))). A se consulta
[2].
(f) Exemplul 6: corpul ciclului cel mai interior se executa n timp
constant deoarece cont ine doar instruct iuni elementare (atribuire,
asare). Se executa de un numar constant de ori, deci ciclul repeta
. . . pana cand k = 5 se executa ntr-un timp constant. La fel este
si cu ciclul repeta . . . pana cand j = 4: corpul sau se excuta n
timp constant, de un numar constant de ori. Idem n cazul ciclu-
lui cu contor exterior pentru. Ca atare, timpul total de execut ie
este marginit superior de o constanta, complexitatea ind (1).
Propunem cititorului scrierea unui algoritm pentru listarea com-
binarilor cate 3 din mult imea 1, 2, . . . , n. Care este n acest caz
complexitatea?
2. Problema 2:
Start ProdusScalar
citeste( n, (a(i), i = 1, n), (b(i), i = 1, n) )
ps = 00 este element neutru pentru adunare
pentru i = 1, n
daca pasul este 1, se poate omite
ps = ps +a(i) b(i)
sfarsit pentru
scrie( Produsul scalar este: , ps )
Stop
Complexitatea este (n).
3. Problema 3.
Ideea este de a parcurge sirul si a compara ecare element cu x; daca
158
acest element este gasit, atunci este oprita cautarea, altfel se merge la
urmatorul element. La sfarsit se raporteaza rezultatul.
Pentru a semnala faptul ca x a fost gasit, vom folosi o variabila booleana
gasit care va primi valoarea adevarat daca x a fost gasit n sir, fals n
caz contrar.
Start CautareLiniara
citeste( n, (a(i), i = 1, n), x )
gasit = falsdeocamdata nu am gasit pe x n a
i = 1i este indicele elementului curent din sir
repeta
daca a(i) = x atunci
gasit = adevarat
pozitie = ipozitie este pozitia elementului x n sir
altfel
i = i + 1
sfarsit daca
pana cand i > n sau (gasit = adevarat)
daca gasit = adevarat atunci
scrie( Am gasit , x, pe pozit ia , pozitie )
altfel
scrie( x, nu a fost gasit )
sfarsit daca
Stop
Complexitatea este (n), cazul cel mai defavorabil ind cand x nu se
aa n sir.
Observat ie: Deoarece execut ia instruct iunilor din interiorul ciclului tre-
buie sa se faca cel put in o data, este corecta utilizarea unui ciclu repeta.
4. Problema 4: vom folosi un algoritm asemanator cu cel de la problema
precedenta, folosind informat ia ca sirul este ordonat crescator. Vom da
doua variante, cu analiza de complexitate.
(a) Prima varianta: ncepem cautarea, dar vom impune o condit ie
suplimentara: trebuie ca permanent x a(i). Daca avem x >
a(i), atunci este clar ca x nu mai poate gasit la dreapta indicelui
i.
Start CautareLiniaraCrescator
citeste( n, (a(i), i = 1, n), x )
gasit = falsdeocamdata nu am gasit pe x n a
i = 1i este indicele elementului curent din sir
159
repeta
daca a(i) = x atunci
gasit = adevarat
pozitie = ipozitie este pozitia elementului x n sir
altfel
i = i + 1
sfarsit daca
pana cand i > n sau gasit = adevarat sau x > a(i)
daca gasit = adevarat atunci
scrie( Am gasit , x, pe pozit ia , pozitie )
altfel
scrie( x, nu a fost gasit )
sfarsit daca
Stop
Complexitatea este aceeasi ca la algoritmul precedent: (n).
Observat ie Este esent ial ca testarea i > n sa se faca nainte de
testarea a(i) x; daca spre exemplu locul lor ar fost inversat,
atunci era posibil ca sa avem i = n + 1, iar condit ia a(i) x sa
e testata, desi a(n + 1) nu exista.
(b) A doua varianta speculeaza mai inteligent faptul ca sirul este gata
sortat. Putem mpart i sirul n doua subsiruri de dimensiuni cat
mai apropiate. Se testeaza daca elementul de la mijloc este egal
cu x. Daca da, atunci cautarea se opreste cu succes. Daca nu, si
x < elementul din mijloc, atunci cautarea va continua sa se facan
prima jumatate a sirului (e clar ca n a doua jumatate nu poate
gasit); daca x este mai mare decat elementul de la jumatate, atunci
cautarea va continua n a doua jumatate. Cautarea continua pana
cand e se gaseste x n sir, e nu mai avem nici un element de
cercetat, caz care nseamna cautare fara succes.
Acest algoritm se numeste algoritmul cautarii binare (prin nju-
matat ire).
Start CautareBinara
citeste( n, (a(i), i = 1, n), x )
gasit = falsvariabila gasit are aceeasi semnicat ie ca n
algoritmul anterior
stanga = 1
dreapta = n
stanga si dreapta reprezinta capetelentre care se face cautarea
lui x
Init ial, cautarea se face n tot vectorul
160
cat timp gasit = fals si stanga dreapta
nu l-am gasit pe x si mai avem unde cauta
mijloc =
_
stanga+dreapta
2

ma pozit ionez la jumatatea sirului


daca a(mijloc) = x atunci
gasit = adevarat
altfel
daca x < a(mijloc) atunci
dreapta = mijloc 1
altfel
stanga = mijloc + 1
sfarsit daca
caut doar n jumatatea corespunzatoare
sfarsit daca
sfarsit cat timp
daca gasit = adevarat atunci
scrie( Am gasit , x, pe pozit ia , pozitie )
altfel
scrie( x, nu a fost gasit )
sfarsit daca
Stop
Complexitate: Timpul T(n) pentru rezolvarea problemei de di-
mensiune n satisface ecuat ia: T(n) = T(n/2)+c, c ind o constata
necesara testarilor si atribuirilor (operat ii elementare, al caror cost
n parte nu depinde de n). Conform teoremei centrale (enunt ata
la capitolul Divide et impera) obt inem ca
T(n) = (log
2
(n)) ,
adica mult mai performant decat n varianta 4a.
5. Problema 4: presupunem ca minimul este primul element din sir. Luam
apoi ecare din celelalte elemente ale vectorului a si le comparam
cu minimul curent cunoscut: daca acest element este mai mic decat
minimul, atunci e clar ca am descoperit un minim mai bun, deci
noul minim va elementul curent. Procedeul continua pana cand se
epuizeaza elementele din sir. La sfarsit minimul gasit va de fapt
minimul absolut al sirului, ceea ce trebuia determinat.
Start Minim
citeste( n, (a(i), i = 1, n) )
minim = a(1)
pentru i=2,n
161
daca a(i) < minim atunci
minim = a(i)
sfarsit daca
sfarsit pentru
scrie( minimul este , minim )
Stop
Numarul de comparat ii este n 1. Nu se poate cobor sub acesta
(demonstrat ia se face prin induct ie).
Observat ie. Exista varianta de a init ializa minim cu o valoare foarte
mare, considerata + pentru tipul de date care este folosit. De multe
ori limbajele de programare pun la dispozit ie constante reprezentand
valorile cele mai mari (mici) repezentabile pe un anumit tip de date
numeric (Pascal, C/C++, Java, C#).
6. Problema 5: vom folosi un contor (o variabila) pentru a urmari de cate
ori apare minimul.
(a) Vom rezolva probleman doi pasi: vom determina minimul printr-
o parcurgere a sirului, ca mai sus, iar apoi vom parcurge sirul nca
o data pentru a numara de cate ori a aparut acesta.
Start ContorMinim1
citeste( n, (a(i), i = 1, n) )
minim = a(1)
pentru i=2,n
daca a(i) < minim atunci
minim = a(i)
sfarsit daca
sfarsit pentru
contor = 0
pentru i = 2, n
daca minim = a(i) atunci
contor = contor + 1
sfarsit daca
sfarsit pentru
scrie( minimul este , minim )
scrie( apare de , contor, ori )
Stop
Complexitate: (n), deoarece sirul se parcurge de doua ori, pen-
tru ecare element efectuanduse operat ii elementare ce nu de-
pind de n (dimensiunea intrarii).
162
(b) Vom rezolva problema printro singura parcurgere a sirului; com-
plexitatea teoretica ramane aceeasi.
Start ContorMinim2
citeste( n, (a(i), i = 1, n) )
minim = a(1)
contor = 1
pentru i = 2, n
daca minim > a(i) atunci
minim = a(i)am gasit un minim mai bun
contor = 1resetam contorul la 1
altfel
daca minim = a(i) atunci
contor = contor + 1am mai gasit o valoare egala cu
minimul curent
sfarsit daca
sfarsit daca
sfarsit pentru
scrie( minimul este , minim )
scrie( apare de , contor, ori )
Stop
7. Problema 6: vom construi doi vectori: unul ret ine numerele distincte
din a, iar celalalt contorizeaza numarul de aparit ii pentru ecare numar.
Vom scrie un subalgoritm de tip funct ie de cautare liniara a unui el-
ement x ntr-un vector v care cont ine un anumit numar de elemente.
Aceasta funct ie returneaza pozit ia pe care se gaseste elementul x n v
sau 0 n cazul n care x nu este cuprins n v:
CautaLiniar(x, v, l)
pozitie = 0
gasit = fals
i = 1
repeta
daca x = v(i) atunci
gasit = adevarat
pozitie = i
altfel
i = i + 1
sfarsit daca
pana cand i > l sau gasit = adevarat
CautaLiniar = pozitie
Return
163
Start CelMaiDes
citeste( n, (a(i), i = 1, n) )
k = 0k este numarul de elemente distincte din a
pentru i = 1, n
pozitieInDiferite =CautaLiniar (a(i), diferite, k)
daca pozitieInDiferite = 0 atunci
k = k + 1a(i) nu a mai fost gasit nainte
punem a(i) n vectorul diferite
diferite(k) = a(i)
contor(k) = 1
altfel
a(i) a mai aparut o data nainte n a
contor(pozitieInDiferite) = contor(pozitieInDiferite)+1l-
am mai gasit o data
sfarsit daca
sfarsit pentru
acum cautam n vectorul contor sa vedem care numar a aparut
cel mai des
maximAparitii = contor(1)
pozMax = 1
pentru i = 2, k
daca contor(i) > maximAparitii atunci
maximAparitii = contor(i)
pozMax = i
sfarsit daca
sfarsit pentru
scrie( Numarul cel mai frecvent: , diferite(pozMax) )
scrie( Apare de , maximAparitii, ori )
Stop
Complexitate: cazul cel mai defavorabil este atunci cand avem doar ele-
mente distincten sirul a.

In acest caz, un apel CautaLiniar(a(i), diferite, k)
are costul de forma a k + b, a si b constante. Ciclul din programul
principal duce la un timp
T(n) =
n

k=1
(a k +b) = (n
2
)
Exemplu: pentru n = 4, a = (10, 20, 30, 40) vom avea:
164
diferit = (10, 20, 30, 40)
contor = (1, 1, 1, 1)
k = 4
cel mai frecvent: 10
frecvent a: 1
8. Problema 8: vom prota de faptul ca vectorul dat este sortat crescator.
Vom cauta o secvent a de numere constante, de lungime maxima.
Start CelMaiDes
inceputSecventa = 1
sfarsitSecventa = 1
lungimeSecventaMaxima = 0
suntInSir = adevarat
cat timp suntInSir = adevarat
cat timp sfarsitSecventa n si a(inceputSecventa) = a(sfarsitSecventa)
sfarsitSecventa = sfarsitSecventa + 1
sfarsit cat timp
daca sfarsitSecventainceputSecventa > lungimeSecventaMaxima
atunci
apareMaxim = a(inceputSecventa)
lungimeSecventaMaxima = sfarsitSecventainceputSecventa
sfarsit daca
inceputSecventa = sfarsitSecventa
daca inceputSecventa > n atunci
suntInSir = falsam parcurs tot sirul
sfarsit daca
sfarsit cat timp
scrie( Numarul cel mai frecvent: , apareMaxim )
scrie( Apare de , lungimeSecventaMaxima, ori )
Stop
Complexitate: se observa ca valoarea sfarsitSecventa ia pe rand val-
orile 1, 2, . . . , n + 1; de ecare data sunt efectuate operat ii elementare,
deci avem T(n) = (n + 1) = (n).
Observat ie: Pentru a rezolva problema de la punctul anterior, am putea
face o sortare a sirului, dupa care sa aplicam algoritmul de mai sus.
Complexitatea totala ar : sortarea implica un timp (nlog n), algo-
ritmul anterior (n), deci per total (nlog n), sensibil mai bine decat
(n
2
) care fusese obt inut anterior.
9. Problema 9:
165
Start Matrice
citeste( n )
citeste( ((a(i, j), j = 1, n), i = 1, n) )
subpunctul a
p = 11 este element neutru pentru nmult ire
pentru i = 1, n
pentru j = 1, n
daca a(i, j) ,= 0 atunci
p = p a(i, j)
sfarsit daca
sfarsit pentru
sfarsit pentru
scrie( Produsul elementelor nenule din matrice este: , p )
subpunctul b
p = 1
pentru i = 1, n
daca a(i, i) ,= 0 atunci
p = p a(i, j)
sfarsit daca
sfarsit pentru
scrie( Produsul elementelor nenule de pe diagonala principala este:
, p )
subpunctul c
p = 1
pentru i = 2, n
pentru j = 1, i 1
daca a(i, j) ,= 0 atunci
p = p a(i, j)
sfarsit daca
sfarsit pentru
sfarsit pentru
scrie( Produsul elementelor de sub diagonala principala este:, p )
Stop
Complexitate:
(a) (n
2
) (ecare element al matricii este luat n considerare o sin-
gura data, efectuandu-se cu el operat ii elementare);
(b) (n);
(c) T(n) =
n

i=2
(i 1)c = c
n

i=2
(i 1) = c
n(n1)
2
, deci T(n) = (n
2
).
166
Rezolvari pentru capitolul 4
1. Problema 1: Vom folosi pentru memorarea elementelor din coada un
vector v de n elemente. Vom presupune ca indicii vectorului sunt ntre
0 si n 1. Deoarece coada este circulara, dupa locat ia de indice n 1
urmeaza locat ia de indice 0. Init ial, coada este vida, fapt semnalat prin
inceput = sfarsit = 0.
x Coada
sfarsit = (sfarsit + 1)mod n
daca sfarsit = inceput atunci
Coada este plina
altfel
v(sfarsit) = x
sfarsit daca
Return
x Coada
daca inceput = sfarsit atunci
Coada este vida
altfel
inceput = (inceput + 1)mod n
x = v(inceput)
sfarsit daca
Return
Complexitatea ecarui subalgoritm este (1). Init ial avem inceput =
sfarsit = 0.
Observat ie: Se folosesc efectiv doar n 1 locat ii ale vectorului; dar n
acest mod putem distinge situat ia de coada plina de situat ia de coada
vida.
2. Problema 2:
(a) Parcurgerea n inordine, iterativ:
InordineIterativ(rad)
i = rad
S = S este o stiva
repeta
cat timp LS(i) ,=
i S
i = LS(i)
sfarsit cat timp
167
scrie( INFO(i) )
cat timp LD(i) =
daca S = atunci
Return se iese din subalgoritm, deci si din ciclul innit
sfarsit daca
i S
scrie( INFO(i) )
sfarsit cat timp
i = LD(i)
pana cand falsciclu innit, din care se iese datorita lui Return
(b) Parcurgerea n postordine, iterativ:
PostordineIterativ( rad )
i = rad
S = S este o stiva
repeta
cat timp LS(i) ,=


i S
i = LS(i)
sfarsit cat timp
cat timp LD(i) =

repeta
scrie( INFO(i) )
daca S = atunci
Returnse iese din subalgoritm, deci si din ciclul in-
nit
sfarsit daca
j = i
i S
pana cand j = LS(i)
sfarsit cat timp
i S
i = LD(i)
pana cand falsciclu innit, din care se iese datorita lui Return
Apelul subalgoritmilor de mai sus se face avand drept parametru de
apel rad, reprezentand adresa radacinii arborelui.
Complexitatea ecareia din proceduri este de (n), unde n este numarul
de varfuri ale arborelui.
3. Problema 3:
168
Vom extrage succesiv varful stivei S si l vom depune ntr-o alta stiva
T. Extragerile nceteaza e cand S devine vida, e cand x este gasit.
Elementele din T vor depuse napoi n S.
Extrage( S, x )
T =
gasitx = fals
cat timp S ,= si gasitx = fals
a S scoatem varful stivei
daca a ,= x atunci
a T l depunem n T
altfel
gasitx = adevarat
sfarsit daca
sfarsit cat timp
cat timp T ,=
a T
a S
sfarsit cat timp
Return
Complexitate: cazul cel mai defavorabil este acela n care x nu se
gaseste n S.

In acest caz, tot cont inutul lui S este trecut n T si
apoi repus n S. Complexitatea este deci ([S[), unde [S[ reprezinta
numarul de elemente aate init ial n S.
Observat ie: Primul ciclu cat timp poate scris mai adecvat ca un ciclu
repeta, avandn vedere faptul ca execut ia ciclui se face cel put in o data.
4. Problema 4:
Rezolvarea este asemanatoare cu cea de la punctul precedent.
Insereaza( S, x, y )
T =
gasitx=fals
cat timp S ,= si gasitx = fals
a S scoatem varful stivei
daca a ,= x atunci
a T l depunem n T
altfel
gasitx = adevarat
a S
sfarsit daca
169
sfarsit cat timp
daca gasitx = adevarat atunci
y S
sfarsit daca
cat timp T ,=
a T
a S
sfarsit cat timp
Return
Complexitatea este ([S[ + 1) = ([S[), motivat ia ind asemanatoare
cu cea de la punctul precedent.
5. Problema 5:
Vom folosi doua stive: Stiva1, Stiva2.
x Coada
daca Stiva1 = atunci
Goleste(Stiva2, Stiva1)Goleste elementele din Stiva2 n Stiva1
sfarsit daca
x Stiva1
Return
x Coada
daca Stiva2 = atunci
Goleste(Stiva1, Stiva2)Goleste elementele din Stiva1 n Stiva2
sfarsit daca
daca Stiva2 = atunci
Coada este vida
altfel
x Stiva2
sfarsit daca
Return
Subalgoritmul Goleste(A, B) unde A si B sunt stive va trece toate ele-
mentele din An B, prin extrageri repetate.
Goleste(A, B)
cat timp A ,=
x A
x B
sfarsit cat timp
Return
Numarul de operat ii de inserare si extragere n ecare caz sunt:
170
(a) Subalgoritmul Goleste(A, B) efectueaza 2[A[ extrageri ([A[ este
numarul de elemente din stiva A);
(b) Subalgoritmul x Coada efectueaza 2[Stiva2[+1 = 2[Coada[+1
operat ii de inserare/extragere;
(c) Subalgoritmul x Coada efectueaza 2[Stiva1[+1 = 2[Coada[+1
operat ii de inserare/extragere;
6. Problema 6:
Vom folosi doua cozi: Coada1, Coada2.
x Stiva
x Coada1
Return
x Stiva
daca Coada1 = atunci
eroare: stiva vida
altfel
cat timp Coada1 ,=
x Coada1
daca Coada1 ,= atunci
x nu este ultimul element din Coada1
x Coada2
sfarsit daca
sfarsit cat timpGoleste Coada2 n Coada1
cat timp Coada2 ,=
y Coada2
y Coada1
sfarsit cat timp
sfarsit daca
Return
Numarul de operat ii de inserare/extragere pentru ecare din cei doi
subalgoritmi sunt:
(a) Subalgoritmul x Stiva efectueaza o inserare
(b) Subalgoritmul x Stiva are numarul de operat ii cerut egal cu
2([Coada1[ 1) + 1 (primul ciclu) adunat cu 2([Coada1[ 1), n
total 4[Coada1[ 3 = 4[Stiva[ 3.
Sugeram cititorului sa gaseasca si alte soluct ii pentru aceasta
problema.
171
Rezolvari pentru capitolul 5
1. Problema 1. Denim maximul unui sir x = (x(1), x(2), . . . , x(n)) sub
forma recursiva astfel:
maxim(x(1 . . . n)) =
_
x(1), daca n=1
maxx(n), x(1 . . . n 1), daca n > 1
unde maxa, b este maximul dintre a si b. Algoritmul este dat mai
jos:
Start MaximRec
citeste( n, (x(i), i = 1, n) )
M = Maxim(x, n)
scrie( M )
Stop
unde subalgoritmul recursiv Maxim este:
Maxim(x, n)
daca n = 1 atunci
MaximRec = x(1)
altfel
MaximRec = maxx(n), Maxim(x, n 1)
sfarsit daca
Return
Complexitatea este data de ecuat ia T(n) = T(n1)+c care are solut ia
T(n) = (n).
2. Problema 2. Denim suma elementelor unu sir x = (x(1), . . . , x(n))
sub forma recursiva astfel:
suma(x(1 . . . n)) =
_
0, daca n=0
x(n) +suma(x(1 . . . n 1)), daca n > 0
Start SumaRec
citeste( n, (x(i), i = 1, n) )
S = Suma(x, n)
scrie( S )
Stop
unde subalgoritmul recursiv Suma este:
Suma(x, n)
daca n = 0 atunci
172
Suma = 0
altfel
Suma = x(n) +Suma(x, n 1)
sfarsit daca
Return
Complexitatea este data de ecuat ia T(n) = T(n1)+c care are solut ia
T(n) = (n).
3. Problema 3. Vom da o formula recursiva de calcul a puterii naturale a
unui numar.
a
n
=
_

_
1, daca n = 0
a, daca n = 1
_
a
n/2
_
2
, daca n > 1, n par
a
_
a
n/2
_
2
, daca n > 1, n impar
Subalgoritmul recursiv este:
Putere(a, n)
daca n = 0 atunci
Putere = 1
Return
sfarsit daca
daca n = 1 atunci
Putere = a
Return
sfarsit daca
temp = Putere(a, n/2|)
daca n mod 2 = 0 atunci
n este par
Putere = temp
altfel
Putere = a temp
sfarsit daca
Return
Complexitatea este data de ecuat ia T(n) = T(n/2)+c, de unde T(n) =
(log n) (rezultat al teoremei 1, pagina 76).
4. Problema 4. Pentru a
15
, conform algoritmului precedent, avem:
a
15
=
_
_
(a)
2
a
_
2
a
_
2
a
173
deci n total 6 nmult iri.
Dar a
15
se poate calcula astfel: se calculeaza termenii a
2
, a
3
= a
2
a, a
6
=
a
3
a
3
, a
12
= a
6
a
6
, a
15
= a
12
a
3
, deci cu 5 nmult iri.
5. Problema 5. Sa consideram matricea:
A =
_
0 1
1 1
_
Calculand produsul:
A
_
f
n1
f
n
_
obt inem matricea
_
f
n
f
n+1
_
de unde deducem
_
f
n1
f
n
_
= A
n1

_
f
0
f
1
_
Modicand algoritmul de la problema 3 astfel ncat sa ridice la putere
o matrice n loc de un scalar, obt inem termenul f
n
n timp (log n).
6. Problema 6. Algoritmii recursivi pentru parcurgeri sunt urmatorii:
(a) Parcurgerean preordine se efectueaza astfel: se prelucreaza informa-
t ia radacinii, apoi se prelucreaza recursiv subarborele stang, apoi
subarborele drept.
Preordine(Rad)
daca Rad ,= atunci
scrie( Info(Rad) )Sau orice alt subalgoritm de prelucrarea
a informat iei din Rad
Preordine(LS(Rad))
Preordine(LD(Rad))
sfarsit daca
Return
Apelul acestui subalgoritm se face cu Preordine(Rad), unde Rad
reprezinta radacina subarborelui.
(b) Parcurgerea recursiva n postordine se efectueaza astfel: se par-
curge recursiv subarborele stang, apoi subarborele drept, apoi se
prelucreaza informat ia din radacina.
174
Postordine(Rad)
daca Rad ,= atunci
Postordine(LS(Rad))
Postordine(LD(Rad))
scrie( Info(Rad) )Sau orice alt subalgoritm de prelucrarea
a informat iei din Rad
sfarsit daca
Return
Apelul se face ca n cazul anterior.
(c) Parcurgerea recursiva n inordine se efectueaza astfel: se par-
curge recursiv subarborele stang, apoi se prelucreaza informat ia
din radacina, apoi se parcurge recursiv subarborele drept.
Inordine(Rad)
daca Rad ,= atunci
Inordine(LS(Rad))
scrie( Info(Rad) )Sau orice alt subalgoritm de prelucrarea
a informat iei din Rad
Inordine(LD(Rad))
sfarsit daca
Return
Apelul se face ca n cazul anterior.
Rezolvari pentru capitolul 6
1. Problema 1.
Vom da doua variante de rezolvare: iterativa si recursiva. Ambele
variante vor folosi doi vectori de sarituri: sarituraI si sarituraJ cu
cate 8 elemente, reprezentand cele 8 deplasari de la pozit ia curenta: de
exemplu, daca pozit ia curenta este pe linia i si coloana j, atunci prima
saritura va duce calul la coordonatele (i+sarituraI(1), j+sarituraJ(1)
(cu condit ia sa nu se iasa din perimetrul tablei).
(a) Varianta iterativa: pentru refacerea pasului napoi vom folosi
o matrice patratica deLa de ordinul n, care va ret ine pentru ecare
celula de coordonate (i, j) indicele sariturii care a determinat atingerea
pozit iei respective (vom putea sti astfel de unde sa sarit n pozit ia
curenta). Solut ia se da sub forma unei matrice patratice de ordinul n
cont inand n ecare celula de coordonate (i, j) indicele sariturii ce se
face n continuare (cu except ia ultimei celule n care se sare).
175
Start CalSah
citeste( n )
sarituraI(1) = +1, sarituraJ(1) = +2
sarituraI(2) = 1, sarituraJ(2) = +2
sarituraI(3) = +1, sarituraJ(3) = 2
sarituraI(4) = 1, sarituraJ(4) = 2
sarituraI(5) = +2, sarituraJ(5) = +1
sarituraI(6) = 2, sarituraJ(6) = +1
sarituraI(7) = +2, sarituraJ(7) = 1
sarituraI(8) = 2, sarituraJ(8) = 1
pentru i = 1, n
pentru j = 1, n
deLa(i, j) = 0
tabla(i, j) = 0
sfarsit pentru
sfarsit pentru
nrSaritura = 1
i = j = 1
cat timp nrSaritura > 0
daca nrSaritura = n
2
atunci
ScrieSolutie(tabla, n)
indiceSarituraInapoi = deLa(i, j)
tabla(i, j) = 0
i = i sarituraI(indiceSarituraInapoi)
j = j sarituraJ(indiceSarituraInapoi)
nrSaritura = nrSaritura 1
sfarsit daca
daca tabla(i, j) < 8 atunci
tabla(i, j) = tabla(i, j) + 1
iInainte = i +sarituraI(tabla(i, j))
jInainte = j +sarituraJ(tabla(i, j))
daca PoateSari(iInainte, jInainte, tabla, n)=adevarat atunci
deLa(iInainte, jInainte) = tabla(i, j)
i = iInainte
j = jInainte
nrSaritura = nrSaritura + 1
sfarsit daca
altfel
daca nrSaritura > 1 atunci
iInapoi = i sarituraI(deLa(i, j))
jInapoi = j sarituraJ(deLa(i, j))
176
tabla(i, j) = 0
i = iInapoi
j = jInapoi
sfarsit daca
nrSaritura = nrSaritura 1
sfarsit daca
sfarsit cat timp
Stop
ScrieSolutie(tabla, n)
pentru i = 1, n
pentru j = 1, n
scrie( tabla(i, j) )
sfarsit pentru
sfarsit pentru
Return
PoateSari(linie, coloana, tabla, n)
daca linie > 0 si linie < n + 1 si coloana > 0 si coloana < n + 1 si
tabla(linie, coloana) = 0 atunci
rezultat = adevarat
altfel
rezultat = fals
sfarsit daca
PoateSari = rezultat
Return
(b) Varianta recursiva
Cal(i, j, n, nrSaritura, tabla)
daca nrSaritura = n n atunci
ScrieSolutie(tabla, n)
altfel
pentru indiceSaritura = 1, 8
iInainte = i +sarituraI[indiceSaritura]
jInainte = j +sarituraJ[indiceSaritura]
daca PoateSari(iUrmator, jUrmator, tabla, n)=adev atunci
tabla[iInainte, jInainte] = nrSaritura + 1
Cal(iInainte, jInainte, n, nrSaritura + 1, tabla)
tabla[iInainte, jInainte] = 0
sfarsit daca
sfarsit pentru
sfarsit daca
Return
177
Subalgoritmii ScrieSolutie si PoateSari sunt identici cu cei de la varianta
iterativa.
Start CalSah
citeste( n )
sarituraI(1) = +1, sarituraJ(2) = +2
sarituraI(2) = 1, sarituraJ(2) = +2
sarituraI(3) = +1, sarituraJ(3) = 2
sarituraI(4) = 1, sarituraJ(4) = 2
sarituraI(5) = +2, sarituraJ(5) = +1
sarituraI(6) = 2, sarituraJ(2) = +1
sarituraI(7) = +2, sarituraJ(2) = 1
sarituraI(1) = 2, sarituraJ(2) = 1
pentru i = 1, n
pentru j = 1, n
tabla(i, j) = 0
sfarsit pentru
sfarsit pentru
tabla(1, 1) = 1
Cal(1, 1, n, 1, tabla)
Stop
2. Problema 2.
Sa demonstrat cu ajutorul calculatorului ca 4 culori sunt suciente
pentru a colora cu restrict iile date orice harta. Vom da doua variante,
iterativa si recursiva.

In ambele variante vectorul culoare de n elemente
va cont ine culorile t arilor.
(a) Varianta iterativa.
Start ColorareHarti
citeste( n )
citeste( ((a(i, j), j = 1, n), i = 1, n) )
pentru i = 1, n
culoare(i) = 0
sfarsit pentru
numarTara = 1
cat timp numarTara > 0
daca numarTara = n + 1 atunci
scrie( (culoare(i), i = 1, n) )
numarTara = numarTara 1
sfarsit daca
daca culoare(numarTara) < 4 atunci
178
culoare(numarTara) = culoare(numarTara) + 1
daca BineColorat(a, numarTara, culoare) = adev atunci
numarTara = numarTara + 1
sfarsit daca
altfel
culoare(numarTara) = 0
numarTara = numarTara 1
sfarsit daca
sfarsit cat timp
Stop
Subalgoritmul BineColorat(vecin, numarTara, culoare) returneaza adevarat
daca culoarea t arii curente (numarTara) satisface restrict iile cerute
fat a de t arile anterior colorate.
BineColorat(a, numarTara, culoare)
corect = adevarat
i = 1
cat timp corect = adevarat si i < numarTara
daca a(i, numarTara) = 1 si culoare(i) = culoare(numarTara)
atunci
corect = fals
altfel
i = i + 1
sfarsit daca
sfarsit cat timp
BineColorat = corect
Return
(b) Varianta recursiva.
Coloreaza(a, n, culoare, numarTara)
daca numarTara = n + 1 atunci
scrie( (culoare(i), i = 1, n) )
altfel
pentru k = 1, 4
culoare(numarTara) = k
daca BineColorat(a, numarTara, culori)= adev atunci
Coloreaza(a, n, culoare, numarTara + 1)
sfarsit daca
sfarsit pentru
sfarsit daca
Return
179
Subalgoritmul BineColorat este identic cu cel de la varianta iterativa.
Utilizarea subalgoritmului recursiv se face astfel:
Start ColorareHarti
citeste( n )
citeste( ((vecin(i, j), j = 1, n), i = 1, n) )
Coloreaza(vecin, n, culoare, 1)
Stop
3. Problema 3.
Vom nota barbat ii cu b
1
, . . . , b
n
iar femeile cu f
1
, . . . , f
m
. Vom genera
delegat iile folosind doi vectori, unul pentru indicii de barbat i, celalalt
pentru indicii de femei (vectorii vb, respectiv vf). Fiecare vector are o
componennta de indice 0 care va avea permanent valoarea 0.

In vectorul
vf vom avea generate p componente (k p m), iar n vectorul vb
vom avea q elemente (0 q n); varianta q = 0 exista deoarece se
pot forma delegat ii n care sa nu existe nici un barbat.
Varianta data mai jos este recursiva. Pentru subalgoritmul Gener-
areDelegatii, parametrii fc si bc reprezinta indicele de vector vf, respec-
tiv vb pentru care se efectueaza alegerea unei femei, respectiv barbat.
GenerareDelegatii(p, fc, m, q, bc, n, vf, vb)
daca fc = p + 1 atunci
am generat tot i indiciii pentru femei
daca bc = q + 1 atunci
am generat tot i indiciii pentru barbat i
scrie( (vf(i), i = 1, p) )
scrie( (vb(i), i = 1, q) )
altfel
pentru i = vb(bc 1) + 1, n q +bc
vb(bc) = i
GenerareDelegatii(p, fc, m, q, bc + 1, n, vf, vb)
sfarsit pentru
sfarsit daca
altfel
pentru i = vf(fc 1) + 1, mp +fc
vf(fc) = i
GenerareDelegatii(p, fc + 1, m, q, bc, n, vf, vb)
sfarsit pentru
sfarsit daca
Return
Start Delegatii
180
citeste( m, n, k )
vf(0) = vb(0) = 0
pentru p = k, m
pentru q = 0, n
GenerareDelegatii(p, 1, m, q, 1, n, vf, vb)
sfarsit pentru
sfarsit pentru
Stop
Pentru o varianta iterativa, a se citi capitolul 7, sectiunea 7 (generare
de combinari).
4. Problema 4.
Vom da mai jos o varianta recursiva. Consideram rest ca ind restul
care mai este de platit, solutie un vector cu n elemente, 0 solutie(i)
b(i), bc tipul bancnotei curente.
Plata(rest, n, solutie, bc)
daca rest = 0 atunci
scrie( (solutie(i), i = 1, bc 1) )
altfel
daca rest > 0 si bc n atunci
pentru k = 0, b(bc)
solutie(bc) = k
Plata(rest k v(bc), solutie, bc + 1)
sfarsit pentru
sfarsit daca
sfarsit daca
Return
Start PlataSuma
citeste( n, S )
citeste( (b(i), i = 1, n) )
citeste( (v(i), i = 1, n) )
Plata(S, n, solutie, 1)
Stop
Observat ie Orice problema cu datele ca mai sus poate transformata
ntruna n care vectorul b cont ine doar valoarea 1, prin crearea unui
vector v

care va cont ine valoarea v(i) de b(i) ori.


Pentru o varianta iterativa n cazul b(i) = 1, i = 1, n a se vedea
capitolul 7, sect iunea 7
181
Rezolvari pentru capitolul 7
1. Problema 1.
(a) Produs cartezian:
CartezianRecursiv(m, n, k, x)
daca k = n + 1 atunci
Asare(x, m)sau orice subalgoritm care prelucreaza informat ia
obt inuta
altfel
pentru p = 1, n(k)
x(k) = p
CartezianRecursiv(m, n, k + 1, x)
sfarsit pentru
sfarsit daca
Return
Subalgoritmul Asare este:
Asare(a, l)
pentru i = 1, l
scrie( a(i) )
sfarsit pentru
Return
Programul principal este:
Start Cartezian
citeste( m, (n(i), i = 1, m) )
CartezianRecrsiv(m, n, 1, x)
Stop
Subalgoritmul recursiv genereaza solut iile n ordine lexicograca.
(b) Submult imi: vom folosi un subalgoritm recursiv cu forma: Sub-
multimiRecursiv(n, k, cate, x) unde n este data de intrare reprezentand
numarul elementelor mult imii init iale, k este indicele curent pen-
tru care se ncearca generarea, cate reprezinta numarul de ele-
mente ale submult imii care se genereaza (1 k cate, pentru
cate > 0), iar x este vectorul solut ie. Vom considera ca x are un
elemente de indice 0 care va avea permanent valoarea 0.
SumbultimiRecursiv(n, k, cate, x)
daca k > cate atunci
182
ScrieSolutie(x, cate)sau orice subalgoritm care prelucreaza
informat ia data
altfel
pentru p = x(k 1), n cate +k
x(k) = p
SubmultimiRecursiv(n, k + 1, cate, x)
sfarsit pentru
sfarsit daca
Return
Subalgoritmul ScrieSolutie este o variatie a celui anterior, care
n plus ia n considerare cazul ncare s-a generat mult imea vida:
ScrieSolutie(a, l)
daca l = 0 atunci
scrie( multimea vida )
altfel
pentru i = 1, l
scrie( a(i) )
sfarsit pentru
sfarsit daca
Return
Subalgoritmul principal este:
Start Submultimi
citeste( n )
x(0) = 0
pentru cate = 0, n
SubmultimiRecursiv(n, 1, cate, x)
sfarsit pentru
Stop
Subalgoritmul recursiv genereaza submult imilen ordine lexicograca.
(c) Combinari: subalgoritmul este acelasi cu cel de la generarea re-
cursiva a submult imilor, cu acceeasi semnicat ie a parametrilor
de apel. Programul principal este:
Start Combinari
citeste( n, m )
x(0) = 0
CombinariRecursiv(n, 1, m, x)
Stop
183
Subalgorimul recursiv genereaza combinarilen ordine lexicograca.
(d) Permutari:
PermutariRecursiv(k, x, n)
daca k = 0 atunci
ScrieSolutie(v, n)
altfel
pentru i = 1, k
v(k) v(i)
PermutariRecursiv(k 1, x, n)
v(k) v(i)
sfarsit pentru
sfarsit daca
Return
Subalgoritmul de ScrieSolutie este cel de la produs cartezian.
Programul principal ar :
Start Permutari
citeste( n )
pentru i = 1, n
v(i) = i
sfarsit pentru
PermutariRecursiv(n, x, n)
Stop
Subalgoritmul recursiv nu genereaza permutarile n ordine lex-
icograca. Sugeram cititorului scrierea unei variante bazate pe
backtracking recursiv, care sa genereze permutarile n ordine lex-
icograca.
Rezolvari pentru capitolul 8
1. Problema 1. Vom proceda n felul urmator: daca trebuie sa umplem
un vector al carui capat stang este st si cel drept este dr, atunci la
mijloc se pune perechea (i, j), dupa care se completeaza jumatatea
stanga a vectorului, urmata de cea dreapta. Varianta de mai jos este
iterativa, folosind o stiva pentru simularea recursivitat ii. Solut iile vor
memorate ntro matrice cu 2
n
1 linii si 2 coloane.
Start Hanoi
citeste( n )
i = 1
184
j = 2
st = 1
dr = 2
n
1
S = S este stiva
(i, j, st, dr) S
cat timp S ,=
(i, j, st, dr) S
sol(
st+dr
2
, 1) = i
sol(
st+dr
2
, 2) = j
daca st
st+dr
2
1 atunci
(i, 6 i j, st,
st+dr
2
1) S
sfarsit daca
daca
st+dr
2
+ 1, dr atunci
(6 i j, j,
st+dr
2
+ 1, dr) S
sfarsit daca
sfarsit cat timp
scrie( (sol(i, 1), sol(1, 2), i = 1, 2
n
1) )
Stop
Adancimea stivei S este (log
2
(2
n
1)) = (n), iar complexitatea este
evident (2
n
).
2. Problema 2. A se vedea rezolvarea de la varianta 4b, pagina 160. Com-
plexitatea obt inuta este T(n) = (log n).
3. Problema 3. A se vedea rezolvarea de la varianta 4a, pagina 159, pentru
care se obt inea o complexitate liniara.
4. Problema 4. La ecare pas din ciclul repeta al algoritmului de partit ionare
i creste cu o unitate, iar j scade cu o unitate. Partit ionarea se opreste
atunci cand j este la jumatatea sirului, deci mpart irea este echilibrata.
Ca atare, complexitatea este data de T(n) = T(n/2) + c n, de unde
T(n) = (n logn).
5. Problema 5. Vom crea o funct ie care determina daca un numar este
sau nu situat ntre alte doua numere:
Intre(x, y, z)returneaza adevarat daca x este ntre y si z, fals altfel
daca (y x si x z) sau (z x si x y) atunci
Intre = adevarat
altfel
Return fals
sfarsit daca
185
Algoritmul de partit ionare modicat este:
Partitie(a, p, q)
r =
p+q
2
daca Intre(a(p, a(q), a(r))) atunci
indiceMediana = p
sfarsit daca
daca Intre(a(q), a(p), a(r)) atunci
indiceMediana = q
sfarsit daca
daca Intre(a(r), a(p), a(q) atunci
indiceMediana = r
sfarsit daca
daca p ,= indiceMediana atunci
a(p) a(indiceMediana)
sfarsit daca
pivot = a(p)
i = p 1
j = r + 1
terminat = fals
repeta
repeta
j = j 1
pana cand a(j) pivot
repeta
i = i + 1
pana cand a(i) pivot
daca i < j atunci
a(i) a(j)
altfel
k = j
terminat = adevarat
sfarsit daca
pana cand terminat = adevarat
Return
Rezolvari pentru capitolul 9
1. Problema 1. Rezolvarea problemei se face n doi pasi:
(a) Se determina mediana sirului init ial x = (x(1), . . . , x(n)); e ea
186
med
x
(b) Se calculeaza sirul auxiliar y = (y(i), i = 1, n) unde y(i) = [x(i)
med
x
[
(c) Se determina a k-a statistica de ordine a sirului y; e ea med
y
(d) Se determina k elemente mai mici sau egale cu med
y
; indicii aces-
tor elemente sunt indicii elementelor cautate din sirul x.
Complexitatea ecarui pas de mai sus este (n), deci complexitatea
algoritumului schit at este (n). Subalgoritmul n pseudocod este:
Start Apropiate
citeste( n, k, (x(i), i = 1, n) )
Selectie(x, 1, n, k, med
x
)
ObtineY(x, n, y, med
x
)
Selectie(x, 1, n, k, margine
y
)
Vecini(x, y, n, margine
y
, z)
Stop
Subalgoritmul Selectie este cel care determina a k-a statistica de ordine
a unui sir (cu complexitate liniara pentru cazul cel mai defavorabil);
subalgoritmul ObtineY este:
ObtineY(x, n, y, med
x
)
pentru i = 1, n
y(i) = [x(i) med
x
[
sfarsit pentru
Return
Subalgoritmul Vecini va determina cei mai apropiat i k vecini ai sirului
x fat a de mediana sa:
Vecini(x, y, n, margine
y
, z)
lungZ = 0
pentru i = 1, n
daca y(i) margine
y
atunci
lungZ = lungZ + 1
z(lungZ) = x(i)
sfarsit daca
sfarsit pentru
Return
187
2. Problema 2. Vom folosi faptul ca cele doua siruri sunt sortate si au
aceeasi lungime. De asemenea ne folosim de observat ia evidenta ca
mediana unui sir sortat se determina n timp constant: daca i este
indicele primului element din sir, iar j este indicele ultimului element
al sirului, atunci mediana este pe pozit ia k =
i+j
2
|.
Pentru doua siruri A(i
A
. . . j
A
) si B(i
B
. . . j
B
) cu acelasi numar de ele-
mente (j
A
i
A
= j
B
i
B
) procedamn felul urmator: daca lungimile lor
sunt mai mici sau egale cu 2, atunci le putem interclasa si obt inem me-
diana lor (timp (1)). Daca numarul de elemente este mai mare decat
2, atunci e k
A
respectiv k
B
indicii mijloacelor vectorilor A(i
A
. . . j
A
)
si B(i
B
. . . j
B
). Daca A(k
A
) < B(k
B
) atunci vom ignora elementele din
A(i
A
. . . j
A
) aate la stanga indicelui k
A
si elementele din B(i
B
. . . j
B
)
aate la dreapta indicelui k
B
si vom considera doar vectorii A(k
A
. . . j
A
)
si B(k
b
. . . j
B
). Analog se procedeaza daca A(k
A
) B(k
B
). Procesul
se reia pentru vectorii njumatat it i.
Justicam faptul ca prin eliminarea unei jumatat i din ecare vector nu
se pierde mediana cautata. Fie de exemplu A(k
A
) < B(k
B
). Fie n =
j
A
i
A
= j
B
i
B
. Fie i astfel ncat i
A
i < k
A
. Atunci A(i) A
(
k
A
)
A
(
p) p = k
A
, . . . j
A
, A(i) A(k
A
) < B(k
B
) B(q) q = k
B
, . . . j
B
.
Obt inem ca A(i) este mai mic sau egal decat 2
_
n
n+1
2
| + 1
_
ele-
mente. Dar 2
_
n
n+1
2
| + 1
_
n +1, deci A(i) este mai mic sau egal
decat cel put in n + 1 elemente. Ca atare, ignorandule, nu pierdem
mediana. Analog se demonstreaza ca eliminand jumatatea dreapta a
lui B nu se pierde mediana. Demonstrat ia este asemanatoare pentru
cazul n care A(k
A
) B(k
B
).
Algoritmul este dat mai jos:
Start MedianaSiruri
citeste( n, (A(i), B(i), i = 1, n) )
i
A
= i
B
= 1
j
A
= j
B
= n
cat timp i
A
< i
B
k
A
=
i
A
+j
A
2
k
B
=
i
B
+j
B
2
n =
n
2
daca A(k
A
) < B(k
B
) atunci
i
A
= k
A
j
B
= k
B
altfel
j
A
= k
A
188
i
B
= k
B
sfarsit daca
sfarsit cat timp
scrie( max(A(i
A
), B(i
B
)) )
Stop
unde max returneaza maximul a doua numere. Complexitatea este:
T(n) = T(n/2) + (1) = (log n)
3. Problema 3. Se poate proceda n mai multe moduri:
(a) Sortam numerele si alegem cele mai mari i numere
(b) Construim un (max)heap si extragem din el de i ori maximul
(c) Prin utilizarea unui algoritm de statistica de ordine
Lasam n seama cititorului scrierea algoritmulor pentru cazurile 3a si
3b. Pentru situat ia 3c determinam a n i + 1a statistica de ordine
(e ea x) si apoi printro parcurgere a sirului numerele mai mari sau
egale cu x. Complexitatea este de (n + i log i). Sugeram cititorului
compararea acestei complexitat i cu cea obt inuta la punctele 3a si 3b.
4. Problema 4, pagina 4. Ideea este de a deplasa elementele dea lun-
gul axei astfel ncat sa devina toate pozitive (caz pentru care algorit-
mul Countsort funct ioneaza). Aceasta deplasare se obt ine adunand o
cantitate potrivita, care poate luata ca min
i=1,n
x(i)!. Dupa ce se
efectueaza sortarea, se revine la valorile originale prin scaderea can-
titat ii adunate anterior.
Start CountSortModicat
citeste( n, (x(i), i = 1, n) )
min = MinimSir(x, n)Functie care determina minimul unui sir
pentru i = 1, n
x(i) = x(i) + (min)
sfarsit pentru
Aici apare algoritmul CountSort
pentru i = 1, n
y(i) = y(i) (min)
sfarsit pentru
Stop
189
Rezolvari pentru capitolul 10
1. Problema 1. Pentru ecare element x(i) se determina daca apare si n
sirul y.

In caz armativ, x(i) va face parte si din mult imea intersect ie.
Faptul ca n acest fel se obt ine mult imea intersect ie este (speram) evi-
dent. Complexitatea algoritmului este dependenta de modul n care se
face cautarea lui x(i) n y.
Daca se face cautare liniara (vezi rezolvarea 3, pagina 158), atunci
complexitatea este (mn)
Daca se cauta binar (vezi rezolvarea de la 4b, pagina 160), atunci:
y trebuie sortatn prealabil, deci avem o complexitate (mlog
2
m)
x(i) este cautat binar n y, pentru i = 1, n, deci se mai
adauga complexitatea (nlog
2
m)

In total se obt ine o complexitate de ((m + n) log m). Este mai


avantajos ca sa se faca sortarea si cautarea n sirul cel mai scurt.
Lasam cititorul sa conceapa algotritmul pentru rezolvarea acestei prob-
leme.

In ceea ce priveste funct ia care se optimizeaza, este vorba de:
max f(x, y) = [a : a n x si a n y[
([A[ reprezinta numarul de elemente ale mult imii A), care se regaseste
si n algoritmul prezentat (cu toate ca nu este evident).
2. Problema 2. Ideea algoritmului este de a calcula pentru ecare obiect
valoarea lui unitara, i.e. cat se castiga din transportarea unei unitat i
din obiectul respectiv. Suntem mai interesat i n a considera obiectele
protabile (pret mare, greutate mica) naintea celor pentru care rapor-
tul pret /greutate este mic. Algoritmul dat mai jos sintetizeaza aceasta
strategie.
Start RucsacContinuu
citeste( n, G, (c(i), g(i), i = 1, n) )
pentru i = 1, n
v(i) =
c(i)
g(i)
sfarsit pentru
Sortare(c, g, v, n)
gc = 0gc reprezinta greutatea curenta pusa n rucsac
190
k = 1k este numarul obiectului curent care se ncearca a pus n
rucsac
S = 0S este suma realizata prin luarea obiectelor
cat timp k n si gc < G
daca gc +g(k) G atunci
f(k) = 1f(k) reprezinta fract iunea care se ia din obiectul k
gc = gc +g(k)
S = S +c(k)
k = k + 1
altfel
f(k) =
Ggc
g(k)
gc = G
S = S +f(k)g(k)
sfarsit daca
sfarsit cat timp
daca k > n atunci
k = n

In cazul n care G este mai mare sau egal cu greutatea


tuturor obiectelor
sfarsit daca
pentru
i = 1, k
scrie( f(i) )
sfarsit pentru
Stop
Subalgoritmul Sortare(c, g, v, n) rearanjeaza elementele vectorilor c, g, v
astfel ncat v(1) v(2) v(n). Corectitudinea algoritmului de
mai sus este data de propozit ia de mai jos:
Propozitia 1. Algoritmul precedent determina castigul maxim n res-
trict iile impuse problemei.
Demonstrat ie. Daca G >
n

i=1
g(i), atunci n mod evident solut ia data
de vectorul f va avea forma f = (1, 1, . . . , 1) (se iau toate obiectele),
ceea ce evident nseamna optim. Vom considera deci cazul n care
G <

g(i). Este usor de vazut ca solut ia data de vectorul f are


forma:
f = (1, 1, . . . , 1, , 0, 0, . . . 0) (B.1)
unde 0 < 1 si apare pe pozit ia k (k ind variabila din algoritm).
191
Avem ca:
S =
n

i=1
f(i)c(i) (B.2)
si
G =
k

i=1
f(i)g(i) (B.3)
Fie S

castigul maxim care se poate realiza n condit iile problemei si e


f

= (f

(1), . . . , f

(n)) (B.4)
fract iunile din obiecte care se iau, pentru a realiza S

:
S

=
n

i=1
f

(i)c(i) (B.5)
Avem:
G

=
n

i=1
f

(i)g(i) (B.6)
unde G

este greutatea totala care se transporta pentru cat igul S

.
Putem avea urmatoarele situat ii:
(a) Daca (prin absurd) S

< S, atunci se contrazice optimalitatea lui


S

; deci aceasta situat ie nu poate sa apara.


(b) Daca S

= S, atunci S este optimal si nu mai avem ce demonstra.


(c) Daca (prin absurd) S

> S, atunci procedam dupa cum urmeaza.


Fie p cel mai mic indice pentru care f

(p) ,= 1 (n ipoteza n
care un asemenea p exista). Vom transforma f

(p) n f

(p) =
f

(p)+ = 1, obt inand un surplus de greutate de g(p) (depasim


greutatea maxima G). Acest surplus de greutate va scazut
dintrun alt obiect de indice t, t > p (sau din mai multe obiecte
de indici mai mari decat p, dar tratarea este analoaga cu cea
pentru un singur obiect). Vom schimba deci f

(t) f

(t) =
f

(t) 0, astfel ncat


g(t) = g(p) (B.7)
Pentru i ,= p, t vom avea f

(i) = f

(i). Atunci:
S

i
f

(i)c(i) =

i=p,t
f

(i)c(i) + (f

(p) +)c(p) +
(f

(t) )c(t) = S

+c(p) c(t) (B.8)


192
Dar: c(p) c(t) = v(p)g(p) v(t)g(t) si conform relat iei
(B.7) obt inem ca:
S

= S

+g(p)(v(p) v(t)) (B.9)


Daca v(p) v(t) = 0, atunci S

= S

si procedeul se continua cu
urmatorul p. Daca S

< S

se contrazice optimalitatea lui S

.
Daca nu (mai) exista nici un p cu proprietatea f

(p) < f(p) =


1, mai avem de studiat relat ia dintre f(k) = si f

(k). Daca
f

(k) < , atunci printrun procedeu analog de marire a lui f

(k)
la (si scaderea unui f

(t), t > k) vom obt ine e o contradict ie,


e S

= S

(ca mai sus). Daca f

(k) > , atunci se contrazice


modul de alegere al lui f

(k) = din algoritm.



In sfarsit, daca
f

(k) = , atunci avem ca f

poate adus la forma f fara a pierde


din castig.
Deci am demonstrat ca S dat de f (conform algoritmului) nu poate
mai mic decat S

, de unde rezulta propozit ia.


3. Problema 3. Algoritmul sugerat n [6] este:
(a) Se sorteaza spectacolele dupa ora terminarii lor.
(b) Primul spectacol programat este cel care ncepe cel mai devreme.
(c) Se alege primul spectacol din cele ce urmeaza n sir ultimului
spectacol programat care ndeplineste conmdit ia ca ncepe dupa
ce sa terminat ultimul spectacol programat.
(d) daca tentativa de mai sus a esuat (nu am gasit un astfel de spec-
tacol), algoritmul se termina, altfel se programeaza spectacolul
gasit si se reia pasul 3c.
Demonstrat ia faptului ca acest algoritm duce la solut ia optima este
data n [6].
Algoritmul este:
Start Spectacole
citeste( n, (st(i), sf(i), i = 1, n) )
Sortare(st, sf, n)
scrie( Spectacol care ncepe la , st(1), si se sfarseste la, sf(1)
)
193
k = 1
pentru i = 2, n
daca st(i) sf(k) atunci
scrie( Spectacol care ncepe la , st(i), si se sfarseste la,
sf(i) )
k = i
sfarsit daca
sfarsit pentru
Stop
Algoritmul Sortarest, sf, n interschimba elementele din st, respectiv sf
astfel ncat sf(1) sf(2) sf(n).
Complexitate: avem o sortare care se poate face n timp (nlog n) si
o parcurgere a sirului st, deci n total (nlog n).
4. Problema 4. Desi problema are un caracter teoretic pronunt at, rezul-
tatul obt inut poate folosit n numeroase cazuri.

In [6] se arata ca
strategia pentru aceasta problema este:
(a) Se sorteaza elementele celor doua mult imi
(b) Daca A = a
1
, . . . , a
m
are k elemente negative si p elemente
pozitive, se aleg primele k elemente ale lui B si ultimele p elemente
ale lui B.
Algoritmul este:
Start Maxim
citeste( m, n, (a(i), i = 1, m), (b(i), i = 1, n) )
Sortare(a, m)
Sortare(b, n)
k = 1
cat timp k m si a(k) < 0
k = k + 1
sfarsit cat timp
k = k 1
suma = 0
pentru i = 1, k
suma = suma +a(i) b(i)
sfarsit pentru
pentru i = k + 1, m
suma = suma +a(i) b(n m +i)
194
sfarsit pentru
Stop
5. Problema 5. Timpul de asteptare pentru un client este compus din
timpii de servire ai client ilor care sunt procesat i naintea lui adunat cu
timpul de servire pentru el nsusi. De aceea timpul total de asteptare
nu este indiferent fat a de ordinea de servire. De exemplu, daca avem
doi client i, cu t
1
= 1 si t
2
= 2, atunci servirea n ordinea 1, 2 duce la
un timp de asteptare de 1 + (1 + 2) = 4, pe cand daca ar procesat i
invers, sar ajunge la timpul 2 + (2 + 1) = 5. Intuitiv, este mai bine
daca client ii sunt procesat i n ordinea crescatoare a timpilor de servire
(n acest fel un timp de servire mare are un impact mai tarziu).
Fie p o permutare a indicilor client ilor (corespunzand unei ordini de
intrare); client ii sunt preluat i n ordinea p
1
, p
2
, . . . , p
n
. Pentru aceasa
ordine, timpul total de servire este:
T(p) = t
p
1
+(t
p
1
+t
p
2
) + +(t
p
1
+t
p
2
+ +t
p
n
) =
n

i=1
(n i +1)t
p
k
(B.10)
Fie p permutarea care determina T din (B.10) minim. Fie p

per-
mutarea care se obt ine din p printro inversiune: p

(i) = p(j), p

(j) =
p(i) (i < j), p

(k) = p(k), k ,= i, j. Atunci avem ca T(p) T(p

), ceea
ce este echivalent cu (j i)(t
p
i
t
p
j
) 0, ceea ce conduce la t
p
i
< t
p
j
,
ceea ce conrma valabilitatea strategiei.
Algoritmul este:
Start Procesare
citeste( n, (t(i), i = 1, n) )
pentru i = 1, n
p(i) = i
sfarsit pentru
Sortaret, p, n
pentru i = 1, n
scrie( p(i) )
sfarsit pentru
Stop
Algoritmul Sortare(t, p, n) sorteaza elementele lui t, n paralel facand
aceleasi interschimbari n vectorul de permutare p.
195
Rezolvari pentru capitolul 11
1. Problema 1. Tablourile m si s, analoage celor din Tabelul 11.2, pagina
120, au valorile:
1 2 3 4 5 6 1 2 3 4 5 6
0 150 330 405 1655 2010 0 1 2 2 4 2
0 0 360 330 2430 1950 0 0 2 2 2 2
0 0 0 180 930 1770 0 0 0 3 4 4
0 0 0 0 3000 1860 0 0 0 0 4 4
0 0 0 0 0 1500 0 0 0 0 0 5
0 0 0 0 0 0 0 0 0 0 0 0
De aici tragem concluzia ca numarul optim de nmult iri scalare este
m(1, 6) = 2010. Pentru determinarea modului n care se facenmult irea,
folosim informat ia din matricea s: s(1, 6) = 2, deci vom avea paran-
tezarea (A
1
A
2
) (A
3
. . . A
6
). Pentru a determina cum se face paran-
tezarea pentru produsul A
36
, folosim s(3, 6) = 4, de unde deducem ca
grupam A
3...6
= (A
3
A
4
) (A
5
A
6
).

In nal, obt inem parantezarea
completa:
((A
1
A
2
) ((A
3
A
4
) (A
5
A
6
)))
2. Problema 2. Demonstrat ia se face prin induct ie matematica dupa
numarul n de matrici. Fie P(n) propozit ia parantezarea completa
a unui sir cu n matrici are exact n 1 paranteze.
Vericarea:
(a) P(1): o matrice reprezinta o expresie complet parantezata
(b) P(2): (A
1
A
2
) este singura expresie complet parantezata asociata
produsului a doua matrici, deci avem o pereche de paranteze.
Demonstrat ie: presupunem propozit ia adevarata pana la n 1
si demonstram ca si P(n) este adevarata. Fie A
1...n
= (A
1...p

A
p+1...n
), 1 p < n. Atunci: conform propozit iei P(p) avem
ca numarul de perechi de paranteze pentru A
1...p
este p 1, iar
pentru A
p...n
este n (p + 1). Pentru A
1...n
avem nevoie de (p
1) + (n p 1) + 1 perechi de paranteze (ultimul termen din
suma se datoreaza perechii de paranteze exterioare). Deci P(n)
este adevarata, de unde concluzia din enunt ul problemei.
196
(c) Problema 3. Relat ia dupa care se calculeaza optimul este:
m(i, j) = min
ik<j
m(i, k) +m(k + 1, j) +p
i1
p
k
p
j
(B.11)
Fie . m(, ) este accesat n cadrul (B.11) e ca m(i, k), e
ca m(k + 1, j). Fie t(, ) numarul de apeluri ce se face pentru
m(, ) n primul caz si T(, ) numarul de apeluri ce rezulta
din al doilea caz.
Pentru primul caz, avem i = , k = . Putem avea j +1, n,
deci T(, ) = n . Pentru U(, ) se poate arata analog ca
U(, ) = n . Obt inem:
R(, ) = T(, ) =
n

=1
n

=
(n + 1) = =
n
3
n
3
(d) Problema 4. Fie a = (a(i, j)) matricea triunghiulara data la in-
trare (1 i n, 1 j i). Observam ca avem 2
n1
posibilitat i
de a forma drumuri de la a(1, 1) la ultima linie (demonstrat ia se
face prin induct ie matematica dupa n). Ca atare, o metoda de
abordare de tip brute force este de la nceput sortita esecului.
De asemenea se observa ca o strategie de tipul coboara la numarul
cel mai mare aat pe linia imediat urmatoare nu duce la solut ie
optima. Vom da un algoritm bazat pe programare dinamica.
Fie T drumul de la a(1, 1) la ultima linie care da suma maixima.
Fie S(i, j) un element de pe acest drum, aat pe linia i si coloana
j. Atunci S(i, j) este valoarea maxima care se poate obt ine
plecand din (i, j) pana la ultima linie. Daca nu ar asa, atunci
nseamna ca ar exista un alt drum de la (i, j) la ultima linie care
da valoare mai mare, iar prin modicarea lui T astfel ncat sa in-
cluda acest ultim drum am obt ine o valoare mai mare, contradict ie
cu alegerea lui T. Ca atare, putem deduce ca:
S(i, j) =
_
S(n, j) daca i = n
a(i, j) + maxS(i + 1, j), S(i + 1, j + 1) daca i < n
(B.12)
pentru 1 i n, 1 j i; ceea ce ne duce la algoritm. Calculul
lui S(i, j) nu se face recursiv, ci folosind o matrice triunghiulara.
Pentru reconstituirea solut iei se foloseste o matrice triunghilara
sol
Start Triunghi
197
citeste( n, (a(i, j), i = 1, n, j = 1, i) )
pentru j = 1, n
s(n, j) = a(n, j)
sfarsit pentru
pentru i = n 1, 1, 1
pentru j = 1, i
daca s(i + 1, j) > s(i + 1, j + 1) atunci
s(i, j) = a(i, j) +s(i + 1, j)
sol(i, j) = j
altfel
s(i, j) = a(i, j) +s(i + 1, j)
sol(i, j) = j + 1
sfarsit daca
sfarsit pentru
sfarsit pentru
scrie( Suma maxima este, s(1, 1) )
scrie( Ea se obt ine astfel: )
i = j = 1
scrie( a(1, 1) )
pentru k = 1, n 1
j = sol(i, j)
i = i + 1
scrie( a(i, j) )
sfarsit pentru
Stop
3. Problema 5. Sugeram cititorului sa urmareasca rezolvarea problemei
1. Rezolvarea se bazeaza pe un algoritm de tip Divide et Impera din
cauza ca pentru un produs de tipul A
i...j
vom determina indicele k
pentru care facem descompunerea A
i...j
= (A
i...k
) (A
k+1...j
), ecare din
cele doua matrici ind la randul lor parantezate independent, pana
cand se ajunge la cate o singura matrice.
Descompunere(s.i, j)
daca i = j atunci
scrie( i )
Return
sfarsit daca
daca j i = 1 atunci
scrie( (, i,*, j, ) )
Return
sfarsit daca
198
k = s(i, j)
scrie( ( )
Inmultiri(s, i, k)
scrie( )*( )
Inmultiri(s, k + 1, j)
scrie( ) )
Return
Propunem cititorului interesat crearea unui algoritm care sa determine
toate modalitat ile de nmult ire a matricilor astfel ncat sa se ajunga la
un numar de nmult iri scalare minim. (Indicat ie: nu se mai foloseste
informat iua din s, ci doar cea din m)
199
200
Bibliograe
[1] Ciurea,Eleonor, Tabarca,Sabin, and Tabarca,Tatiana. Algoritmi. Metode
de elaborare. Ed. Univ. Transilvania Brasov, 1997.
[2] Cormen, Thomas H, Leiserson, E Charles, and Rivest, Ronald R. Intro-
ducere n algoritmi. Computer Libris Agora, 2000.
[3] Iacob,Paul and Marinescu,Daniela. Upon a cutting problem with two op-
timization criteria. Conference on functional analysis, equations, approx-
imation and convexity. Cluj-Napoca, 1999. pp 84-88.
[4] Iacob,Paul, Marinescu,Daniela, and Luca, Cristina. Covering a rectangle
with rectangular pieces. Proceedings of the 17
th
International Logistic
Congress on Logistics from to : Strategies and applications. Salonic,
Greece, 2001. pp 506-513.
[5] Livovschi, Leon and Georgescu, Horia. Sinteza si analiza algoritmilor.
Editura Stiint ica si Enciclopedica, 1986.
[6] Tudor, Sorin. Tehnici de programare (Manual pentru clasa a X-a). L&S
Infomat, 1996.
201

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