Algorithmics - Herbert Wilf - Algorithms and Complexity

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 18

Algoritmi

Mihai Budiu | mihaib+@cs.cmu.edu, http://www.cs.cmu.edu/~mihaib/


1 iunie 1997

Subiect: Noi directii ^n cercetari legate de algoritmi


Cunostinte necesare: Cunostinte elementare despre algoritmi, analiza matematica elementara,
teoria grafurilor
Cuvinte cheie: algoritm, invariant, complexitate, aproximatie, aleator, on-line.
Cuprins
1 Algoritmi; complexitate 1
1.1 Limbajul de descriere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1.1 Un exemplu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Instante si probleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Complexitate asimptotica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3.1 Simbolul lui Landau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Complexitatea revizuita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5 Complexitatea unei probleme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.6 Clasa P; alte clase deterministe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.7 Clasa NP; algoritmi nedeterministi; NP-completitudine . . . . . . . . . . . . . . . . 9
2 Algoritmi aproximativi 11
2.1 Optim si aproximare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2 Problema rucsacului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.3 Performanta absoluta; un rezultat negativ . . . . . . . . . . . . . . . . . . . . . . . 13
3 Algoritmi Monte Carlo 14
4 Algoritmi Las Vegas 15
4.1 Radacinile unui polinom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2 Izomor smul arborilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5 Algoritmi on-line 17
5.1 Problema schiorului . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6 Rezumat 18
^In ultimii ani cercetarea ^n domeniul algoritmilor a apucat pe niste cai extrem de interesante
si foarte deosebite de cele traditionale. Unele dintre aceste cai erau pre gurate de descoperiri
facute cu multa vreme ^n urma, dar nu fusesera urmate sistematic. Altele sunt de data recenta.
Metodele noi ^ncearca sa depaseasca criza ^n care intrasera metodele de rezolvare a anumitor clase

1
de probleme (cum ar cele NP-complete), sau sa faca fata unor probleme de naturi diferita:
informatie incompleta (de exemplu c^nd trebuie luate decizii fara a cunoaste cererile ulterioare),
informatie distribuita (^ntr-o retea de calculatoare), informatie ascunsa (^n criptogra e), etc. Acest
articol ^si propune sa ilustreze foarte sumar c^teva dintre noile directii de actiune.

1 Algoritmi; complexitate
^In aceasta sectiune vom face o scurta recapitulare a principalelor notiuni care ne sunt necesare
^n ^ntelegerea celorlalte parti. Acestea sunt bine-cunoscute din studiul algoritmilor clasici, astfel
^nc^t cititorul informat le poate sari fara pierderi de informatie. Tratarea va desigur sumara;
cititorul ne-informat este invitat sa parcurga carti clasice ^n domeniu pentru o discutie mai ampla.
Pe de alta parte aceste notiuni nu sunt simple, si foarte arar sunt tratate ^ntr-adevar riguros. Desi
expunerea de fata va sumara, sper ca nu va pacatui si prin lipsa de corectitudine.
1.1 Limbajul de descriere
Un algoritm este o descriere a unui proces de calcul, care din niste date initiale produce niste
rezultate interesante. Descrierea se face ^n termenii unor operatii elementare (operatii aritmetice,
comparatii, decizii, etc.).
Aparent modul ^n care rezolvam problemele depinde de operatiile pe care le avem la-ndem^na.
^In cazul acesta se iveste natural ^ntrebarea daca anumite operatii nu sunt mai expresive dec^t altele.
Acest lucru este adevarat, dupa cum se vede si din proliferarea limbajelor de programare; un astfel
de limbaj de neste practic o colectie de operatii elementare.
Se poate demonstra absolut riguros, ca ^n oarecare masura alegerea limbajului este irelevanta,
pentru ca, din momentul ^n care avem un limbaj su cient de expresiv, putem simula cu ajutorul
lui operatiile care se fac ^n toate celelalte limbaje cunoscute. Astfel, toate formalismele care ex-
prima procese de calcul au fost demonstrate ca ind echivalente ca putere expresiva (limbajele de
programare, lambda calculul, functiile recursive, gramaticile de tip 0, masinile Turing: toate aceste
metode de calcul p^na la urma sunt echivalente).
Din acest motiv ne putem xa asupra unui limbaj anume, fara a pierde nimic din generalitatea
expunerii. Voi folosi pentru exemplele din acest articol un limbaj foarte simplu, asemanator cu
limbajele obisnuite de programare. Limbajul (\guarded command language") a fost introdus de
Dijkstra, si se bazeaza pe folosirea garzilor, care sunt niste simple expresii booleene. Garzile sunt
folosite pentru a descrie doua constructii: bucla do si instructiunea if. Astfel:
do garda_1 -> instructiune_1
[] garda_2 -> instructiune_2
...
[] garda_n -> instructiune_n
od

functioneaza astfel: garzile se evalueaza; daca:


 toate sunt false, atunci ciclul do se termina.
 daca cel putin o garda este adevarata, atunci instructiunea corespunzatoare se executa, dupa
care bucla se reia.
 ^n caz ca mai multe garzi sunt adevarate, atunci una dintre instructiuni se va executa, dar
care, nu se stie.

2
Daca programatorul vrea sa e sigur ce instructiune se executa, nu are dec^t sa construiasca
programul ^n asa fel ^nc^t doua garzi sa nu e adevarate simultan.
Constructia do este asemanatoare cu un while urmat de un switch din C, dar este mai usor
de folosit. Oricum, este evident ca este la fel de expresiva.
Folosim apoi constructia if pe post de switch (case din Pascal):
if garda_1 -> instructiune_1
[] garda_2 -> instructiune_2
...
[] garda_n -> instructiune_n
fi

Semni catia este foarte asemanatoare cu a lui do. Astfel:


 Daca nici o garda nu este adevarata programul se termina imediat (eroare);
 Daca o garda este adevarata instructiunea corespunzatoare se executa;
 C^nd mai multe garzi sunt adevarate, una dintre instructiunile care le corespund este execu-
tata, dar nu se precizeaza care.
Mai folosim si atribuirea paralela:
v_1, v_2, ..., v_n := e_1, e_2, ..., e_n

Prin care expresiile din dreapta sunt toate evaluate si atribuite simultan variabilelor din st^nga.
Din cauza asta schimbul valorilor a doua variabile se poate face cu
x, y := y, x

care operatie nu este echivalenta nici cu


x := y
y := x

si nici cu
y := x
x := y

1.1.1 Un exemplu
Ca sa ne familiarizam cu limbajul, sa scriem un mic algoritm, care, d^ndu-se o valoare x si un
vector a cu n elemente, partitioneaza vectorul ^n asa fel ^nc^t valorile mai mici ca x ajung ^n st^nga,
cele mai mari ^n dreapta, iar toate cele egale cu x sunt contigue, undeva ^ntre celelalte doua (acesta
este un fragment din quicksort):
l, r, m := 1, n, 1
do a[m] = x -> m := m+1
[] a[m] < x -> a[l], a[m], l, m := a[m], a[l], l+1, m+1
[] (a[m] > x) and (m < r) -> a[r], a[m], r := a[m], a[r], r-1
[] a[r] > x -> r := r-1
od

3
Acest algoritm opereaza asupra vectorului a mentin^nd urmatorul invariant (o relatie care este
^ntotdeauna adevarata):
| < | = | ? | > | a
-----------------------------------------------------------
1 ^ ^ ^ n
l m r

Variabilele l, m si r sunt indici ^n vectorul a. Tot ce e la st^nga lui l e mai mic dec^t x, tot
ce este cuprins ^ntre l (inclusiv) si m (exclusiv) este egal cu x, iar tot ce se a a la dreapta lui r
este mai mare ca x. Elementele dintre m si r sunt ^nca ne-explorate. Aceasta relatie este adevarata
atunci c^nd algoritmul ^ncepe, din modul ^n care se initializeaza variabilele, si ram^ne adevarata la
ecare parcurgere a buclei do, dupa cum se poate veri ca. Bucla se termina c^nd toate garzile sunt
adevarate, ceea ce se poate doar daca m = r, deci daca zona ne-explorata s-a redus la 0.
Limbajul acesta nu este foarte e cace pentru a scrie sisteme de operare, dar pentru a exprima
algoritmi este foarte succint si elegant. Invariantul anterior se reduce, ^n cazul terminarii, deci c^nd
m = r la

| < | = | > | a
-----------------------------------------------------------
1 ^ ^ n
l m=r

ceea ce implica si corectitudinea algoritmului, pentru ca acesta este rezultatul pe care trebuia sa-l
obtinem.
Ca sa demonstram ca algoritmul se termina ^ntotdeauna, independent de valorile lui x, n si a,
observati ca ori toate garzile sunt false (si atunci gata), ori cel putin o garda este adevarata, si
atunci e m creste, e r scade. Cum ^ntotdeauna trebuie sa avem m < r, bucla se poate parcurge
de cel mult n ori ^nainte de terminare.
Observati ca acest algoritm este nedeterminist, pentru ca daca a[r] > x poate face doua alegeri.
Interesant este ca rezultatul nal nu depinde de care operatie este facuta, pentru ca ambele operatii
pastreaza invariantul indicat si reprezinta un progres. De asemenea, observati ca algoritmul ram^ne
corect daca eliminam ultima linie din do, si ^n acest caz devine si determinist!
1.2 Instante si probleme
O distinctie foarte importanta pe care trebuie s-o facem este ^ntre clasa de probleme pe care o
rezolva un algoritm, si instantele speci ce ale acelei probleme. De exemplu, algoritmul descris mai
sus rezolva toate problemele care contin un vector de n elemente si o valoare x, aduc^nd vectorul
la forma indicata. C^nd rulam acest algoritm ^nsa, o facem cu o instanta particulara a problemei:
de exemplu vectorul cu n=5 elemente a = [1, 2, 5, 3, 2], si cu x = 2.
Distinctia este esentiala, mai ales c^nd vrem sa evaluam e cacitatea unui algoritm. Masurarea
performantei unui algoritm cu ceasul ^n m^na nu este o operatie foarte semni cativa, daca algo-
ritmul va rezolva si alte instante ale problemei dec^t cea masurata. Daca algoritmul de mai sus,
implementat pe un anumit calculator, rezolva instanta indicata ^n 5 milisecunde, asta nu spune
absolut nimic despre viteza lui pentru o cu totul alta instanta. Daca vrem sa evaluam calitatea
algoritmilor trebuie sa gasim o metoda care nu depinde de instante, ci de problema ^nsasi.

4
1.3 Complexitate asimptotica
O ^ntrebare pe care ne-o putem imediat pune este: c^t de bun este un algoritm? Nu se poate scrie
un altul mai bun (care sa rezolve aceeasi problema, reste)? Pentru a putea raspunde, trebuie
sa cadem de acord asupra unei metode prin care masuram calitatile unui algoritm; putem masura
timpul lui de executie pentru o anumita problema, sau cantitatea de memorie folosita, sau numarul
de instructiuni care descriu programul, sau poate o alta dimensiune.
Daca am doi algoritmi pentru aceeasi problema, atunci poate pentru anumite instante ale
problemei unul este mai rapid, iar pentru alte instante celalalt. Dintre algoritmii de sortare sortarea
prin selectie este preferata pentru vectori mici, iar quicksort sau heapsort pentru vectori mari. Daca
valorile din vector sunt mici, atunci le bate pe am^ndoua radixsort. Si atunci, cum comparam doi
algoritmi?
Exista un raspuns relativ unanim acceptat la aceasta ^ntrebare, dar, ^nainte de a-l prezenta,
trebuie ^nca odata sa spunem ca acesta este doar un punct de vedere ^n comparatie, si ca ^n
practica se pot prefera algoritmii si din alte motive. Cel mai interesant atribut al performantei
a fost judecat a timpul de executie al unui algoritm. Timpul este apoi asimilat cu numarul de
operatii elementare pe care le efectueaza un algoritm pentru a rezolva o problema.
Din pacate, chiar pentru o instanta xata a unei probleme, numararea instructiunilor executate
este o sarcina foarte di cila. Din aceasta cauza se socoteste su cient a se masura de c^te ori se
repeta instructiunea care se executa cel mai mult. Aceasta este instructiunea dominanta, si se
gaseste de regula ^n interiorul tuturor buclelor. Numarul de repetitii al instructiunii dominante este
o aproximatie rezonabila pentru numarul total de instructiuni executat de algoritm. Oricum, din
moment ce nici o instructiune nu se mai executa at^t de mult, daca ^nmultim lungimea programului
cu numarul de repetitii al instructiunii dominante avem imediat o margine superioara pentru timpul
de executie. Vom vedea mai jos ca folosirea pentru a indica complexitatea a ordinului de marime
a unei functii face neimportant un factor multiplicativ (anume lungimea programului).
Observati ca pentru instante diferite ale unei aceleiasi probleme, numarul de instructiuni exe-
cutat este ^n general diferit. De exemplu, acest scurt program, care cauta un numar x ^n vectorul
a:

i = 1
do (i <= n) and not (a[i] = x) -> i := i + 1
od

va avea un timp de executie egal cu 1 daca x = a[1] sau cu n daca x nici nu apare ^n vector.
Este de asemenea evident ca timpul de executie depinde adesea de cantitatea datelor de intrare;
^n exemplele date mai sus el depinde de numarul de elemente din vectorul a.
Sa recapitulam deci: avem un algoritm care rezolva o clasa de probleme. Pentru ecare instanta,
complexitatea algoritmului se masoara ^n numarul de instructiuni executate pentru a rezolva acea
instanta.
Noi ne dorim^nsa o masura unica, globala a unui algoritm, care sa-l caracterizeze, si nu complex-
itatea pentru ecare instanta. Atunci procedam astfel: alegem o valoare arbitrara care o numim
marimea datelor de intrare. C^nd algoritmul lucreaza pe un vector (ca ^n exemplul de mai sus), o
alegere posibila este numarul de elemente. ^In general valoarea care caracterizeaza marimea datelor
de intrare arata c^t de multa informatie este prezenta ^n datele de intrare. Acesta este un lucru
normal, pentru ca ne putem astepta ca atunci c^nd avem mai multe date la intrare algoritmul sa
lucreze mai multa vreme.
^In acest fel partitionam multimea intrarilor ^n multimi (disjuncte) de \marimi" egale. Pentru
algoritmul precedent vom avea astfel probleme de \marime 1": cele care au vectorul dintr-un singur

5
element. Vom avea probleme de \marime k", cu vectori de lungime k, s.a.m.d. Fireste, exista mai
multe instante cu marimea k.
Mai departe exista doua metode rasp^ndite pentru a decide complexitatea unui algoritm pentru
date de marime xata. Cea mai comuna se cheama: \cel mai rau caz" (worst-case complexity).
Pe scurt: xam marimea, masuram numarul de instructiuni pentru ecare instanta de aceasta
marime, si apoi luam maximumul.
T (n) = max timp(P )
marime(P )=n
Complexitatea T pentru marimea xata n este maximumul timpilor pentru toate problemele
de marime n.
De exemplu, pentru algoritmul de cautare expus mai sus, complexitatea pentru vectori de
marime n este n, pentru instantele ^n care x nu se regaseste ^n vector.
^In acest fel complexitatea unei probleme se exprima ca o functie de marimea problemei.
date de intrare P
------------------------
| instante de marime 1 | -> max timp(P) = T(1)
------------------------
| instante de marime 2 | -> max timp(P) = T(2)
------------------------
....
------------------------
| instante de marime n | -> max timp(P) = T(n)
------------------------
....

A doua metoda de a evalua complexitatea problemelor pentru o marime xata este de a pune
o distributie de probabilitate peste instantele de o anumita marime (de exemplu toate pot egal
probabile) si de a evalua apoi valoarea medie a variabilei aleatoare care descrie timpul de rulare.
Consider^nd numai problemele de marime n, daca rezolvarea problemei x va dura un timp t(x) iar
problema se va ivi cu probabilitatea p(x), atunci complexitatea algoritmului va
X
T (n) = t(x)p(x):
marime(x)=N
O astfel de evaluare se numeste \cazul mediu": \average case complexity".
Aceasta tehnica este mult mai rar folosita, pentru ca:
 Este greu de argumentat o distributie de probabilitate pentru un set de date de intrare (practic
distributia a rma ce sansa are ecare instanta de a ^nt^lnita c^nd se ruleaza algoritmul).
De exemplu, pentru un algoritm pe grafuri, care este probabilitatea de a primi un arbore?
Nu exista un raspuns natural la aceasta ^ntrebare.
 ^In general este mult mai greu de evaluat analitic formula obtinuta dec^t ^n cazul folosirii
maximumului.
Metoda cu distributia de probabilitate a fost ^n general aplicata la algoritmi de cautare si
sortare, dar chiar si ^n aceste cazuri simple rezultatele nu sunt ^ntotdeauna facile.
De aici ^nainte vom presupune ca folosim complexitate \worst case".
C^nd cineva spune \acesta este un algoritm de complexitate n patrat", de fapt vrea sa spuna:
\pentru anumite de intrare de marime n algoritmul executa instructiunea dominanta de cel mult
n patrat ori." Acest n este implicit deci dimensiunea datelor de intrare. Vom folosi si noi aceasta
litera liber, fara a mai indica sursa ei de provenienta.
6
1.3.1 Simbolul lui Landau
Pentru ca de fapt noi socotim numai numarul de repetitii al instructiunii dominante, si nu toate
instructiunile executate, nu are foarte mult sens sa comparam ^ntre un algoritm cu complexitatea n
si unul cu complexitate n +1. Toate instructiunile care nu au fost masurate au o contributie care sa
faca algoritmul cu n sa dureze ^n realitate mai mult dec^t cel cu n +1. Ceea ce trebuie sa comparam
de fapt este ordinul de marime al complexitatii, care pune ^n evidenta cresteri substantial diferite.
Pentru a face evident acest lucru se foloseste o notatie pentru ordinul de marime al unei functii,
introdus de zicianul Lev Davidovich Landau. Notatia foloseste simbolul O (\o mare") pentru a
indica multimea functiilor care cresc mai repede dec^t o functie data. Aceasta notatie compara
numai functii la limita, ^n cresterea lor spre in nit. Pentru a putea compara complexitatea a doi
algoritmi care rezolva o aceeasi problema ^n acest fel, trebuie ca ei sa poata lucra cu probleme de
marimi arbitrar de mari!
De nitie: e data o functie f : N ! N, astfel ^nc^t de la un rang ^ncolo f (n) > 0; atunci
multimea functiilor dominate de f se noteaza cu O(f ) si se de neste astfel:
 g ( n ) 
O(f ) = g : N ! N j 9N0; 9c < 1 8n > N0; f (n) < c :
^In cuvinte, o functie este^n multimea O(f ) daca la \creste mai^ncet" dec^t f la in nit. De exemplu,
functia g (n) = n este ^n multimea O(n2 ), pentru ca g (n)=n2 ! 0. ^In general, un polinom de grad
 k este ^n multimea O(nk ).
Din pacate notatia se foloseste ^n uzajul comun ^n mod gresit, scriindu-se f = O(g ) ^n loc de
f 2 O(g): O(g ) este o multime de functii, toate dominate de g .
Din considerentele indicate, metoda preferata pentru a indica complexitatea unui algoritm este
de a o face prin ordinul de marime al functiei sale de complexitate. Din cauza ca analizeaza aceasta
comportare spre in nit complexitatea algoritmilor se numeste \complexitate asimptotica".
Ce ^nseamna deci ca un algoritm \are o complexitate O(n log n)"? ^Inseamna ca pe masura ce
datele de intrare cresc ^n marime ca n, numarul de operatii facut de algoritm ^n raport cu marimea
datelor de intrare este mai mica de n log n ori.
Astfel complexitatea asimptotica exprima concis o limita superioara a timpului de executie a
unui algoritm. O gramada de informatie se pierde din descrierea complexitatii unui algoritm d^nd
numai ordinul de marime:
 ^In primul r^nd functia al carei ordin de marime este evaluata era obtinuta lu^nd maximumul
peste toate instantele de o anumita marime.
 ^In al doilea r^nd, daca f 2 O(g) asta ^nseamna numai ca de la un rang ^ncolo f e \mai mica"
dec^t g ; rangul acesta ar putea foarte bine mai mare dec^t numarul de atomi din univers,
deci mai mare dec^t al oricarei probleme practice pe care vrem s-o rezolvam.
 Notatia cu O indica numai limita superioara a unei functii; observati ca at^t f (n) = n 2 O(n2)
c^t si g (n) = n2 2 O(n2). Numai informatia ca f si g sunt ^n aceeasi clasa nu ne permite
de fapt sa le comparam ^ntre ele. Pentru a indica si faptul ca limita se atinge, se foloseste
o alta notatie, cu
1 . De exemplu, daca stiu despre un algoritm doar ca este O(n2), asta
spune ceva. Dar daca mi se spune si ca exista o serie de instante, crescatoare ^n marime, pe
care algoritmul face c  n2 + : : :, atunci stiu mult mai mult; stiu de exemplu ca algoritmul este
\mai prost" dec^t un algoritm O(n), iar complexitatea lui poate indicata cu semnul
(n2).
1
Mai exact f
(g) f O(g) g O(f ).
2 , 2 ^ 2

7
Cu toate aceste dezavantaje, notatia cu O s-a impus, si s-a dovedit ^n general destul de e cace
pentru a caracteriza algoritmii. Proprietatile notatiei O sunt foarte interesante, dar depasesc cadrul
acestui articol; ^n general sunt destul de intuitive (de exemplu: daca f = O(g ) si g = O(h), atunci
f = O(h), etc.
^In nal, relu^nd o observatie de la ^nceputul sectiunii, sa observam ca ^ntr-adevar n = O(n + 1)
si n + 1 = O(n), asa ca ^ntr-adevar notatia cu O arunca termenii nesemni cativi, si faptul ca
am numarat numai instructiuni dominante nu are nici o importanta. Mai exact, este foarte usor
de aratat ca timpul real de executie a unui algoritm este O(numarul de repetitii al instructiunii
dominante).
1.4 Complexitatea revizuita
Am admis tacit ca toate operatiile elementare se pot efectua ^n timp unitar, dar acest lucru poate
adesea
2
sa ne induca ^n eroare. De exemplu, atunci urmatorul algoritm, care calculeaza numarul
2 de n ori, functioneaza ^n n pasi:
2:::

x, i := 2, 1
do i <= n -> x, i := x * x, i+1
od

Numarul care se obtine^n acest fel este extrem de lung, si este mult mai rezonabil sa presupunem
ca operatiile cu numere iau un timp care depinde de lungimea numarului ^n biti.
Vom ignora ^nsa aceste considerente usor ezoterice, si ne vom multumi sa presupunem ca ^n
algoritmii nostri toate operatiile pot facute ^n timp constant.
1.5 Complexitatea unei probleme
Un algoritm rezolva o problema. Adesea pentru a rezolva o aceeasi problema putem folosi mai
multi algoritmi, poate cu complexitati diferite. Exista cel putin 30 de metode de a sorta un sir
de valori, de exemplu! Putem vorbi deci de complexitatea unui algoritm, dar si de complexitatea
unei probleme. Complexitatea unei probleme este complexitatea celui mai \rapid" algoritm care
o poate rezolva. Complexitatea unei probleme este deci o limita inferioara a e cacitatii cu care
putem rezolva o problema: orice algoritm care va rezolva acea problema va mai complex dec^t
complexitatea problemei.
^In general este extrem de di cil de evaluat complexitatea unei probleme, pentru ca rareori
putem demonstra ca un algoritm este cel mai bun posibil. Tabloul arata cam asa:

limita inferioara complexitatea cel mai bun


dovedita problemei algoritm cunoscut
---------|------------------?----------------------|----------------
f g

Cu alte cuvinte, putem spune: \problema asta nu se poate face mai repede de f , si noi stim s-o
rezolvam ^n g ". Dar care este complexitatea reala, si care este algoritmul care rezolva problema
optim, asta foarte rar se poate spune.
Pentru o problema at^t de banala ca ^nmultirea a doua numere, consider^nd numerele scrise ^n
baza 2, iar marimea lor numarul total de biti n, complexitatea celui mai bun algoritm de ^nmultire
cunoscut este de O(n log n log log n), dar limita inferioara dovedita este de n. Sau pentru ^nmultirea

8
a doua matrici de n  n elemente: se gasesc ^ncontinuu algoritmi din ce ^n ce mai buni (asimptotic
vorbind), dar limita inferioara de n2 este ^nca departe de cel mai bun (si foarte so sticat algoritm),
care este aproximativ O(n2:3) (comparati cu algoritmul \naiv" imediat, care este O(n3)).
1.6 Clasa P; alte clase deterministe
Unele probleme se pot rezolva, altele nu. De exemplu, o problema notorie, a carei imposibilitate
este riguros demonstrata ^n anii '30 de catre matematicianul englez Alan Turing, este de a decide
daca un program se va opri vreodata pentru o anumita instanta a datelor de intrare.
Pe de alta parte, chiar ^ntre problemele care pot rezolvate, teoreticienii trag o linie imaginara
^ntre problemele care au rezolvari \rezonabil" de rapide, si restul problemelor, care se numesc
\intratabile".
^In mod arbitrar, dar nu ne-justi cabil, o problema se numeste \intratabila" daca complexitatea
ei este exponentiala ^n marimea datelor de intrare. (Nu uitati, este vorba de complexitate \worst-
case" asimptotica.) O problema este \tratabila" daca putem scrie complexitatea ei sub forma unui
polinom, de un grad oric^t de mare.
Multimea tuturor problemelor de decizie (adica a problemelor la care raspunsul este da sau nu )
cu complexitate polinomiala se noteaza cu P (de la polinom). De exemplu, problema de a gasi
daca o valoare se a a ^ntr-un vector este ^n clasa P; algoritmul exhibat mai sus este un algoritm ^n
timp linear (O(n)) pentru a raspunde la aceasta ^ntrebare.
Un exemplu de problema cu complexitate exponentiala (ne-polinomiala)? Iata unul: daca se
da o formula logica peste numerele reale, cu cuanti catori existentiali (9) si universali (8), care
foloseste numai operatii de adunare, comparatii cu < si conectori logici (^; _; ); : : :), este formula
adevarata? (Un exemplu de formula: \8x9y 8z (x + z < y ) ^ (2x , z > y )"). Decizia se poate face
numai ^ntr-un timp exponential ^n lungimea formulei (pentru anumite instante), dar demonstratia
nu este de loc simpla.
(Ca o curiozitate: exista si probleme cu o complexitate \ne-elementara", care este mai mare
dec^t complexitatea oricarei probleme exponentiale. O astfel de problema este cea de decizie a
adevarului unei formule ^n teoria numita S1S, sau \teoria monadica a succesorilor de ordinul 2".
Nu va lasati intimidati de terminologie: aceasta este practic o teorie logica peste numerele naturale,
^n care avem voie sa scriem formule cu cuanti catori si conectori logici, ca mai sus, dar avem si
dreptul sa cuanti cam peste multimi. Complexitatea deciziei unei formule logice ^ntr-o astfel de
teorie este mai mare dec^t 2| 2{z } pentru orice k natural!)
n
:::

1.7 Clasa NP; algoritmi nedeterministi; NP-completitudine


Algoritmii cu care suntem obisnuiti sa lucram zi de zi sunt deterministi. Asta ^nseamna ca la un
moment dat evolutia algoritmului este unic determinata, si ca instructiunea care urmeaza sa se
execute este unic precizata ^n ecare moment. Am vazut ^nsa ca limbajul pe care l-am folosit ne
permite scrierea unor algoritmi care au mai multe posibilitat i la un moment dat; constructia if
din limbajul cu garzi permite evaluarea oricarei instructiuni care are garda adevarata.
Acest tip de algoritmi este surprinzator de bogat ^n consecinte cu valoare teoretica. Acesti
algoritmi nu sunt direct aplicabili, ^nsa studiul lor da nastere unor concepte foarte importante.
Surprinzatoare este si de nitia corectitudinii unui astfel de algoritm. Un algoritm nedeterminist
este corect daca exista o posibilitate de executare a sa care gaseste raspunsul corect. Pe masura
ce un algoritm nedeterminist se executa, la anumiti pasi se confrunta cu alegeri nedeterministe. Ei
bine, daca la ecare pas exista o alegere, care facuta sa duca la gasirea solutiei, atunci algoritmul
este numit corect.
Astfel, un algoritm nedeterminist care cauta iesirea dintr-un labirint ar arata cam asa:
9
do not iesire(pozitie_curenta) ->
if not perete(nord(pozitie_curenta)) ->
pozitie_curenta := nord(pozitie_curenta)
[] not perete(est(pozitie_curenta)) ->
pozitie_curenta := est(pozitie_curenta)
[] not perete(sud(pozitie_curenta)) ->
pozitie_curenta := sud(pozitie_curenta)
[] not perete(vest(pozitie_curenta)) ->
pozitie_curenta := vest(pozitie_curenta)
fi
od

Pe scurt algoritmul se comporta asa: daca la nord nu e perete mergi ^ncolo, sau, poate, daca
la sud e liber, mergi ^ncolo, sau la est, sau la vest. ^In care dintre directii, nu se precizeaza (este
ne-determinat). Este clar ca daca exista o iesire la care se poate ajunge, exista si o suita de aplicari
ale acestor reguli care duce la iesire.
Utilitatea practica a unui astfel de algoritm nu este imediat aparenta: ^n de nitiv pare sa nu
spuna nimic util: solutia este e spre sud, e spre nord, e spre este, e spre vest. Ei si? Este clar
ca acesti algoritmi nu sunt direct implementabili pe un calculator real.
^In realitate existenta un astfel de algoritm deja ^nseamna destul de mult. ^Inseamna ^n primul
r^nd ca problema se poate rezolva algoritmic; va reamintesc ca exista probleme care nu se pot
rezolva deloc.
^In al doilea r^nd, se poate arata ca ecare algoritm nedeterminist se poate transforma^ntr-unul
determinist ^ntr-un mod automat. Deci de ^ndata ce stim sa rezolvam o problema ^ntr-un mod
nedeterminist, putem sa o rezolvam si determinist! Transformarea este relativ simpla: ^ncercam sa
mergem pe toate drumurile posibile ^n paralel, pe ecare c^te un pas. (O astfel de tehnica aplicata
^n cazul labirintului se transforma ^n ceea ce se cheama \ ood ll": evoluez radial de la pozitia de
plecare ^n toate directiile).
Clasa tuturor problemelor care se pot rezolva cu algoritmi nedeterministi ^ntr-un timp polino-
mial se noteaza cu NP (Nedeterminist Polinomial). Este clar ca orice problema care se a a ^n P
se a a si ^n NP, pentru ca algoritmii deterministi sunt doar un caz extrem al celor deterministi: ^n
ecare moment au o singura alegere posibila.
Din pacate transformarea^ntr-un algoritm determinist se face pierz^nd din e cienta. ^In general
un algoritm care opereaza ^n timp nedeterminist polinomial (NP) poate transformat cu usurinta
^ntr-un algoritm care merge ^n timp exponential (EXP). Avem deci o incluziune de multimi ^ntre
problemele de decizie: P  NP  EXP.
Partea cea mai interesanta este urmatoarea: stim cu certitudine ca P 6= EXP. ^Insa nu avem nici
o idee despre relatia de egalitate ^ntre NP si P sau ^ntre NP si EXP. Nu exista nici o demonstratie
care sa in rme ca problemele din NP au algoritmi e cienti, determinist polinomiali! Problema
P=NP este cea mai importanta problema din teoria calculatoarelor, pentru ca de solutionarea ei
se leaga o gramada de consecinte importante.
Problema aceasta este extrem de importanta pentru ^ntreaga matematica, pentru ca ^nsasi
demonstrarea teoremelor este un proces care ^ncearca sa veri ce algoritmic o formula logica (cum
am vazut mai sus de pilda); teoremele la care exista demonstratii \scurte" pot asimilate cu
problemele din multimea NP (la ecare pas dintr-o demonstratie putem aplica mai multe metode
de inferenta, ^n mod nedeterminist; un algoritm trebuie sa ghiceasca ^nsiruirea de metode aplicate
pentru demonstrarea enuntului); daca orice problema din NP este si ^n P, atunci putem automatiza
o mare parte din demonstrarea de teoreme ^n mod e cient!
Problema P=NP este foarte importanta pentru criptogra e: decriptarea este o problema din

10
NP (cel care stie cheia stie un algoritm determinist polinomial de decriptare, dar cel care nu o
stie are ^n fata o problema pe care nedeterminist o poate rezolva ^n timp polinomial). Daca s-ar
demonstra ca P=NP acest lucru ar avea consecinte extrem de importante, iar CIA si KGB ar
^ntr-o situatie destul de proasta, pentru ca toate schemele lor de criptare ar putea sparte ^n
timp polinomial (asta nu ^nseamna neaparat foarte repede, dar oricum, mult mai repede dec^t timp
exponential)!
Mai mult, ^n 1971 Cook a demonstrat ca exista o problema speciala ^n NP (adica pentru care
se poate da un algoritm e cient nedeterminist), numita problema satis abilitatii (notata cu SAT).
Problema este foarte simpla: daca se da o formula booleana care cuprinde mai multe variabile, poate
formula facuta adevarata d^nd anumite valori variabilelor? De pilda formula (x1 ^ x2 ) _ (x1 ^:x2 )
devine adevarata pentru x1 = adevarat si x2 arbitrar. SAT este foarte importanta, pentru ca Cook a
demonstrat ca daca SAT poate rezolvata ^n P (adica folosind un algoritm determinist polinomial),
atunci orice problema din NP poate rezolvata ^n timp polinomial! Problema satis abilitatii este
cumva \cea mai grea problema" din NP, pentru ca rezolvarea oricarei alte probleme din NP se
poate face \mai repede" dec^t a ei. Din cauza asta SAT se numeste o problema NP-completa.
De la Cook ^ncoace s-au mai descoperit c^teva sute de probleme NP-complete. Unele probleme
care se ivesc foarte adesea ^n practica s-au dovedit NP-complete! Acesta este un alt motiv pentru
care clasa at^t de abstracta NP a problemelor cu algoritmi nedeterministi este at^t de importanta:
foarte multe probleme practice au algoritmi polinomiali nedeterministi, dar cei mai buni algoritmi
deterministi iau un timp exponential!
Iata c^teva exemple de probleme NP-complete:
 Problema comis-voiajorului (turneu Hamiltonian de cost minim): d^ndu-se o retea de orase,
o retea de drumuri ^ntre orase si o lungime k, exista un traseu de cost mai mic dec^t k trec^nd
prin ecare oras o singura data si revenind la punctul de plecare?
 D^ndu-se o multime de numere naturale, se poate ^mparti ^n doua multimi de numere de
sume egale2 ?
 \Clica": d^ndu-se un graf G si un numar k, are G un subgraf complet cu k v^rfuri (adica o
multime de k v^rfuri unite ecare cu ecare)?
 \Acoperire": d^ndu-se un graf G si un numar k, pot alege k v^rfuri ^n asa fel ^nc^t toate
muchiile din G au un capat ales?
O cantitate enorma de efort si ingeniozitate a fost risipita pentru a ^ncerca sa se demonstreze
ca P=NP sau opusul acestei a rmatii, dar nici un rezultat concret nu a fost obtinut. Credinta
cvasi-unanima este ca P6=NP, dar numai matematica poate oferi vreo certitudine...
Din cauza ca foarte multe probleme practice sunt ^n NP, si ca aparent nu putem avea algo-
ritmi deterministi e cace pentru ele, cercetatorii si-au ^ndreptat atentia asupra unor clase noi de
algoritmi, care vor face obiectul sectiunilor urmatoare.

2 Algoritmi aproximativi
^In sectiunile care urmeaza folosim tot timpul premiza nedemonstrata ca P6=NP. Daca P=NP, atunci
problemele pe care ne batem capul sa le rezolvam prin metode ciudate pot de fapt rezolvate exact
si e cient, asa ca restul articolului cade si nu se mai ridica.
2
Problema este ^ntr-adevar NP-completa, daca socotim ca marime de intrare lungimea tuturor numerelor ^n biti;
altfel exista un algoritm de programare dinamica de complexitate S  n, unde S este suma numerelor, iar n este
numarul de numere. Observati ^nsa ca S este exponentiala ^n lungimea numerelor.

11
2.1 Optim si aproximare
Foarte multe probleme de optimizare se dovedesc a NP-complete3 : probleme ^n care vrem sa
calculam maximumul sau minimumul a ceva. Bine, dar daca de fapt ma multumesc sa obtin o
valoare care nu este chiar optima, dar este \su cient de aproape"? Poate ^n acest caz complexitatea
problemei poate redusa, si sunt ^n stare sa scriu un algoritm e cient... (polinomial). Avem deci
de a face cu un compromis:

solutie optima; solutie sub-optima:


<-------------->
algoritm NP sau algoritm polinomial
algoritm exponential

^Intr-adevar, aceasta metoda se bucura de un oarecare succes, dar nu de unul general. Algoritmii
care rezolva o problema de optimizare ^n speranta unui rezultat sub-optimal se numesc \algoritmi
aproximativi".
Exista o sumedenie de rezultate ^n ceea ce priveste problemele de optimizare si aproximarile
lor. Se demonstreaza ca unele probleme pot foarte bine aproximate (putem obtine solutii c^t
dorim de aproape de optim ^n timp polinomial), altele pot aproximate numai ^n anumite limite
(de exemplu putem obtine solutii de 2 ori mai slabe, dar deloc mai bune), sau altele nu pot
aproximate deloc (^n ipoteza ca P6=NP).
Teoria algoritmilor aproximativi este relativ recenta (desi ideea exista de multa vreme), iar
unele rezultate sunt extrem de complicate. Ne vom multumi sa dam niste exemple pentru a ilustra
algoritmi aproximativi ^n actiune, si tipul de rezultate care se pot obtine.
Vom ilustra doua rezultate diferite din teoria algoritmilor aproximativi: algoritmi de aproximare
relativa, algoritmi de aproximare absoluta a solutiei (lamurim terminologia imediat).
Sa notam o instanta a unei probleme cu I . Fie OPT (I ) valoarea solutiei optime pentru acea
instanta (care exista, dar pe care nu stim s-o calculam e cient), si e A(I ) valoarea calculata de
algoritmul nostru aproximativ. Numim aproximatia absoluta daca exista un numar K , independent
de instanta I , care are proprietatea ca jOPT (I ) , A(I )j < K . Numim aproximatia relativa daca
exista un R (numit \performanta") astfel ca pentru orice instanta I avem A(I )=OPT (I ) < R (daca
problema cauta un maximum, atunci fractia din de nitie trebuie inversata).
2.2 Problema rucsacului
Iata o varianta a problemei rucsacului care este NP-completa (nu am discutat deloc ^n acest articol
despre cum se demonstreaza asa ceva, asa ca trebuie sa ma credeti pe cuv^nt), dar pentru care se
poate obtine cu foarte mare usurinta un algoritm aproximativ relativ e cient.
Se dau o multime (mare) de rucsaci de capacitate egala (cunoscuta, un numar natural). Se mai
da o multime nita de obiecte, ecare de un volum cunoscut (numar natural). ^Intrebarea este:
care este numarul minim de rucsaci necesari pentru a ^mpacheta toate obiectele?
Problema rucsacului are un algoritm de aproximare relativa cu performanta 2.
Algoritmul este banal: metoda \greedy": pune de la st^nga ecare greutate ^n primul rucsac
liber:
3
Cititorul atent va observa ca notiunea de NP-completitudine a fost de nita numai pentru probleme de decizie:
cu raspuns Da/Nu, pe c^nd problemele de optimizare au ^n general un raspuns numeric; cititorul poate ^nsa sa e
linistit, pentru ca putem re-formula o problema de optimizare ca o problema de decizie: ^n loc de \care este drumul
minim?", ^ntrebam \nu-i asa ca exista un drum mai scurt de 100?".

12
Date de intrare: nrobiecte, capacitate, marime[1..nrobiecte]

Initializari:
o, folositi := 1, 0
do o <= nrobiecte -> liber[o] := capacitate od

Algoritm:
o := 1
do o <= nrobiecte ->
r := 1
do (liber[r] < marime[o]) -> r := r+1
od
folositi, liber[r], o :=
max(r, folositi), liber[r] - marime[o], o+1
od

Cum demonstram ca performanta relativa este 2? Foarte simplu: sa observam ca la sf^rsitul
algoritmului nu pot exista doi rucsaci folositi pe mai putin de jumatate am^ndoi, pentru ca atunci
continutul celui de-al doilea ar fost varsat ^n primul. Cu alte cuvinte, la terminare avem: liber[r]
< 1/2 capacitate. Dar daca ^nsumam pentru toti rucsacii, vom avea ca spatiul liber este mai putin
de jumatate din cel disponibil, deci cel ocupat este mai mult de jumatate. Dar daca obiectele au
marime totala M, atunci orice-am face nu putem folosi mai putin de M spatiu total pentru a le
^mpacheta. Dar noi am folosit mai putin de M + M = 2M, deci algoritmul are performanta 2.
QED.
2.3 Performanta absoluta; un rezultat negativ
Vom folosi o alta problema NP-completa, pentru care avem imediat un algoritm de aproximare rel-
ativa de performanta 2, dar pentru care vom demonstra ca nu exista nici un algoritm de aproximare
absoluta.
Problema este cea a acoperirii unui graf, enuntata mai sus. Ca problema de optimizare, ea se
enunta astfel: \care este numarul minim de v^rfuri care trebuie \acoperite" astfel ca toate muchiile
dintr-un graf sa e atinse?"
Pentru aceasta problema algoritmul greedy nu face multe parale ca algoritm de aproximare.
Exista ^nsa un algoritm relativ simplu, cu performanta 2, care se foloseste ^nsa de un alt algoritm
clasic, cel al \cuplarii" (matching). Fara a intra ^n detalii, exista un algoritm polinomial relativ
so sticat pentru a calcula cuplari maximale pe grafuri4. Calculam o cuplare maximala, dupa care
luam capetele tuturor muchiilor care o formeaza: astfel obtinem o acoperire (usor de demonstrat)
care e cel mult dubla ca marime fata de optim (pentru ca ^n optim trebuie sa se gaseasca cel putin
c^te un v^rf pentru ecare muchie din cuplare, iar noi am luat c^te doua).
Iata si un rezultat negativ interesant: pentru orice K xat, nu exista nici un algoritm care sa
dea pentru problema acoperirii o solutie aproximativa absoluta la distanta K de cea optima pentru
orice instanta. Demonstratia este foarte simpla, odata ce ai vazut ideea, si se bazeaza pe \tehnica
ampli carii". Iata cum se face, prin reducere la absurd:
Sa presupunem ca avem un algoritm A care calculeaza pentru orice graf o acoperire care este
cu cel mult K noduri mai mare ca cea optima (K e xat). Cu alte cuvinte jOPT (G) , A(G)j < K
Sa luam o instanta arbitrara a problemei cuplarii, G. Formam un nou graf G1 din G, care nu este
4
O cuplare este un set de muchii care nu are v^rfuri comune, iar o cuplare maximala este una care are un numar
maxim de muchii.

13
conex, si care consta din K + 1 copii ale lui G, alaturate. Aceasta este o instanta perfect corecta
a problemei acoperirii, asa ca rulam pe ea algoritmul nostru A. Acesta va oferi o acoperire care
are cel mult cu K noduri mai mult dec^t acoperirea optima. (Va reamintesc notatiile: OPT (G)
este valoarea optima: numarul minim de noduri pentru a acoperi muchiile, iar A(G) este valoarea
calculata de algoritmul nostru.
Datorita faptului ca cele K + 1 copii ale lui G sunt neconectate, optimumul pentru G1 este
reuniunea a K +1 optimumuri pentru G. Din cauza asta avem relatia OPT (G1) = (K +1)OPT (G).
Fie acum H copia lui G pe care A a marcat cele mai multe v^rfuri; atunci A(G1)  (K + 1)A(H ).
Dar din proprietatile lui A avem: jOPT (G1) , A(G1 )j < K , sau j(K +1)OPT (H ) , (K +1)A(H )j <
K , ori jOPT (H ) , A(H )j < K=(K + 1) < 1. ^Insa stim ca OPT (H ) si A(H ) sunt numere naturale,
deci am obtinut OPT (H ) = A(H )!
Asta ^nseamna ca daca avem un algoritm aproximativ absolut pentru problema acoperirii,
putem imediat construi un algoritm exact la fel de rapid. Ori asta ar ^nsemna ca P=NP, ceea ce
am presupus fals.
Exemplele pe care le-am ales sunt ^n mod deliberat simple; teoria algoritmilor aproximativi
este ^n plina dezvoltare si are rezultate foarte spectaculoase si ^n general complicate. ^In orice caz,
aplicabilitatea ei este imediata, pentru ca multe probleme practice care nu pot astepta au numai
rezolvari aproximative.

3 Algoritmi Monte Carlo


O tehnica foarte spectaculoasa pentru rezolvarea problemelor este cea a folosiri numerelor aleatoare.
Practic algoritmii aleatori sunt identici cu cei obisnuiti, dar folosesc ^n plus o noua instructiune,
care s-ar putea chema \da cu banul". Aceasta instructiune genereaza un bit arbitrar ca valoare.
^In mod paradoxal, incertitudinea ne poate oferi mai multa putere...
La ce se foloseste aleatorismul? Sa ne amintim ca ^n general complexitatea unei probleme este
de nita lu^nd ^n considerare cea mai defavorabila instanta. De exemplu, pentru problema comis
voiajorului, faptul ca aceasta problema este NP-completa nu ^nseamna ca nu putem rezolva nici
o instanta a ei, ci ca exista instante pentru care algoritmii cunoscuti nu au prea multe sanse sa
termine ^n cur^nd.
Acest lucru este adevarat si pentru alte clase de algoritmi; de pilda algoritmul quicksort are
pentru majoritatea vectorilor de intrare o comportare O(n log n). Daca ^nsa datele de intrare sunt
prost distribuite, atunci quicksort poate face n2 comparatii. Pentru n = 100 asta ^nseamna de 10
ori mai mult! Numarul de instante pentru care quicksort este slab este mult mai mic dec^t numarul
de instante pentru care merge bine. Ce te faci ^nsa daca ^ntr-un anumit context lui quicksort i
se dau numai date rele? (Datele preluate din masuratori reale sunt foarte rar complet uniform
distribuite). O solutie paradoxala consta ^n a amesteca aleator vectorul ^nainte de a-l sorta.
Complexitatea medie (average case) a lui quicksort este O(n log n). Complexitatea ^n cazul cel
mai rau (worst case) este O(n2 ). Daca datele vin distribuite cu probabilitate mare ^n zona \rea",
atunci amestec^ndu-le putem transforma instante care pica ^n zona \worst-case" ^n instante de tip
\average-case". Fireste, asta nu ^nseamna ca nu putem avea ghinion, si ca amestecarea sa produca
tot o instanta \rea", dar probabilitatea ca acest lucru sa se ^nt^mple este foarte mica, pentru ca
quicksort are putine instante rele5 .
Acesta este un caz de folosire a aleatorului pentru a ^mbunatati performanta medie a unui
algoritm.
5
Numarul de instante rele poate estimat din distribut ia variabilei aleatoare complexitate, si este ^ntr-adevar
mic.

14
C^teodata c^stigul este si mai mare, pentru ca putem rezolva probleme NP-complete foarte
rapid folosind aleatorismul. De obicei avem ^nsa un pret de platit. C^nd folosim algoritmi din clasa
prezentata mai jos, putem risca sa nu primim raspunsul corect.

4 Algoritmi Las Vegas


Evolutia unui algoritm care foloseste numere aleatoare nu mai depinde numai de datele de intrare,
ci si de numerele aleatoare pe care le genereaza. Daca are \noroc" algoritmul poate termina repede
si bine; daca da prost cu zarul, ar putea eventual chiar trage o concluzie gresita. (^In cazul quicksort
de mai sus raspunsul este ^ntotdeauna corect, dar c^teodata vine mai greu. Aceasta este diferenta
dintre algoritmii Monte Carlo, mereu corecti, si cei Las Vegas, care pot uneori, rar, gresi.)
Vom de ni acum algoritmii probabilisti pentru probleme de decizie (tineti minte, la care
raspunsul este Da sau Nu). Majoritatea problemelor pot exprimate ^n forma unor probleme
de decizie, deci simpli carea nu este prea drastica.
Exista doua clase de algoritmi probabilisti, dar ne vom concentra atentia numai asupra uneia
dintre ele, pentru care vom da si doua exemple simple si spectaculoase. Vom de ni totodata clasa
problemelor care pot rezolvate probabilist ^n timp polinomial, numita RP (Random Polinomial).
Observati ca daca indicam de la ^nceput care sunt numerele aleatoare care vor generate,
evolutia algoritmului este perfect precizata.
De nitie: O problema de decizie este ^n RP daca exista un algoritm aleator A care ruleaza
^ntr-un timp polinomial ^n lungimea instantei (nc pentru un c oarecare), si care are urmatoarele
proprietati:
 Daca raspunsul la o instanta I este \Da", atunci cu o probabilitate mai mare de 1/2 algoritmul
va raspunde \Da".
 Daca raspunsul la o instanta I este \Nu", atunci cu probabilitate 1 algoritmul va raspunde
\Nu".
De cine este data \probabilitatea" de mai sus? De numarul de siruri aleatoare. C^nd rulam
un algoritm aleator pentru o instanta I avem la dispozitie 2n siruri aleatoare de biti; pentru
c

unele dintre ele algoritmul raspunde \Da", pentru celelalte raspunde \Nu". Ceea ce facem este sa
numaram pentru c^te siruri algoritmul ar raspunde \da" si sa facem raportul cu 2n . Aceasta este
c

probabilitatea ca algoritmul sa raspunda \da". Opusul ei este probabilitatea sa raspunda \nu".
O tehnica foarte simpla de ampli care poate creste nede nit aceasta probabilitate: daca exe-
cutam algoritmul de 2 ori pe aceleasi date de intrare, probabilitatea de a gresi pentru raspunsuri
\nu" ram^ne 0. Pe de alta parte, ajunge ca algoritmul sa raspunda macar odata \da" pentru a sti
ca raspunsul este \da" cu siguranta! Din cauza asta, daca probabilitatea de eroare este p pentru
algoritm, execut^nd de k ori probabilitatea coboara la pk (nu uitati ca p este subunitar, ba chiar
sub 1/2). Aceasta metoda se numeste \boost" ^n engleza, si face dintr-un algoritm probabilist slab
ca discriminare o scula extrem de puternica!
Pentru a scadea probabilitatea de eroare a unui algoritm care poate gresi cu probabilitatea p
p^na sub o limita dorita siguranta, se procedeaza astfel:
raspuns, probabilitate = nu, 1
do (raspuns = nu) and (probabilitate > siguranta) ->
raspuns, probabilitate := executa(algoritm), probabilitate * p
od

Iata un exemplu si o aplicatie al algoritmilor aproximativi.


15
4.1 Radacinile unui polinom
Fie un polinom de mai multe variabile, x1 ; x2; : : :xn . Acest polinom poate descris printr-o formula
aritmetica, de pilda: (x1 + 1)(x2 + 1) : : : (xn + 1). ^Intrebarea este: este acest polinom identic nul
sau nu?
Desigur, o posibilitate este de a \expanda" acest polinom ^n forma canonica (suma de pro-
duse), si de a compara ecare coe cient cu 0. Dar ^n general aceasta operatie poate lua un timp
exponential! (De exemplu polinomul anterior genereaza 2n termeni!).
Solutia este sa ne bazam pe doua proprietati elementare ale polinoamelor:
 Un polinom identic nul este 0 pentru orice combinatie de valori a variabilelor;
 Un polinom ne-nul are \putine" radacini ^ntr-un corp . 6

De aici rezulta ca:


 Daca polinomul este nul, atunci evaluarea lui ^n orice punct va da 0;
 Daca polinomul este ne-nul, atunci probabilitatea de a obtine valoarea 0 ^ntr-un punct
(v ; v ; : : :vn ) ales arbitrar din S n este < d=jS j.
1 2

Pentru polinomul de mai sus gradul este n, si putem alege pentru K de exemplu Zp , unde p
este un numar prim relativ mare ^n raport cu n (de doua ori mai mare ajunge!).
Aleg^nd arbitrar numerele v1 ; v2; : : :; vn ^n Zp si evalu^nd q (v1; v2; : : :; vn ) (mod p), putem
imediat a rma cu probabilitate mare (> 1 , n=p) despre q daca este nul sau nu! Observati ca
evaluarea polinomului nu este prea costisitoare, put^ndu-se face ^n timp polinomial ^n lungimea
expresiei care descrie polinomul.
Folosind metoda de \boost" putem creste rapid siguranta noastra despre rezultatul algoritmului.
4.2 Izomor smul arborilor
Iata si o aplicatie imediata a acestei proprietati.
Se dau doi arbori, cu radacina precizata. Sunt acesti doi arbori \izomor " (identici prin re-
ordonarea ilor)? Aceasta problema este surprinzator de di cila pentru un algoritm determinist
(am impresia chiar ca este NP-completa). Iata ^nsa o solutie aproape imediata: construim pentru
ecare arbore c^te un polinom care nu depinde de ordinea ilor unui nod, ^n asa fel ^nc^t daca si
numai daca arborii sunt izomor polinoamele sunt egale. Apoi pur si simplu testam ca mai sus
daca polinomul diferenta este nul.
O metoda de a asocia recursiv un polinom unui arbore este de pilda urmatoarea: ecarui
nod ^i asociem o variabila xk , unde k este ^naltimea nodului (distanta p^na la cea mai departata
frunza). Frunzele vor avea toate asociate variabila x0 . Apoi asociem nodului v de ^naltime k cu
i v1 ; : : :vl polinomul fv = (xk , fv1 )(xk , fv2 ) : : : (xk , fv ). Se arata usor ca polinoamele sunt
egale pentru arbori izomor , baz^ndu-ne pe unicitatea descompunerii ^n factori a unui polinom.
l

Gradul polinomului asociat unui nod este egal cu suma gradelor ilor, care la r^ndul ei este egala
cu numarul de frunze care se a a sub acel nod (cum se demonstreaza imediat prin inductie dupa
^naltime). Si asta-i tot!
Pentru a ^ncheia sectiunea, sa observam ca singurul algoritm e cient cunoscut pentru a veri-
ca primalitatea unui numar este tot probabilist7 ! Pentru ca numerele prime mari stau la baza
6
Aceasta este Teorema Lipton-Schwartz-Zippel: e S K o submultime a unui corp K , iar q(x) un polinom de


n variabile de grad d cu coe cienti ^n K . Atunci ecuatia q(x) = 0 are cel mult d S ,1 solutii ^n S .
j j
n

Asa se genereaza numere prime: se genereaza un numar aleator si se veri ca primalitatea cu un astfel de algoritm.
7

16
criptogra ei cu cheie publica ^n sistemul RSA (probabil cel mai rasp^ndit la ora actuala), iata ca
unele dintre cele mai importante aplicatii se bazeaza indirect pe algoritmi probabilisti. Nimeni nu
va putea obiecta asupra utilitatii lor!

5 Algoritmi on-line
Adesea trebuie luate decizii cu informatii incomplete. Un caz particular este luarea de decizii pe
masura ce datele devin disponibile. Deciziile afecteaza viitorul, dar sunt luate fara a avea cunostinte
despre datele viitoare. Sa vedem ^n actiune un exemplu foarte simplu:
5.1 Problema schiorului
Se pune problema: ce este mai bine: sa ^nchiriezi sau sa cumperi schiuri? (Vom presupune ca
pretul schiurilor este constant de-a lungul timpului, ca sa simpli cam problema). Dilema consta
din faptul ca ^n ecare sezon, nu stii daca te vei mai duce odata. Daca le cumperi si nu te mai
duci, ai dat banii degeaba. Daca le tot ^nchiriezi si te duci des, s-ar putea sa le platesti de mai
multe ori. Totusi, trebuie sa iei o decizie. Pe care?
Exista un raspuns foarte simplu, care promite nu ca da rezultatul cel mai ieftin ^n orice
circumstanta, ci doar ca nu vei cheltui de doua ori mai mult dec^t ^n cazul ^n care ai face de-
cizia perfecta (decizia perfecta este cea care stie precis daca te vei mai duce, si de c^te ori; ea nu
este accesibila dec^t \post-factum", deci este pur teoretica).
Algoritmul este: ^nchiriezi schiuri p^na ai dat pe chirie costul schiurilor. Dupa aceea daca mai
vrei sa mergi le cumperi. Voi demonstra rapid ca ^n felul asta orice s-ar ^nt^mpla nu pierzi mai
mult de jumate din banii pe care i-ai cheltuit ^n cazul ideal.
Avem 3 posibilitat i:
1. Te opresti ^nainte de a le cumpara: ^n cazul asta ai jucat perfect, pentru ca ai schiat si nu
puteai iesi mai ieftin nicicum;
2. Te opresti imediat dupa ce le-ai cumparat. ^In cazul asta ai dat de doua ori pretul (odata pe
^nchirieri, si odata pe cumparare), dar ai schiat c^t ai putut schia d^nd numai odata pretul
(mai ieftin de odata nu puteai iesi);
3. Te opresti mai t^rziu: ^n cazul asta cel mai ieftin era tot sa le cumperi din prima zi, deci iar
ai cheltuit dublu.
Orice alta schema folosesti pentru a decide cumpararea, exista un scenariu ^n care poti cheltui
mai mult de dublu fata de optim.
Algoritmii on-line apar foarte natural ^ntr-o multime de situatii: de exemplu ^n retele de calcu-
latoare, algoritmii care decid traseul unui pachet cu informatii sunt algoritmi on-line; daca decid
trasee proaste, reteaua poate deveni supra-aglomerata ^n viitor; astfel de algoritmi nu au idee
despre cererile viitoare, asa ca actioneaza cu informatie incompleta.
Un alt exemplu este ^n sistemele de operare: algoritmii dupa care cache-urile (sau sistemele
de memorie virtuala) aleg paginile care trebuie ^nlocuite. Alegerea aceasta nu poate optima ^n
absenta informatiilor despre viitoarele cereri. Cu toate acestea, anumite alegeri sunt mai bune
dec^t altele.
Un al treilea exemplu, tot din contextul sistemelor de operare, este al algoritmilor de plani care,
care trebuie sa stabileasca ^n ce moment se executa ecare proces pe un calculator (paralel). Acolo
unde minutul de rulare costa o gramada de bani, deciziile trebuie sa risipeasca c^t mai putin timp.

17
^Insa job-uri pentru prelucrare sosesc dinamic, asa ca algoritmii trebuie sa faca fata unui mediu ^n
continua schimbare.
Algoritmii on-line sunt ^n general analizati compar^ndu-i cu algoritmii o -line, care ar avea
^nainte de a face deciziile informatii perfecte despre toate cererile viitoare. Este clar ca informatia
aceasta este un mare avantaj, asa ca ^n general algoritmii on-line au performante mult mai proaste
dec^t cei corespunzatori o -line.
Cercetarile ^n acest domeniu sunt doar la ^nceput; se exploreaza si variante de algoritmi hibrizi
on/o -line, ^n care algoritmul are o idee despre viitor, dar nu neaparat o vedere completa. Asta
nu face ^ntotdeauna sarcina algoritmului mai simpla, pentru ca adesea problema cu informatie
completa este NP-completa...

6 Rezumat
^In acest articol am trecut razant printr-o gramada de probleme fascinante. Iata recapitulate sumar
conceptele esentiale ^nt^lnite:
 Orice algoritm se exprima folosind un set de operatiuni elementare;
 Un algoritm poate rezolva o instanta a unei probleme dintr-o clasa ^ntreaga;
 Complexitatea algoritmilor este o functie de marimea instantei si masoara operatiile efectuate
pentru a rezolva cel mai nefavorabil caz;
 Complexitatea se exprima concis prin ordinul de marime al functiei complexitate spre in nit;
 Invariantii sunt o metoda foarte utila pentru a demonstra corectitudinea unui algoritm;
 Complexitatea unei probleme este complexitatea celui mai rapid algoritm care o poate rezolva;
 Exista probleme care au nevoie de un timp exponential (^n marimea problemei) sau chiar
mai mult pentru a rezolvate; exista probleme care nu se pot rezolva deloc cu algoritmi;
 Clasa problemelor care au algoritmi nedeterministi polinomiali include foarte multe probleme
practice; nimeni nu stie cum sa rezolve aceste probleme ^n mod e cient;
 Clasa problemelor NP-complete este un set de probleme care se rezolva toate la fel de repede;
un algoritm care ar rezolva deterministic polinomial una din ele ar cauza rezolvarea tuturor
problemelor din NP rapid;
 Algoritmii aproximativi ^ncearca sa gaseasca mai repede solutii sub-optimale la probleme
grele;
 Algoritmii aleatori folosesc aleatorismul pentru a forta comportarea unor probleme mai cur^nd
ca ^n cazul mediu dec^t ca ^n cazul cel mai rau;
 Algoritmii probabilisti gasesc solutiile cu mare probabilitate, dar nu ^ntotdeauna, ^nsa o fac
repede;
 Algoritmii on-line trebuie sa ia decizii ^nainte de a avea toate informatiile disponibile;
 Multe domenii practice bene ciaza masiv de noile tehnici, cea mai notabila ind criptogra a.

18

You might also like