Sunteți pe pagina 1din 48

Proiectarea algoritmilor

Scheme de algoritmi

DIVIDE ET IMPERA

DIVIDE ET IMPERA

Divide et impera
Avantaje i dezavantaje

Divide et impera- Algoritmi simpli


de sortare a tablourilor
Sortarea tabloului este ordonarea componentelor acestuia dup valoarea lor.
Dac tipul componentelor tabloului este numeric, relaia de ordine este cea specific mulimii
de valori a tipului respectiv.
Pentru diferite clase de obiecte se pot, de
asemenea, defini relaii de ordine, depinznd
de scopul n care se face sortarea.

Sortarea prin selecie

Una din cele mai intuitive metode de


ordonare a datelor ntr-un tablou este
urmtoarea:
Se caut n tablou cel mai mic element i se
schimb cu cel de pe prima poziie.
Se caut apoi cel mai mic element dintre
cele rmase i se aduce n tablou pe poziia
a doua i aa mai departe.

n pseudocod, acest algoritm se


poate formula astfel:

Fie tabloul tab cu n componente;

Fie i, j, k numere ntregi;


For i de la 0 la n-2{
/* se caut cel mai mic element de pe poziiile i .. n1 */
k=i; /* s-a notat cu k indicele celui mai mic element */
For j de la i la n-1
Dac tab[j]>tab[k]
Atunci k=j;
/* se aduce pe poziia i cel mai mic element de pe poziiile i
.. n-1
acesta fiind tab[k] */
Dac k este diferit de i
Atunci se interschimb tab[i] cu tab[k];
}

Complexitatea acestui algoritm de


sortare poate fi evaluat astfel:
Pentru fiecare valoare a lui i se fac n-i1 comparaii, iar i ia valori de la 0 la n2, deci ordinul de mrime al numrului
de operaii elementare este
(n-1)+(n-2)+(n-3)+...+1=[(n-1)+1]*(n-1)/2.
Aceasta nseamn c complexitatea
algoritmului de sortare prin selecie este
O(n2).

Sortarea prin inserie

Se consider c, pentru o poziie oarecare de


indice i, zona de tablou de la indicele 0 la i-1 este deja
ordonat.
Se ia elementul de pe poziia de indice i i se
caut la stnga lui, de la dreapta la stnga, poziia pe
care trebuie plasat, a. s se respecte ordinea
impus.
Fie aceasta poziia de indice j<i.
Elementele de pe poziiile de la j la i-1 se
deplaseaz cu cte o poziie la dreapta.
Repetndu-se acest procedeu pentru i de la 1
la n (unde n este numrul de elemente din tablou),
se obine un tablou ordonat.

Complexitatea algoritmului de
sortare prin inserie
Se

constat c pentru fiecare valoare a


indicelui i (de la 1 la n-1) se fac cel mult i-1
deplasri.
n consecin, ordinul de mrime al numrului
de operaii elementare este 1+2+3+...+(n1)=n*(n-1)/2, iar complexitatea este O(n2).
Algoritmul de sortare prin inserie prezint
avantajul c, dac tabloul dat initial este deja
ordonat, sortarea se oprete dup prima
parcurgere a tabloului i deci complexitatea
operatiei devine O(n).

Cutare binar varianta recursiv


#include <iostream.h>
class CautBinRec {
public:
// Metoda de cautare recursiva intr-o zona de tablou
int cautrec(double tab[],double,int,int);
};

int CautBinRec::cautrec(double tab[], double val, int inf, int sup)

{
if(inf>sup) return -1;
// interval gresit
int k=(inf+sup)/2;
// se ia indicele de la mijlocul zonei
if(val==tab[k]) return k;
// s-a gasit elementul cautat
if(val<tab[k]) return cautrec(tab, val, inf, k-1);
//se cauta valoarea val in jumatatea din stanga a zonei
else return cautrec(tab, val, k+1, sup);
// se cauta valoarea val in jumatatea din dreapta a zonei
}

void main()
{
CautBinRec a;
double t[]={-1.35,2.146,7.258,12.9,21.43};
cout<<"-1.35 se afla pe pozitia << a.cautrec(t,1.35,0,4)
<<'\n';
cout<<"7.258 se afla pe pozitia "<<a.cautrec(t,7.258,0,4)
<<'\n';
cout<<"3.055 se afla pe pozitia "<<a.cautrec(t,3.055,0,4)
<<'\n';
}

Algoritmii de sortare (prin selecie, inserie,


prin metoda bulelor) aveau complexitatea
O(n2), deci timpul de calcul crete cu patratul
numrului de componente din tablou.
Pentru tablouri de lungime mare, acesta este
un dezavantaj important, astfel c s-au
conceput algoritmi mai rapizi.
Dintre acetia, vom studia algoritmii de sortare
prin interclasare i de sortare rapid.

Interclasarea a dou tablouri


ordonate

Fie dou tablouri ordonate tab1 de lungime m i tab2


de lungime n.
Prin interclasare se obtine un nou tablou
tab3 de lungime p=m+n, procednd astfel:

- se compar primele elemente din tab1 i tab2 i se transfer


cel mai mic dintre ele n tab3;
- se continu astfel, comparnd la fiecare pas primele dintre
elementele nc netransferate din cele dou tablouri i
punndul n tab3 pe cel mai mic dintre ele;
- dup ce componentele din unul din cele dou tablouri date
s-au epuizat, se adaug la tab3 toate componentele rmase
n cellalt tablou.

Tabloul tab3, astfel obinut, conine elementele


din cele dou tablouri date puse n ordine.

Algoritmul de interclasare

i=0; j=0; k=0;


ct timp (i<m si j<n) {
dac (tab1[i] precede lui tab2[j])
atunci
{ tab3[k]=tab1[i
]; i=i+1;
}
altfel
{ tab3[k]=tab2[j
]; j=j+1;
}
k=k+1;
}
/* n acest moment componentele din unul din tablourile tab1 si tab2 s-au terminat */
/* Daca mai exist componente n tab1, se adaug la tab3 */
ct timp (i<m)
{ tab3[k]=tab1[i
]; i=i+1; k+1;
}
/* Daca mai exista componente in tab2, se adauga la tab3 */
ct timp (j<n)
{ tab3[k]=tab2[j
]; j=j+1; k=k+1;
}

Algoritmul Merge Sort

17

Aceasta metoda de ordonare are la baza


interclasarea a doi vectori: fiind dati doi
vectori ordonati se obtine un al treilea
vector ordonat care va contine elementele
din cei doi vectori.
In cazul sortarii prin interclasare vectorii
care se interclaseaza sunt doua secvente
ordonate din acelasi vector
Sortarea prin interclasare
utilizeaza metoda Divide et Impera:

18

-se

imparte vectorul in secvente din ce in ce mai


mici., astfel incat fiecare secventa sa fie
ordonata la un moment dat si interclasata cu o
alta secventa din vector corespunzatoare.
-practic interclasarea va incepe cnd se ajunge
la o secven format din 2 elemente. Aceasta
odata ordonata se va interclasa cu o alta
corespunzatoare. Cele 2 secvene vor alcatui un
subir ordonat din vector mai mare care la
rndul lui se va interclasa cu subirul
corespunztor .a.m.d.

Fie vectorul

8 7 9 3 6

4 17 16

Se mparte n 2 secvene:

8 7 9 3 6 4 17 16
n

continuare pentru prima secven se


procedeaz la fel:

Dup o nou mprire se obine:

Se incepe interclasarea. Se considera ca avem doi


vectori de lungime 1 care se interclaseaza:

8 7

8 7

Rezult 7 8
9 3
La fel i pentru secvana
3 9
Rezult:
Ceea ce nseamn c cele dou secvene
determin obinerea urmtorului subir din
vector:

Pentru care se intercaleaz cele 2 zone.


Rezult:
3

La fel se procedeaz i cu secvena


6

Care

prin interclasarea celor 2 zone va conduce

4
6
16
17
la:
Cele 2 secvene iniiale din vector au devenit:

7 8

Care se interclaseaz obinnd:


3

4 6

Mergesort.cpp

23

Merge Sort - Complexitate

24

Divide et Impera Alte exemple

25

Divide et Impera Alte exemple

Calculul celei mai scurte distane ntre 2


puncte din plan

26

Algoritmul naiv

27

Problem propus
Se d o multime M de numere ntregi
i un numr x. Se cere s se determine
dac exist a,b M, a..
a+b=x
Algoritmul propus trebuie s aib
complexitatea (n*log n)

28

Cutarea cu revenire
(backtracking)
Tehnica

cunoscut sub numele de


backtracking (cutare cu revenire) este
folosit la parcurgerea (traversarea) n
adncime a arborilor i la explorarea n
adncime a grafurilor.
ntr-un cadru mai larg, aceast tehnic se
folosete la rezolvarea unor probleme de
decizie i este, de asemenea, larg folosit n
inteligena artificial.

Cutarea cu revenire
(backtracking)
Fie

problema P, care poate fi rezolvat, n


principiu, pe mai multe ci. Fie P1, P2, ..., Pn
subproblemele corespunztoare fiecreia din
aceste ci.
Important este c, pentru a obine soluia
problemei P este suficient s se rezolve numai
una dintre subproblemele P1, P2, ..., Pn, dar nu
se tie dinainte care din ele.
Trebuie, deci, s se ia o decizie, pe care din
aceste ci s se mearg, fr ca n momentul
lurii deciziei s existe informaia necesar n
acest scop.
n consecin, problema este nedeterminist.

Cutarea cu revenire
(backtracking)
Cazul determinist este cel al structurii de decizie
if <condiie>
then <aciune 1>
else <aciune 2>
n care se consider ca expresia <condiie> poate fi
evaluat nainte de a se executa aciunea 1 sau 2.
n cazul nedeterminist discutat aici, se consider c
la luarea deciziei nu exist informaia necesar pentru a
determina cu siguran pe ce cale trebuie s se continuie executarea programului.
Remarcm c, n cazul problemelor
deterministe soluia este unic, n timp ce
problemele nedeter- ministe pot avea mai multe
soluii, sau niciuna.

Cutarea cu revenire
(backtracking)

Aplicnd tehnica backtracking, rezolvarea problemei P


menionate mai sus se face astfel:
se stabilete o ordine a "succesorilor" (subproblemelor)
P1, P2, ..., Pn;
se trece la rezolvarea subproblemei P1;
dac s-a gsit soluia, executarea programului se
ncheie;
altfel, se trece la subproblema urmtoare (P2), apoi
la P3 i aa mai departe, pn se gsete soluia;
dac au fost parcurse toate cile posibile (P1, P2, ...,
Pn) fr a se gsi soluia, nseamn c problema P nu
are soluie pentru datele de intrare furnizate.

Cutarea cu revenire
(backtracking)
Dac i subproblemele P1, P2, ..., Pn sunt tot
nedeterministe, pentru rezolva-rea lor se procedeaz
n acelai mod, astfel c rezolvarea devine recursiv.

Tehnica backtracking poate fi privit i ca o


tehnic de cutare n spaiul strilor.

Numim stare a sistemului ansamblul valorilor


tuturor variabilelor sistemului la un moment dat.
La efectuarea fiecrei operaii are loc o modificare a
strii sistemului.

n consecin, putem s ne imaginam un graf


orientat al strilor, n care fiecare vrf este o stare, iar
fiecare arc este o operaie.

Cutarea cu revenire
(backtracking)
La

aplicarea tehnicii backtracking, se consider c problema care se rezolv este de aa


natur, nct nu este posibil s se ajung n
aceeai stare pe dou ci diferite.
Se consider, deci, c spaiul strilor are o
structur arborescent (ntruct nici un nod al
arborelui nu poate avea doi prini).
Implicit, aceasta nseamn c la executarea
programului nu pot exista cicluri.
n plus, se consider c nlimea acestui
arbore al strilor este finit.

Cutarea cu revenire
(backtracking)
Aceasta nseamn c, la parcurgerea n
adncime, dup un anumit numr de pai
(posibil mare), se va ajunge la o stare fr
succesor (la o "frunz" a arborelui strilor),
ceea ce face posibil ca, dac nu s-a gsit
soluia, s se revin la o stare anterioar i
s se continue cutarea pe alt cale.
Dac nlimea arborelui ar fi infinit, sar merge mereu n adncime pe o
singur cale, iar revenirea nu ar mai fi
posibil.

Cutarea cu revenire
(backtracking)
Avnd n vedere cele expuse mai sus, la
fel ca la parcurgerea arborilor n adncime,
pentru realizarea cutrii cu revenire
(backtracking) se folosete o stiv.
n fiecare punct de ramificaie (din care
pornesc mai multe ci posibile), starea
curent se pune n stiv pentru a se putea
reveni la ea ulterior, dac pe calea aleas
nu s-a gasit soluia sau dac se caut i
alte soluii.

Probleme tipice abordrii prin


backtraking
Generarea tuturor numerelor de n cifre ntr-o
baz dat;
Generarea tuturor permutrilor de n obiecte;
Generarea tuturor aranjamentelor de m
obiecte luate cte n;
Generarea tuturor combinrilor de m obiecte
luate cte n;
Generarea tuturor produselor carteziene ntre
n mulimi;
Problema celor n dame.

Generarea tuturor numerelor de n


cifre ntr-o baz dat
Considerm

c se d tabloul tuturor caracterelor folosite ca cifre ale unui sistem de numeraie poziional i se cere s se genereze toate
numerele de n cifre ale sistemului respectiv.
De exemplu, dac cifrele sunt 0 i 1, numerele
de 4 cifre vor fi 0000, 0001, 0010, 0011, 0100,
0101, 0110, 0111, 1000, 1001, 1010, 1011,
1100, 1101, 1110, 1111.
Dac se genereaz toate numerele de n cifre
n baza m, se obin mn numere.

Generarea tuturor numerelor de n


cifre ntr-o baz dat
Fie tabCifre tabloul cifrelor sistemului de numeraie
utilizat.
Baza sistemului este egal cu lungimea acestui tablou.
Numrul generat se formeaz n stiva folosit pentru
backtracking.
Pe orice poziie a numrului generat se poate gsi
oricare din elementele tabloului tabCifre.
n consecina, orice element al acestui tablou este
succesor valid al elementului precedent al stivei (deci
orice cifr din tabCifre poate sa succead cifrei precedente a numrului).
Soluia se obine cnd stiva conine toate cele n cifre
ale numrului generat.

Generarea tuturor permutrilor de n


obiecte
Considerm c se d un tablou de n obiecte i se cer
toate permutrile acestora.
Exist, deci, n! soluii.

Problema permutrilor se rezolv prin


bactracking n mod asemntor cu cea a generrii de
numere ntr-o baz dat discutat mai sus, cu
deosebirea c, la validarea succesorilor, se pune
condiia suplimentar ca succesorul respectiv s nu
existe deja n stiv.

Aceast condiie este necesar, deoarece ntr-o


permutare nu poate s apar de mai multe ori acelai
obiect.

Se consider c stiva conine o soluie (o


permutare), atunci cnd ea conine toate cele n
obiecte ale permutrii.

Permutri folosind o funcie


recursiv de generare
Funcia recursiv numit permuta face
generarea tuturor permutrilor prin
interschimbarea elementului de pe
poziia curent k, pe rnd cu elementele
din poziiile anterioare, de la 1 la k+1.
Cnd se ajunge la prima poziie
se tiprete permutarea general.
permutcl.cpp

Generarea tuturor aranjamentelor


de m obiecte luate cte n
Considerm c se d un tablou tabObj
care conine m obiecte i se cere s se
genereze aranjamentele acestor obiecte
luate cte n (unde n <= m).
Problema se rezolv prin backtracking la
fel ca cea a permutrilor, dar se consider ca soluia este obinut atunci cnd
stiva conine cele n obiecte ale unui
aranjament.

Generarea tuturor combinrilor de m


obiecte luate cte n
Combinrile

se genereaz similar cu aranjamentele, cu deosebirea c nu se permite s


avem dou combinri care conin aceleai
obiecte, indiferent de ordinea obiectelor
respective.
Aceasta se poate face punnd condiia suplimentar ca obiectele dintr-o combinare s fie
situate ntr-o ordine prestabilit, de exemplu n
ordine cresctoare.
n acest caz, se consider c este valid numai
acel succesor, care este mai mare dect
elementul din vrful stivei.

Generarea produsului cartezian


ntre n mulimi
Fie n mulimi M0, M1, M2, ..., Mn-1.

Produsul cartezian al acestor mulimi, M0 x M1 x...


x Mn-1 este o mulime, ale crei elemente sunt n-upluri
care conin cte un element din fiecare din mulimile
date.
De exemplu, dac se dau mulimile {a0, a1} i {b0,
b1}, produsul lor cartezian este multimea {(a0,b0),
(a0,b1), (a1,b0), (a1,b1)}. Mulimile pot avea cardinale
diferite.
Generarea elementelor produsului cartezian se
poate face prin backtracking, n mod asemntor cu
genera- rea numerelor dintr-un sistem de numeraie.
Deosebirea este c, de data aceasta, fiecrei poziii
din stiv i corespunde alt list (sau alt tablou) de
succeso- ri posibili. Aceasta este lista elementelor
mulimii de pe poziia corespunztoare a produsului
cartezian.

Produsul cartezian
Funcia

recursiv de generare prod_cart are


ca parametru poziia elementului generat i i
d valori acesteia de la 1 la x[i] (numrul de
elemente ale mulimii i).
Dac s-au generat toate poziiile atunci se
scrie cu ajutorul funciei tipar produsul
cartezian obinut.
Altfel se trece la urmtoarea component.
prodcart.cpp

Problema celor n dame


Una

din problemele clasice care pot fi rezolvate


prin backtracking este "problema celor n dame".
Se consider o tabl de ah cu n carouri pe
fiecare latur.
Se cere s se aeze pe aceast tabl n dame,
astfel nct ele s nu se atace reciproc.
Conform regulilor jocului de ah, aceasta nseamn c nu trebuie s se aeze dou dame
pe aceeai coloan, pe aceeai linie, sau pe
aceeai diagonal.

Problema celor n dame


Pentru rezolvarea acestei probleme prin
bactracking, vom considera c elementul
de indice i al stivei conine indicele j al
damei puse pe linia i a tablei de ah.
Avnd n vedere c nu pot exista doua
dame pe aceeai linie, indicarea coloanei n care se afl unica dam de pe fiecare linie a tablei este suficient pentru a
caracteriza ntreaga situaie.

Soluia a doua
Condiia

de a putea plasa o regin pe poziia k


presupune verificarea ca s nu se atace cu nici una
dintre celelalte k-1 regine deja plasate pe tabla.
Dac pe poziia k din vectorul X punem o valoare ea
va reprezenta coloana pe care se plaseaz pe tabl
regina k.
Condiiile devin astfel:
x[i]=x[k] sau |k-i|=|x[k]-x[i]| cu i de la 1 la k-1, |x|
repre-zentnd modului lui x.
Condiia de soluie este simpl i presupune
plasarea corect a tuturor celor n regine.
Arangreg.cpp