Documente Academic
Documente Profesional
Documente Cultură
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
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
= 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).
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.
, 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
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
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
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
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
i=1
n(i) elemente.
n
ordine lexicograca este cel n care 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
(i) = x(i) + 1
- 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
(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
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
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
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
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 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
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)).
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
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
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
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
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
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 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
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
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
_
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
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 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.
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
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
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 <
i=1
f(i)c(i) (B.2)
si
G =
k
i=1
f(i)g(i) (B.3)
Fie S
= (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
.
Putem avea urmatoarele situat ii:
(a) Daca (prin absurd) S
(p) ,= 1 (n ipoteza n
care un asemenea p exista). Vom transforma f
(p) n f
(p) =
f
(t) f
(t) =
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
= S
= S
si procedeul se continua cu
urmatorul p. Daca S
< S
.
Daca nu (mai) exista nici un p cu proprietatea f
(k). Daca
f
(k)
la (si scaderea unui f
= S
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
), 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