Sunteți pe pagina 1din 18

Referat la tema: tehnici

de programare
DISCIPLINA : INFORMATICA

Executat : Ion Borfotin


|

PROFESOR : GINGA SERGIU

Apariia primelor calculatoare electronice a constituit un salt uria n direcia


automatizrii activitii umane. Nu exist astzi domeniu de activitate n care calculatorul s nu
i arate utilitatea.
Calculatoarele pot fi folosite pentru a rezolva probleme, numai dac pentru rezolvarea
acestora se concep programe corespunztoare de rezolvare. Termenul de program
(programare) a suferit schimbri n scurta istorie a informaticii. Prin anii '60 problemele
rezolvate cu ajutorul calculatorului erau simple i se gseau algoritmi nu prea complicai pentru
rezolvarea lor. Prin program se nelegea rezultatul scrierii unui algoritm ntr-un limbaj de
programare. Din cauza creterii complexitii problemelor, astzi pentru rezolvarea unei
probleme adesea vom concepe un sistem de mai multe programe.
Dar ce este un algoritm? O definiie matematic, riguroas, este greu de dat, chiar
imposibil fr a introduce i alte noiuni. Vom ncerca n continuare o descriere a ceea ce se
nelege prin algoritm.
Ne vom familiariza cu aceast noiune prezentnd mai multe exemple de algoritmi i
observnd ce au ei n comun. Cel mai vechi exemplu este algoritmul lui Euclid, algoritm care
determin cel mai mare divizor comun a dou numere naturale. Evident, vom prezenta mai
muli algoritmi, cei mai muli fiind legai de probleme accesibile absolvenilor de liceu.
Vom constata c un algoritm este un text finit, o secven finit de propoziii ale unui
limbaj. Din cauz c este inventat special n acest scop, un astfel de limbaj este numit limbaj de
descriere a algoritmilor. Fiecare propoziie a limbajului precizeaz o anumit regul de calcul,
aa cum se va observa atunci cnd vom prezenta limbajul Pseudocod.
Oprindu-ne la semnificaia algoritmului, la efectul execuiei lui, vom observa c fiecare
algoritm definete o funcie matematic. De asemenea, din toate seciunile urmtoare va reiei
foarte clar c un algoritm este scris pentru rezolvarea unei probleme. Din mai multe exemple se
va observa ns c, pentru rezolvarea aceleai probleme, exist mai muli algoritmi.
Pentru fiecare problem P exist date presupuse cunoscute (date iniiale pentru
algoritmul corespunztor, A) i rezultate care se cer a fi gsite (date finale). Evident, problema
s-ar putea s nu aib sens pentru orice date iniiale. Vom spune c datele pentru care problema
P are sens fac parte din domeniul D al algoritmului A. Rezultatele obinute fac parte dintr-un
domeniu R, astfel c executnd algoritmul A cu datele de intrare xD vom obine rezultatele
rR. Vom spune c A(x)=r i astfel algoritmul A definete o funcie
A : D ---> R .
Algoritmii au urmtoarele caracteristici: generalitate, finitudine i unicitate.
Prin generalitate se nelege faptul c un algoritm este aplicabil pentru orice date iniiale
xD. Deci un algoritm A nu rezolv problema P cu nite date de intrare, ci o rezolv n general,
oricare ar fi aceste date. Astfel, algoritmul de rezolvare a unui sistem liniar de n ecuaii cu n
necunoscute prin metoda lui Gauss, rezolv orice sistem liniar i nu un singur sistem concret.
Prin finitudine se nelege c textul algoritmului este finit, compus dintr-un numr finit
de propoziii. Mai mult, numrul transformrilor ce trebuie aplicate unei informaii admisibile
xD pentru a obine rezultatul final corespunztor este finit.

Prin unicitate se nelege c toate transformrile prin care trece informaia iniial
pentru a obine rezultatul rR sunt bine determinate de regulile algoritmului. Aceasta
nseamn c fiecare pas din execuia algoritmului d rezultate bine determinate i precizeaz n
mod unic pasul urmtor. Altfel spus, ori de cte ori am executa algoritmul, pornind de la
aceeai informaie admisibil xD, transformrile prin care se trece i rezultatele obinute sunt
aceleai.
n descrierea algoritmilor se folosesc mai multe limbaje de descriere, dintre care cele
mai des folosite sunt:
- limbajul schemelor logice;
- limbajul Pseudocod.
n continuare vom folosi pentru descrierea algoritmilor limbajul Pseudocod care va fi
definit n cele ce urmeaz. n ultima vreme schemele logice sunt tot mai puin folosite n
descrierea algoritmilor i nu sunt deloc potrivite n cazul problemelor complexe. Prezentm
ns i schemele logice, care se mai folosesc n manualele de liceu, ntruct cu ajutorul lor vom
preciza n continuare semantica propoziiilor Pseudocod.
METODA BACKTRACKING
La dispoziia celor care rezolv probleme cu ajutorul calculatorului exist mai multe
metode. Dintre acestea cel mai des utilizate sunt:
metoda Greedy;
metoda Divide et impera;
metoda Branch and Bound;
metoda Backtracking;
Metoda backtracking se aplic problemelor n care soluia poate fi reprezentat sub forma
unui vector x = (x1, x2, x3, xk, xn) S, unde S este mulimea soluiilor problemei i S = S1
x S2 x x Sn, i Si sunt mulimi finite avnd s elemente si xi si , ()i = 1..n.
Pentru fiecare problem se dau relaii ntre componentele vectorului x, care sunt numite
condiii interne; soluiile posibile care satisfac condiiile interne se numesc soluii rezultat. Metoda
de generare a tuturor soluiilor posibile si apoi de determinare a soluiilor rezultat prin verificarea
ndeplinirii condiiilor interne necesit foarte mult timp.
Metoda backtracking evit aceast generare i este mai eficient. Elementele vectorului
x, primesc pe rnd valori n ordinea cresctoare a indicilor, x[k] va primi o valoare numai daca au
fost atribuite valori elementelor x1.. x[k-1]. La atribuirea valorii lui x[k] se verifica ndeplinirea
unor condiii de continuare referitoare la x1x[k-1]. Daca aceste condiii nu sunt ndeplinite, la
pasul k, acest lucru nseamn ca orice valori i-am atribui lui x[k+1], x[k+1], .. x[n] nu se va ajunge
la o soluie rezultat.
Metoda backtracking construiete un vector soluie n mod progresiv ncepnd cu prima
component a vectorului i mergnd spre ultima cu eventuale reveniri asupra atribuirilor
anterioare.
Metoda se aplica astfel :
1) se alege prima valoare sin S1 si I se atribuie lui x1 ;
2) se presupun generate elementele x1x[k-1], cu valori din S1..S[k-1]; pentru generarea lui
x[k] se alege primul element din S[k] disponibil si pentru valoarea aleasa se testeaz
ndeplinirea condiiilor de continuare.
Pot aprea urmtoarele situaii :

a) x[k] ndeplinete condiiile de continuare. Daca s-a ajuns la soluia final (k = n)


atunci se afieaz soluia obinut. Daca nu s-a ajuns la soluia final se trece la
generarea elementului urmtor x [k-1];
b) x[k] nu ndeplinete condiiile de continuare. Se ncearc urmtoarea valoare
disponibila din S[k]. Daca nu se gsete nici o valoare n S[k] care s ndeplineasc
condiiile de continuare, se revine la elementul x[k-1] i se reia algoritmul pentru o
nou valoare a acestuia. Algoritmul se ncheie cnd au fost luate in considerare
toate elementele lui S1.
Problemele rezolvate prin aceast metod necesit timp mare de execuie, de aceea este
indicat sa se foloseasc metoda numai daca nu avem alt algoritm de rezolvare.
Dac mulimile S1,S2,Sn au acelai numr k de elemente, timpul necesar de execuie al
algoritmului este k la n. Dac mulimile S1, S2.. Sn nu au acelai numr de elemente, atunci se
noteaz cu m minimul cardinalelor mulimilor S1Sn si cu M, maximul. Timpul de execuie
este situat n intervalul [m la n .. M la n]. Metoda backtracking are complexitatea exponenial, in
cele mai multe cazuri fiind ineficient. Ea insa nu poate fi nlocuit cu alte variante de rezolvare
mai rapide n situaia n care se cere determinarea tuturor soluiilor unei probleme.
Generarea permutrilor. Se citete un numr natural n. S se genereze toate permutrile
mulimii {1, 2, 3, ,n}.
Generarea permutrilor se va face innd cont c orice permutare va fi alctuit din
elemente distincte ale mulimii A. Din acest motiv, la generarea unei permutri, vom urmri ca
numerele s fie distincte.
Prezentm algoritmul corespunztor cazului n=3:

1
1

2
1

1
2
1

2
2
1

3
2
1

3
1

1
3
1

2
3
1

3
3
1

1
2

1
1
2

2
1
2

3
1
2

3
2

1
3
2

2
2

se ncarc n stiv pe nivelul 1 valoarea 1;


ncrcarea valorii 1 pe nivelul al 2-lea nu este posibil, ntruct aceast valoare
se gsete i pe nivelul 1 al stivei;
ncrcarea valorii 2 pe nivelul al 2-lea este posibil, deoarece aceast valoare nu
mai este ntlnit;
valoarea 1 din nivelul al 3-lea se regsete pe nivelul 1;
valoarea 2 din nivelul al 3-lea se regsete pe nivelul al 2-lea;
valoarea 3 pe nivelul al 3-lea nu e ntlnit pe nivelurile anterioare; ntruct
nivelul 3 este completat corect. Tiprim: 1 2 3

Algoritmul continu pn cnd stiva devine vid.


Stiva este acea form de organizare a datelor (structur de date) cu proprietatea c
operaiile de introducere i scoatere a datelor se fac n vrful ei.
Stivele se pot simula utiliznd vectori.
Fie ST(i) un vector. ST(1), ST(2), ..., ST(n) pot reine numai litere sau numai cifre. O
variabil K indic n permanent vrful stivei.

Exemplificm, n continuare, modul de lucru cu stiva:


n stiva iniial vid se introduce litera A, vrful stivei va fi la nivelul 1 (k-1);
A
B

introducem n stiv litera B, deci k va lua valoarea 2;

scoatem din stiv pe B (A nu poate fi scos);


A

scoatem din stiv pe A; stiva rmne vid

n mod practic la scoaterea unei variabile din stiv, scade cu 1 valoarea variabilei ce indic
vrful stivei, iar atunci cnd scriem ceva n stiv, o eventual valoare rezidual se pierde:
Pe un anumit nivel se retine, de regul, o singur informaie (liter sau cifr), ns este
posibil; aa cum va rezulta din exemplele, prezentate n lucrare, s avem mai multe informaii, caz
n care avem de a face cu stive duble, triple, etc.
ntreaga teorie a recursivitii se bazeaz pe structura de tip stiv.
Prezentarea tehnicii Backtracking
Aceast tehnic se folosete n rezolvarea problemelor care ndeplinesc simultan
urmtoarele condiii:
soluia lor poate fi pus sub forma unui vector S=x1,x2, ...,xn, cu x1 A1, x2 A2 ,
xn An
mulimile A1, A2 , ., An sunt mulimi finite, iar elementele lor se consider c se
afl ntr-o relaie de ordine bine stabilit;
nu se dispune de o alt metod de rezolvare, mai rapid
x1 x2 , xn pot fi la rndul lor vectori;
A1, A2 , An pot coincide.
La ntlnirea unei astfel de probleme, dac nu cunoatem aceast tehnic, suntem tentai s
generm toate elementele produsului cartezian A1,A2 ,An si fiecare element s fie testat dac
este soluie. Rezolvnd problema n acest mod, timpul de execuie este att de mare, nct poate fi
considerat infinit, algoritmul neavnd nici o valoare practic.
De exemplu, dac dorim s generm toate permutrile unei mulimi finite A, nu are rost s
generm produsul cartezian AxAx.....xA, pentru ca apoi, s testm, pentru fiecare element al
acestuia, dac este sau nu permutare (nu are rost s generm 1.1,1.......1, pentru ca apoi s
constatm c nu am obinut o permutare, cnd de la a doua cifr 1 ne puteam da seama c cifrele
nu sunt distincte).
Tehnica Backtracking are la baz un principiu extrem de simplu:
se construiete soluia pas cu pas: x1, x2 ,xn
dac se constat c, pentru o valoare aleas, nu avem cum s ajungem la soluie, se
renun la acea valoare i se reia cutarea din punctul n care am rmas.
Concret:
se alege primul element x, ce aparine lui A;
presupunnd generate elementele x1,x2 ,xk , aparinnd mulimilor A1, A2 ,Ak,
se alege (dac exist) xk+1, primul element disponibil din mulimea Ak+1, apar dou
posibiliti:
1) Nu s-a gsit un astfel de element, caz n care caz n care se reia cutarea
considernd generate elementele x1,x2 ,xk+1 , iar aceasta se reia de la urmtorul
element al mulimii Ak rmas netestat;

2) A fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii de
continuare aprnd astfel dou posibiliti:
ndeplinete, caz n care se testeaz dac s-a ajuns la soluie si apar din nou dou
posibiliti:
- s-a ajuns la soluie, se tiprete soluia si se reia algoritmul considernd
generate elementele x1,x2 ,xk, (se caut n continuare, un alt element al
mulimii Ak, rmas netestat);
- nu s-a ajuns la soluie, caz n care se reia algoritmul considernd generate
elementele x1,x2 ,xk , si se caut un prim element xk+2 Ak.
nu le ndeplinete caz n care se reia algoritmul considernd generate elementele
x1,x2 , xk , iar elementul xk-1 se caut ntre elementele mulimii A, rmase
netestate.
Algoritmii se termin atunci cnd nu exist nici un element x1 A1 netestat.
Observaie: tehnica Backtracking are ca rezultat obinerea tuturor soluiilor problemei. n cazul
n care se cere o sigur soluie se poate fora oprirea, atunci cnd a fost gsit.
Am artat c orice soluie se genereaz sub form de vector. Vom considera c generarea
soluiilor se face intr-o stiv. Astfel, x1 A1, se va gsi pe primul nivel al stivei, x2 A2 se va gsi
pe al doilea nivel al stivei,... xk Ak se va gsi pe nivelul k al stivei. n acest fel, stiva (notat ST)
va arta astfel:
Nivelul k+1 al stivei trebuie iniializat (pentru a alege, n ordine, elementele mulimii
k+1 ). Iniializarea trebuie fcut cu o valoare aflat (n relaia de ordine considerat, pentru
mulimea Ak+1 ) naintea tuturor valorilor posibile din mulime. De exemplu, pentru
xk generarea permutrilor mulimii {1,2.....n}, orice nivel al stivei va lua valori de la 1 la n.
Iniializarea unui nivel (oarecare) se face cu valoarea 0. Procedura de iniializare o vom
numi INIT i va avea doi parametri: k (nivelul care trebuie iniializat si ST (stiva)).

Gsirea urmtorului element al mulimii Ak (element care a fost netestat) se face


cu ajutorul procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o
variabil boolean. n situaia n care am gsit elementul, acesta este pus n stiv i AS ia

valoarea TRUE, contrar (nu a rmas un element netestat) AS ia valoarea FALSE..


Odat ales un element, trebuie vzut dac acesta ndeplinete condiiile de
x2
continuare (altfel spus, dac elementul este valid). Acest test se face cu ajutorul procedurii VALID
(EV,ST,K).
Testul dac s-a ajuns sau nu la soluia final se face cu ajutorul funciei SOLUTIE(k) iar
o soluie se tiprete cu ajutorul procedurii TIPAR. Prezentm n continuare rutina Backtracking:

...

k:=1; CALL init(1,st);


while k>0
do
CALL succesor (as, st, k) ;
if as then CALLvalid(ev,st,k) then
loop until (not as) or (as and ev) ;
if as then
if solutie(k) then
CALL tipar
else
k:=k+l;
CALL init ( k, st );
end;
else
k:=k-1
wend

Observaie: Problemele rezolvate prin aceast metod necesit un timp ndelungat. Din acest
motiv, este bine s utilizm metoda numai atunci cnd nu avem la dispoziie un alt algoritm mai
eficient. Cu toate c exist probleme pentru care nu se pot elabora ali algoritmi mai eficieni,
tehnica backtracking trebuie aplicat numai n ultim instan.
Fiind dat o tabl de ah, de dimensiune n, xn, se cer toate soluiile de aranjare a n dame,
astfel nct s nu se afle dou dame pe aceeai linie, coloan sau diagonal (dame s nu se atace
reciproc).
Exemplu: Presupunnd c dispunem de o tabl de dimensiune 4x4, o soluie ar fi urmtoarea:
D
D
D
D
Observm c o dam trebuie s fie plasat singur pe linie. Plasm prima dam pe linia 1, coloana
1.
D

A doua dam nu poate fi aezat dect n coloana 3.


D
D

Observm c a treia dam nu poate fi plasat n linia 3. ncercm atunci plasarea celei de-a doua
dame n coloana 4.
D
D

A treia dam nu poate fi plasat dect n coloana 2.


D
D
D

n aceast situaie dama a patra nu mai poate fi aezat.

ncercnd s avansm cu dama a treia, observm c nu este posibil s o plasm nici n


coloana 3, nici n coloana 4, deci o vom scoate de pe tabl. Dama a doua nu mai poate avansa, deci
i ea este scoas de pe tabl. Avansm cu prima dam n coloana 2.
D

A doua dam nu poate fi aezat dect n coloana 4.


D
D

Dama a treia se aeaz n prima coloan.


D
D
D

Acum este posibil s plasm a patra dam n coloana 3 si astfel am obinut o soluie a
problemei.
D
D
D
D
Algoritmul continu n acest mod pn cnd trebuie scoas de pe tabl prima dam.
Pentru reprezentarea unei soluii putem folosi un vector cu n componente (avnd n vedere
c pe fiecare linie se gsete o singur dam).
Exemplu pentru soluia gsit avem vectorul ST ce poate fi asimilat unei stive.
Dou dame se gsesc pe aceeai diagonal dac si numai dac este ndeplinit condiia:
|st(i)-st(j)|=|i-j| ( diferena, n modul, ntre linii si coloane este aceeai).
n general ST(i)=k semnific faptul c pe linia i dama ocup poziia k.
3

ST(4)

ST(3)

ST(2)

ST(1)

Exemplu: n tabla 4 x4 avem situaia:


D

st(1)= 1 i = 1
st(3)= 3 j = 3
|st(1) - st(3)| = |1 3| = 2
|i j| = |1 3| = 2

D
D
D
sau situaia
D
D
D
D

st(1) = 3 i = 1
st(3) = 1 j = 3
|st(i) - st(j)| = |3 1| = 2
|i j| = |1 3| = 2

ntruct doua dame nu se pot gsi n aceeai coloan, rezult c o soluie este sub form de
permutare. O prim idee ne conduce la generarea tuturor permutrilor si la extragerea soluiilor
pentru problema ca dou dame s nu fie plasate n aceeai diagonal. A proceda astfel, nseamn
c lucrm conform strategiei backtracking. Aceasta presupune ca imediat ce am gsit dou dame
care se atac, s relum cutarea.
Iat algoritmul, conform strategiei generate de backtracking:
n prima poziie a stivei se ncarc valoarea 1, cu semnificaia c n linia unu se
aeaz prima dam n coloan.
Linia 2 se ncearc aezarea damei n coloana 1, acest lucru nefiind posibil ntruct
avem doua dame pe aceeai coloan.
n linia 2 se ncearc aezarea damei n coloana 2 , ns acest lucru nu este posibil,
pentru c damele se gsesc pe aceiai diagonal (|st(1)-st(2)|=|1-2|);
Aezarea damei 2 n coloana 3 este posibil.
Nu se poate plasa dama 3 n coloana 1, ntruct n liniile 1-3 damele ocupa acelai
coloan.
i aceast ncercare eueaz ntruct damele de pe 2 i 3 sunt pe aceeai diagonal.
Damele de pe 2-3 se gsesc pe aceeai coloan.
Damele de pe 2-3 se gsesc pe aceeai diagonal.
Am cobort n stiv mutnd dama de pe linia 2 i coloana 3 n coloana 4.
Algoritmul se ncheie atunci cnd stiva este vid. Semnificaia procedurilor utilizate este
urmtoarea:
INIT - nivelul k al stivei este iniializat cu 0;
SUCCESOR - mrete cu 1 valoarea aflat pe nivelul k al stivei n situaia n care
aceasta este mai mic dect n i atribuie variabilei EV valoarea TRUE, n caz
contrar, atribuie variabilei EV valoarea FALSE;
VALID - valideaz valoarea pus pe nivelul k al stivei, verificnd dac nu avem
dou dame pe aceeai linie (st(k)=st(i)), sau dac nu avem dou dame pe aceeai
diagonal (st(k)-st(i)=|k-i|)caz n care variabilei EV i se atribuie FALSE; n caz
contrar, variabilei EV i se atribuie TRUE;
SOLUTIE - verific dac stiva a fost completat pn la nivelul n inclusiv;
TIPAR - tiprete o soluie.
Subprogramele prezentate in limbajul Visual Basic sunt descrise mai jos:
Global n As Integer, am_suc As Boolean, ev As Boolean
Type stiva
ss(100) As Integer
End Type
Global st As stiva

Sub init(k As Integer, st As stiva)


st.ss(k) = 0
End Sub
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)
If st.ss(k) < n Then
am_suc = True
st.ss(k) = st.ss(k) + 1
Else
am_suc = False
End If
End Sub
Sub valid(ev As Boolean, st As stiva, k As Integer)
ev = True
For i = 1 To k - 1
If (st.ss(i) = st.ss(k)) Or (Abs(st.ss(i) - st.ss(k)) =
Abs(k - i)) Then
ev = False
End If
Next
End Sub
Function solutie(k As Integer) As Integer
If k = n Then
solutie = True
Else
solutie = False
End If
End Function
Sub tipar()
Dim i As Integer, b As String
b = " "
For i = 1 To n
b = b + "(" + Str$(i) + "," + Str$(st.ss(i)) + "),"
Next
MsgBox b
End Sub
Sub back()
Dim k As Integer
k = 1
While k > 0
Do
succesor am_suc, st, k
If am_suc = True Then
valid ev, st, k
End If
Loop Until (Not am_suc) Or (am_suc And ev)
If am_suc Then
If solutie(k) Then
tipar
Else
k = k + 1
init k, st
End If

Else
k = k - 1
End If
Wend
End Sub
Sub Button2_Click()
n = InputBox("n=", ib_title)
back
End Sub

Metoda diviede et impera


Metoda de programare DIVIDE ET IMPERA consta in impartirea problemei initiale de
dimensiuni [n] in doua sau mai multe probleme de dimensiuni reduse. In general se executa
impartirea in doua subprobleme de dimensiuni aproximativ egale si anume [n/2]. Impartirea in
subprobleme are loc pana cand dimensiunea acestora devine suficient de mica pentru a fi rezolvate
in mod direct(cazul de baza). Dupa rezolvarea celor doua subprobleme se executa faza de
combinare a rezultatelor in vederea rezolvarii intregii probleme.
Metoda DIVIDE ET IMPERA se poate aplica in rezolvarea unei probleme care
indeplineste urmatoarele conditii:
se poate descompune in (doua sau mai multe) suprobleme;
aceste suprobleme sunt independente una fata de alta (o subproblema nu se
rezolva pe baza alteia si nu se foloseste rezultate celeilalte);
aceste subprobleme sunt similare cu problema initiala;
la randul lor subproblemele se pot descompune (daca este necesar) in alte
subprobleme mai simple;
aceste subprobleme simple se pot solutiona imediat prin algoritmul simplificat.
Deoarece putine probleme indeplinesc conditiile de mai sus ,aplicarea metodei este destul
de rara.
Dupa cum sugereaza si numele "desparte si stapaneste "etapele rezolvarii unei probleme
(numita problema initiala) in DIVIDE ET IMPERA sunt :
descompunerea problemei initiale in subprobleme independente, smilare
problemei de baza, de dimensiuni mai mici;
descompunerea treptata a subproblemelor in alte subprobleme din ce in ce mai
simple, pana cand se pot rezolva imediata ,prin algoritmul simplificat;
rezolvarea subproblemelor simple;
combinarea solutiilor gasite pentru construirea solutiilor subproblemelor de
dimensiuni din ce in ce mai mari;
combinarea ultimelor solutii determina obtinerea solutiei problemei initiale
Metoda DIVIDE ET IMPERA admite o implementare recursiva, deorece subproblemele
sunt similare problemei initiale, dar de dimensiuni mai mici.
Principiul fundamental al recursivitatii este autoapelarea unui subprogram cand acesta este
activ; ceea ce se intampla la un nivel, se intampla la orice nivel, avand grija sa asiguram conditia
de terminare ale apelurilor repetate. Asemanator se intampla si in cazul metodei DIVITE ET
IMPERA; la un anumit nivel sunt doua posibilitati:
s-a ajuns la o (sub)problema simpla ce admite o rezolvare imediata caz in care
se rezolva (sub)problema si se revine din apel (la subproblema anterioara, de
dimensiuni mai mari);
s-a ajuns la o (sub)problema care nu admite o rezolvare imediata, caz in care o
descompunem in doua sau mai multe subprobleme si pentru fiecare din ele se
continua apelurile recursive (ale procedurii sau functiei).

In etapa finala a metodei DIVIDE ET IMPERA se produce combinarea subproblemelor


(rezolvate deja) prin secventele de revenire din apelurile recursive.
Etapele metodei DIVIDE ET IMPERA (prezentate anterior) se pot reprezenta prin
urmatorul subprogram general (procedura sau functie )recursiv exprimat in limbaj natural:
Subprogram DIVIMP (PROB);
Daca PROBLEMA PROB este simpla
Atunci se rezolva si se obtine solutia SOL
Altfel pentru i=1,k executa DIVIMP(PROB) si se obtine SOL1;
Se combina solutiile SOL 1,... ,SOL K si se obtine SOL;
Sfarsit_subprogram;
Deci, subprogramul DIVIMP se apeleaza pentru problema initiala PROB; aceasta admite
descompunerea in K subprobleme simple; pentru acestea se reapeleaza recursiv subprogramul; in
final se combina solutiile acestor K subprobleme.
De obicei problema initiala se descompune in doua subprobleme mai simple; in acest caz
etapele generale ale metodei DIVIDE ET IMPERA se pot reprezenta concret, in limbaj pseudocod,
printr-o procedura recursiva astfel:
Procedura DIVIMP(li,ls,sol);
Daca ((ls-li)<=eps)
Atunci REZOLVA (li,ls,sol);
Altfel
DIVIDE (li,m,ls);
DIVIMP(li,msol1);
DIVIMP(m,ls,sol2);
COMBINA(sol1,sol2,sol);
Sfarsit_procedura;
Procedura DIVIMP se apeleaza pentru problema initiala care are dimensiunea intre limita
inferioara (li) si limita inferioara(ls); daca (sub)problema este simpla (ls-li<=eps), atunci procedura
REZOLVA ii afla solutia imediat si se produce intoarcerea din apelul recursiv; daca
(sub)problema este (inca) complexa, atunci procedura DIVIDE o imparte in doua subprobleme,
alegand pozitia m intre limitele li si ls; pentru fiecare din cele doua subprobleme se reapeleaza
recursiv procedura DIVIMP; in final, la intoarcerile din apeluri se produce combinarea celor doua
soluitii sol1 si sol2 prin apelul procedurii COMBINA.
PROBLEMA TURNURILOR DIN HANOI
Prezentarea algoritmului rezolvarii
Fie trei tije verticale notate A,B,C. Pe tija A se gasesc asezate n discuri de diametre diferite,
in ordinea crescatoare a diametrelor, privind de sus in jos. Initial, tijele B si C sunt goale. Sa se
afiseze toate mutarile prin care discurile de pe tija A se muta pe tija B, in aceeasi ordine, folosind
ca tija de manevra C si resspectand urmatoarele reguli:
la fiecare pas se muta un singur disc;
un disc se poate aseza numai peste un disc cu diametrul mai mare.
Rezolvarea acestei probleme se bazeaza pe urmatoarele considerente logice:
daca n=1, atunci mutarea este immediata AB (mut discul de pe A pe B);
daca n=2, atunci sirul mutarilor este: AC,AB,CB;
daca n>2 procedam astfel :
- mut (n-1) discuri AC;
- mut un disc AB;
- mut cele (n-1) discuri CB.
Observam ca problema initiala se descompune in trei subprobleme mai simple, similare
problemei initiale: mut (n-1)discuri AC, mut ultimul disc pe B, mut cele (n-1)discuri C-->B.
Dimensiunile acestor subprobleme sunt: n-1,1,n-1.

Aceste subprobleme sunt independente, deoarece tijele initial (pe care sunt dispuse
discurile), tijele finale si tijele intermediare sunt diferite. Notam H(n,A,B,C)=sirul mutarilor a n
discuri de pe A pe B, folosind C.
PENTRU
n=1 AB
n>1 H(n,A,B,C)= H(n-1,A,C,B),AB, H(n-1,C,B,A)
Sortare rapida (quicksort)
Un tablou V se completeaza cu n elemente numere reale .Sa se ordoneze crescator folosind
metoda de sortare rapida .
Solutia problemei se bazeaza pe urmatoarele etape implementate in programul principal:
se apeleaza procedura quick cu limita inferioara li=1 si limita superioara ls=n;
functiapoz realizeaza mutarea elementului v[i] exact pe pozitia ce o va ocupa
acesta in vectorul final ordonat ; functiapoz intoarce (in k ) pozitia ocupata de
acest element;
in acest fel , vectorul V se imparte in doua parti: li k-1 si k+1ls;
pentru fiecare din aceste parti se reapeleaza procedura quick, cu limitele
modificate corespunzator;
in acest fel, primul element din fiecare parte va fi pozitionat exact pe pozitia
finala ce o va ocupa in vectorul final ordonat (functiapoz);
fiecare din cele doua parti va fi, astfel, inpartita in alte doua parti; procesul
continua pana cand limitele partilor ajung sa se suprapuna ,ceea ce indica ca toate
elementele vectorului au fost mutate exact pe pozitiile ce le vor ocupa in vectorul
final ;deci vectorul este ordonat ;
in acest moment se produc intoarcerile din apelurile recursive si programul isi
termina executia.
Observaii:
daca elementul se afla in stanga, atunci se compara cu elementele din dreapta lui
si se sar (j:=j-1) elementele mai mari decat el;
daca elementul se afla in dreapta, atunci se compara cu elemente din stanga lui
si se sar (i:=i+1) elementele mai mici decat el.
Sortare prin interclasare(mergesort)
Tabloul unidimensional V se completeaza cu n numere reale. Sa se ordoneze crescator
folosind sortare prin interclasare.
Sortarea prin interclasare se bazeaza pe urmatoarea logica:
vectorul V se imparte, prin injumatatiri succesive,in vectori din ce in ce mai mici;
cand se ating vectorii de maxim doua elemente, fiecare dintre acestia se
ordoneaza printr-o simpla comparare a elementelor;
cate doi astfel de mini-vectori ordonati se interclaseaza succesiv pana se ajunge
iar la vectorul V.
Observaii:
mecanismul general de tip Divide et Impera se gaseste implementat in procedura
divi;
astfel de abordare a problemei sortarii unii vector conduce la economie de timp
de calcul, deoarece operatia de interclasare a doi vectori deja ordonati este foarte
rapida, iar ordonarea independenta celor doua jumatati (mini-vectori) consuma in
total aproximativ a doua parte din timpul care ar fi necesar ordonarii vectorului luat
ca intreg .

Metoda Greedy

Algoritmii greedy (greedy = lacom) sunt in general simpli si sunt folositi la probleme de
optimizare, cum ar fi: sa se gaseasca cea mai buna ordine de executare a unor lucrari pe calculator,
sa se gaseasca cel mai scurt drum intr-un graf etc. In cele mai multe situatii de acest fel avem:
multime de candidati (lucrari de executat, varfuri ale grafului etc)
o functie care verifica daca o anumita multime de candidati constituie o solutie
posibila
o functie care verifica daca o multime de candidati este fezabila, adica daca este
posibil sa completam aceasta multime astfel incat sa obtinem o solutie posibila, nu
neaparat optima, a problemei
o functie de selectie care indica la orice moment care este cel mai promitator
dintre candidatii inca nefolositi
o functie obiectiv care da valoarea unei solutii (timpul necesar executarii tuturor
lucrarilor intr-o anumita ordine, lungimea drumului pe care l-am gasit etc); aceasta
este functia pe care urmarim sa o optimizam (minimizam/maximizam)
Pentru a rezolva problema noastra de optimizare, cautam o solutie posibila care sa
optimizeze valoarea functiei obiectiv. Un algoritm greedy construieste solutia pas cu pas. Initial,
multimea candidatilor selectati este vida. La fiecare pas, incercam sa adaugam acestei multimi cel
mai promitator candidat, conform functiei de selectie. Daca, dupa o astfel de adaugare, multimea
de candidati selectati nu mai este fezabila, eliminam ultimul candidat adaugat; acesta nu va mai fi
niciodata considerat. Daca, dupa adaugare, multimea de candidati selectati este fezabila, ultimul
candidat adaugat va ramane de acum incolo in ea. De fiecare data cand largim multimea
candidatilor selectati, verificam daca aceasta multime nu constituie o solutie posibila a problemei
noastre. Daca algoritmul greedy functioneaza corect, prima solutie gasita va fi totodata o solutie
optima a problemei. Solutia optima nu este in mod necesar unica: se poate ca functia obiectiv sa
aiba aceeasi valoare optima pentru mai multe solutii posibile. Descrierea formala a unui algoritm
greedy general este:
function greedy(C)
{C este multimea candidatilor}
S
{S este multimea in care construim solutia}
while not solutie(S) and C do
x un element din C care maximizeaza/minimizeaza select(x)
C C \ {x}
if fezabil(S {x}) then S S {x}
if solutie(S)
then return S
else return nu exist soluie
Este de inteles acum de ce un astfel de algoritm se numeste lacom (am putea sa-i spunem
si nechibzuit). La fiecare pas, procedura alege cel mai bun candidat la momentul respectiv, fara
sa-i pese de viitor si fara sa se razgandeasca. Daca un candidat este inclus in solutie, el ramane
acolo; daca un candidat este exclus din solutie, el nu va mai fi niciodata reconsiderat. Asemenea
unui intreprinzator rudimentar care urmareste castigul imediat in dauna celui de perspectiva, un
algoritm greedy actioneaza simplist. Totusi, ca si in afaceri, o astfel de metoda poate da rezultate
foarte bune tocmai datorita simplitatii ei.
Functia select este de obicei derivata din functia obiectiv; uneori aceste doua functii sunt
chiar identice.
Un exemplu simplu de algoritm greedy este algoritmul folosit pentru rezolvarea urmatoarei
probleme. Sa presupunem ca dorim sa dam restul unui client, folosind un numar cat mai mic de
monezi. In acest caz, elementele problemei sunt:
candidatii: multimea initiala de monezi de 1, 5, si 25 unitati, in care
presupunem ca din fiecare tip de moneda avem o cantitate nelimitata

solutie posibila: valoarea totala a unei astfel de multimi de monezi selectate


trebuie sa fie exact valoarea pe care trebuie sa o dam ca rest
multime fezabila: valoarea totala a unei astfel de multimi de monezi selectate
nu este mai mare decat valoarea pe care trebuie sa o dam ca rest
functia de selectie: se alege cea mai mare moneda din multimea de candidati
ramasa
functia obiectiv: numarul de monezi folosite in solutie; se doreste minimizarea
acestui numar
Se poate demonstra ca algoritmul greedy va gasi in acest caz mereu solutia optima (restul
cu un numar minim de monezi). Pe de alta parte, presupunand ca exista si monezi de 12 unitati
sau ca unele din tipurile de monezi lipsesc din multimea initiala de candidati, se pot gasi
contraexemple pentru care algoritmul nu gaseste solutia optima, sau nu gaseste nici o solutie cu
toate ca exista solutie.
Evident, solutia optima se poate gasi incercand toate combinarile posibile de monezi. Acest
mod de lucru necesita insa foarte mult timp.
Un algoritm greedy nu duce deci intotdeauna la solutia optima, sau la o solutie. Este doar
un principiu general, urmand ca pentru fiecare caz in parte sa determinam daca obtinem sau nu
solutia optima.
Minimizarea timpului mediu de asteptare
O singura statie de servire (procesor, pompa de benzina etc) trebuie sa satisfaca cererile a
n clienti. Timpul de servire necesar fiecarui client este cunoscut in prealabil: pentru clientul i este
necesar un timp ti, 1 i n. Dorim sa minimizam timpul total de asteptare
(timpul de asteptare pentru clientul i)
ceea ce este acelasi lucru cu a minimiza timpul mediu de asteptare, care este T/n. De exemplu,
daca avem trei clienti cu t1 = 5, t2 = 10, t3 = 3, sunt posibile sase ordini de servire. In primul caz,
clientul 1 este servit primul, clientul 2 asteapta pana este servit clientul 1 si apoi este servit, clientul
3 asteapta pana sunt serviti clientii 1, 2 si apoi este servit. Timpul total de asteptare a celor trei
clienti este 38.
Ordinea
T
1 2 3
5+(5+10)+(5+10+3)
= 38
1 3 2
5+(5+3)+(5+3+10)
= 31
2 1 3
10+(10+5)+(10+5+3)
= 43
2 3 1
10+(10+3)+(10+3+5)
= 41
3 1 2
3+(3+5)+(3+5+10)
= 29 optim
3 2 1
3+(3+10)+(3+10+5)
= 34
Algoritmul greedy este foarte simplu: la fiecare pas se selecteaza clientul cu timpul minim
de servire din multimea de clienti ramasa. Vom demonstra ca acest algoritm este optim.
Fie I = (i1 i2 ... in) o permutare oarecare a intregilor {1, 2, ..., n}. Daca servirea are loc in
ordinea I, avem

Presupunem acum ca I este astfel incat putem gasi doi intregi a < b cu
Interschimbam pe ia cu ib in I; cu alte cuvinte, clientul care a fost servit al b-lea va fi servit
acum al a-lea si invers. Obtinem o noua ordine de servire J, care este de preferat deoarece

Prin metoda greedy obtinem deci intotdeauna planificarea optima a clientilor.


Problema poate fi generalizata pentru un sistem cu mai multe statii de servire.
Interclasarea optima a sirurilor ordonate
Sa presupunem ca avem doua siruri S1 si S2 ordonate crescator si ca dorim sa obtinem prin
interclasarea lor sirul ordonat crescator care contine elementele din cele doua siruri. Daca
interclasarea are loc prin deplasarea elementelor din cele doua siruri in noul sir rezultat, atunci
numarul deplasarilor este #S1 + #S2.
Generalizand, sa consideram acum n siruri S1, S2, ..., Sn, fiecare sir Si, 1 i n, fiind format
din qi elemente ordonate crescator (vom numi qi lungimea lui Si). Ne propunem sa obtinem sirul S
ordonat crescator, continand exact elementele din cele n siruri. Vom realiza acest lucru prin
interclasari succesive de cate doua siruri. Problema consta in determinarea ordinii optime in care
trebuie efectuate aceste interclasari, astfel incat numarul total al deplasarilor sa fie cat mai mic.
Exemplul de mai jos ne arata ca problema astfel formulata nu este banala, adica nu este indiferent
in ce ordine se fac interclasarile.
Fie sirurile S1, S2, S3 de lungimi q1 = 30, q2 = 20, q3 = 10. Daca interclasam pe S1 cu S2, iar
rezultatul il interclasam cu S3, numarul total al deplasarilor este (30+20)+(50+10)=110. Daca il
interclasam pe S3 cu S2, iar rezultatul il interclasam cu S1, numarul total al deplasarilor este
(10+20)+(30+30)=90.
Atasam fiecarei strategii de interclasare cate un arbore binar in care valoarea fiecarui varf
este data de lungimea sirului pe care il reprezinta. Daca sirurile S1, S2, ..., S6 au lungimile q1 = 30,
q2 = 10, q3 = 20, q4 = 30, q5 = 50, q6 = 10, doua astfel de strategii de interclasare sunt reprezentate
prin arborii din Figura 11.1.

Figura 11.1 Reprezentarea strategiilor de interclasare.


Observam ca fiecare arbore are 6 varfuri terminale, corespunzand celor 6 siruri initiale si
5 varfuri neterminale, corespunzand celor 5 interclasari care definesc strategia respectiva.
Numerotam varfurile in felul urmator: varful terminal i, 1 i 6, va corespunde sirului Si, iar
varfurile neterminale se numeroteaza de la 7 la 11 in ordinea obtinerii interclasarilor respective
(Figura 11.2).

Figura 11.2 Numerotarea varfurilor arborilor din Figura 11.1


Strategia greedy apare in Figura 11.1b si consta in a interclasa mereu cele mai scurte doua
siruri disponibile la momentul respectiv.
Interclasand sirurile S1, S2, ..., Sn, de lungimi q1, q2, ..., qn, obtinem pentru fiecare strategie
cate un arbore binar cu n varfuri terminale, numerotate de la 1 la n, si n1 varfuri neterminale,
numerotate de la n+1 la 2n1. Definim, pentru un arbore oarecare A de acest tip, lungimea externa
ponderata:

unde ai este adancimea varfului i. Se observa ca numarul total de deplasari de elemente pentru
strategia corespunzatoare lui A este chiar L(A). Solutia optima a problemei noastre este atunci
arborele (strategia) pentru care lungimea externa ponderata este minima.
Proprietate :Prin metoda greedy se obtine intotdeauna interclasarea optima a n siruri ordonate,
deci strategia cu arborele de lungime externa ponderata minima.

Alte metode de rezolvare a problemelor


Metoda "branch and bound"
Este o metoda nrudita cu backtracking nsa apar diferente n ceea ce priveste ordinea de
parcurgere a spatiului starilor si privitor la modul de eliminare a ramurilor ce nu pot conduce la
rezultat.
Astfel, metoda presupune folosirea unei liste n care sunt memorate vrfurile arborelui spatiului
solutiilor care trebuie parcurs. Initial lista vrfurilor active este vida, iar cautarea porneste de la un
vrf oarecare. La un moment dat, printr-o anume metoda se considera un vrf activ, dintre cele
memorate din lista. Pentru acest vrf, sunt generati descendentii si se memoreaza acesti
descendenti n lista vrfurilor active ale arborelui. Cautarea se opreste la gasirea unei solutii, si
anume n momentul cnd se ajunge la o frunza a arborelui spatiului solutiilor.

Metoda programarii dinamice


Se aplica problemelor de optim n care solutia poate fi privita ca si rezultatul unui sir de decizii
secventiale dependente de cele luate anterior, fiecare decizie respectnd principiul optimalitatii.
Astfel, daca d1, d2, . dn este un sir de decizii optime care transforma starea s0 n starea finala sn
trecnd prin starile intermediare s1, s2, ., sn-1, atunci pentru orice i = 1,.,n-1, rezulta ca d1, d2, .,
di este un sir de decizii optime pentru perechea de stari (s0,si) si di+1,.,dn este un sir de decizii
optime pentru perechea de stari (si, sn).
Exemplu: determinarea drumurilor cele mai scurte ntr-un graf. Fie un graf orientat cu n vrfuri,
reprezentat prin matricea de adiacenta. Astfel, n matricea de adiacenta elementul de pe pozitia
(i,j) indica lungimea drumului direct de la nodul i la nodul j. Daca n graf nu exista arc de la i la j
atunci elementul (i, j) este nul. Se cere sa se determine lungimea drumului minim de la i la j.
Solutie. Presupunem ca drumul minim de la i la j trece prin nodul k. atunci, conform principiului
optimalitatii, drumurile de la i la k si de la k la j sunt minime. Initial, matricea C contine lungimile

drumurilor directe de la un element i la un nod j. Vom construi matricea A (nxn) care va contine n
final toate drumurile minime ntre 2 noduri i si j. Initial, A(i,j) = C(i,j). pentru fiecare k, k=1,n, se
verifica daca A(i,j) > A(i,k) + A(k,j), pentru orice i si j. n caz afirmativ, se inlocuieste valoarea lui
A(i,j) cu valoarea A(i,k) + A(k,j). n final, vom avea n matricea A lungimea drumurilor minime.

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