Sunteți pe pagina 1din 65

Învăţământul profesional şi tehnic în domeniul TIC

Proiect cofinanţat din Fondul Social European în cadrul POS DRU 2007-2013
Beneficiar – Centrul Naţional de Dezvoltare a Învăţământului Profesional şi Tehnic
str. Spiru Haret nr. 10-12, sector 1, Bucureşti-010176, tel. 021-3111162, fax. 021-3125498, vet@tvet.ro

METODE ŞI TEHNICI CLASICE DE PROGRAMARE


Material de învăţare – partea I
Domeniul: Informatică
Calificarea: Analist programator
Nivel 3 avansat

2009
AUTOR:
ROMANA SĂLĂJAN – Profesor grad didactic I

COORDONATOR:

MARIANA VIOLETA CIOBANU – Profesor, grad didactic II, Colegiul


Tehnic “ Media “ Bucureşti

CONSULTANŢĂ:

IOANA CÎRSTEA – expert CNDIPT


GABRIELA CIOBANU – expert CNDIPT
ANGELA POPESCU – expert CNDIPT
DANA STROIE – expert CNDIPT

Acest material a fost elaborat în cadrul proiectului Învăţământul profesional şi tehnic în


domeniul TIC, proiect cofinanţat din Fondul Social European în cadrul POS DRU 2007-
2013
Cuprins
I. Introducere...................................................................................................................................5
II. Resurse........................................................................................................................................9
Tema 1. Recursivitate- noţiuni generale...................................................................................10
Fişa de documentare 1.1 Elementele recursivităţii................................................................10
Activitatea de învăţare 1.1 Identificarea unor procese recursive..........................................13
Activitatea de învăţare 1.2 Ordinea de execuţie a funcţiilor recursive..................................13
Tema 2. Recursivitate şi iterativitate.........................................................................................15
Fişa de documentare 2.1 Algoritmi care implementează definiţii recursive.........................15
Activitatea de învăţare 2.1 Identificarea definiţiei recursive corecte....................................17
Activitatea de învăţare 2.2 Condiţia de terminarare..............................................................18
Activitatea de învăţare 2.3 Identificarea soluţiei corecte.......................................................19
Activitatea de învăţare 2.4 Aplicarea definiţiei recursive.....................................................20
Fişa de documentare 2.2 Algoritmi de traversare, inversare a unei structuri........................21
Activitatea de învăţare 2.5 Existenţa unui element(1)..........................................................21
Activitatea de învăţare 2.6 Existenţa unui element(2)...........................................................22
Activitatea de învăţare 2.7 Existenţa unui element(3)...........................................................23
Activitatea de învăţare 2.8 Determinarea algoritmului pseudocod.......................................24
Fişa de documentare 2.3 Tipuri de algoritmi de divizare......................................................26
Activitatea de învăţare 2.9 Căutare binară.............................................................................27
Fişa de documentare 2.4 Tipuri de algoritmi recursivi cu revenire.......................................29
Activitatea de învăţare 2.10 Permutari..................................................................................29
Activitatea de învăţare 2.11 Dame.........................................................................................30
Activitatea de învăţare 2.12 Partiţii.......................................................................................32
Fişa de documentare 2.5 Algoritmi iterativi şi recursivi.......................................................34
Activitatea de învăţare 2.13 Metode iterative şi recursive....................................................34
Activitatea de învăţare 2.14 Tratare comparativă..................................................................35
Tema 3. Avantajele şi dezavantajele recursivităţii....................................................................36
Fişa de documentare 3.1 Eliminarea recursivităţii................................................................36
Activitatea de învăţare 3.1 Şirul lui Fibonacci......................................................................36
Activitatea de învăţare 3.2 Recursivitate indirectă................................................................37
Tema 4. Tehnica de programare “ Divide et Impera”...............................................................39
Fişa de documentare 4.1 Descriere generală.........................................................................39
Activitatea de învăţare 4.1 Divide et Impera.........................................................................40
Fişa de documentare 4.2 Aplicaţii practice............................................................................42
Activitatea de învăţare 4.2 Maximul dintr-un şir...................................................................42
Activitatea de învăţare 4.3 Căutare binară..........................................................................43
Activitatea de învăţare 4.4 Sortarea prin interclasare...........................................................44
Activitatea de învăţare 4.5 Turnurile din Hanoi...................................................................45
Tema 5. Tehnica de programare Backtracking..........................................................................47
Fişa de documentare 5.1 Descrierea tehnicii........................................................................47
Activitatea de învăţare 5.1 Rutina de backtracking..............................................................48
Activitatea de învăţare 5.2 Problema damelor......................................................................49
Fişa de documentare 5.2 Aplicaţii practice............................................................................50
Activitatea de învăţare 5.3 Generarea permutărilor..............................................................50
Activitatea de învăţare 5.4 Generarea aranjamentelor..........................................................51
Activitatea de învăţare 5.5 Generarea combinărilor.............................................................51
Activitatea de învăţare 5.6 Problema colorării hărţilor........................................................52
Activitatea de învăţare 5.7 Problema comis- voiajorului.....................................................54
Fişa de documentare 5.3 Backtracking recursiv....................................................................56
Activitatea de învăţare 5.8 Problema damelor rezolvată recursiv........................................56
Activitatea de învăţare 5.9 Probleme rezolvate recursiv......................................................58
Tema 6. Tehnica de programare Greedy...................................................................................59
Fişa de documentare 6.1 Descrierea tehnicii........................................................................59
Activitatea de învăţare 6.1 Exerciţii de fixare a cunoştinţelor teoretice...............................60
Activitatea de învăţare 6.2 Problema spectacolelor..............................................................61
Activitatea de învăţare 6.3 Problema continuă a rucsacului.................................................62
III. Glosar.......................................................................................................................................64
IV. Bibliografie..............................................................................................................................65
I. Introducere
Materialul de învăţare are rolul de a conduce elevul la dobândirea competenţelor din
unitatea de competenţă tehnică specializată Utilizarea metodelor şi tehnicilor clasice
de programare din cadrul structurii programului pentru nivel 3 avansat.
Conţinuturile ce trebuie parcurse pentru a putea construi aceste competenţe, apar în
programa modulului şi sunt corelate cu Criteriile de Performanţă şi Condiţiile de
Aplicabilitate din Standardul de Pregătire Profesională pentru unităţile de competenţă
corespunzătoare modulului.

Domeniul : Informatică
Calificarea : Analist programator
Nivelul de calificare : 3 avansat
Materialul cuprinde:
- fişe de documentare
- activităţi de învăţare
- glosar

Prezentul material de învăţare, se adresează elevilor din cadrul şcolilor postliceale,


domeniul Informatică, calificarea Analist programator.
Conţinuturile ce trebuie parcurse pentru a putea construi aceste competenţe, apar în
programa modulului şi sunt corelate cu Criteriile de Performanţă şi Condiţiile de
Aplicabilitate din Standardul de Pregătire Profesională pentru unităţile de competenţă
corespunzătoare modulului.

Tabelul de corelare a competenţelor cu temele şi fişele documentare


corespunzătoare conţinuturilor

Competenţa /
Rezultatul Teme
învăţării Elemente componente

Aplică principiile  Tema 1 Recursivitate- noţiuni ● Fişa de documentare 1.1:


generale Elementele recursivităţii
recursivităţii şi
● Activitatea de invăţare 1.1.
iterativităţii în Identificarea unor procese
recursive
rezolvarea
● Activitatea de invăţare 1.2.
problemelor Ordinea de execuţie a
funcţiilor recursive
 Tema 2 Recursivitate şi ●Fişa 2.1 Algoritmi care
iterativitate implementează definiţii
recursive

●Activitatea de învăţare 2.1


Identificarea definiţiei
recursive corecte
Competenţa /
Rezultatul Teme
învăţării Elemente componente

●Activitatea de învăţare 2.2


Condiţia de terminare

●Activitatea de învăţare 2.3


Identificarea soluţiei
corecte
●Activitatea de învăţare 2.4
Aplicarea definiţiei
recursive
●Fişa de documentare 2.2
Algoritmi de traversare,
inversare a unei structuri

●Activitatea de învăţare 2.5


Existenţa unui element(1)
●Activitatea de învăţare 2.6
Existenţa unui element(2)

●Activitatea de învăţare 2.7


Existenţa unui element(3)

●Activitatea de învăţare 2.8


Determinarea algoritmului
pseudocod

●Fişa de documentare 2.3


Tipuri de algoritmi de divizare
●Activitatea de învăţare 2.9
Căutare binară
●Fişa de documentare 2.4
Tipuri de algoritmi recursivi cu
revenire
●Activitatea de învăţare 2.10
Permutări
●Activitatea de învăţare 2.11
Dame

●Activitatea de învăţare 2.12


Partiţii
●Fişa de documentare 2.5
Algoritmi iterativi şi recursivi

●Activitatea de învăţare 2.13


Metode iterative şi recursive
Competenţa /
Rezultatul Teme
învăţării Elemente componente

●Activitatea de învăţare 2.14


Tratare comparativă
Tema 3 Avantajele şi dezavantajele ●Fişa 3.1 Eliminarea
utilizării recursivităţii recursivităţii
●Activitatea de învăţare 3.1
Şirul lui Fibonacci
●Activitatea de învăţare 3.2
Recursivitate indirectă

Utilizează Tema 4 Tehnica de programare ●Fişa 4.1 Descriere generală


" Divide et Impera "
tehnicile clasice ●Activitatea de învăţare 4.1
Divide et impera
de programare ●Fişa 4.2 Aplicaţii practice
●Activitatea de învăţare 4.2
Maximul dintr-un şir

●Activitatea de învăţare 4.3


Căutare binară
●Activitatea de învăţare 4.4
Sortarea prin interclasare
●Activitatea de învăţare 4.5
Turnurile din Hanoi

Tema 5 Tehnica de programare ●Fişa 5.1 Descrierea tehnicii


Backtracking
●Activitatea de învăţare 5.1
Rutina de backtracking
●Activitatea de învăţare 5.2
Problema damelor
●Fişa 5.2 Aplicaţii practice

●Activitatea de învăţare 5.3


Generarea permutărilor

●Activitatea de învăţare 5.4


Generarea aranjamentelor

●Activitatea de învăţare 5.5


Generarea combinărilor

●Activitatea de învăţare 5.6


Problema colorării hărţilor

●Activitatea de învăţare 5.7


Competenţa /
Rezultatul Teme
învăţării Elemente componente

Problema comis- voiajorului


●Fişa 5.3 Backtracking
recursiv

●Activitatea de învăţare 5.8


Problema damelor rezolvată
recursiv
●Activitatea de învăţare 5.9
Probleme rezolvate recursiv
Tema 6 Tehnica de programare ●Fişa 6.1 Descrierea tehnicii
Greedy
●Activitatea de învăţare 6.1
Exerciţii de fixare a
cunoştinţelor teoretice
●Activitatea de învăţare 6.2
Problema spectacolelor

●Activitatea de învăţare 6.3


Problema continuă a
rucsacului

Absolventul nivelului 3 avansat, şcoală postliceală, calificarea Analist programator, va fi


capabil să aplice principiile recursivităţii şi iterativităţii în rezolvarea problemelor şi să
utilizeze tehnicile clasice de programare.
II. Resurse

Prezentul material de învăţare cuprinde diferite tipuri de resurse care pot fi folosite
de elevi:

- fişe de documentare

- activităţi de învăţare

Elevii pot folosi atât materialul prezent (în forma printată) cât şi varianta echivalentă
online.
Tema 1. Recursivitate- noţiuni generale
Fişa de documentare 1.1 Elementele recursivităţii
Recursivitatea este una din noţiunile fundamentale ale informaticii. Utilizarea frecventă
a recursivităţii s-a făcut după anii 80.

Definiţie
Procesul recursiv este procesul care  în timpul execuţiei, generează apariţia unor
procese identice aflate în legătură directă cu procesul ce le generează. Aceste procese 
pot fi finite si infinite.
Un proces recursiv finit  este caracterizat printr-o acţiune  care se repetă, un motor care
susţine această activitate şi o condiţie de oprire.
În cazul proceselor infinite lipseşte condiţia de oprire, acţiunea generându-se în mod
continuu.
Un proces recursiv poate fi descris printr- un subprogram.

Definiţie
Recursivitatea este un mecanism general de elaborare a programelor, care constă în
posibilitatea ca un subprogram să se autoapeleze.
A apărut din necesităţi practice date de transcrierea directă a formulelor matematice
recursive. Astăzi este utilizat în elaborarea multor algoritmi.

Sugestii metodologice
Caută exemple intuitive de procese recursive din realitatea cotidiană. De exemplu:

1. O cameră de luat vederi are în obiectiv un televizor care transmite imaginile primite
de la cameră. Evident, în televizor se va vedea un televizor iar în acesta, un
televizor…,ş.a.m.d.
Pe scurt, în orice televizor se vede un televizor.
2. În anumite restaurante întâlnim anunţul “ Azi nu se fumează “.
3. Respiraţia este un proces recursiv.

Atunci când scri un algoritm recursiv, este suficient să gândeşti exact ce se


întâmplă la un anumit nivel, pentru că la orice nivel se întâmplă exact acelaşi lucru.

Un algoritm recursiv corect trebuie să se termine, contrar programul se va termina cu


eroare şi nu vei primi rezultatul aşteptat. Procesele descrise prin subprogram sunt
procese finite. Condiţia de terminare este pusă de către programator.

Elementele recursivităţii sunt:


 Procesul care se repetă;
 Autoapelul(Motorul procesului);
 Condiţia de terminare.

A nu se uita condiţia de terminare, de oprire a autoapelului procesului.


Este prezentat următorul fractal , ce reprezintă un copac cu două
ramuri, care fac un unghi dat şi au lungime egală cu jumătate din lungimea trunchiului,
din care provin. Prin recursivitate copacul creşte după aceleşi reguli.

Sugestii metodologice

Atenţie, recursivitatea trebuie să fie definită corect, adică să ai o condiţie de oprire. O


greşeală frecventă este încălcarea acestui principiu.

Care este mecanismul intern al limbajului care permite ca un algoritm recursiv să


poată fi implementat?
Pentru a putea implementa recursivitatea, se foloseşte structura de date numită stivă
care nu este gestionată de programator, ci chiar de limbaj. În fapt, o parte din memoria
internă rezervată programului este rezervată stivei ( segmentului de stivă). Un registru
al microprocesorului reţine în permanenţă adresa bazei stivei, altul adresa vârfului ei.
La apelul unui subprogram (funcţii) care are x parametri efectivi, aceştia se reţin în
stivă. Astfel, pentru parametrii transmişi prin valoare se reţine valoarea lor (din această
cauză nu putem întoarce valori utilizând variabile transmise astfel- la revenire nu mai
avem acces la stivă), iar pentru parametrii transmişi prin referinţă se reţine adresa lor
(în stivă se rezervă spaţiu pentru adresă, iar conţinutul va fi obţinut prin utilizarea
acesteia).

Mecanismul prezentat mai sus poate fi generalizat cu uşurinţă pentru obţinerea


recursivitaţii. Atunci când o funcţie se autoapelează se depun în stivă:
 valorile parametrilor transmişi prin valoare;
 adresele parametrilor transmişi prin referinţă;
 valorile tuturor variabilelor locale (declarate la nivelul procedurii sau funcţiei);
 adresa de revenire.

Revenind la autoapel, să presupunem că funcţia s-a autoapelat. Instrucţiunile rămân


nemodificate. Funcţia va lucra asupra datelor transmise pe stivă. În cazul unui nou
autoapel, se creează un alt nivel pentru stivă, în care se depun noile valori. Odată
îndeplinită condiţia de terminare, urmează să se revină din autoapelări. Funcţia care s-a
autoapelat se reia de la instrucţiunea care urmează autoapelului. Ea va lucra cu
variabilele (valorile) reţinute pe stivă în momentul autoapelului, la care se adaugă
valorile returnate .

Primul apel al subprogramului recursiv se realizează din exteriorul subprogramului


Sugestii metodologice
Să se afle termenul general al n-lea al şirului cu termenul general a n= an-1+5, pentru
n>1, ştiind că primul termen din şir este 2, iar n se alege dintr-o listă (1,2,...,6).
Programul corespunzătoare este:
#include <iostream.h>
int n;
int termen(int n)
{if(n==1) return 2;
else return termen(n-1)+5;
}
void main()
{ do {cin>>n;} while (n<1 || n>6);
cout<<termen(n);
}
Subprogramul termen este recursiv- se autoapelează din corpul său. Condiţia de oprire
este if(n==1) return 2, iar autoapelul este termen(n-1)+5. Pe stivă se depun adresa de
revenire din apel şi parametrul n .
Activitatea de învăţare 1.1 Identificarea unor procese recursive

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să recunoşti un proces recursiv;
Durata: 10 minute

Tipul activităţii: Învăţarea prin categorisire


Sugestii
Activitatea se poate face individual, un elev la câte un calculator, pe grupe sau în
perechi.

Sarcina de lucru
Care din imaginile următoare îţi sugerează procese recursive şi care procese
nerecursive?

 somn,  arta, diviziune celulară

mers variat, fractal,  sortare mere

Activitatea de învăţare 1.2 Ordinea de execuţie a funcţiilor recursive

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să determini ordinea de execuţie a apelurilor unei funcţii recursive care
are mai multe autoapeluri în corpul ei.
Să fii capabil să determini ce se memorează pe stivă de fiecare dată.

Durata: 20 minute
Tipul activităţii: Studiu de caz
Sugestii
Activitatea se poate face individual, un elev la câte un calculator, pe grupe sau în
perechi.

Sarcina de lucru
Se dă urmatorul program:
#include <iostream.h>
int v[6]=(3,5,1,8,4,9,10,12);
int impar(int n, int m)
{ if (n==m) return v[n]%2;
else return impar(n,(n+m)/2)+impar((n+m)/2+1,m);
}
void main()
{ cout<<impar(0,7);
}
Precizează ordinea de efectuare a autoapelurilor în acest caz şi valorile parametrilor
memoraţi pe stivă la fiecare nivel, indicând rezultatul obţinut.
Tema 2. Recursivitate şi iterativitate
Fişa de documentare 2.1 Algoritmi care implementează definiţii recursive

Definiţie

O definiţie recursivă este definiţia în care un obiect se defineşte prin el insuşi. Definiţia
conţine condiţia de părăsire a definiţiei şi o parte ce precizează definirea recursivă
propriu-zisă.

Definiţie

Se numeşte recursivitate liniară recursivitatea in care nu pot apărea pe ramuri diferite


ale execuţiei programului mai multe apeluri recursive, adică pe un anumit nivel apare
doar un singur apel recursiv.

Sugestii metodologice
Aprofundează exemplele următoare, rulează-le în C++ pentru mai multe date de intrare
şi urmăreşte cu fereastra Watch ( Ctrl+F7) valorile parametrilor la fiecare apel al funcţiei
recursive.

Exemplu 1. Se dau două numere naturale a şi b.Se cere să se calculeze cel mai mare
divizor comun al lor folosind algoritmul lui Euclid.
Foloseşti definiţia recursivă a celui mai mare divizor comun pentru două numere
naturale a şi b.
a , a  b

Cmmdc(a,b)= 
cmmdc ( a  b, b ), a
cmmdc ( a , b  a ) , a



b
b

Formula este transcrisă în funcţia recursivă cmmdc.

int cmmdc(int a,int b){


if (a==b) return a;
else if(a>b) return cmmdc(a-b,b);
else return cmmdc(a,b-a);
}

Programul corespunzător care apelează funcţia este:

#include <iostream.h>
int cmmdc(int a,int b) {
if (a==b) return a;
else if(a>b) return cmmdc(a-b,b);
else return cmmdc(a,b-a);
}
void main(){
int a,b;
cout<<"Introduceti numerele: "; cin>>a>>b;
cout<<"cmmdc dintre "<<a<<" şi "<<b<<" este "<<cmmdc(a,b);
}

Exemplu 2.
Fie fib: N  N. Să se calculeze fib(n), pentru n natural.
1, n  0

Fib(n)= 
1, n  1

 fib ( n  1)  fib ( n  2), altfel

Funcţia corespunzătoare este următoarea


int fib(int n)
{ if(n==0 || n==1) return 1;
else return fib(n-1)+fib(n-2);
}

Programul aferent este:


#include<iostream.h>
int n ;
int fib(int n)
{ if(n==0 || n==1) return 1;
else return fib(n-1)+fib(n-2);
}
void main(){
cout<<”n=” ;
cin>>n;
cout<<fib(n);
}

Ce se întâmplă dacă n este relativ mare ( n=100) ? Dar foarte mare?

Exemplu 3.
Calculul funcţiei Manna-Pnueli pentru un x intreg.:
 x  1, x.  12

F(x)= 


 F ( F ( x  2)), x  12

Transpunem formula în funcţia recursivă:

int manna(int x)
{ if(x>=12) return x-1;
else return manna(manna(x+2));
}

Mai jos este programul ce apelează această funcţie:


# include <iostream.h>
int manna(int x)
{ if(x>=12) return x-1;
else return manna(manna(x+2));
}
void main()
{ int n;
cout<<”n=”;
cin >>n;
cout<<mana(n);
}

Exemplu 4.
Să se calculeze recursiv suma cifrelor unui număr natural.
Indicaţie: Se izolează ultima cifră, iar lui n i se atribuie câtul întreg dintre vechea valoare
şi 10. Astfel găsim o relaţie de recurenţă, necesară elaborării variantei recursive:
0, n  0

S(n)= 

n %10  S ( n / 10), altfel

Avem programul:
#include <iostream.h>
int suma(long n){
if (n<10) return n;
else return n%10+suma(n/10);
}
void main(){
int n;
cout<<"n="; cin>>n;
cout<<"suma cifrelor este "<<suma(n);
}

Activitatea de învăţare 2.1 Identificarea definiţiei recursive corecte

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să identifici dacă o definiţie recursivă este corectă sau nu.

Durata: 10 minute

Tipul activităţii : Găseşte eroarea

Sugestii
Activitatea se poate face individual pe caiet, sau toată clasa folosind tabla.

Sarcina de lucru
Se dau următoarele definiţii recursive:
a) f: N→ N
0 daca x  1

f(x)= 
f (x  2 )

f (x)  5
daca
daca
x par
x im par

b) g: Z→Z
1 daca x  0
g(x)= 
g(x - 1)  5 altfel
c) h: N→N
0 daca x  1
h(x)= 
h(x - 1)  5 , altfel

Sunt corecte aceste definiţii? Justifică răspunsul.

Activitatea de învăţare 2.2 Condiţia de terminarare

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să găseşti condiţia de terminare într-un subprogram recursiv dat.
Să recunoşti principiul recursivităţii în programare şi să dobândeşti tehnica de realizare
a recursivităţii.

Durata: 10 minute

Tipul activităţii Completează spaţiile

Sugestii
Activitatea se poate face individual, un elev la câte un calculator, pe grupe sau în
perechi.

Sarcina de lucru
Completează spaţiile libere din subprogramul recursiv prezentat mai jos cu o expresie
corespunzătoare, astfel încât în urma apelului f(12) să se afişeze şirul de valori:
12 6 3 1 1 3 6 12.

void f(int i)
{ if ( )
{ cout<<i<<” “;
f(12);
cout<<i<<” “;}}

Activitatea de învăţare 2.3 Identificarea soluţiei corecte

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să interpretezi tehnica recursivă aplicată într-o problemă atunci când ţi se
dau datele de intrare.
Să fii capabil să determini rezultatul unui subprogram recursiv.
Durata: 10 minute

Tipul activităţii: Problematizare


Sugestii
Activitatea se poate face individual, fiecare elev pe caiet, pe grupe sau în perechi. Se
verifică la tablă sau rulând programul pe calculator

Sarcina de lucru
Se dă următorul subprogram:
void scrie (int x)
{ if (x>1)
scrie (x-2);
cout<<x%2;
}
Ce se afişează pe ecran la apelul scrie(12)?
a) 10101
b) 11111
c) 01010
d) 00000.

Activitatea de învăţare 2.4 Aplicarea definiţiei recursive

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să aplici tehnica recursivă la rezolvarea unei probleme atunci când ţi se dă
o definiţie recursivă.
Să fii capabil să identifici situaţiile în care poţi aplica principiul recursivităţii.

Durata: 20 minute

Tipul activităţii: Exerciţiul practic


Sugestii
Activitatea se poate face individual, fiecare elev pe caiet, pe grupe sau în perechi
Sarcina de lucru
Se dă funcţia lui Ackermann, definită mai jos. Se citesc numerele m şi n naturale. Să se
calculeze Ack(m,n).
 n  1, m  0

Ack(m,n)= 
 Ac k ( m  1,1), n  0
 Ac k ( m  1, Ack ( m, n  1)), altfel

Ce se întâmplă pentru valori mici ale lui m şi n ? De exemplu, Ack(4,4).


Încearcă.

Fişa de documentare 2.2 Algoritmi de traversare, inversare a unei structuri

Definiţie

Traversarea şi inversarea unei structuri înseamnă efectuarea unor operaţii oarecare


asupra tuturor elementelor unei structuri în ordine directă, respectiv în ordine inversă.
Variantele recursive sunt mai elegante şi concise, decât alte metode. Se pot aplica
structurilor de tip tablou, listă, fişier şi pot fi o soluţie pentru diverse probleme
(transformarea unui întreg dintr-o bază în alta, etc). Într-o formă generală, algoritmii se
pot scrie:

funcţie traversare(tip_element element)


{
dacă( element <> ultimul_din_structură) atunci
traversare(element_următor)
prelucrare(element);
}

Apelul iniţial al procedurii se face cu primul element al structurii. De observat


importanţa ca parametrul formal al celor două funcţii să fie de tip valoare, pentru a nu fi
alterat de apelul recursiv.
Exemplu 1:
Se citesc şi se afisează elementele întregi ale unui vector. Cele două funcţii recursive,
pentru citire şi afişare pot începe cu ultimul element din vector şi se termină cu primul.
#include <iostream.h>
int n,a[100];
void citeste(int i)
{if (i!=n-1) citeste(i+1);
cout<<i<<” “;
cin>>a[i];}
void scrie(int i)
{if (i!=n-1) scrie(i+1);
cout<<a[i]<<” “;}
void main()
{cout<<”n=”;
cin>>n; citeste(0); scrie(0);}

Activitatea de învăţare 2.5 Existenţa unui element(1)

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să identifici situaţiile în care poţi aplica principiul recursivităţii.
Să fii capabil să aplici tehnica recursivă pentru rezolvarea unei probleme date.
Să fii capabil să determini o variantă de rezolvare.

Durata: 20 minute

Tipul activităţii: Harta traseu


Sugestii
Activitatea se poate face individual, pe caiet, pe grupe sau în perechi la laborator.
Sarcina de lucru
Se dă un vector a=(a1,a2,...,an) cu n elemente întregi, şi un element cu valoarea
întreagă x. Folosind funcţia recursivă gasit(x,i) definită mai jos, să descrii în ordine
logică etapele de rezolvare a verificării existenţei elementului x între componentele
vectorului.
 true, daca x  ai

gasit(x,i)=

false , daca x  ai

Activitatea de învăţare 2.6 Existenţa unui element(2)


Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să aplici tehnica recursivă pentru rezolvarea unei probleme date.
Să fii capabil să determine o altă variantă de rezolvare,când ţi se dă una.
Să fii capabil să determini instrucţiunea de apel corectă.

Durata: 20 minute
2
1 3
P
Tipul activităţii: Transformare
Sugestii
Activitatea se poate face individual, fiecare elev pe caiet, pe grupe sau în perechi.
Sarcina de lucru
Să se verifice dacă există într-un vector cu n elemente întregi, cel puţin un element cu
valoarea intreagă x. Fie vectorul a=(a1,a2,...,an) şi o variantă de rezolvare.

Varianta 1:

#include <iostream.h>
int a[100];
int gasit(int x, int i)
{if(i = = 0) return x = = a[0];
else return ((x = = a[i]) || gasit(x,i-1));}
void main()
{int x,i,n;
cout<<”n= ”;
cin>>n;
cout<<”x= ”;
cin>>x;
for(i=0;i<n;i++)
{cout<<”a[”<<i<<”]=”;
cin>>a[i];}
if(gasit(x,n-1))
cout<<”s-a gasit elementul”<<x;
else cout<<”nu s-a gasit elementul”<<x;}

Activitatea de învăţare 2.7 Existenţa unui element(3)

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să determini o alta variantă de rezolvare, când ţi se dă una.
Să fii capabil să găsesti algoritmul optim.

Ce vreau?
Durata: 20 minute Ce ?
De ce vreau?
vreau?
Tipul activităţii: Starbursting
Cum? Pot?
Sugestii vreau?
Pot? Ce
Activitatea se poate face individual, fiecare elev pe caiet, pe grupe sau în perechi la
vreau?
teorie.
Sarcina de lucru
Să se verifice dacă există într-un vector cu n elemente întregi, cel puţin un element cu
valoarea intreagă x. Fie vectorul a=(a1,a2,...,an) şi o variantă de rezolvare a problemei.
Să se optimizeze această variantă de rezolvare răspunzând şi la întrebările din colţurile
steluţei.

Varianta 3 :
#include <iostream.h>
int a[100];
int gasit(int x, int i)
{if(i > n) return 0];
else if(x = = a[i]) return 1 ;
else return gasit(x,i+1);}
void main()
{int x,i,n;
cout<<”n= ”;
cin>>n;
cout<<”x= ”;
cin>>x;
for(i=1;i<=n;i++)
{cout<<”a[”<<i<<”]=”;
cin>>a[i];}
if(gasit(x,1))
cout<<”s-a gasit elementul”<<x;
else cout<<”nu s-a gasit elementul”<<x;}

Activitatea de învăţare 2.8 Determinarea algoritmului pseudocod

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să determini datele de intrare.
Să fii capabil să determini datele de ieşire.
Să fii capabil să determini schema de rezolvare a problemei soluţionată de programul
dat.

Durata: 5 minute

B A
C

Tipul activităţii: Reducere

Sugestii
Activitatea se poate face individual, fiecare elev pe caiet, pe grupe sau în perechi, la
clasă.
Sarcina de lucru
Se dă programul de mai jos. Folosind limbajul pseudocod să se rescrie acest program.

#include <iostream.h>
int suma(int i, int j, int m, int a[20][20])
{if (i = = 0 && j = = 0)
if (a[0][0]%2==0) return a[0][0];
else return 0;
else if (a[i][j]%2==0)
if (j==0) return a[i][j]+suma(i-1,m-1,m,a);
else return a[i][j]+suma(i,j-1,m,a);
else if(j==0) return suma(i-1,m-1,m,a);
else return suma(i,j-1,m,a);}

void citeste (int a[20][20], int &n, int &m)


{int i,j;
cout<<”n=”; cin>>n;
cout<<”m=”;cin>>m
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{cout<<”a(”<<i+1<<”,”<<j+1<<”)= ”;cin>>a[i][j];}}

void main()
{int n,m,a[20][20];
citeste(a,n,m); cout<<”suma este”<<suma(n-1,m-1,m,a)<<endl;}
Fişa de documentare 2.3 Tipuri de algoritmi de divizare

Definiţie

Tehnica divizării ("divide and conquer" sau “divide et impera”), este fundamentală în
elaborarea algoritmilor şi constă în descompunerea unei probleme complexe în mai
multe subprobleme a căror rezolvare e mai simplă şi din soluţiile cărora se poate
determina soluţia problemei iniţiale (exemple: găsirea minimului şi maximului valorilor
elementelor unui tablou, căutarea binară, sortare Quicksort, turnurile din Hanoi). Un
algoritm de divizare general se elaborează astfel: la un anumit nivel avem două
posibilităţi:

1. s-a ajuns la o problemă care admite o rezolvare imediată (condiţia de terminare),


caz în care se rezolvă şi se revine din apel;
2. nu s-a ajuns în situaţia de la punctul 1, caz în care problema curentă este
descompusă în (două sau mai multe) subprobleme, pentru fiecare din ele
urmează un apel recursiv al funcţiei, după care combinarea rezultatelor are loc
fie pentru fiecare subproblemă, fie la final, înaintea revenirii din apel.
Exemplul 1.
Se citeşte un vector cu n componente numere naturale. Să se tipărească valoarea
maximă din vector.

Problema se rezolvă eficient cu metodele cunoscute , dar poate fi folosită ca un


exemplu şi pentru tehnica recursivă.

Se procedează astfel:

 dacă(i==j) maxim va fi v[i];


 altfel se împarte vectorul în doi vectori , primul cu componente de la i la (i+j)/2 ; al
doilea cu componente de la (i+j)/2+1 pâna la j; se rezolvă subproblemele, iar
soluţia va fi dată de maximul dintre cele două subprobleme.

#include <iostream.h>
int v[10],n;

int max(int i, int j)


{ int a, b;
if (i==j) return v[i];
else
{ a=max(i,(i+j)/2);
b=max((i+j)/2+1,j);
if(a>b)return a;
else return b;}}

void main()
{cout<<”n=”;
cin>>n;
for(int i=1;i<=n;i++)
{cout<<”v[“<<i<<”]=”;
cin>>v[i];}
cout<<”max=”<<max(1,n);
}

Activitatea de învăţare 2.9 Căutare binară

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să determini ordinea de execuţie corectă a instrucţiunilor unui program.
Să fii capabil să-ţi însuşeşti logica programului.
Să fii capabil să determini ordinea corectă a instrucţiunilor programului.
Durata: 15 minute
Tipul activităţii: Reconstrucţie

Sugestii
Activitatea se poate face individual, fiecare elev pe caiet sau pe grupe.
Sarcina de lucru
Se dau instrucţiunile de mai jos reprezentând algoritmul căutarii binare ( care se referă
la următoarea problemă: se citeşte un vector cu n componente numere întregi, unde
numerele se presupun ordonate crescător şi o valoare intreagă nr. Să se decidă dacă nr
se găseşte sau nu printre numerele citite, iar în caz afirmativ să se tipărească indicele
componentei care conţine acea valoare.).
Instrucţiunile nu sunt in ordinea corectă de execuţie. Aranjează aceste instrucţiuni
pentru a obţine varianta corectă a programului.

Indicaţie: Problema este de a decide dacă valoarea căutată se găseşte printre


numerele de indice cuprins între i şi j (iniţial i=1 , j=n). Procedăm astfel:
 dacă nr coincide cu valoarea de indice (i+j)/2 ( mijloc ) se tipăreşte indicele şi se
revine din apel;
 contrar, dacă i<j (nu s-a căutat peste tot) problema se descompune astfel:
 Dacă numărul este mai mic decât valoarea testată (din mijloc), inseamnă că
avem şanse să-l găsim între componentele cu indicele cuprins între i şi
(i+j)/2-1, caz in care reapelam funcţia cu aceşti parametri.
 Dacă numărul este mai mare decât valoarea testată (din mijloc), inseamnă că
avem şanse să-l găsim între componentele cu indicele cuprins între (i+j)/2+1 şi
j, caz în care reapelăm funcţia cu aceşti parametri.

#include <iostream.h>
cin>>n;
{cout<<”n=”;
if (nr<v[(i+j)/2])
caut(1,n);}
void main()
cin>>nr;
for(int i=1;i<=n;i++)
cout<<”gasit”<<’ ‘<<”indice “<<(i+j)/2;
cout<<”nr=”;
else caut ((i+j)/2+1,j);}}
else if(i<j)
void caut(int i,int j)
{cout<<”v[“<<i<<”]”;
int v[100],n,nr;
{if (nr==v[(i+j)/2])
caut (i,(i+j)/2-1);
cin>>v[i];}
Fişa de documentare 2.4 Tipuri de algoritmi recursivi cu revenire

Definiţie
Algoritmii cu revenire (algoritmi de tip backtracking) se aplică problemelor în care soluţia
se poate reprezenta sub forma unui vector x=(x1,x2,...xn) cu S=S1 x S2 x...x Sn, unde
mulţimile Si sunt finite, S numindu-se spaţiul soluţiilor posibile. În particular, Si sunt
identice având acelaşi număr M de elemente. Pentru fiecare problemă concretă sunt
date anumite relaţii între componentele vectorului x, numite condiţii interne.

Determinarea tuturor soluţiilor rezultat se poate face generând toate soluţiile posibile şi
verificând apoi dacă satisfac condiţiile interne. Dar timpul de calcul ar fi foarte mare
(dacă mulţimile Si ar avea numai câte 2 elemente, timpul ar fi proporţional cu 2 n).
Elementele vectorului x primesc valori pe rând, lui xi i se atribuie valori, doar dacă
x1,x2,...,xi-1 au primit deja valori, valorile atribuite trebuind să verifice condiţiile de
continuitate referitoare la x1,x2,...,xi. Doar apoi se trece la calculul lui xi+1. În cazul
neîndeplinirii condiţiilor de continuitate, se alege următoarea valoare posibilă pentru xi.
Dacă Si a fost epuizat, se micşorează i, încercând o altă alegere pentru xi-1.
Pe acestă metodă se bazează rezolvarea unor probleme clasice ca: permutări de n,
"opt regine", partiţii, "relaţii stabile", colorarea unei hărti, tăierea unui fir de lungime l în
părţi de lungimi date, etc.

Se consideră rutina generală recursivă back cu un parametru p, care reprezintă nivelul


stivei, Contorul i al ciclului for ia pe rând toate valorile posibile fiecărui nivel. Se obţine
soluţie când stiva este completă.
void back(int p)
{int i;
for(i=1;i<=n;i++)
{st[p]=i;
if valid(p)
if(p==n)
tipar (p)
else back(p+1);
} }

Activitatea de învăţare 2.10 Permutari

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să execuţi pas cu pas algoritmul de afişare a permutărilor de n.
Să fii capabil să-ţi însuşeşti tehnica rutinei recursive a programului.
Să fii capabil să enunţi o situaţie reală in care se poate aplica acest algoritm.

Durata: 15 minute

Tipul activităţii: Urmează paşii

Sugestii
Activitatea se poate face individual sau pe grupe.
Sarcina de lucru

Să se calculeze recursiv permutări de n, n natural citit de la tastatură. Găseşte o


problemă din viaţa reală la care se poate aplica acest algoritm.

#include <iostream.h>
int t[20],n;

void tipar()
{for(int i=1;i<=n;i++)
cout<<t[i];
cout<<endl;}

void perm(int k)
{int i,j,corect;
if (k==n+1) tipar();
else {for(i=t[k]+1;i<=n;i++)
{ t[k]=i;
corect=1;
for(j=1;j<=k-1;j++)
if(t[j]==t[k] )
corect=0;
if (corect) perm(k+1);}}
t[k]=0;}

void main()
{cout<<”n=”;
cin>>n;
perm(1);}

Activitatea de învăţare 2.11 Dame

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să modifici algoritmul generării permutărilor astfel incât să rezolvi
problema aşezării damelor.
Să fii capabil să descoperi care este condiţia ca două dame să nu se atace pe o tablă
de şah.
Să fii capabil să aplici funcţionarea acestui algoritm pentru un caz particular dat.

Durata: 15 minute

Tipul activităţii: Problematizare

Sugestii
Activitatea se poate face individual sau pe grupe la teorie sau laborator.
Sarcina de lucru
Se dau n dame pe o tablă de şah de dimensiune n*n. Să se afişeze toate soluţiile
posibile de aranjare a celor n dame pe tablă astfel încât să nu se atace. Exemplificare
pentru n=4

Indicaţie Metoda de rezolvare seamană cu rezolvarea permutărilor pe care o aveţi


mai jos, doar că în condiţia de validare se adaugă condiţia ca damele să nu se
atace( două dame se atacă dacă se află pe aceeaşi linie sau pe aceeaşi coloană sau
pe aceeaşi diagonală) Se va modifica şi funcţia de tipărire.

#include <iostream.h>
int t[20],n;

void tipar()
{for(int i=1;i<=n;i++)
cout<<t[i];
cout<<endl;}

void perm(int k)
{int i,j,corect;
if (k==n+1) tipar();
else {for(i=t[k]+1;i<=n;i++)
{ t[k]=i;
corect=1;
for(j=1;j<=k-1;j++)
if(t[j]==t[k] )
corect=0;
if (corect) perm(k+1);}}
t[k]=0;}

void main()
{cout<<”n=”;
cin>>n;
perm(1);}

Activitatea de învăţare 2.12 Partiţii

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să deduci modul de funcţionare a funcţiei recursive din program care
calculează partiţia numărului dat.
Să fii capabil să înţelegi necesitatea celor doi parametri din funcţia recursivă şi
semnificaţia lor.
Să fii capabil să observi de ce ajungem cu siguranţă la soluţie.
Să fii capabil să determini ce face programul pentru o dată de intrare specificată.

Durata: 15 minute

Tipul activităţii: Observare sistematică şi independentă


Sugestii
Activitatea se poate face individual sau pe grupe la clasă.
Sarcina de lucru
Se dă programul de mai jos, care citeşte n natural şi tipăreşte toate modurile de
descompunere a lui ca sumă de numere naturale. Care este modul de funcţionare a
funcţiei recursive din program care calculează partiţia numărului dat, care este
semnificaţia celor doi parametri din această funcţie şi de ce se ajunge sigur la soluţie?
Pentru n=4 ce se afişează?

#include <iostream.h>
int s[20],n;

void tipar(int k)
{for(int i=1;i<=k;i++)
cout<<s[i];
cout<<endl;}

void part(int k, int v)


{int i;
s[k]=v;
tipar(k);
for(i=1;i<=s[k]-1;i++)
{s[k]=s[k]-i;
part(k+1,i);
s[k]=s[k]+i;}}

void main()
{cout<<”n=”;
cin>>n;
part(1,n);}
Fişa de documentare 2.5 Algoritmi iterativi şi recursivi

Axioma
S-a demonstrat matematic că orice algoritm recursiv poate fi scris iterativ, şi reciproc.
Activitatea de învăţare 2.13 Metode iterative şi recursive

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să găseşti legătura între părţile precizate.
Să fii capabil să recunoşti definiţiile specificate.

Durata: 15 minute

Tipul activităţii: Împerechere

Sugestii
Activitatea se poate face individual, un elev la câte un calculator, folosind fişa de lucru.
Activitatea se poate face şi pe grupe sau în perechi.

Sarcina de lucru
Se dau următoarele tipuri de informaţii: 1.iteraţie, 2.recursiv, 3.metodă, 4. subprogram,
5. programare.
Să se împerecheze corespunzător cu următoarele enunţuri: a. parte a unui program.
b. ansamblu de mijloace socotite proprii pentru realizarea unui scop; mod de executare
a unui lucru.
c. care poate fi repetat în mod nelimitat.
d. repetare a unui anumit procedeu de calcul prin aplicarea lui la rezultatul calculului din
etapa precedentă.
e. operaţia de elaborare a programului în vederea rezolvării unei probleme cu
calculatorul electronic.

Activitatea de învăţare 2.14 Tratare comparativă

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să transformi o definiţie recursivă intr-un algoritm iterativ.
Să fii capabil să găseşti asemănări între metoda iterativă şi recursivă.
Să fii capabil să găseşti diferenţe între metodele iterativă şi recursivă.

Durata: 15 minute

Tipul activităţii: Asemănări şi diferenţe

Sugestii
Activitatea se poate face individual sau pe grupe, la teorie, respectiv laborator.
Sarcina de lucru
Să se studieze cele două metode de rezolvare, iterativă şi recursivă, făcându-se o
tratare comparativă a lor pentru algoritmul lui Euclid:

a , a  b

Cmmdc(a,b)= 
cmmdc ( a  b, b ), a

cmmdc ( a , b  a ) , a


b
b
Tema 3. Avantajele şi dezavantajele recursivităţii
Fişa de documentare 3.1 Eliminarea recursivităţii

Avantaje
De multe ori, soluţia unei probleme poate fi elaborată mult mai uşor, mai clar şi mai
simplu de verificat, printr-un algoritm recursiv.

Dezavantaje
Varianta recursivă poate duce la timp de execuţie şi spaţiu de memorie prea mari,
transformarea în una nerecursivă, eliminând aceste dezavantaje.

Se va utiliza una din metodele de eliminare a recursivităţii ce foloseşte o structură de


date de tip stivă. În scrierea unei variante nerecursive, trebuie parcurşi toţi paşii implicaţi
în varianta recursivă, prin tehnici nerecursive.

Din aplicaţiile prezentate în fişele 2.1 şi 2.5 se observă diferenţele dintre cele două
metode de rezolvare astfel:
Avantajul recursivităţii constă în faptul că soluţile recursive sunt mult mai clare , mai
scurte şi mai uşor de urmărit, deci mult mai elegante. Ele sunt mult mai avantajoase
decât cele iterative dacă:
 Soluţiile problemei sunt definite recursiv;
 Cerinţele problemei sunt formulate recursiv;

În unele cazuri este foarte greu de definit o soluţie iterativă , cum este cazul algoritmilor
în care o funcţie recursivă apelează o altă funcţie recursivă care depinde de prima
funcţie (recursivitate indirectă) şi atunci în mod obligatoriu este preferabil algoritmul
recursiv.

Activitatea de învăţare 3.1 Şirul lui Fibonacci

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să enumeri dezavantajul folosirii recursivităţii în acest caz.
Să fii capabil să găseşti varianta ce elimină dezavantajele metodei recursive.

Durata: 30 minute
Tipul activităţii: Cubul

Sugestii
Activitatea se face pe 6 grupe la clasă, sau individual.
Sarcina de lucru
Problemă nostimă:
Câte perechi de iepuri se pot obţine în n luni dintr-o singură pereche ştiind că:
- la momentul iniţial, iepurii din prima pereche sunt nou-născuţi;
- fiecare nouă pereche de iepuri devine fertilă după o lună;
- fiecare pereche produce o pereche de descendenţi în fiecare lună;
- nici un iepure nu moare.
Numărul perechilor de iepuri din fiecare lună este descris de şirul:

Luna 0 1 2 3 4 5 6 7 8 …….
Nr. perechi 1 1 2 3 5 8 1 2 3 ………
Fiecare grupă va rezolva cerinţa fiecărei feţe.
Faţa 1: ce tip de problemă este?
Faţa 2: scrie formula ce rezolvă problema.
Faţa 3: ce variante avem pentru rezolvare?
Faţa 4: scrie varianta cea mai avantajoasă.
Faţa 5: argumentează alegerea variantei.
Faţa 6: enumeră un dezavantaj al variantei neutilizate.

Activitatea de învăţare 3.2 Recursivitate indirectă

Competenţa:
Aplică principiile recursivităţii şi iterativităţii în rezolvarea problemelor

Obiectivul vizat:
Să fii capabil să elaborezi programul ce rezolvă cerinţa problemei date.
Să fii capabil să enumeri necesitatea folosirii recursivităţii în acest caz.

Durata: 45 minute

Tipul activităţii: Problematizare

Sugestii
Activitatea se poate face individual, în perechi sau pe grupe la laborator.
Sarcina de lucru
Se consideră şirurile definite recurent astel:
a0=a; b0=b; a,b>0:
a  bn 1
a n  n 1 , bn  a n 1bn 1
2
Să se scrie un program care să citească a,b şi n şi să se calculeze an şi bn.(Dacă două
şiruri sau mai multe se apelează reciproc avem recursivitate indirectă sau încrucişată.)
Tema 4. Tehnica de programare Divide et Impera
Fişa de documentare 4.1 Descriere generală

Divide et impera este o tehnică specială prin care se pot rezolva anumite probleme.

Tehnica Divide et Impera constă în două mari etape:

 Divide. Problema dată este împărţită în două sau mai multe subprobleme de
acelaşi tip, dar de dimensiuni mai mici. Subproblemele se rezolvă direct, dacă
dimensiunea lor permite aceasta (cazuri elementare), sau, fiind de acelaşi tip, se
rezolvă în mod recursiv, prin acelaşi procedeu.
 Impera. Se combină soluţiile subproblemelor pentru a obţine soluţia problemei
iniţiale.

Restricţii
Tehnica Divide et Impera se poate aplica în rezolvarea unei probleme care îndeplineşte
următoarele condiţii :
- se poate descompune în ( două sau mai multe) subprobleme ;
- aceste subprobleme sunt independente una faţă de alta (o subproblemă nu se rezolvă
pe baza alteia şi nu se foloseşte de rezultatele celeilalte);
- aceste subprobleme sunt similare cu problema iniţială;
- la rândul lor subproblemele se pot descompune (dacă este necesar) în alte
subprobleme mai simple;
- aceste subprobleme simple se pot soluţiona imediat prin algoritmul simplificat.

Numărul problemelor care se rezolvă prin această metodă este relativ mic, tocmai
datorită restricţiilor de mai sus.

Pentru a intui funcţionarea algoritmului luăm ca exemplu un turneu de tenis. Participanţii


sunt împărţiţi în două grupe, se organizează turneul în cadrul fiecărei grupe, iar finala se
va disputa între cei doi câştigători ai turneului pe grupe. Câştigătorul finalei este
câştigătorul întregului turneu. Organizarea turneului pe grupe se face după acelaşi
procedeu: se împart concurenţii din cadrul grupei pe semigrupe, se organizează turneul
pe semigrupe, iar câştigătorul grupei se decide într-un meci de semifinală între cei doi
câştigători din cele două semigrupe ş.a.m.d. Împărţirea se repetă până când avem doar
doi jucători, care joacă un meci “direct”.

Schema generală
Tehnica Divide et Impera admite o implementare recursivă, deoarece subproblemele
sunt similare problemei iniţiale, dar de dimensiuni mai mici.
Principiul fundamental al recursivităţii este autoapelarea unui subprogram când acesta
este activ; ceea ce se intamplă la un nivel, se intamplă la orice nivel, având grijă să
asigurăm condiţia de terminare a apelurilor repetate. Asemănător se intâmplă şi în cazul
tehnicii Divite et Impera ; la un anumit nivel sunt doua posibilităţi:
 s-a ajuns la o (sub)problemă simplă ce admite o rezolvare imediată, caz în care
se rezolvă (sub)problema şi se revine din apel (la subproblema anterioară, de
dimensiuni mai mari);
 s-a ajuns la o (sub)problemă care nu admite o rezolvare imediată, caz în care o
descompunem în două sau mai multe subprobleme şi pentru fiecare din ele se
continuă apelurile recursive (ale funcţiei).

În etapa finală a tehnicii Divide et Impera se produce combinarea subproblemelor


(rezolvate deja) prin secvenţele de revenire din apelurile recursive.

Etapele tehnicii Divide et Impera sunt:

Identificarea dimensiunii subproblemelor


În general un subprogram Divide et Impera se aplică unui tablou (vector) V = <v 1,...,vn>
(V[1..n], n=dim[V]), asupra căruia vrem să aplicăm o operaţie oarecare (sortare,
determinarea valorii maxime, determinarea cmmdc, etc).

Identificarea modalităţii de împărţire în subprobleme


În acest caz se execută împărţirea în două subprobleme de dimensiuni aproximativ
egale şi anume [n/2] . Împărţirea în subprobleme are loc până când dimensiunea
acestora devine suficient de mică pentru a fi rezolvate în mod direct (cazul de bază).

Rezolvarea subproblemelor
Se rezolvă subproblema directă.

Combinarea soluţiilor
După rezolvarea celor două subprobleme se execută faza de combinare a rezultatelor
în vederea rezolvării întregii probleme. Se face prin interclasarea soluţiilor.

Subprogramul divide
Subprogram DivImp(V,p,q)
      Daca q-p <= 1 atunci  Rezolva(V,p,q)
               altfel  m=(p+q) div 2
                         DivImp(V,p,m)
                         DivImp(V,m+1,q)
                         Combina(V,p,m,q)
      Sf_Daca
Sf_subprogram.

Apelul subprogramului
Iniţial p=1, q=n, rezultă DivImp(V,1,n).

Activitatea de învăţare 4.1 Divide et Impera


Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să precizezi etapele tehnicii Divide et Impera.
Să fii capabil să explici rolul funcţional al fiecărei etape.

Durata: 15 minute

Tipul activităţii: Diagrama păianjen

Sugestii
Activitatea se poate face individual sau pe grupe mici ( 2 – 3 elevi ), la clasă.
Sarcina de lucru
Realizaţi o modalitate de a organiza informaţiile necesare tehnicii Divide et Impera,
ţinându-se cont de rolul lor în cadrul ei.
Fişa de documentare 4.2 Aplicaţii practice

Exemplu : Maximul dintr-un vector


Se citeşte un vector cu n componente, numere naturale. Se cere să se tipărească
valoarea maximă din şir.

Trebuie tiparită valoarea maximă dintre numerele reţinute în vector de la i la j (iniţial i=


1, j=n). Pentru aceasta procedăm astfel :
 daca i=j, valoarea maximă va fi v[i] ;
 contrar vom împărţi vectorul în doi vectori (primul vector va conţine
componentele de la i la (i+j) div 2, al doilea va conţine componentele de la ((i+j)
div 2 +1 la j ) , rezolvăm subproblemele (aflăm maximul pentru fiecare din ele) iar
soluţia problemei va fi dată de valoarea maximă dintre rezultatele celor două
subprobleme.
#include<iostream.h>
int v[10],n;

int max(int i ,int j)


{ int a,b;
if (i==j) return v[i] ;
else
{ a=max(i, (i+j)/2);
b=max((i+j)/2+1,j);
if (a>b) return a;
else return b;
}
}

main( )
{ cout<<”n=”;cin>>n;
for (int i=1;i<=n;i++)
{cout<<”v[“<<i<<”]=”;cin>>v[i]; }
cout<<”max=”<<max(1,n);
}

Activitatea de învăţare 4.2 Maximul dintr-un şir

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să descrii pas cu pas algoritmul din fişa de documentare 4.2.
Să înţelegi algoritmul ce descrie tehnica Divide et Impera.

Durata: 15 minute
Tipul activităţii: Urmează paşii

Sugestii : Elevii se pot organiza în grupe mici ( 2-3 elevi) sau pot lucra individual

Sarcina de lucru
Urmând exemplul din fişa de documentare 4.2 să se descrie pas cu pas algoritmul
prezentat pentru şirul 89, 10, 11, 23, -1, 78, 4. Care este numărul de comparări?

Activitatea de învăţare 4.3 Căutare binară

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să compari timpul de obţinere a rezultatului cu tehnica Divide et Impera
faţă de alte metode.
Să înţelegi şi însuşeşti algoritmul prezentat.

Durata: 45 minute

Tipul activităţii: Expansiune

Sugestii: Elevii vor lucra individual fiecare la un calculator

Sarcina de lucru:
Se citeşte un vector cu n componente numere întregi, ordonate crescător şi o valoare
întreagă - nr. Să se decidă dacă nr se găseşte sau nu printre numerele citite, iar în caz
afirmativ să se tipărească indicele componentei care conţine acea valoare (Căutare
binară).

Problema este de a decide dacă valoarea căutată se găseste printre numerele de


indice cuprins între i şi j (iniţial i=1, j=n ). Pentru aceasta vom proceda astfel:
 dacă valoarea nr coincide cu valoarea de indice (i+j)/2 ( valoarea de la mijloc ) ,
se tipăreşte indicele şi se revine din apel (problema a fost rezolvată).
 Contrar, dacă i<j (nu s-a căutat peste tot) problema se descompune astfel:
- dacă număul este mai mic decât valoarea testată (din mijloc), înseamnă
că avem şanse să-l găsim între componentele cu indicele între i şi (i+j)/2-1
caz în care reapelăm funcţia cu aceşti parametri.
- dacă numărul este mai mare decât valoarea testată (din mijloc), înseamnă
că avem şanse să-l găsim între componentele cu indicele între (i + j)/2+1
şi j , caz în care reapelăm funcţia cu aceşti parametri.
Problema nu se descompune în altele care se rezolvă, după care nu se compară
soluţia, ci se reduce la o subproblemă. În linii mari , acest raţionament este de tip Divide
et Impera.

Activitatea de învăţare 4.4 Sortarea prin interclasare

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să înţelegi şi însuşeşti algoritmul prezentat.
Să fii capabil să determini numărul maxim de comparaţii.

Durata: 45 minute

Tipul activităţii: Observare sistematică şi independentă

Sugestii: Elevii vor lucra individual fiecare la un calculator

Sarcina de lucru:

Se consideră vectorul a cu n componente numere întregi ( sau reale ). Să se sorteze


crescător, utilizând sortarea prin interclasare. Care este numărul maxim de comparaţii?

Algoritmul de sortare prin interclasare se bazează pe următoarea idee: pentru a


sorta un vector cu n elemente îl împăţim în doi vectori care, odată sortaţi, se
interclasează.
Conform strategiei Divide et Impera, problema este descompusă în alte două
subprobleme de acelaşi tip şi, după rezolvarea lor, rezultatele se combină (în particular
se interclasează). Descompunerea unui vector în alţi doi vectori care urmează a fi
sortaţi are loc până când avem de sortat vectori de una sau două componente.

În aplicaţie, funcţia sort sortează un vector cu maximum două elemente; funcţia interc
interclasează rezultatele; divimp implementează strategia generală a tehnicii studiate.

#include<iostream.h>
int a[10],n;
void sort (int p,int q, int a[10] )
{
int m;
if (a[p]>a[q])
{
m=a[p];
a[p]=a[q];
a[q]=m;}
}
void interc (int p,int q, int m, int a[10])
{
int b[10],i,j,k;
i=p; j=m+1; k+1;

while ((i<m) && (j<=q))


if (a[i]<=b[j] c[k]=a[i++]
else c[k++]=b[j++]
if (i<=m)
for (j=1;j<=m;j++) c[k++]=a[j]
else
for (i=j;i<=q;i++) c[k++]=b[i]

void divimp (int p, int q, int a[10])


{
int m;
if ((q-p)<=1) sort (p,q,a);
else
{ m=(p+q)/2;
divimp(p,m,a);
divimp(m+1,q,a);
interc(p,q,m,a);
}
}
void main ( )
{ int i ;
cout<<”n=”;cin>>n;
for (i=1;i<=n;i++)
{
cout<<”a[“<<i<<”]=”;cin>>a[i];}
divimp(1,n,a);
for (i=1;i<=n;i++) cout<<a[i]<<” “;
}

Activitatea de învăţare 4.5 Turnurile din Hanoi

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să determini o formulă recursivă pentru problema dată.
Să exemplifici pentru un n dat, ordinea mutărilor.
Să fii capabil să scrii programul corespunzător.

Durata: 35 minute
Tipul activităţii: Problematizare
Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Se dau 3 tije simbolizate prin a,b,c. Pe tija a se găsesc n discuri de diametre diferite,
aşezate în ordine descrescătoare a diametrelor privite de jos în sus. Se cere să se mute
de pe tija a pe b, utilizând ca tijă intermediară tija c, respectând următoarele reguli:
 la fiecare pas se mută un singur disc ;
 nu este permis să se aşeze un disc cu diametrul mai mare peste un disc cu
diametrul mai mic.

Se observă că în cazul în care n>2, problema se complică. Notăm cu H(n,a,b,c)


şirul mutărilor celor n discuri de pe tija a pe tija b , utilizând ca tijă intermediară, tija c.
Conform strategiei Divide et Impera încercăm să descompunem problema în alte două
subprobleme de acelaşi tip, urmând apoi combinarea soluţiilor. În acest sens, observăm
că mutarea celor n discuri de pe tija a pe tija b, utilizând ca tijă intermediară tija c, este
echivalentă cu:
 mutarea a n-1 discuri de pe tija a pe tija c , utilizând ca tijă intermediară tija b;
 mutarea discului rămas pe tija b;
 mutarea a n-1 discuri de pe tija c pe tija b , utilizând ca tijă intermediară tija a.
Tema 5. Tehnica de programare Backtracking
Fişa de documentare 5.1 Descrierea tehnicii standard (iterativ)

Această tehnică se foloseşte în rezolvarea problemelor care îndeplinesc simultan


următoarele condiţii:
- soluţia lor poate fi pusă sub forma unui vector S=x 1,x2, ...,xn, cu x1 € A1, x2 €
A2 ,...,xn € An;
- mulţimile A1, A2 , …., An sunt mulţimi finite, iar elementele lor se consideră că se
află într-o relaţie de ordine bine stabilită;
- nu se dispune de o altă metodă de rezolvare, mai rapidă;
- x1 x2 …, xn pot fi la rândul lor vectori;
- A1, A2 …, An pot coincide.

Tehnica Backtracking are la bază un principiu extrem de simplu:


- se construieşte soluţia pas cu pas: x1, x2 …,xn
- dacă se constată că, pentru o valoare aleasă, nu avem cum să ajungem la
soluţie, se renunţă la acea valoare şi se reia căutarea din punctul în care am rămas.

Concret:
- se alege primul element x1, ce aparţine lui A1;
- presupunând generate elementele x1,x2 …,xk , aparţinând mulţimilor A1,
A2 …,Ak , se alege (dacă există) xk+1 , primul element disponibil din mulţimea A k+1. Apar
două posibilităţi :
1) Nu s-a găsit un astfel de element, caz în care se reia căutarea considerând
generate elementele x1,x2 …,xk+1 , iar aceasta se reia de la următorul element al
mulţimii Ak rămas netestat;
2) A fost găsit, caz în care se testează dacă acesta îndeplineşte anumite condiţii
de continuare apărând astfel două posibilităţi:
- îndeplineşte, caz în care se testează dacă s-a ajuns la soluţie şi apar din nou
două posibilităţi:
- s-a ajuns la soluţie, se tipăreşte soluţia şi se reia algoritmul considerând
generate elementele x1,x2 …,xk , (se caută în continuare, un alt element al mulţimii A k ,
rămas netestat);
- nu s-a ajuns la soluţie, caz în care se reia algoritmul considerând generate
elementele x1,x2 …,xk , şi se caută un prim element xk+2 € Ak.
- nu le îndeplineşte, caz în care se reia algoritmul considerând generate
elementele x1,x2 …,xk , iar elementul xk-1 se caută între elementele mulţimii A, rămase
netestate.
Algoritmul se termină atunci când nu există nici un element x 1 € A1 netestat.

Observaţie: tehnica Backtracking are ca rezultat obţinerea tuturor soluţiilor problemei.


În cazul în care se cere o sigură soluţie se poate forţa oprirea, atunci când aceasta a
fost găsită.

Am arătat că orice soluţie se generează sub formă de vector. Vom considera că


generarea soluţiilor se face intr-o stivă. Astfel, x 1 € A1, se va găsi pe primul nivel al
stivei, x2 € A2 se va găsi pe al doilea nivel al stivei,..., x k € Ak se va găsi pe nivelul k al
stivei. În acest fel, stiva (notată ST) va arăta astfel:
xk

ST

Nivelul k+1 al stivei trebuie iniţializat (pentru a alege, în ordine,


elementele mulţimii k+1 ).
x2 Iniţializarea trebuie făcută cu o valoare
aflată (în relaţia de ordine considerată, pentru mulţimea A k+1 ) înaintea
tuturor valorilor posibile din x1 mulţime. De exemplu, pentru generarea
permutărilor mulţimii {1,2.....n}, orice nivel al stivei va lua valori de la 1 la n.
Iniţializarea unui nivel (oarecare) se face cu valoarea 0. Funcţia de iniţializare o vom
numi init().
Găsirea următorului element al mulţimii Ak (element care a fost netestat) se face cu
ajutorul funcţiei am_succesor(). Variabila as este o variabilă booleană. În situaţia în
care am găsit elementul, acesta este pus în stivă şi as ia valoarea TRUE, contrar (nu a
rămas un element netestat) as ia valoarea FALSE.
Odată ales un element, trebuie văzut dacă acesta îndeplineşte condiţiile de continuare
(altfel spus, dacă elementul este valid). Acest test se face cu ajutorul funcţiei e_valid().
Testul dacă s-a ajuns sau nu la soluţia finală se face cu ajutorul funcţiei solutie(), iar o
soluţie se tipăreşte cu ajutorul funcţiei tipar(). Prezentăm în continuare rutina back():

void back () {
int as;
k=1;
init();
while (k>0)
{
do {} while ((as=am_succesor()) && !e_valid());
if (as)
if (solutie()) tipar();
else {k++; init();}
else k--;
}
}

Activitatea de învăţare 5.1 Rutina de backtracking

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să precizezi funcţiile subrutinei back.
Să fii capabil să explici rolul fiecărei funcţii din subrutina back.

Durata: 15 minute
Tipul activităţii: Harta tip traseu
Sugestii: Elevii vor lucra individual sau pe grupe la teorie.

Sarcina de lucru:
Să realizezi o hartă tip traseu pornind de la tehnica Backtracking în care să se
regăsească toate funcţiile componente rutinei back, ţinând cont de rolul avut de acestea
în cadrul metodei.

Activitatea de învăţare 5.2 Problema damelor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să identifici ce reprezintă ce pui pe stivă şi ce reprezintă nivelul stivei
pentru problema dată.
Să fii capabil să scrii conţinutul funcţiilor ce apar în rutina back, relativ la problema
damelor.

Durata: 20 minute

Tipul activităţii: Rezumare


Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Fiind dată o tablă de şah, de dimensiune n x n, se cere să se scrie conţinutul funcţiilor
standard din rutina back ce generează toate soluţiile de aranjare a n dame, astfel încât
să nu se afle două dame pe aceeaşi linie, coloană sau diagonală (damele să nu se
atace ). Precizaţi ce punem pe stivă şi ce reprezintă nivelul stivei în acest caz, precum
şi funcţiile programului.
Fişa de documentare 5.2 Aplicaţii practice

Se exemplifică mai întâi problemele de bază, din care, prin mici modificări, se obţin
probleme mai complexe. Se foloseşte metoda Backtracking standard ( cu funcţiile
prezentate în fişa 5.1 de la tema 5).

Activitatea de învăţare 5.3 Generarea permutărilor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să înţelegi algoritmul prezentat.
Să fii capabil să exemplifici pe algoritm pentru o valoare mică dată lui n.
Să fii capabil să identifici condiţia de oprire a algoritmului

Durata: 25 minute

Tipul activităţii: Studiul de caz


Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Se citeşte un număr natural n. Să se genereze toate permutările mulţimii {1,2,…,n}.
Generarea permutărilor se face ţinând cont că orice permutare va fii alcătuită din
elemente distincte ale mulţimii A={1,2,..,n}. Exemplifică pentru n=3 pe programul de mai
jos. Până când se continuă algoritmul?

#include<iostream.h>
int st[10],n,k;
void init()
{ st[k]=0;}
int am_succesor()
{ if (st[k]<n)
{ st[k]++;
return 1;}
else
return 0;}
int e_valid()
{ for(int i=1;i<k;i++)
if (st[i]==st[k])
return 0;
return 1;}
int solutie()
{ return k==n;}
void tipar()
{ for(int i=1;i<=n;i++)
cout<<st[i];
cout<<endl;}
void back()
{ int as;
k=1;init();
while(k>0)
{ do{} while((as=am_succesor()) && !e_valid());
if(as)
if(solutie()) tipar();
else
{ k++;
init();}
else k--;
}}
main()
{ cout<<"n=";
cin>>n;
back();
}

Activitatea de învăţare 5.4 Generarea aranjamentelor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să determini asemănări şi deosebiri între algoritmul de generare a
permutărilor şi cel al aranjamentelor.
Să fii capabil să modifici un program pentru a rezolva un alt tip de problemă
asemănător.

Durata: 15 minute
2
1 3
P
Tipul activităţii: Transformare
Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Se citesc n şi p. Să se genereze toate aranjamentele de n luate câte p. Care sunt
asemănarile şi deosebirile cu generarea permutărilor?

Activitatea de învăţare 5.5 Generarea combinărilor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să scrii corect un program cu tehnica Backtracking standard.
Să fii capabil să găseşti un algoritm cu care se aseamănă.

Durata: 25 minute

Tipul activităţii: Problematizare

Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Se citesc n şi p numere naturale, n ≥ p. Se cere să se genereze toate submulţimile cu p
elemente ale mulţimii {1,2,...,n}.
Pentru rezolvarea problemei trebuie ţinut cont de următoarele:
 Stiva are inalţimea p
 Elementele aflate pe niveluri diferite ale stivei trebuie să fie distincte.
 Pentru a evita repetiţia, elementele se aşează în ordine crescătoare: pe nivelul
k, se va afla o valoare mai mare decat pe nivelul k-1 şi mai mică sau egală cu
n-p+k.

Felicitări dacă ai observant că nu are rost să apelezi e_valid ().

Activitatea de învăţare 5.6 Problema colorării hărţilor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să înţelegi şi să-ţi însuşeşti algoritmul prezentat.
Să fii capabil să exemplifici pe algoritm pentru o valoare dată n.

Durata: 25 minute

Tipul activităţii: Studiu de caz


Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Fiind dată o hartă cu n ţări, se cer toate soluţiile de colorare a hărţii, utilizând cel mult 4
culori, astfel încât 2 ţări cu frontiera comună să fie colorate diferit. Este demonstrat
matematic faptul că sunt suficiente numai 4 culori pentru ca orice hartă să fie colorată
astfel.

4
3

2
5

Pentru exemplificare, vom considera harta de mai sus unde ţările sunt numerotate cu
cifre cuprinse între 1 şi 5:

An , n
Harta este furnizată programului cu ajutorul unei matrice (tablou) .
1, tara i are frontiera cu tara j
A(i , j )  
0, altfel

Matricea A este simetrică. Pentru rezolvarea problemei se utilizează stiva st , unde


nivelul k al stivei simbolizează ţara k, iar st[k] culoarea ataşată ţarii k. Stiva are
înălţimea n şi pe fiecare nivel ia valori intre 1 şi 4.

#include<iostream.h>
int st[10],a[20][20],n,k;
void init()
{st[k]=0;}

int am_succesor()
{if(st[k]<4)
{st[k]++;
return 1;}
else return 0; }

int e_valid()
{for(int i=1;i<=k-1;i++)
if(st[i]==st[k] && a[i][k]==1) return 0;
return 1; }

int solutie()
{return k==n;}
void tipar()
{cout<<"Varianta"<<endl;
for(int i=1;i<=n;i++) cout<<"Tara"<<i<<"culoarea"<<st[i]<<endl;
cout<<endl; }

void back()
{int as;
k=1;Init();
while(k>0)
{ do {} while ((as=am_succesor()) && !e_valid());
if (as)
if (solutie()) tipar();
else {k++;Init();}
else k--; } }

main()
{cout<<"Numar de tari";cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=i-1;j++)
{cout<<"a["<<i<<","<<j<<"]=";cin>>a[i][j];
a[j][i]=a[i][j]; }
back(); }

O soluţie a acestei probleme este următoarea:


 Ţara 1 – culoarea 1
 Ţara 2 – culoarea 2
 Ţara 3 – culoarea 1
 Ţara 4 – culoarea 3
 Ţara 5 – culoarea 4
Care sunt următoarele două soluţii?

Activitatea de învăţare 5.7 Problema comis- voiajorului

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să scrii corect un program cu tehnica Backtracking standard.
Să fii capabil să identifici un algoritm cu care se aseamănă.
Să fii capabil să implementezi algoritmul găsit.

Durata: 25 minute

Tipul activităţii: Exerciţiul practic

Sugestii: Elevii vor lucra individual sau pe grupe la laborator.

Sarcina de lucru:
Un comis-voiajor trebuie să viziteze un număr de n oraşe. Iniţial, acesta se află într-unul
dintre ele, notat 1. Comis-voiajorul doreşte să nu treacă de două ori prin acelaşi oraş,
iar la intoarcere sa revină în oraşul 1. Cunoscând legăturile existente între oraşe, se
cere să se tipărească toate drumurile posibile pe care le poate efectua comis-voiajorul.
În figura de mai jos sunt simbolizate, pentru n=6, cele 6 oraşe, precum şi drumurile
existente între ele.

2 3

1
4

6 5

Comis-voiajorul are următoarele posibilităţi de parcurgere:


 1,2,3,4,5,6,1
 1,2,5,4,3,6,1
 1,6,3,4,5,2,1
 1,6,5,4,3,2,1
Tema 5. Tehnica de programare Backtracking
Fişa de documentare 5.3 Backtracking recursiv.

În fişa suport 5.1 am prezentat tehnica Backtracking clasic, iterativ, iar în fişa suport 5.2
am rezolvat câteva probleme cu această tehnică. Pentru tehnica Backtracking recursiv,
soluţiile finale st[i] sunt generate în cadrul funcţiei back_recursiv(int k), unde k
reprezintă nivelul până la care s-a ajuns pe stivă. Adică la fiecare execuţie din lanţul de
auto-apeluri, funcţia back_recursiv tratează nivelul k al stivei.

Algoritmul recursiv de backtracking este prezentat mai jos în limbajul pseudocod.


back_recursiv( int k)
pentru contor de la <v1> la <vn> execută
st[k]←contor
dacă valid(k) atunci dacă<soluţia este finală> atunci apel tipar
altfel auto-apel back_recursiv(k+1)
sfârşit dacă
sfârşit dacă
sfârşit pentru

Întrun ciclu, prin variabila contor vor trece pe rând toate valorile din intervalul <v1> la
<vn> care ar putea fi încercate pe nivelul k al stivei. La fiecare pas al ciclului, pentru
fiecare dintre valorile variabilei contor:
 Se memorează pe nivelul k valoarea contor prin st[k]←contor. Se obţine astfel
soluţia parţială(st[1],st[2],…,st[k]).
 Se verifică dacă această soluţie este validă prin funcţia valid(k). Dacă da atunci
se verifică dacă soluţia este finală :
- Dacă este soluţie finală atunci se apelează funcţia tipar;
- În caz contrar, avem o soluţie validă dar care nu este şi finală.Vom .
urca la nivelul următor în stivă prin apelul back_recursiv(k+1).
Algoritmul se reia de lacapăt, dar cu k+1 în loc de k.

Activitatea de învăţare 5.8 Problema damelor rezolvată recursiv

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să înţelegi şi să-ţi însuşeşti algoritmul de backtracking recursiv prezentat.
Să determini modul de iniţializare al stivei, găsirea succesorului şi ajungerea la soluţie.
Să fii capabil să exemplifici pe algoritm pentru o valoare dată n.

Durata: 35 minute

Tipul activităţii: Studiu de caz


Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.
Sarcina de lucru:
Se cere găsirea tuturor soluţiilor de aşezare pe tabla de şah de n linii şi n coloane a n
dame, astfel încât ele să nu se atace. Se consideră că ele se atacă dacă sunt pe
aceeaşi linie, coloană sau diagonală. Exemplificaţi pentru n=4. Cum se face
iniţializarea, cum se găseşte un successor şi cum se ajunge la soluţie?
Varianta recursivă este următoarea:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define nmax 10
int n; /*dimensiunea (ordinul) tablei de şah */
int nr_solutie;
int x[nmax];
int valid(int k)
{
/*testează condiţiile de continuare */
int p;
for(p=1;p<=k-1;p++)
if((x[k]==x[p]) || (abs(k-p) == abs(x[k]-x[p]))) return 0;
return 1;
}
void back_recursiv(int k)
{
int i,j,p;
for(j=1;j<=n;j++)
{
x[k]=j;
if(valid(k)==1)
if(k<n) back_recursiv(k+1);
else {
/*tipărirea soluţiei */
nr_solutie++;
cout<<"\nSOLUTIA nr. " <<nr_solutie);
for(i=1;i<=n;i++)
{
for(p=1;p<=n;p++)
if(x[i]==p) cout<<"1";
else cout<<0<<endl;
};
getch();
}
}
}
void main()
{
cout<<"\nOrdinul tablei de sah n=";
cin>>n;
nr_solutie=0;
back_recursiv(1);
cout<<"\nSFARSIT\n";
}
Activitatea de învăţare 5.9 Probleme rezolvate recursiv

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să identifici probleme a căror rezplvare necesită tehnica Backtracking recursiv.
Să fii capabil să aplici tehnica Backtracking recursiv.
Să identifici algoritmul de rezolvare.
Să implementezi algoritmul găsit.
Să găseşti date de intrare corespunzătoare tuturor cazurilor problemei pentru testarea
programulului.

Durata: o săptămână

Tipul activităţii: Proiect


Sugestii: Elevii vor lucra individual sau pe grupe la laborator acasă sau la laborator.

Sarcina de lucru:
Să se realizeze un portofoliu de minim 7 probleme ce au ca algoritm de rezolvare
tehnica Backtracking recursiv. Se va urmări:
- concordanţă temă- realizare
- capacitate de analiză şi sinteză a informaţiei
- originalitate
- prezenţa comentariilor în program
- testarea datelor de intrare şI soluţiile obţinute
- lucrul în echipă
- design
- prezentarea proiectului
Tema 6. Tehnica de programare Greedy
Fişa de documentare 6.1 Descrierea tehnicii

Este practic imposibil să fie dată forma generală, a unei probleme rezolvabile cu tehnica
Greedy, totuşi.
Să considerăm o mulţime A cu n elemente. Se cere o submulţime a sa cu m<=n
elemente (în cazul m=n este importantă ordinea alegerii elementelor), astfel încât să fie
îndeplinite anumite condiţii (acestea diferă de la o problemă la alta).

Exemplu: se consideră o mulţime de n numere reale. Se cere o submulţime a sa, astfel


încât suma elementelor sale să fie maximă.
Pentru rezolvare, se va alege un prim element al mulţimii de numere reale. Dacă este
posibil, acesta va fi adăugat soluţiei, iniţial vide. Posibilitatea ca acesta să fie adăugat
este dată de semnul numărului (acesta trebuie să fie mai mare ca 0).
Se alege un al doilea număr, cu care se procedează în mod asemănătorş.a.m.d.
Algoritmul se încheie când au fost alese şi eventual adăugate toate elementele
mulţimii.

Pentru a rezolva o problemă cu Greedy, soluţia se construieşte, după regula: pentru


fiecare element care urmează să fie adăugat soluţiei finale, se efectuează o alegere a
sa din elementele mulţimii A (după un mecanism specific fiecărei probleme în parte), iar
dacă este posibil, acesta este adăugat. Algoritmul se termină fie când a fost găsită
soluţia cerută, fie când s-a constatat inexistenţa acesteia.
Intuitiv, alegem un element, al doilea,...până când obţinem ce dorim sau până când au
fost testate toate elementele mulţimii. De aici provine şi numele tehnicii, greedy (lacom).

Definiţie
Tehnica Greedy poate fi privită ca o particularizare a tehnicii Backtracking, în care se
renunţă la mecanismul de întoarcere.

 Ambele tehnici oferă soluţii sub formă de vector.


 Tehnica Backtracking poate oferi toate soluţiile problemei, în timp ce
tehnica Greedy oferă o singură soluţie.

Tehnica Greedy nu dispune de mecanismul întoarcerii, specific tehnicii Backtracking.


Aceasta este diferenţa esenţială dintre cele două tehnici, diferenţă care are consecinţe
uriaşe în ce priveşte aplicabilitatea lor.

Consecinţa 1.
Este necesar ca cel care elaborează un algoritm Greedy să ştie faptul că, procedând în
modul ales de el, ajunge la rezultatul dorit. Pentru fiecare problemă în parte, după ce se
identifică un algoritm, este obligatoriu să se demonstreze că acesta conduce la soluţia
optimă. Demonstraţia faptului că se ajunge la soluţia optimă este specifică fiecărei
probleme în parte.

Tehnica Greedy conduce la timp de calcul polinomial


Consecinţa 2.
Motivul care conduce la acest timp de calcul, ţine de mecanismul tehnicii. Să
presupunem că mulţimea din care se face alegerea are n elemente şi că soluţia are tot
n elemente (caz maxim). Se fac n alegeri, la fiecare alegere se fac n teste, rezultă un
algoritm cu timp O(n2).

Schema generală Greedy

 Selectarea elementelor ce formează soluţia


De multe ori, este necesar ca elementele mulţimii A să fie sortate, pentru ca apoi să
alegem din acestea, iar sortarea necesită un timp minim O(nxlog 2n). Însă sortarea se
efectuează la început.
Pentru cele mai multe probleme, nu se cunosc algoritmi Greedy.
 Generarea şi afişarea soluţiei.
Deoarece soluţia problemelor ce se rezolvă cu acestă tehnică este sub formă de vector,
acesta se completează pas cu pas şi apoi se afişează.

Avantajul tehnicii
Avantajul timpului polinomial, conduce la necesitatea utilizării tehnicii Greedy. Pentru
problemele pentru care nu se cunosc algoritmi care necesită timp polinomial, se caută
soluţii, chiar dacă nu optime, dar apropiate de acestea, dar care au fost obţinute în timp
util. Multe din aceste soluţii sunt obţinute cu Greedy.

Concluzii
Metoda rezolvă probleme de optim în care soluţia se construieşte pe parcurs. Optimul
global se determină prin estimări succesive ale optimului local. Dintr-o mulţime de
elmente A trebuie determinată o submulţime B, care verifică anumite condiţii şi care, de
obicei, este soluţia unei probleme de optimizare. Soluţia problemei se construieşte
treptat. Iniţial B este mulţimea vidă. Se adaugă în B succesiv elemente din A,
atingându-se de fiecare dată un optim local. Dar, această contruire nu asigură
întodeauna atingerea unui optim global. De aceea tehnica Greedy nu poate fi aplicată
decât dacă se demonstrează că modul de construire a mulţimii B duce la obţinerea unui
optim global.
Datorită modului de construire a soluţiei, tehnica se mai numeşte tehnica optimului
local.

Activitatea de învăţare 6.1 Exerciţii de fixare a cunoştinţelor teoretice

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să-ţi fixezi anumite informaţii prezentate.

Durata: 10 minute

Tipul activităţii: Completează spaţiile libere


Sugestii: Elevii vor lucra individual fiecare pe caiet la clasă.
Sarcina de lucru:
Să se completeze spaţiile libere din textul de mai jos, folosind noţiunile învăţate la fişa
de documentare 6.1.

Numele metodei Înseamnă ... .


Tehnica Greedy poate fi privită ca o particularizare a tehnicii ... în care se renunţă la
mecanismul de întoarcere.
Ambele tehnici oferă soluţii sub formă de ....
Tehnica Backtracking poate oferi ... soluţiile problemei, în timp ce tehnica Greedy
oferă ... soluţie.
Tehnica Greedy conduce la timp de calcul ....
Soluţiile se construiesc ... pas.
Pentru multe probleme .. se cunosc algoritmi Greedy.
Schema generală Greedy are prima etapă ... şi a doua etapă....

Activitatea de învăţare 6.2 Problema spectacolelor

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să înţelegi şi să-ţi însuşeşti algoritmul Greedy prezentat.
Să fii capabil să exemplifici pe algoritm pentru o valoare dată n.

Durata: 35 minute

Tipul activităţii: Studiu de caz


Sugestii: Elevii vor lucra individual fiecare la un calculator sau pe grupe la laborator.

Sarcina de lucru:
Într-o sală, într-o zi, trebuie planificate n spectacole. Pentru fiecare spectacol se
cunoaşte intervalul în care se desfăşoară:[st, sf]. Se cere să se planifice un număr
maxim de spectacole astfel încât să nu se suprapună. Exemplificaţi pentru n=5, cu
unele spectacole care au ora de terminare peste ora de început a altora.

Rezolvare
Fie o planificare optimă a spectacolelor(un număr maxim k de spectacole i 1,i2,...ik, unde
i1,i2,...ik є {1,2,..n} şi spectacolul ij are lor înaintea spectacolului i j+1).O astfel de
planificare îndeplineşte condiţia: spectacolul i j+1 începe după terminarea spectacolului ij.
O consecinţă imediată a condiţiei de mai sus este: spectacolul i j ia sfârşit înaintea
terminării spectacolului ij+1 (consecinţa nu implică un efort de gândire deosebit).
Vom construi o soluţie după următorul algoritm:
1) sortăm spectacolele după ora terminării lor;
2) primul spectacol programat este cel care se termină cel mai devreme;
3) alegem primul spectacol dintre cele care urmează în şir ultimului spectacol
programat, care îndeplineşte condiţia că începe după ce s-a terminat ultimul
spectacol programat;
4) dacă tentativa de mai sus a eşuat (nu am găsit un astfel de spectacol) algoritmul
se termină, altfel se programează spectacolul găsit şi algoritmul se reia de la
pasul 3.

Algoritmul de mai sus conduce la soluţia optimă(număr maxim de spectacole


programate).
Acest program se încadrează în tehnica Greedy pentru că: la un pas se alege un
spectacol cu ora de începere mai mare decât ora de terminare a ultimului spectacol
programat şi este adăugat soluţiei. Odată adăugat (programat) un spectacol, acesta
rămâne în cadrul soluţiei.

#include<iostream.h>
int s[2][10],o[10],n,I,h1,m1,h2,m2,ora;
void sortare()
{ int gata,m,i;
do
{ gata=1;
for(i=1;i<=n-1;i++)
if (s[1][o[i]]>s[1][o[i+1]])
{ m=o[i] ; o[i]=o[i+1]; o[i+1]=m;
gata=0;}
} while (!gata);
}

main()
{int i;
cout<<"n=";cin>>n;
for(i=1;i<=n;i++)
{o[i]=i;
cout<<"ora de inceput pentru spectacol "<<i<<" (hh mm)=";
cin>>h1>>m1;
s[0][i]=h1*60+m1;
cout<<"ora de sfarsit pentru spectacolul "<<i<<" (hh mm)=";
cin>>h2>>m2;
s[1][i]=h2*60+m2;
}
sortare();
cout<<"ordinea spectacolelor este"<<endl<<o[1]<<endl;
ora=s[1][o[1]];
for(i=2;i<=n;i++)
if (s[0][o[i]]>=ora)
{cout<<o[i]<<endl;
ora=s[i][o[i]];}
}

Activitatea de învăţare 6.3 Problema continuă a rucsacului

Competenţa:
Utilizează tehnicile de programare

Obiectivul vizat:
Să fii capabil să scrii un algoritm când se descrie modul de rezolvare al problemei.
Să fii capabil să implementezi algoritmul.
Să fii capabil să testezi programul pentru valori date.

Durata: 45 minute

Tipul activităţii: Exerciţiul practic


Sugestii: Elevii vor lucra individual sau pe grupe la laborator.

Sarcina de lucru:
O persoană are un rucsac cu care poate transporta o greutate maximă G. Persoana are
la dispoziţie n obiecte şi cunoaşte pentru fiecare obiect greutatea şi câştigul care se
obţine în urma transportului său la destinaţie. Se cere să se precizeze ce obiecte
trebuie să transporte persoana în aşa fel încât câştigul sa fie maxim ştiind că obiectele
se pot tăia.

Algoritmul este următorul:


• se calculează, pentru fiecare obiect în parte, eficienţa de transport rezultată prin
împărţirea câştigului la greutate (de fapt, acesta reprezintă câştigul obţinut prin
transportul unităţii de greutate);
• obiectele se sortează în ordine descrescătoare a eficienţei de transport şi se
preiau în calcul în această ordine;
• câştigul iniţial va fi 0, iar greutatea rămasă de încărcat va fi greutatea rucsacului;
• atât timp cât nu a fost completată greutatea maximă a rucsacului şi nu au fost
luate în considerare toate obiectele, se procedează astfel:
• dintre obiectele neîncărcate se selectează acela cu cea mai ridicată eficienţă de
transport şi avem două posibilităţi:
• acesta încape în totalitate în rucsac, deci se scade din greutatea rămasă de
încărcat greutatea obiectului, la câştig se cumulează câştigul datorat transportului
acestui obiect; se tipăreşte 1, în sensul că întregul obiect a fost încărcat;
• obiectul nu încape în totalitate în rucsac, caz în care se calculează ce parte din
el poate fi transportată, se cumulează câştigul obţinut cu transportul acestei părţi din
obiect, se tipăreşte procentul care s-a încărcat din obiect, iar greutatea rămasă de
încărcat devine 0.

Să se exemplifice pentru:
Greutatea care poate fi transportată cu ajutorul rucsacului aste 3
Avem la dispoziţie 3 obiecte. Greutatea şi câştigul pentru fiecare obiect sunt prezentate
mai jos:
III. Glosar
Algoritm: metodă sau o procedură de calcul, alcătuită din paşi elementari necesari
pentru rezolvarea unei probleme sau categorii de probleme.
Apel: chemare.
Backtracking: o tehnică de rezolvare a unor probleme ce au soluţia sub formă de
vector şi la care se cer toate soluţiile. Se construieşte soluţia pas cu pas x1,x2,…xn,
dacă se constată că pentru o valoare aleasă, nu avem cum să ajungem la soluţie, se
renunţă la acea valoare şi se reia căutarea din punctul în care am rămas.
Divide et Impera: o tehnică specială prin care se pot rezolva anumite probleme. Divide
et Impera se bazează pe un principiu extrem de simplu: descompunem problema în
două sau mai multe subprobleme (mai uşoare), care se rezolvă, iar soluţia pentru
problema iniţială se obţine combinând soluţiile problemelor în care a fost descompusă.
Greedy: tehnică de rezolvare a unor probleme, asemănătoare cu tehnica Backtracking,
însă nu are mecanismul de revenire şi generează doar o singură soluţie.
Iteraţie: care poate fi repetat în mod nelimitat;
Metodă: ansamblu de mijloace socotite proprii pentru realizarea unui scop; mod de
executare a unui lucru;
Program: reprezintă un set de instrucţiuni prin care se comunică unui calculator cum să
efectueze un anumit grup de operaţii.
Programare: operaţia de elaborare a programului în vederea rezolvării unei probleme
cu calculatorul electronic;
Recursiv: repetare a unui anumit procedeu de calcul prin aplicarea lui la rezultatul
calculului din etapa precedentă;
Stivă: tip special de listă în care toate inserţiile şi suprimările de noduri au loc la un
singur capăt, numit vârf.
Subprogram: parte a unui program;
Tehnică: metode şi capacităţi pentru aplicaţii practice ale ştiinţelor naturii.
IV. Bibliografie

1. Sorin, Tudor (1998). Tehnici de programare,Bucuresti:Editura PegasuS.


2. Mateescu, Daniel George. Moraru, Florin Pavel(2006). Informatica pentru liceu si
bacalaureat Materia de clasa a XI-a, Sibiu: Editura Donaris.
3. Cerchez, Emanuela. Şerban, Marinel.(2005) Programarea in limbajul C/C++
volumul 2, Bucuresti:Editura Polirom.
4. Milosescu, Mariana.(2005) Informatica clasa a X-a, Bucuresti: Editura Diactica si
Pedagogica.
5. Sorin, Tudor. (2008) Informatica clasa a IX si X –a , Bucuresti: L&S Info-Mat.
6. ***. La http://www.timsoft.ro/aux/module/modul11.html 02.05.2009
7. ***. La http://labs.cs.utt.ro/labs/sdaa/html/sda/l1.html 04.05.2009
8. *** La http://ro.wikipedia.org/wiki/Divide_et_impera 15.08.2009
9. *** La www.educativ.ro 12.05.2009
10. *** La http://www.scribd.com/doc/8066145/Metoda-Backtracking 13.05.2009
11. *** La www.didactic.ro/files/12/metoda_greedy.doc 13.05.2009
12. *** La http://www.advancedelearning.ro/materiale/cataloage/ro/cat_inf_ro.pdf
13.05.2009
13.*** La http://portal2.ise.ro la 14.05.2009

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