Sunteți pe pagina 1din 6

Algoritmic i programare Laborator 10

Recursivitate
Recursivitatea este una dintre noiunile fundamentale ale informaticii.
Def: Recursivitatea este un mecanism general de elaborare al programelor. Ea
const n posibilitatea unui subprogram de a se autoapela.
Recursivitatea a aprut din necesitatea de a transcrie direct formule
matematice recursive. n timp acest mecanism a fost extins i pentru ali
algoritmi.
Mecanismul recursivitii
Care este mecanismul prin care programele se autoapeleaz? S ne
amintim cum memoreaz programele parametrii transmii: pentru memorarea
parametrilor, subprogramele folosesc o zon de memorie numit stiv.
Memorarea parametrilor transmii se face n ordinea n care acetia figureaz
n antet: de la stnga la dreapta. Pentru parametrii transmii prin valoare,
se transmite valoarea, iar pentru cei transmii prin referin se transmite
adresa. n cadrul subprogramului, parametrii transmii i memorai n stiv
sunt variabile. Numele lor este cel din lista parametrilor formali.
Subprogramul lucreaz cu datele aflate pe un anumit nivel al stivei
pentru variabilele transmise prin valoare, dar i cu variabilele funciei
main(), dac acestea sunt transmise prin referin.
Exist posibilitatea ca subprogramul s lucreze direct cu variabilele
globale fr ca acestea s fie transmise prin referin. Dup cum tim
variabilele globale pot fi accesate din orice subprogram, dac sunt declarate
la nceputul codului surs.
n cazul unui numr foarte mare de autoapelri, exist posibilitatea ca
segmentul de stiv s se ocupe total, caz n care programul se va termina cu
eroare.
Recursivitatea presupune mai mult memorie.
O gndire recursiv exprim concentrat o anumit stare, care se repet
la infinit. Aceast gndire se aplic n elaborarea algoritmilor recursivi cu
o modificare esenial: adugarea condiiei de terminare. n absena acestei
condiii nu se poate vorbi despre un algoritm deoarece acetia sunt finii.
Pai de elaborare:
Ce se ntmpl la un nivel se ntmpl la orice nivel.
Subprogramul care se autoapeleaz trebuie s conin instruciunile
corespunztoare unui nivel.
Un algoritm recursiv se elaboreaz folosind acest tip de gndire , nu o
gndire precum cea folosit pn acum, cnd am elaborat algoritmi iterativi.
Pentru orice algoritm recursiv exist unul iterativ care rezolv aceeai
problem.

Problema 1. Un exemplu simplu de algoritm recursiv este calculul lui n!, aa


cum putem vedea n cele ce urmeaz.
// calzulez n! fara recursivitate
#include<iostream>
using namespace std;
unsigned long fact(int n)
{
int i;
unsigned long p=1;
if(n==0)
return 1;
else
{
for(i=1;i<=n;i++)
p*=i;
return p;
}
}
void main()
{
int n;
cout<<"Introduceti n= ";cin>>n;
cout<<n<<"! este "<<fact(n)<<endl;
}
// calzulez n! prin recursivitate
#include<iostream>
using namespace std;
int factorial(int n) {
if(n == 0)
return 1;
else
return n*factorial(n-1);
}
void main()
{
int n;
cout<<"Introduceti n= ";cin>>n;
cout<<n<<"! este "<<factorial(n)<<endl;
}
Problema 2. Folosind o metod recursiv, s se determine primii n termeni ai
irului lui Fibonacci, numrul n fiind introdus de la tastatur.
#include<iostream>
using namespace std;
int Fibonacci(int n) {
if(n<2)
return n;
else
return Fibonacci(n-1)+Fibonacci(n-2);
}
void main()

int i,n;
cout<<"Introduceti n= ";cin>>n;
for(i=1;i<=n;i++)
cout<<"Termenul "<<i<<" din sir este : "<<Fibonacci(i)<<endl;
cout<<endl;

Problema 3. Folosind o metod recursiv, s se determine cel mai mare divizor


comun al numerelor a i b, introduse de la tastatur.
#include<iostream>
using namespace std;
int cmmdc(int m, int n) {
if(!n) return m;
return cmmdc(n,m%n);
}
void main()
{
int a,b;
cout<<"Introduceti a = ";cin>>a;
cout<<"Introduceti b = ";cin>>b;
cout<<"("<<a<<","<<b<<")="<<cmmdc(a,b)<<endl;
}
Problema 4. S se citeasc un numr ntreg n de la tastatur i, folosind o
metod recursiv, s se afieze descresctor ntregii de la n la 1.
#include<iostream>
using namespace std;
void afiseaza(int p) {
if(p==0)
return;
cout<<p<<" ";
afiseaza(p-1);
return;
}
void main()
{
int n;
cout<<"Introduceti n = ";cin>>n;
afiseaza(n);
cout<<"BUMMM !!!!"<<endl;
}
Problema 5. S se citeasc un numr ntreg n de la tastatur i, folosind o
metod recursiv, s se afieze cresctor ntregii de la 1 la n.
#include<iostream>
using namespace std;
void afiseaza(int p) {
if (p==0)
return;
afiseaza(p-1);
cout<<p<<" ";
return;

}
void main()
{
int n;
cout<<"Introduceti n = ";cin>>n;
afiseaza(n);
cout<<"BUMMM !!!!"<<endl;
}
Problema 6. Folosind o metod recursiv, s se stabileasc dac un numr
ntreg citit de la tastatur este numr prim sau nu.
#include<iostream>
using namespace std;
bool isPrime(int p, int i) {
if(i==p) return 1;
if(p%i==0) return 0;
return isPrime(p,i+1);
}
void main()
{
int n;
cout<<"Introduceti n = ";cin>>n;
if(isPrime(n,2))
cout<<n<<" este prim !"<<endl;
else
cout<<n<<" nu este prim !"<<endl;
}
*********************************

Metoda Backtracking
Se aplic problemelor n care soluia poate fi reprezentat sub forma
unui vector x=(x1, x2, x3, xk, xn) din S, unde S este mulimea soluiilor
problemei i S=S1 S2 Sn i Si sunt mulimi finite avnd s elemente i xi
aparine lui Si .
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 i 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 dac au fost atribuite valori
elementelor x[1]...x[k-1]. La atribuirea valorii lui x[k] se verific
ndeplinirea unor condiii de continuare referitoare la x[1]...x[k-1]. Dac
aceste condiii nu sunt ndeplinite la pasul k, acest lucru nseamn c orice
valori am atribui lui x[k], 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:

Se alege prima valoare din S1 i i se atribuie lui x1 .


Se presupun generate elementele x[1],,x[k-1], cu valori din S1..Sk-1 .
Pentru generarea lui x[k] se alege primul element din Sk disponibil i
pentru
valoarea
aleas
se
testeaz
ndeplinirea
condiiilor
de
continuare. Pot aprea urmtoarele situaii :
1. x[k] ndeplinete condiiile de continuare. Dac s-a ajuns la soluia
final (k=n) atunci se afieaz soluia obinut. Dac nu s-a ajuns la
soluia final se trece la generarea elementului urmtor x[k+1]
2. x[k] nu ndeplinete condiiile de continuare. Se ncearc urmtoarea
valoare disponibil din Sk. Dac nu se gsete nici o valoare n Sk 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 n considerare toate elementele lui S1 .
Problemele rezolvate prin aceat metod necesit timp mare de execuie,
de aceea este indicat s se foloseasc metoda numai dac 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 puterea n. Dac mulimile S1,
S2,...,Sn nu au acelai numr de elemente, atunci se noteaz cu m minimul
cardinalelor mulimilor S1,S2,Sn i cu M maximul. Timpul de execuie este
situat n intervalul
[mn , Mn]. Metoda backtracking are complexitatea
exponeial, n cele mai multe cazuri fiind ineficient. Ea ins nu poate fi
nlocuit cu alte variante de rezolvare mai rapide n situaia n care se
cere determinarea tuturor soluiilor unei probleme.
Exemplu - Problema 7. Pe o tabl de ah de dimensiune n x n, n>3, trebuie
aezate n dame astfel nct s nu se atace ntre ele. S se afieze toate
posibilitile de a realiza acest lucru.
Aceast problem se poate rezolva usor cu metoda backtracking. Ideile
principale ale algoritmului sunt:
1. Se caut un loc pe o coloan de pe linia i, se gsete primul loc n care
se poate pune o dam i se trece la linia i+1 i coloana 1 de pe aceasta.
2. Dac pe coloana i nu s-a gsit un loc unde se poate pune o dam (este
atacat de altele) atunci se rentoarce pe linia i-1 i se caut un alt
loc de pe aceasta care ndeplinete condiiile i apoi se trece din nou la
linia i i coloana 1.
#include<iostream>
#include<math.h>
using namespace std;
int n,sol,st[25],v[25];
void initializari() {
int i;
cout<<"Introduceti n = ";cin>>n;
for(i=1;i<=25;i++)
st[i]=0;

sol=0;
}
void tipar(int p) {
int i,j;
sol++;
cout<<"Solutia numarul "<<sol<<" este : "<<endl;
for(i=1;i<=p;i++) {
for(j=1;j<=p;j++)
if(j==st[i])
cout<<" * ";
else
cout<<" o ";
cout<<endl;
}
cout<<"==================="<<endl;
}
int valid(int p) {
int i,ok;
ok=1;
for(i=1;i<p;i++)
if(st[p]==st[i]||abs(st[p]-st[i])==abs(p-i))
ok=0;
return ok;
}
void bktr(int p) {
int pval;
for(pval=1;pval<=n;pval++) {
st[p]=pval;
if (valid(p))
if (p==n)
tipar(p);
else bktr(p+1);
}
}
void main() {
initializari();
bktr(1);
}

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