Sunteți pe pagina 1din 40

Complexitate si metode de

programare
Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

Complexitate si metode de programare


5 dintre cele mai cunoscute mai multe tehnici (concepte)
generale de proiectare a unor algoritmi eficienti pentru
clase semnificative de probleme:

Divide et impera;
Programarea dinamica;
Backtracking;
Cautarea locala;
Greedy.

Nici una dintre aceste tehnici nu s-a dovedit capabila sa


rezolve probleme NP-dificile
=> combinari ale tehnicilor de proiectare cu noi abordari
pot furniza solutii practice pentru unele clase/subclase
de probleme dificile.
2

Complexitate si metode de programare


1.

DIVIDE ET IMPERA

Fie U o problema rezolvabila algoritmic => un algoritm divide-et-impera


pentru U:
Intrare: o instanta I a problemei U, cu dim(I)=n, n1.
Pas 1. if n=1 then se calculeaza rezultatul lui I printr-o metoda oarecare else
go to Pas 2.
Pas 2. Cu ajutorul lui I se obtin instantele I1,I2,,Ik, kN\{0} ale problemei U
astfel incat 1jk: dim(Ij) = nj<n.
(De obicei, pasul 2 consta in partitionarea lui I in I1,I2,,Ik , care se mai
numesc si subinstante ale I).
Pas 3. Se aplica recursiv aceeasi procedura si se calculeaza rezultatele
U(I1), U(I2), ,U(Ik) ale subinstantelor I1,I2,, respectiv Ik.
Pas 4. Se utilizeaza rezultatele U(I1), U(I2), ,U(Ik) si se calculeaza rezultatul
lui I.
In cazul standard, analiza complexitatii revine la rezolvarea unei recurente.
Utilizand schema de mai sus, complexitatea timp a algoritmului divide-et3
impera A se poate calcula astfel:

Complexitate si metode de programare


TimeA(1) b,
1. if n=1 then se calculeaza
rezultatul lui I printr-o
unde b = timpul de lucru necesar pentru efectuarea Pasului 1
metoda oarecare else go to
asupra oricarei intrari U de dimensiune 1.
Pas 2.
TimeA(n)=i=1k TimeA(ni)+g(n)+f(n),
2. Cu ajutorul lui I se obtin
instantele I1,I2,,Ik, kN\{0}
unde g(n)=complexitatea timp a partitionarii instantei I de
ale problemei U astfel incat
dimensiune n in subinstantele I1,I2,,Ik (Pasul 2) si
1jk: dim(Ij) = nj<n.
f(n)= complexitatea timp a calcularii solutiei U(I) cu
(De obicei, pasul 2 consta
in partitionarea lui I in
ajutorul solutiilor U(I1), U(I2), ,U(Ik) deja obtinute
I1,I2,,Ik, care se mai
(Pasul 4).
numesc si subinstante ale
In aproape toate cazurile, instanta I este partitionata la Pasul 2
I).
in k subinstante de dimensiune [n/m] =>
3. Se aplica recursiv aceeasi
procedura si se calculeaza
=>
Recurenta tipica este de forma
rezultatele U(I1), U(I2),
,U(Ik) ale subinstantelor
n
Time (n) k Time h(n)
I1,I2,, respectiv Ik.
A
A m
4. Se utilizeaza rezultatele
U(I1), U(I2), ,U(Ik) si se
calculeaza rezultatul lui I.
unde h:N->N, h(n)n, k,m Z+, constante.
4

Complexitate si metode de programare

Analiza complexitatii algoritmilor: rezolvarea unei anumite


recurente.
In general, aceasta recurenta este de forma:
T(n)=d.T(n/k)+f(n),
c g(n)
unde: d,kN, f:NR+.
.

f(n)

Pentru a rezolva aceste recurente,


atunci cand f(n)(n)
se aplica teorema fundamentala a
analizei algoritmilor

c2.g(n)

n0

Complexitate si metode de programare


Teorema Akra-Bazzi
rezolva recurentele generale de forma
T ( x0 ) ,

T ( x) g ( x) n a T (k x h ( x)), x x ,
i
i
i
0

i 1

unde:

i : di 0, cons tan te;


i : 0 ki 1, cons tan te;
| g ' ( x) | O( x c ), unde c cons tan ta;

;
i : | hi ( x) | O
(log x) 2

x0 , cons tan te.


6

Complexitate si metode de programare


Forma generala a teoremei fundamentale
Fie d, kN si T : NN prin:
T(1) = 0
T(n) = d.T(n/k) + h(n).

O(n),
daca d k ,

T (n) O(n log n), daca d k ,


log k d

), daca d k .
O(n

unde: n = dimensiunea instantei initiale;


d = numarul subinstantelor recursive, d 1;
n/k = dimensiunea subinstantelor, k > 1;
h(n) = costul prelucrarilor efectuate inafara apelurilor recursive
(care inlocuieste functiile g si f din cazul general, deci include
costul descompunerii instantei in subinstante si al
recompunerii solutiilor acestora pentru obtinerea solutiei
finale).
7

Complexitate si metode de programare

Exemple de probleme rezolvate cu metoda Divide et Impera:

Cautarea binara,

Quicksort,

Mergesort,

Algoritmul Strassen pentru inmultirea matricelor.

Complexitate si metode de programare


Exemplu: Inmultirea intregilor mari
Fie A=Nr(a), B=Nr(b) doi intregi pozitivi reprezentabili pe n=2k
biti, kN:
a=anan-1a1, b=bnbn-1b1.
Se cere sa se calculeze reprezentarea binara a produsului A.B.
Algoritmul clasic (fie el A1) presupune efectuarea, pentru
i=1,2,,n, a n produse partiale dintre bnbn-1b1 si a

=> complexitatea: TimeA1(n) O(n2).

Complexitate si metode de programare


Aplicam tehnica Divide et Impera => algoritmul A2:

A2: Fiecare intreg a, b de cate n biti este descompus in 2 intregi de cate


n/2 biti:

n
A Nr ( a ) Nr ( an ...a n ) 2 2 Nr ( a n ...a1)
1
2

2
A1
A2
n
B Nr (b) Nr (bn ...bn ) 2 2 Nr (bn ...b1)
1
2
2
B1
B2

=> Nr(a).Nr(b) = A.B = A1.B1.2n + (A1.B2 + A2.B1) .2n/2 + A2.B2.


10

Complexitate si metode de programare


=> Nr(a).Nr(b) = A.B = A1.B1.2n + (A1.B2 + A2.B1) .2n/2 + A2.B2.

=> am redus operatia de inmultire a celor 2 intregi la


4 inmultiri de intregi de cate n/2 biti (A1.B1, A1.B2, A2.B1, A2.B2);
3 adunari de intregi de cel mult 2n biti,
2 deplasari (inmultiri cu 2n si 2n/2).
Calculam complexitatea timp a algoritmului A2:
adunarea in cost logaritmic are complexitate lineara =>
=> adunarile (si deplasarile) c.n pasi

=> complexitatea A2 poate fi calculata dupa formula de recurenta:


TimeA2(1) = 1
TimeA2(n) = 4.TimeA2(n/2) + c.n.

11

Complexitate si metode de programare


Fie d,k,vN si T : NN prin:
T(1) = 0 si
T(n) = d.T(n/k) + v.n

O(n),
daca d k ,

T (n) O(n log n), daca d k ,


log k d

), daca d k .
O(n

=> Aplicam teorema T.F.C.A. pentru d=4 si k=2.

=> d>k =>

log 2 4
Time A2 (n) O n
O(n 2 ).

=> nu am obtinut nicio imbunatatire a complexitatii fata de


algortimul clasic.

12

Complexitate si metode de programare


A3: Pentru a obtine o imbunatatire a algoritmului trebuie sa
micsoram numarul subinstantelor, adica numarul de
inmultiri de intregi de n/2 biti.
=> utilizam formula:
Nr(a).Nr(b) = A.B = A1.B1.2n + [(A1.B1+A2.B2+(A1A2).(B2B1)].2n/2
+ A2.B2=>

3 inmultiri de intregi de n/2 biti (A1.B1, (A1A2).(B2B1),


A2.B2 ),
4 adunari si 2 scaderi de intregi de cel mult 2n biti,
2 deplasari (inmultiri cu 2n si 2n/2).
13

Complexitate si metode de programare


Complexitatea algoritmului A3 este data de recurenta:
TimeA3(1) = 1
TimeA3(n) = 3.TimeA3(n/2) + j.n.
=>Aplicam T.F.A.C. pentru d=3 si k=2 => d>k
log 3
=> Time (n) O n 2 .

A3

Intrucat log23 1,59 =>


acest algoritm e mai rapid decat cel clasic.
14

Complexitate si metode de programare

Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

15

Complexitate si metode de programare


F (1) F (2) 1,

F (n) F (n 1) F (n 2), n 3.

Sirul lui Fibonacci:

Algoritmul DPF: metoda programarii dinamice:


F(1)=1, F(2)=1, F(3)=F(1)+F(2)=1+1=2, F(4)=F(2)+F(3)=1+2=3, , F(n)=F(n-1)+F(n-2)
=> TimeDPF(n)O(n).
Algoritmul DCF: metoda Divide & Conquer:
F(n)
F(n-1)

F(n-2)

F(n-2)

F(n-3)

F(n-3)

F(n-4)

F(n-4)

F(n-3)

F(n-5)

F(n-4)

arborele apelurilor recursive =>TimeDCF(n)O(2n).

F(n-4)

F(n-5)

F(n-5)

F(n-6)

16

Complexitate si metode de programare


Exercitii
1. Sa se calculeze de cate ori rezolva algoritmnul DCF
subproblema F(n-i), 1i n-1.
2. Sa se calculeze complexitatea timp a algoritmilor dinamic si
respectiv Divide et Impera utilizati pentru calcularea C nk dupa
formula (complexitatea se va calcula in ambii parametri: n si k).

Cnk Cnk1 Cnk11

Aplicatii ale metodei:


Algoritmul lui Floyd pentru calcularea drumului minim;
Algoritmul pseudopolinomial pentru problema rucsacului
17

Complexitate si metode de programare


Exemplu: Algoritmul lui Floyd
Fie o retea (G,c), unde G=(V,E) si c:E N\{0}.
Sa se calculeze costul drumului minim dintre oricare doua noduri
ale G.
Ideea algoritmului:
Fie V = {v1, v2, , vn}; se calculeaza pe rand valorile:
costk(i,j) = valoarea celui mai scurt drum dintre nodurile vi si vj
care trece numai prin noduri care fac parte din
multimea {v1,v2,,vk}, 0kn.
18

Complexitate si metode de programare


Pentru k=0: se porneste de la matricea de adiacenta:
c({vi , v j }), daca {vi , v j } E ,

cos t0 (i, j ) ,
daca {vi , v j } E ,

0, daca i j.

Pentru 1kn: se calculeaza costk(i,j) din valorile costk-1(r,s),


1r,sn pe baza formulei:

costk(i,j)=min{costk-1(i,j), costk-1(i,k)+costk-1(k,j)}, 1i,jn.


Justificare: cel mai scurt drum dintre nodurile vi si vj care trece
numai prin nodurile din multimea {v1,v2,,vk}:
sau nu trece prin vk ,
sau, daca trece prin vk, o face 1! data.
19

Complexitate si metode de programare


Intrare: o retea G=(V,E) unde V={v1,v2,,vn}, nN\{0} si
o functie de cost c : E N \ {0}.
Pas 1. for i:=1 to n do
begin cost[i,i]=0;
for j:=1 to n do
if {vi,vj} E then cost[i,j]:=c({vi,vj})
else if ij then cost[i,j]:= end;
Pas 2. for k:=1 to n do
for i:=1 to n do
for j:=1 to n do
cost[i,j]:=min{cost[i,j], cost[i,k]+cost[k,j]}.

=> Complexitatea algoritmului lui Floyd este O(n3).


20

Complexitate si metode de programare

Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

21

Complexitate si metode de programare


Metoda Backtracking poate fi folosita pentru:
rezolvarea problemelor de optimizare printr-o cautare
bruta in multimea tuturor solutiilor (cand acest lucru este
posibil);
determinarea unei strategii optime intr-un joc finit printr-o
cautare bruta in multimea tuturor configuratiilor jocului.
Aici: utilizarea metodei pentru problemele de optimizare.

22

Complexitate si metode de programare


Aplicarea metodei backtracking pt rezolvarea unei probleme
de optimizare structurarea multimii solutiilor posibile
ale acesteia (astfel incat nicio solutie posibila nu este
examinata de 2 ori).
Specificarea fiecarei solutii posibile: un n-tuplu (p1,p2,,pn),
unde fiecare pi poate fi ales dintr-o multime finita Pi,
=> putem structura multimea tuturor solutiilor posibile
astfel:

23

Complexitate si metode de programare


Fie M(x) multimea tuturor solutiilor posibile pentru instanta x
a unei probleme de optimizare U;
definim TM(x) ca fiind un arbore etichetat, cu urmatoarele
proprietati:
(i) fiecare nod din TM(x) este etichetat cu o multime S M(x);
(ii) radacina arborelui TM(x) este etichetata cu M(x);
(iii) daca v1,,vm sunt fiii nodului v din TM(x) atunci etichetele lor
indeplinesc conditiile:

m
Sv Sv si 1 i j m : Sv Sv
i
j
i 1 i

(iv) pt fiecare frunza u din TM(x): |Su| 1 (i.e.: frunzele


corespund solutiilor posibile din M(x) ).

24

Complexitate si metode de programare

Daca fiecare solutie posibila poate fi specificata ca mai sus, se poate


incepe construirea arborelui TM(x) luand p1=a;
=> fiul stang al radacinii corespunde multimii solutiilor posibile cu
p1=a;
fiul drept al radacinii corespunde multimii solutiilor posibile cu p1a.
Se aplica aceasta strategie in continuare pana se construieste intreg
arborele TM(x)
Avand arborele, metoda backtracking revine la o parcurgere a TM(x) (in
adancime / latime).

25

Complexitate si metode de programare


Exemplu: Backtracking: TSP
Fie o instanta a TSP:
x=(G,c), G =(V,E), V={v1,v2,,vn}, E={eij|1i,jn}, nN\{0}, c:EN\{0}.
Orice solutie posibila (ciclu hamiltonian) pentru (G,c) poate fi specificata
clar printr-un (n-1)-tuplu
({v1, vi }, {vi , vi },..., {vi
, vi
}) E n1, unde{1, i1, i2 ,..., in1} {1,2,..., n},
1
1 2
n2 n1
adica ciclul hamiltonian consta din muchiile e1i , ei i ,..., ei
, ei 1.
i
n2 n1 n1
1 12

Notam prin Sx=(h1,,hr,k1,,ks) submultimea solutiilor posibile care


contin muchiile h1,,hr dar nu contin nici una dintre muchiile
k1,,ks, r,s N.
Arborele TM(x) poate fi construit prin divizarea multimii solutiilor posibile
M(x) in multimile Sx{e12}M(x) - care consta din toate solutiile
posibile care contin muchia e12 - si, respectiv Sx{e12}M(x) - care
consta din toate ciclurile hamiltoniene care nu contin muchia e12 etc.
26

Complexitate si metode de programare


Fie o instanta a TSP si fie arborele sau, construit dupa strategia de
mai sus:
Sx()
1

v1
2

v2
3

Sx(e12)

v4

v3
1

Sx(e12)
15

Sx(e12,e23)

Sx(e12,e23)
12

Sx(e12,e23)={(e12,e23,e34,e41)}: v1,v2,v3 v4 v1: cost(v1,v2,v3,v4,v1)=12;


Sx(e12,e23)={e12,e24,e43,e31} => cost(v1,v2,v4,v3,v1)=7;
Sx(e12) )={(e13,e23,e24,e14)}=Sx(e13,e14): e12 e13 , e14 => v4,v1,v3 sau
v3,v1,v4
v2 v4,v1,v3,v2,v4 = v1,v3,v2,v4,v1 de cost 15.

27

Complexitate si metode de programare

Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

28

Complexitate si metode de programare


Metoda cea mai uzuala de a stabili aceasta ordine: transformarea
locala
Definitie
Fie si doua solutii posibile; ele se numesc vecine
poate fi obtinuta din (si reciproc) printr-o transformare locala a
specificatiilor sale.
Exemplu
Doua cicluri hamiltoniene H1 si H2 se numec vecine daca putem
obtine H2 din H1 prin inlocuirea a 2 muchii din H1 cu alte doua
muchii.

29

Complexitate si metode de programare


Observatie
Putem privi M(x) ca pe un graf (fie el G(M(x)) ):
Nodurile: solutiile posibile ale problemei de optimizare date;
Muchiile: exista muchie intre doua solutii posibile si iff si
sunt vecine.
=> cautarea locala o cautare in G(M(x)) in care se ajunge dintr-un
nod intr-un nod de-a lungul muchiei {, } numai atunci cand:

cost()>cost(), in cazul problemelor de maximizare,

cost()<cost(), in cazul problemelor de minimizare.

30

Complexitate si metode de programare


Algoritmul de cautare locala:
Intrare: o instanta x.
Pasul 1: Fie o solutie posibila oarecare din M(x).
Pasul 2. Se inlocuieste cu unul dintre vecinii sai, cu
proprietatea: costul acestuia reprezinta o imbunatatire
in raport cu costul solutiei .
Pasul 3. Se repeta Pasul 2 pana cand se obtine o solutie
cu proprietatea ca niciunul dintre vecinii sai nu
poate fi considerat o solutie mai buna decat .
Iesire:
.
31

Complexitate si metode de programare


Exemplu: Un algoritm de cautare locala pentru arborele de cost
minim (minimum spanning tree= MST)
Fie G=(V,E,c) =>? un arbore T=(V,E), EE, de cost minim
Definitie
Fie T1=(V,E1) si T2=(V,E2) doi arbori de acoperire ai lui G. Spunem ca T1 si
T2 sunt vecini daca T1 se poate obtine din T2 prin schimbarea unei
muchii (adica: |E1-E2|=|E2-E1|=1)

32

Complexitate si metode de programare

Cea mai simpla metoda de a face o transformare consistenta:


se adauga o noua muchie e la T1=(V,E1).
=> se obtine un graf (V,E1{e}) care contine exact un ciclu.

Daca se elimina o muchie h din ciclul cu c(h)>c(e),


atunci se obtine un arbore de acoperire (V,(E1{e})\{h})
mai bun pt G si care este un vecin al T1.

33

v1
2

v2

Complexitate si metode
de programare

v4

v3
1
1

v1

v2

v4

v3

v2

v1

v4

v3

v4

v3

(a)

(b)

(c)

v2

v1

v2

v4

v3

v2

v1

v1

v1
2

v4

v3

v2

v4

v3

(d)

(e)

(f)

Exercitiu: Algoritmul de cautare locala pentru arborele de cost minim


calculeaza intotdeauna solutia optima in timp O(|E|2).
34

Complexitate si metode de programare

Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

35

Complexitate si metode de programare


Exemplu:
Algoritmul Greedy pt TSP incepe prin a decide ca muchia cu
cel mai mic cost trebuie sa faca parte din solutie.
La pasii urmatori algoritmul adauga mereu cea mai ieftina
muchie pana obtine un ciclu hamiltonian.
2 exemple:
MST: eficienta dar
TSP: prea slaba.

36

Complexitate si metode de programare


Exemplu: Algoritm greedy pentru MST
Intrare: o retea conexa G=(V,E,c), c:E N\{0};
Pas 1. Se sorteaza muchiile in functie de costul fiecareia;
fie e1,e2,,em aceasta secventa, deci c(e1)c(e2)c(em).
Pas 2. Fie E:={e1,e2}; I:=3;
Pas 3. while |E|<|V|-1 do
begin
se adauga eI la E daca (V,E{eI}) nu contine niciun ciclu;
I:=I+1
end
Iesire: (V,E).
Cum |E|=|V|-1 si (V,E) nu contine niciun ciclu este evident ca (V,E)
este un arbore de acoperire pentru G. Mai trebuie demonstram ca
(V,E) este un arbore de cost minim (exercitiu).
37

Complexitate si metode de programare


Ilustrare (acelasi graf):
Fie {v1,v2}, {v3,v4}, {v1,v3}, {v2,v3}, {v2,v4}, {v1,v4} secventa de
muchii dupa ordonarea de la Pasul 1.
Figura de mai jos ilustreaza pasii efectuati pt a obtine
specificatia solutiei optime: (V,{{v1,v2}, {v3,v4}, {v1,v3}})
1

v1
2

v2
3

v4

v3
1

v1

v2
3

v4

v3
1

Exercitiu: Alg. greedy pentru MST calculeaza intotdeauna o


solutia optima.
38

Complexitate si metode de programare


Exemplu: Algoritm greedy pentru TSP
Intrare: o retea conexa G=(V,E,c), c:E N\{0}, |V|=n, nN;
Pas 1. Se sorteaza muchiile in functie de costul fiecareia;
fie e1,e2,,en/2 secventa muchiilor din G cu propr.:
c(e1)c(e2)c(en/2).
Pas 2. Fie E:={e1,e2}; I:=3;
Pas 3. while |E|<n do
begin se adauga eI la E daca (V,E{eI}) nu contine
niciun nod de grad mai mare decat 2 si niciun ciclu de
lungime mai mica decat n;
I:=I+1
end
Iesire: (V,E).
Cum |E|=n si niciun nod nu are gradul mai mare ca 2, rezulta ca
39
(V,E) este un ciclu hamiltonian.

Complexitate si metode de programare

Divide et impera
Programarea dinamica
Backtracking
Cautarea locala
Greedy

40

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