Sunteți pe pagina 1din 45

MINISTERUL EDUCAIEI, CERCETRII I TINERETULUI I

SPORTULULUI
COLEGIUL TEHNIC MTSARI

ATEST
AT
PROF
ESION
AL

PROF. COORDONATOR:
SCEANU ION
ELEV:
Voica Cornelia
Alexandra
Clasa a XII-a B
Profil: Matematic-informatic
Colegiul Tehnic Mtsari

2015-

MINISTERUL EDUCAIEI, CERCETRII I TINERETULUI I


SPORTULULUI
COLEGIUL TEHNIC MTSARI

RECU
RSIVI
TATE
PROF. COORDONATOR:
SCEANU ION
ELEV:
Voica Cornelia
Alexandra
CLASA a XII-a B
Profil: Matematic-informatic
Colegiul Tehnic Mtsari

2015-

CUPRINS:

1. Aspecte
teoretice1
2. Proceduri
recursive7
3. Funcii recursive
.14
4. Backtracking recursiv.
..20
5. Funcii Forward. Referine
forward..22
6. Probleme
recursive...25
7. Figuri
recursive...44

8. Bibliografie
50

Recursivitate
1.Aspecte teoretice
1.1 Ce este recursivitatea?
Recursivitatea, folosit cu mult eficien n matematic, s-a impus n
programare, odata cu apariia unor limbaje de nivel inalt, ce permit scrierea de
module ce se autoapeleaz (PASCAL,LISP,ADA,ALGOL,C sunt limbaje
recursive, spre deosebire de FORTRAN,BASIC,COBOL, nerecursive).
Recursivitatea e strns legat de iteratie, dar dac iteratia e execuia
repetat a unei poriuni de program, pn la ndeplinirea unei conditii (while,
repeat, for din PASCAL), recursivitatea presupune executia repetata a unui
modul, insa n cursul executiei lui (i nu la sfrsit, ca n cazul iteratiei), se
verifica o conditie a crei nesatisfacere, implica reluarea executiei modulului de
la inceputul sau. Atunci un program recursiv poate fi exprimat: P=M(i,P) ,
unde M este multimea ce contine instructiunile i i pe P insusi.
Structurile de program necesare i suficiente n exprimarea recursivitii
sunt procedurile i subrutinele ce pot fi apelate prin nume.
Recursivitatea poate fi:

-direct - un modul P contine o referin la el insui


-indirect - un modul P contine o referin la un modul Q ce include o
referin la P.

1.2 Parametrii-valoare i parametrii-variabil


Discuia se face pentru cazul implementrii recursivitii n PASCAL, dar
lucrurile sunt similare pentru C.
n PASCAL, exist dou tipuri de parametri formali (ce apar n antetul
unei proceduri sau funcii) : valoare i variabil (ultimii au numele precedat de
cuvntul cheie var).
Apelul recursiv al unei proceduri (funcii) face ca pentru toi parametriivaloare s se creeze copii locale apelului curent (n stiv) , acestea fiind referite
i asupra lor fcndu-se modificrile n timpul execuiei curente a procedurii
(funciei). Cnd execuia procedurii (funciei) se termin, copiile sunt extrase
din stiv, astfel nct modificrile operate asupra parametrilor-valoare nu
afecteaz parametrii efectivi de apel, corespunztori.
De asemenea pentru toate variabilele locale se rezerva spaiu la fiecare
apel recursiv. n cazul parametrilor-variabila, nu se creaz copii locale, ci
operarea se face direct asupra spaiului de memorie afectat parametrilor efectivi,
de apel.
De reinut:
-pentru fiecare apel recursiv al unei proceduri (funcii) se creaz copii locale ale
parametrilor valoare i variabilelor locale, ceea ce poate duce la risip de
memorie;
-orice parametru-variabila poate fi suprimat prin referirea direct n procedura
(funcie) a variabilei ce figura ca parametru de apel

1.3 Verificarea i simularea programelor recursive


Se face n cazul celor nerecursive, printr-o demonstraie formal, sau
testnd toate cazurile posibile. Se verific nti dac toate cazurile particulare
(ce se execut cnd se ndeplinete condiia de terminare a apelului recursiv)
funcioneaz corect.
Se face apoi o verificare formal a procedurii (funciei) recursive, pentru
restul cazurilor, presupunnd c toate componentele din codul procedurii
(funciei) funcioneaz corect. Verificarea e deci inductiv.Acesta e un avantaj
al programelor recursive, ce permite demonstrarea corectitudinii lor simplu i
clar.
Exemplificare: Funcia recursiv de calcul a factorialului:
function fact(n:integer):integer;

begin
if n=1 then fact:=1
else fact:=n*fact(n-1)
end;
Demonstrarea corectitudinii cuprinde doi pai:
-pentru n=1 valoarea 1 ce se atribuie factorialului este corect
-pentru n>1, presupunnd corect valoarea calculat pentru predecesorul lui n
de fact(n-1), prin nmulirea acesteia cu n se obine valoarea corect a
factorialului lui n.

1.4 Tehnica eliminrii recursivitii


Orice program recursiv poate fi transformat n unul iterativ, dar
algoritmul sau poate deveni mai complicat i mai greu de neles. De multe ori,
soluia unei probleme poate fi elaborat mult mai uor, mai clar i mai simplu
de verificat, printr-un algoritm recursiv.
Dar pentru implementare, poate fi necesar transformarea algoritmului
recursiv n unul nerecursiv, n situaiile:
-solutia problemei trebuie scris ntr-un limbaj nerecursiv; un caz
particularsuntcompilatoarele ce "traduc" un program recursiv dintr-un limbaj de
nivel nalt n cod main (nerecursiv)
-varianta recursiv ar duce la o vitez de execuie i spaiu de memorie prea
mari, transformarea n una nerecursiv, eliminnd dezavantajele.
Se va prezenta una din metodele de eliminare a recursivitii ce folosete
o structur de date de tip stiv. n scrierea unei varianta nerecursive, trebuie
parcuri toi paii implicai n varianta recursiv, prin tehnici nerecursive.
Recursivitatea implica folosirea a cel puin unei stive. La fiecare apel
recursiv sunt depuse n stiv nite date, care sunt extrase la revenirea din acel
apel. E simplu dac datele pentru un apel se organizeaz ntr-un record, un apel
nsemnnd introducerea n stiv a unui record, revenirea, extragerea lui.
Se prezint eliminarea recursivitii pentru un program simplu, care
citete caracterele tastate pe o linie, tiprindu-le apoi n ordine invers.
program var_recursiv;
procedure prel_car;
var car:char;
begin
read(car);
if not eoln then prel_car;
write(car)
end;
begin

prel_car
end.
program var_nerecursiv;
begin
*iniializeaz stiv
while not eoln do
begin
read(car);
push(car)
end;
while not stiva_goal do
begin
pop(car);
write(car)
end
end.
1.5 Exemple de algoritmi recursivi

1.5.1 Algoritmi de traversare i inversare a unei


structuri
Traversarea i inversarea unei structuri nseamn efectuarea unor operaii
oarecare asupra tuturor elementelor unei structuri n ordine direct, respectiv n
ordine invers.
Dei mai uzuale sunt variantele iterative, caz n care inversarea
echivaleaz cu dou traversri directe (o salvare n stiva urmat de parcurgerea
stivei), variantele recursivesuntmai elegante i concise. Se pot aplica
structurilor de tip tablou, lista, fiier i pot fi o soluie pentru diverse probleme
(transformarea unui ntreg dintr-o baz n alta, etc).
ntr-o form general, algoritmii se pot scrie:
procedure traversare(element:tip_element); {apelul iniial}
{al procedurii se face cu primul element al structurii}
begin
prelucrare(element);
if element <> ultimul_din_structura then
traversare(element_urmtor)
end;
procedure inversare(element:tip_element); {apelul iniial}
{al procedurii se face cu primul element al structurii}

begin
if element <> ultimul_din_structura then
traversare(element_urmtor);
prelucrare(element)
end;
De observat important ca parametrul formal al celor dou proceduri s fie de
tip valoare, pentru a nu fi alterat de apelul recursiv.

1.5.2 Algoritmi care implementeaz definiii


recursive
O definiie recursiv e cea n care un obiect se definete prin el nsui.
Definiia conine o condiie de terminare, indicnd modul de prsire a
definiiei i o parte ce precizeaz definirea recursiv propriu-zis.
Ca exemple: algoritmul lui Euclid de aflare a c.m.m.d.c., factorialul,
ridicarea la o putere ntreag (prin nmuliri repetate), definirea recursiv a unei
expreii aritmetice, curbele recursive, un mod de a privi permutrile, etc.

2. Proceduri recursive
Procedurile de asemenea pot fi recursive. Ca un exemplu considerm
algoritmul pentru transformarea ntregilor zecimali n numere binare. Astfel, lui
(13)10 i corespunde (1101)2

Presupunem ca dorim s scriem o procedura care tipareste astfel de


rezultate pentru orice n pozitiv, mai mare ca maxint.
Alegem o procedura i nu o functie deoarece noi cautam mai mult dect
un raspuns - mai multe cifre binare: 1, 1, 0, 1 n exemplul ales.

O problema care intervine n scrierea acestei proceduri este aceea ca


entitatile (1, 1, 0, 1) trebuie tiparite n sens invers (prima valoare obtinuta
trebuie tiparita ultima).
O prim solutie ar fi aceea de a utiliza o imprimanta care poate tipari de
la dreapta la stnga, dar este putin probabil ca veti gasi! Alta solutie ar fi s
scriem o rutina complicata care ntr-un fel supraimprima aceeasi linie a outputului fara a permite orice interventie napoi, dar aceasta solutie nu este nici
eleganta, nici eficienta!
Am putea salva aceste cifre ntr-un masiv (ARRAY) dar scopul nostru,
pentru acest exemplu este acela de a arata ca putem folosi recursivitatea.
Asadar, s... navigam! Priviti din nou la 13 scris n binar: 1101. Observati
ca primele 3 cifre, 110, sunt evaluate la 6. Adaugam un 0 n dreapta oricarui
numar binar, valoarea s se dubleaza, astfel nct 1100 este 12.
n aceeasi idee, 13=(6x2)+1. n mod corespunzator, un numar par, cum ar
fi 20 poate fi exprimat ca (10x2)+0.
Observatie!
Cifra dup semnul plus va fi 0 pentru numere pare i 1 pentru numere
impare. Ea poate fi uor obtinut, pentru orice n folosind relaia: n MOD 2.
Acum priviti la primul ct obtinut n mpartirea succesiva folosita pentru
transformarea lui 13 din zecimal --> binar. Este 6, nu? Asadar, acum avem baza
unui algoritm:
IF n<2 THEN
reprezentarea binara a lui n este n {conditia bootstrap}
ELSE {se aplica pasul inductiv}
{reprezentarea binara a lui n este reprezentarea binara a lui n div 2 adaugnd n
mod 2}
S testam acest algoritm numai pentru cteva cazuri simple. Conditia
bootstrap este aceea ca reprezentarea binara a lui 0 este 0 i reprezentarea binara
a lui 1 este 1. Deocamdata este bine. Pentru a obtine reprezentarea binara a lui
2, avem nevoie s aplicam pasul inductiv o data.
Astfel (2)10 --> (10)2. Pentru 5, pasul inductiv va fi aplicat de doua ori,
folosind rezultatul anterior (pentru 2). Astfel (5)10 --> (101)2.

Reprezentarea binara a lui 2= reprezentarea binara a lui 2 div 2 adaugnd


2 mod 2
(2)10=(10)2
Reprezentarea binara a lui 5= reprezentarea binara a lui 5 div 2 adaugnd
5 mod 2
(5)10=(101)2
Implementarea (Borland) PASCAL a acestui algoritm recursiv este
programul binar.
PROGRAM binar;
{Afiseaza echivalentul binar al ntregilor zecimali}
VAR n:integer;
PROCEDURE binary(n:integer);
{Conversie recursiva a lui n zecimal n forma binara}
BEGIN
IF n<2 THEN write(n:2) ELSE
{aplica pasul inductiv:}
BEGIN
binary (n div 2);write(n mod 2)
END;
END {binary};
BEGIN {principal}
WHILE NOT eof DO
BEGIN
write('Intoduceti un numar zecimal ntreg pozitiv);
readln(n);
write('zecimal ',n:2, ' binar ');
binary(n);
writeln
END;
END {binar}.
Tiparirea cifrelor a fost... amnata n exemplul precedent. Aceasta tehnica
are numeroase aplicatii. n programul tipar (exemplul urmator), procedura
recursiva flipcon pregateste pentru editare o secventa de caractere (care intra)
pna cnd conditia eof este detectata i apoi, i numai apoi, tipareste caracterele
citite n ordine inversa.
PROGRAM tipar;
{Citeste propozitiile pn la eof dupa care tipareste propozitia n sens invers}

PROCEDURE flipcar;
{Inverseaza recursiv caracterele pn la eoln}
VAR ch:char;
BEGIN
read(ch);
IF eoln THEN write(ch) ELSE
BEGIN {pasul inductiv}
flipcar;
write(ch)
END
END {flipcar};
BEGIN {principal}
WHILE NOT eof DO
BEGIN
writeln('Introduceti o propozitie pe o singura linie de input');
flipcar;
writeln
END
END {tipar}.
Rezultatele execuiei programului:
Input
AFARA PLOUA LINISTIT
UNIVERSITATEA DE VEST ESTE N TIMISOARA
AM FOST N BUCURESTI

Output
TITSINIL AUOLP ARAFA
ARAOSIMIT NI ETSE TSEV ED AETATISREVINU
ITSERUCUB NI TSOF MA

Problema: Turnurile din Hanoi.


Presupunem c avem cinci discuri (turnuri), gurite n centru, ca n
exemplul urmtor (numrul de ace este trei ntotdeauna, dar numrul de discuri

poate varia). Ce se dorete? S mutm discurile (turnurile) unul cte unul, de la


acul 1 la acul 3, folosind acul 2 ca... gazd temporar, n condiiile n care la
fiecare mutare se deplaseaz un singur disc, i n nici o etap nu este admis c
un disc mai mare s stea pe un disc mai mic. Rspunsul dorit este o list de
mutri, de genul: "Muta un disc de la acul 1 la acul 3".
Configuraia pentru cinci discuri (turnurile din Hanoi):

Desigur, v vei ntreba unde intervine recursivitatea? Analiznd


problema observm c pentru cele 5 discuri, am fi capabili s mutm ultimul
disc numai dac, ntr-un mod oarecare am putea manevra cele patru discuri de
deasupra, pe acul al doilea, lsnd acul al treilea liber pentru a primi discul
rmas (cel mai mare) de la primul ac. Alt problem, de aceeai dimensiune,
este mutarea celor patru discuri la acul trei (dup mutarea discului mai mare,
conform descrierii anterioare). Noi generalizam problema, realiznd o
procedur move (n, a, b, c) care, ntr-un fel, tie cum s mute n discuri, de la
acul a la acul b prin intermediul acului c i care listeaz toate mutrile
necesare pentru... atingerea obiectivului. Dac procedura move lucreaz
corect, soluia la problema cu cinci discuri este cea ilustrata n continuare.

MOVE(4,1,3,2);
{Mut 4 discuri de la acul 1 la 3 prin intermediul acului 2}
Writeln('Muta un disc de la acul 1 la acul 3');
MOVE(4,3,2,1);
{Mut 4 discuri de la acul 3 la acul 2 prin intermediul acului 1 pentru a
completa soluia problemei cu 5 discuri}
Cum procedm s realizm primul i al treilea pas? Recursivitatea
direct: problema cu cinci discuri poate fi rezolvat dac soluionam problema
cu patru discuri i aa mai departe, pn la problema care nu implic nici un

disc. Problema cu nici un disc este uor de rezolvat i furnizeaz bootstrap-ul:


pentru n=0, nu se face nimic!
Funcia cheie move (vezi programul de mai jos) este folosit n cadrul
unui program care permite utilizatorului s introduc numrul de discuri ce
trebuie mutate. Testai funcia pentru valori mici, cum ar fi n=7 dar, atenie la
valori mari, deoarece ele tind s consume foarte mult timp!
PROGRAM turnuri;
TYPE
Inputdisk=integer;
Inputac=1..3;
VAR
Inputndisk:integer;
PROCEDURE MOVE(n:disk;a,b,c:ac);
{Mut n disk-uri de la acul a la acul b,via c}
BEGIN
InputIF n>0 THEN {se aplic pasul inductiv}
InputBEGIN
InputInputMOVE(n-1, a,c,b);
InputInputwriteln('Muta un disc de la',a:2,'la',b:2);
InputInputMOVE(n-1,c,b,a)
InputEND
END {MOVE};
BEGIN {principal}
InputWHILE NOT eof DO
InputBEGIN
InputInputwrite('Introduceti numarul de discuri ce trebuie mutate:')
InputInputreadln(ndisk);
InputInputwriteln;
InputInputMOVE(ndisk,1,3,2);
InputInputwriteln
InputEND
END {turnuri}.

Introduceti numarul de discuri ce trebuie mutate:3


Muta un disc de la 1 la 3
Muta un disc de la 1 la 2
Muta un disc de la 3 la 2
Muta un disc de la 1 la 3
Muta un disc de la 2 la 1
Muta un disc de la 2 la 3
Muta un disc de la 1 la 3

Remarc!
n descrierea originala a problemei turnurilor din Hanoi se
spune ca un grup de calugari au fost... provocati s mute 64 de
discuri de aur utiliznd o platforma de alama cu trei ace de
diamant. Legendele sustin ca preotii joaca acest joc n mod
curent i ca sfrsitul jocului va nsemna sfrsitul lumii!

3. Funcii recursive
Una din cele mai simple funcii matematice este, fr ndoiala funcia
factorial.
Din moment ce (Borland) PASCAL-ul nu are o funcie (de bibliotec)
standard pentru calculul factorialului, va trebui s scriem noi una. Definirea
lui n! (se citete "n factorial") este produsul:
n x (n-1) x (n-2) x...x 3 x 2 x 1 (pentru un ntreg mai mare ca 0; 0!=1).
Aceasta definiie poate fi implementata n (Borland) PASCAL prin funcia
descris n continuare:
Exemplu:
FUNCTION fact(n:integer):integer;
VAR i,t:integer;

BEGIN
t:=1;
FOR i:=n downto 2 DO t:=t*i;
fact:=t
END {fact};
Cnd vrem s subliniem c o funcie nu este recursiv (dar ar fi putut
fi !) noi o numim funcie iterativ. Remarcai c enunul iterativ folosit (o bucl
FOR) nu este executat niciodat pentru n mai mic ca 2 - funcia returneaz
valoarea 1 att pentru 1! ct i pentru 0!. Variabil de control al buclei (i) ia
valori pn la 2, nu pn la 1 pentru a evita o nmulire inutil cu 1 n final.
Variabil (de stare) t este necesar pentru a evita folosirea lui fact (numele
funciei) n partea dreapt a enunului de atribuire t:=t*i. Compilatorul
(Borland) PASCAL se ateapt ca un nume de funcie s apar numai n partea
dreapt a enunului de atribuire, acela care leag numele funciei de o valoare
particular. Iat n exemplul urmtor o alternativ de definire a lui n! care este
mai degrab recursiva dect iterativa.

IF n=0 THEN fact:=1


ELSE fact:=n*fact(n-1)
Clauza IF este extrem de important, din moment ce fr ea secvena
va... curge, indefinit:
.3!= 3x2!
...= 3x2x1!
...= 3x2x1x0!
...= 3x2x1x0x(-1)!
...= 3x2x1x0x(-1)!x(-2)!
......
Testul care previne o asemenea recursivitate nedefinit se numete
bootstrap condition i reprezint un element esenial al oricrei rutine
recursive. Aici, bootstrap condition este <IF n=0 THEN fact:=1> care oprete
calculul lui n! de la o rulare nedefinit. Iat funcia recursiv (Borland)
PASCAL pentru calculul lui n!
FUNCTION fact(n:integer):integer;
{funcia recursiv pentru calculul lui n!}
BEGIN
IF n=0 THEN fact:=1
ELSE fact:=n*fact(n-1)
END {fact};
Cele dou apariii ale lui fact n partea stnga a enunurilor de atribuire
respecta regul prin care unei funcii i se atribuie o valoare particular. Ceea

ce face ca fact s fie o funcie recursiv este prezena lui fact (n-1) n membrul
drept al enunului fact:=n*fact (n-1). Asocierea lui fact cu argumentul n-1,
presupune c atunci cnd implicm funcia fact, ea se va apela pe ea nsi.
Aa cum a trebuit s nvm cum s scriem bucle care se termin
dup un numr finit de iteraii, trebuie s nvm s construim funcii
recursive care se termin cu succes dup o serie finit de referiri la sine.
nvarea modului de folosire a recursivitii este mai important dect
nelegerea modului cum lucreaz. Prezentm dou reguli simple, dar eseniale.
Reguli:
1) Orice funcie sau procedura recursiv trebuie s aib cel puin o
bootstrap condition, care specific rspunsul corect sau aciunea pentru cea
mai simpl situaie imaginabil, n general una corespunztoare celei mai mici
valori parametru (cea de final);
2) Orice funcie sau procedura recursiv trebuie s aib un pas inductiv
(inductive step) care leag problem ce trebuie rezolvat de cea mai simpl
versiune.
Pentru funcia factorial (fact recursiv), bootstrap condition este 0!=1,
iar inductive step (pasul inductiv) leag pe n! de (n-1)! care rmne nchis la
bootstrap.
La prima vedere, funcia factorial - fact recursiva pare s aib nevoie de
mai puin memorie dect omoloaga s nerecursiva deoarece este folosit
variabil nontemporara (stare) t, dar aceasta este o iluzie. n spatele ... scenei,
o rutin recursiv trebuie s salveze una sau mai multe valori intermediare ori
de cte ori ea se apeleaz pe ea nsi. Ea salveaz aceste valori n form de
stack, o structur de date n care ultimul item salvat este primul ce poate fi
rechemat.
Remarc!
Alte nume pentru stack sunt pushdown stack i lifo list (lifo este
prescurtarea de la "last n, first ou").
Alt posibil operaie recursiv este an - a ridicat la puterea n (unde n
>= 0).
Ceea ce urmeaz este o soluie nerecursiva, bazat pe multiplicarea lui a cu el
nsui de n ori.
FUNCTION putere (a:real; n:integer):real;
{O funcie iterativ pentru calculul lui a la puterea n}
VAR t:real;
i:integer;
BEGIN

t:=1;
FOR i:=1 TO n DO t:=t*a;
putere:=t
END {putere};
Pentru n=0, bucla FOR nu se va executa, genernd a0=1, valoare evident
corect. Pentru n>=1, t devine n ordine a, a2, a3 i tot aa pn la an.
Definirea recursiv a lui an este:
IF n=0 THEN an:=1; unde an =a*an-1
Condiia bootstrap este a0=1. Pasul inductiv (inductive step) an=a*an-1,
leag problem general an de problema an-1, care rmne pe loc la bootstrap.
Traducerea (Borland) PASCAL a acestei definiii este ilustrata n
secvena urmtoare:
FUNCTION putere (a:real; n:integer):real;
BEGIN
IF n=0 THEN putere:=1
ELSE putere:=a*putere(a,n-1)
END {putere};
Exist ceva dezorganizat n ambele versiuni ale lui putere. Ai calculat
a , fcnd 15 nmuliri ? Probabil c nu; ai observat c a16 =(a8)2 i c a8
=(a4)2 i tot aa mai departe. Astfel, n realitate avem nevoie de 4 nmuliri
pentru a calcula a16. Evident, aceasta njumtire maxim nu va lucra la fel,
dac n este impar. n consecin, un algoritm recursiv mbuntit trebuie s fie
structurat astfel:
16

IF n=0 THEN an=1


ELSE IF n s odd THEN an=a*an-1
ELSE an=(an/2)2
Aceasta definire are doi pai inductivi, unul folosit pentru n impar,
cellalt utilizat pentru n par. Aa cum s-a cerut, ambii pasi inductivi leag
problem de o dimensiune dat, de una care rmne nchisa la bootstrap.
Programul (Borland) PASCAL ce codific acest algoritm mbuntit este
prezentat n continuare:
Exemplu:
FUNCTION putere (a:real;n:integer):real;
BEGIN
IF n=0 THEN putere:=1
ELSE IF odd(n) THEN putere:=a*putere(a,n-1)
ELSE {chiar pentru n}
putere:=sqr(putere(a,n div 2))
END {putere};

Pentru valori mari ale lui n, aceast versiune a lui putere folosete mai
degrab un numr de nmuliri egal cu log2n dect cu n-1, ca n versiunea
precedenta. Pentru n=64, unde log264=6, aceasta reprezint o economie
nzecita.
Observaie!
Remarcai c ntruct exista o mic diferen ntre numrul de enunuri
(Borland) PASCAL folosite pentru versiunile recursiva, respectiv iterativa ale
lui fact sau pentru primele dou versiuni (ineficiente) ale lui putere, este pe
undeva prea dificil s recodificam versiunea eficient a lui putere fr a folosi
recursivitatea.
Implementarea recursiv a unui algoritm este adesea mult mai natural
i mult mai lizibila dect implementarea iterativ echivalent.
Unul dintre cei mai cunoscui algoritmi este algoritmul lui Euclid, care
calculeaz cel mai mare divizor comun (gcd) a doi ntregi pozitivi, nenuli m i
n. De exemplu, dac m este 45 i n este 30, c.m.m.d.c. al lor este 15; dac m
este 8 i n este 12, atunci c.m.m.d.c. este 4.
Pentru a calcula c.m.m.d.c. reamintim algoritmul lui Euclid. Dac m=n,
atunci c.m.m.d.c. este m (sau n); n caz contrar, se nlocuiete numrul mai
mare cu diferena celor dou numere i procesul se repet.
Funcia iterativ (Borland) PASCAL care corespunde acestei definiii
este ilustrat de:
FUNCTION gcd1(m,n:integer):integer;
BEGIN
WHILE m<>n DO
IF m>n THEN m:=m-n
ELSE n:=n-m;
gcd1:=m
END {gcd1};
Versiunea recursiv, cu aceeai logic, este prezentat n continuare:
FUNCTION gcd2(m,n:integer):integer;
BEGIN
IF m=n THEN gcd2:=m ELSE
IF m>n THEN gcd2:=gcd2(m-n,n)
ELSE gcd2:=gcd2(m,n-m)
END {gcd2};
Remarc!
Cele dou versiuni sunt foarte ineficiente cnd diferena dintre m i n
este mare , deoarece determina un numr considerabil de scderi succesive pn

cnd numerele sunt aduse n acord. Dar o asemenea scdere repetat se


constituie ntr-un paravan; un algoritm recursiv mult mai bun poate fi codificat
folosind operatorul mod.
FUNCTION gcd(m,n:integer):integer;
{Returneaz c.m.m.d.c. al lui m i n>0}
VAR r:integer;
BEGIN
r:=m mod n;
IF r=0 THEN gcd:=n
ELSE gcd:=gcd(n,r){Din moment ce n este divizibil prin n,al doilea argument
mai
vechi este acum primul}
END {gcd};

4. Backtracking recursiv
n acest capitol prezentm rutin de backtracking recursiv. Procedurile i
funciile folosite sunt n general aceleai ca la backtracking, cu dou mici
excepii:
-SUCCESOR nu mai este procedura ci funcie booleana ;
-rutina backtracking se transform n procedura,care se
apeleaz prin BACK(1)
Principiul de funcionare al procedurii BACK,corespunztor unui nivel k
este urmtorul:
-in situaia n care avem o soluie,o tiprim i revenim pe nivelul anterior
-in caz contrar se iniializeaz nivelul i se cauta un succesor
-cand am gsit unul verificm dac este valid;procedura se autoapeleaza
pentru (k+1) , n caz contrar urmnd a se continua cutarea succesorului;
-daca nu avem succesor,se trece pe nivel inferior (k-1) prin ieirea din
procedur BACK
Vom explica n continuare utilizarea backtrackingului recursiv prin
generarea permutrilor:
type stiv=array[1..9] of integer;
var st:stiv;
ev:boolean;n,k:integer;
procedure init(k:integer;var st:stiv);
begin
st[k]:=0;
end;

function succesor(var st:stiv;k:integer):boolean;


begin
if st[k]<n then
begin
st[k]:=st[k]+1;
succesor:=true;
end
else succesor:=false;
end;
procedure valid(var ev:boolean;st:stiv;k:integer);
var i:integer;
begin
ev:=true;
for i:=1 to k-1 do
if st[i]=st[k] then ev:=false;
end;
function soluie(k:integer):boolean;
begin
soluie:=(k=n+1);
end;
procedure tipar;
var i:integer;
begin
for i:=1 to n do writeln(st[i]);
writeln;
end;
procedure back(k:integer);
begin
if soluie (k) then tipar
else
begin
init(k,st);
while succesor(st,k) do
begin
valid(ev,st,k);
if ev then back(k+1);
end;
end;
end;
begin
write('n=');readln(n);
back(1);
end.

Desigur orice problem care admite rezolvare backtracking,poate fi


rezolvat n acest mod.ns,de multe ori, aceeai problem se poate rezolva
scriind mai puin, dac renunm la standardizare.

5. Funcii Forward. Referine


forward
O funcie sau o procedur nu poate fi recursiva numai intrinsec, ea poate
deveni de asemenea recursiva indirect prin interaciunea cu alte proceduri sau
funcii care nu au fost nc declarate. De exemplu, p1 i p2 pot forma o pereche
recursiv mutual (mutually recursive pair, n limba englez) dac p1 cheam
pe p2 i p2 cheam pe p1, sau mai multe rutine pot crea o recursivitate indirect
printr-un lan circular de apelri cum ar fi p1-> p2-> p3-> ...-> pn-> p1.
Considerm urmtorul exemplu de recursivitate mutual. S presupunem
c nu exista funciile (Borland) PASCAL de biblioteca sn i co i c dorim s
implementm o pereche care s se cheme sine i cosine. Considerm identitile
trigonometrice cunoscute.
sn(x)=2 sin(x/2)cos(x/2)
cos(x)=cos2(x/2)-sin2(x/2)
Pentru c ambele identiti s constituie baza rutinelor sine i cosine
trebuie s observm urmtoarele:
att sine ct i cosine se apeleaz pe el nsele, deci sunt recursive;
fiecare funcie apeleaz pe cealalt, astfel ele formeaz o pereche
mutual recursiv;
condiiile bootstrap sunt necesare pentru a duce la bun sfrit programul;
indiferent de ordinea de scriere a rutinelor, compilatorul (Borland)
PASCAL va obiect, n mod normal la ntlnirea unei referiri la o funcie
al crei cod se afla mai departe (n continuare).
Primele dou puncte sunt numai observaii. Ultimele dou sunt probleme
ce trebuie rezolvate.
Pentru nceput, s abordm problema condiiilor bootstrap. ntruct sin(x)
i cos(x) folosesc ca argumente unghiul pe jumtate care n interiorul... cuibului
recursiv devin din ce n ce mai mici, am putea avea propriile noastre bootstrapuri.

Pentru valori mici ale lui x este aproape adevrat c sin x i cos x au
valorile definite de primii doi termeni: (x-x3/6), respectiv 1-x2/2 dintr-o serie
infinit.
sinx @ x-x3/6
cosx @ 1-x2/2
Ne ntrebam: ct de mic trebuie s fie x pentru a ne permite nou s ne
bazm pe aceste aproximaii. Aceasta depinde de ct de multe zecimale ne vom
atepta la rspunsurile date. Un matematician ne-ar rspunde c pentru x < 0.02
aproximarea lui cos x poate fi fcut cu 8 zecimale, iar pentru sinx este chiar
mai bun.
n rutinele pe care le vom prezenta, valorile mai mici dect 0.02 i 0.01
servesc ca bootstrap-uri i sunt numite epsilon. n fiecare rutin epsilon este
declarat c o constant astfel nct valoarea s poate fi uor modificat, n
funcie de experiment .
Impedimentul final l constituie situaia "chicken-and-egg" (gaina-i-oul)
referitoare la ordinea relativ a lui sine i cosine din interiorul codului sursa.
Din fericire, un pas de compilare n (Borland) PASCAL cere ca numai o
procedur sau o funcie s poat fi alimentate cu elementele pentru header-ul
rutinii apelate.
Cnd este definit un asemenea header, includerea cuvntului rezervat
forward va anuna compilatorul (Borland) PASCAL ca ntreg corpul logic al
rutinei mpreuna cu toate declaraiile sale vor aprea mai trziu n program. n
cazul nostru, vom scrie urmtorul header:
FUNCTION cosine(x:real): real; forward;
dup care vom proceda la fel pentru funcia sine.
FUNCTION cosine(x:real):real;forward;
FUNCTION sine(x:real):real;
Prezentm n cele ce urmeaz funciile mutuale complet recursive cosine
i sine:
FUNCTION cosine(x:real):real;forward;
FUNCTION sine(x:real):real;
CONST epsilon=0.01;
BEGIN
IF abs(x)<epsilon THEN sine:=x*(1-x*x/6)
ELSE sine:=2*sine(x/2)*cosine(x/2)
END {sine};
FUNCTION cosine(x:real):real;
CONST
epsilon=0.02;

BEGIN
IF abs(x)<epsilon THEN cosine:=1-x*x/2
ELSE cosine:=sqr(cosine(x/2))-sqr(sine(x/2))
END {cosine};

5. Probleme recursive
5.1. Recursivitatea n prelucrarea datelor elementare
1. S se scrie un subprogram recursiv care apelat ntr-un program
principal s conduc la afiarea urmtorului triunghi de stelue, pentru citirea de
la tastatur a valorii n=4.
*
**
***
****
var n:integer;
procedure rec(k:integer);
var i: integer;
begin
if k=n then for i:=1 to k do write(* )
else begin
for i:=1 to k do write(* );
writeln;
rec(k+1)
end;
end;
begin {pp}
write(n= );
readln(n);
rec(1);
readkey
end.
2.S se scrie un program care s utilizeze recursivitatea i care pentru
citirea de la tastatur a valorii n=5, s afieze urmtorul triunghi de numere:
5
45
345

2345
12345
var n: integer;
procedure tiplinie(l:integer);
begin
if l=1 then write(n-l+1, )
else begin
write(n-l+1, );
tiplinie(l-1);
end
end ;
procedure rec(k:integer);
begin
if k=n then tiplinie(n)
else begin
tiplinie(k)
writeln;
rec(k+1)
end
end;
begin{pp}
write(n= );
rec(1);
readkey
end.
3. Se citesc de la tastatur coeficienii reali a,b,c,d, a0 ai ecuaiei: ax?
+bx?+cx+d=0. Notm cu x1,x2,x3 rdcinile acestei ecuaii. Pentru un n natural
i strict pozitiv citit de la tastatur, s se scrie un program ce utilizeaz
recursivitatea pentru calculul sumei: Sn= x1n+x2n+x3n
S0=x10+x20+x30=3
S1=x1+x2+x3= -b/a
S2=x12+x22+x32= (x1+x2+x3)2-2(x1x2+x1x3+x2x3)=S12-2c/a

avem c a Sn+bSn-1+cSn-2+dSn-3=0, adic


Sn=-b/aSn-1 - c/aSn-2 - d/aSn-3
(am folosit relaiile lui Viete pentru ecuaia de gradul al II-lea)
var a,b,c,d: real;
n:integer;

function s(k:integer):real;
begin
if k=0 then s:=3
else if k=1 then s:=-b/a
else if k=2 then s:= sqr(b)/sqr(a)-2*c/a
else s: =-b/a*s(k-1) - c/a*s(k-2) - d/a*s(k-3);
end;
begin {pp}
write(a= );readln(a);
write(b= );readln(b);
write(c= );readln(c);
write(d= );readln(d);
write(n= );readln(n);
writeln(Suma este: , s(n):6:3);
readkey
end.
4. Se citete de la tastatur un numr natural ce va fi memorat ntr-o
variabil de tipul longint. Se cere s se scrie un subprogram recursiv care s
afieze numrul format cu cifrele sale inversate.
var n:longint ;
procedure invers(k:longint);
begin
if k<>0 then begin
write (k mod 10);
invers(k div 10);
end;
end;
begin
write(n= );
readln(n);
invers(n);
readkey
end.

5. S se calculeze cel mai mare divizor comun a dou numere naturale


citite de la tastatur.
Vom folosi urmtoarea formul recursiv:

cmmdc(a,b)=

nu exist, dac a 0 si b 0
b, dac a 0

a, dac b 0
cmmdc(b, a mod b), n rest

var a,b,c: integer;


function cmmdc(x,y:integer):integer;
begin
if (x=0) and (y=0) then cmmdc:=0
else if y=0 then cmmdc:=x
else if x=0 then cmmdc:=y
else cmmdc:=cmmdc(y,x mod y)
end ;
begin
write(a= );
readln(a);
write(b= );
readln(b);
c:=cmmdc(a,b);
if c=0 then writeln (cmmdc(0,0) nu este definit)
else writeln(cmmdc(, a,,,b,)= ,c);
readkey
end.

6. Se citete de la tastatur un numr natural n>0. S se afieze, utiliznd


recursivitatea, descompunerea lui n n factori primi.
Vom scrie un subprogram recursiv, care primind ca argument un numr
natural K, determin cel mai mic divizor al su precum i puterea la care acest
divizor apare n cadrul descompunerii n factori primi. Apoi, subprogramul se
va apela recursiv pentru numrul obinut prin mprirea lui k la numrul
obinut prin ridicarea la putere a divizorului la factorul lui.

var n,s: integer;


procedure descompunere(k:integer);
var divizor, putere: integer;
begin
if k>1 then
begin
divizor:=s+1;
while k mod divizor <>0 do
divizor:=divizor+1;
putere:=0;
while k mod divizor=0 do begin
putere:=putere+1;
k:=k div
divizor;
end;
writeln(divizor, ^ ,putere);
s:=divizor;
descompunere(k);
end;
end;
begin
write(n= );
readln(n);
s:=1;
if n<>1 then descompunere(n)
else write(n);
readkey
end.
7. S se scrie un subprogram recursiv care calculeaz
formula de recuren:
1, dac k = 0
n, dac k = 1
k
Cn =

Ckn-1 + Ckn--11 , in rest

k
Cn ,

utiliznd

var n,k: longint;


function comb(n,k:longint):longint;
begin
if k=0 then comb:=1
else if k>n then comb:=0
else comb:=comb(n-1,k)+comb(n-1,k-1)
end;
begin
write(n= );
readln(n);
write(k= );
readln(k);
writeln(comb(,n,,,k,)= , comb(n,k));
readkey
end.

5.2.Recursivitatea n prelucrarea tablourilor unidimensionale


1. S se scrie un subprogram recursiv care determin minimul dintre
componentele unui vector citit de la tastatur.
type vect=array[1..10] of integer;
var v:vect;
n,i: integer;
function min(a,b:integer):integer;
begin
if a>=b then min:=b
else min:=a
end;
function minvect(n:integer):integer;
begin
if n=1 then minvect:=v[1]
else if n=2 then minvect:=min(v[1],v[2])
else minvect:=min(v[n],minvect(n-1))
end;
begin
write(Introduceti dimensiunea vectorului: );
readln(n);
for i:=1 to n do begin

write(v[,i,]= );
readln(v[i]);
end;
write(minimul este: , minvect(n));
readkey
end.
2. S se scrie un program care determin recursiv media aritmetic a
componentelor unui vector citit de la tastatur.
type vect=array[1..10] of real;
var v:vect;
n,i:integer;
function suma(k:integer):real;
begin
if k=1 then suma:=v[1];
else suma:=v[k]+suma(k-1);
end;
begin
write(Intoduceti dimensiunea vectorului: );
readln(n);
for i:=1 to n do begin
write(v[,i,]= );
readln(v[i]);
end;
writeln(Media aritmetica a elementelor vectorului este: ,
(suma(n)/n):6:2);
readkey
end.

3.S se scrie un program care determin recursiv produsul scalar a doi


vectori de numere ntregi citii de la tastatur.
type vect=array[1..10] of longint;
var a,b:vect;
n,i:integer;
function prods(k:integer):longint;
begin
if k=n then prods:=a[n]*b[n]

else prods:=a[k]*b[k]+prod(k+1);
end;
begin
write(Introduceti dimensiunea vectorilor: )
readln(n);
for i:=1 to n do begin
write(a[,i,]= );
readln(a[i]);
end;
writeln;
for i:=1 to n do begin
write(b[,i,]= );
readln(b[i]);
end;
writeln(Produsul scalar al vectorilor a i b este: , prods(1));
readkey
end.
4. S se scrie un program care caut existena unui element x citit de la
tastatur ntr-un ir ordonat cresctor, folosind metoda cutrii binare.
Ideea implementrii metodei cutrii binare este urmtoarea:
- se compar elementul x cu elementul din mijloc al irului;
- dac ele sunt egale, s-a gsit elementul cutat i algoritmul se
ntrerupe;
- dac elementul x este mai mnc dect cel din mijloc, vom relua
cutarea pentru prima parte a irului;
- dac este mai mare, cutarea se va face numai n partea dreapt a
irului fa de elemntul din mijloc.
Type vect=array[1..20] of integer;
Var v:vect;
poz,x,n,i:integer;
function cautbin(inc,sf:integer):integer;
var mij:integer;
begin
if inc<=sf then begin
mij:=(inc+sf) div2;
if x=v[mij] then cautbin:=mij;
else if x<v[mij] then
cautbin:=cautbin(inc,mij-1)
else

cautbin:=cautbin(mij+1,sf)
end;
else cautbin:=0;
end;
begin
writeln(Introduceti elementul cutat: );
readln(x);
write(Introduceti dimensiunea vectorului: );
readln(n);
for i:=1 to n do begin
write(v[,i,]= );
readln(v[i]);
end;
poz:=cautbin(1,n);
if poz=0 then
writeln(Elementul ,x, nu se afla n sir)
else writeln (Elementul ,x, se gsete n ir pe poziia:
,poz);
readkey
end.
5. S se rezolve recursiv problema punctului fix: fiind dat un vector
ordonat de numere ntregi distincte, s se determine un indice m (1<=m<=n), cu
v[m]=m, dac este posibil.
Vom folosi ideea problemei anterioare: determinm m mijlocul
vectorului i verificm dac v[m]>m, cum vectorul este ordonat cresctor, vom
efectua cutarea n stnga, altfel n dreapta.
type vect=array[1..20] of integer;
Var v:vect;
poz,n,i:integer;
function cautbin(inc,sf:integer):integer;
var mij:integer;
begin
if inc<=sf then begin
mij:=(inc+sf) div2;
if x=v[mij] then cautbin:=mij;
else if x<v[mij] then
cautbin:=cautbin(inc,mij-1)
else
cautbin:=cautbin(mij+1,sf)
end;

else cautbin:=0;
end;
begin
write(Introduceti dimensiunea vectorului: );
readln(n);
for i:=1 to n do begin
write(v[,i,]= );
readln(v[i]);
end;
poz:=cautbin(1,n);
if poz=0 then writeln(Sirul nu admite punct fix)
else writeln(Punctul fix se gsete n ir pe poziia ,poz);
readkey
end.

5.3. Alte probleme ce utilizeaz recursivitatea


1. Se citesc n,A1,r (numere naturale). S se calculeze
suma A1!+A2!+A3!+...+An!, unde A1,A2,,An reprezint termeni ai
progresiei aritmetice cu prim termen A1 i raie r, iar K!=1*2*3**k.
Se folosesc urmtoarele funcii recursive:
- function A(n:integer):integer- calculeaz termenul n al progresiei
aritmetice.
- function fact(n:integer):longint- calculeaz n!.
- function suma(n:integer):integer- calculeaz suma primilor n termeni
din irul cerut.
Toate sunt funcii pentru care nainte de implementare se caut o relaie de
recuren pentru funcia A.
var n,a1,r :integer;
function A(n:integer):integer;
begin
if n=1 then A:=A1
else A:=A(n-1)+r;
end;
function fact(n:integer):longint;
begin
if n=1 then fact:=1
else fact:=n*fact(n-1);
end;

function suma(n:integer):longint;
begin
if n=0 then suma:=0
else suma:=fact(A(n))+suma(n-1);
end;
begin
readln(n,A1,r);
writeln(suma(n));
end.
2 Se d un numr natural n. S se scrie n ca sum de
numere prime. Obs! 1 se va considera numr prim.
var a,x:array[0..100] of integer ;
n,I,s,m: integer;ok:boolean;
function prim(n:integer):boolean;
var i:integer;
begin
prim:=true;
for i:=2 to trunc(sqrt(n)) do
if n mod i=0 then
begin
prim:=false;break;
end;
end;
procedure tipar (k:integer);
var i:integer;
begin
for i:=1 to k do
write(a[x[i]]);
writeln;
end;
procedure back(k:integer);
var i:integer;
begin
for i:=x[k-1]+1 to n do
begin
x[k]:=I; s:=s+a[x[k]];

if s<=n then
if s=n then
tipar(k)
else
back(k+1);
s:=s-a[x[k]];
end;
end;
begin{main}
write(n= );readln(n);
m:=0;
for i:=1 to n do
if prim(i) then
begin
inc(m);
a[m]:=i;
end;
x[0]:=0;s:=0;
back(1);
readln;
end.

2. Se d un alfabet care conine v vocale i c consoane. S


se genereze toate cuvintele de lungime n care nu conin trei vocale sau trei
consoane alturate.
Vocalele i consoanele alfabetului vor fi memorate n vectorul a.
Primelev elemente reprezint vocalele, urmtoarele c elemente consoanele.
Vectorul soluie x=(x1,x2,,xn) va avea ca valori indicii elementelor din a iar
elementele sale vor lua valori din mulimea {1,,v+c}. Vocalele vor fi
elemente din a din poziiile {1,,v} , iar consoanele elementele din a din
poziiile {v+1,,v+c}.
Var x:array[1..20] of integer;
n,i,v,c,m:integer;
a:array[1..20] of char;
car:char;f:text;
function cont (k:integer):boolean;
var i:integer;

begin
cont:=true;
if k>2 then
if (x[k]<=v) then
begin
if (x[k-1]<=v) and (x[k-2]<=v) then
cont:=false;
end
else
if (x[k-1]>v) and (x[k-2]>v) then
cont:=false;
end;
procedure tipar;
var i:integer;
begin
for i:=1 to n do
write(a[x[i]]);
writeln;
end;
procedure back(k:integer);
var i:integer;
begin
for i:= 1 to v+c do
begin
x[k]:=1;
if cont(k) then
if k=n then
tipar
else
back(k+1);
end;
end;
begin
assign(f,date.in);
reset(f);
readln(f,n);
readln(f,v);
m:=0;
for i:=1 to v do
begin

read(f,car);inc(m);a[m]:=car;
end;
readln(f,c);
for i:=1 to c do
begin
read(f,car);inc(m);a[m]:=car;
end;
close(f);
back(1);
readln;
end.

3. Se consider n soldai numerotai de la 1 la n. Se citesc


de la intrare k perechi de numere (i,j) cu i<>j, 1<=i<=n, 1<=j<=n, cu
semnificaia c i este superiorul lui j. se cere s se aeze soldaii ntr-un rnd, n
mod ierarhic, astfel nct fiecare soldat s aib subalternii si situai dup el.
Exemplu : pentru n=6, k=4 i perechile (1,5), (4,5), (2,3), (1,4), ieirile
posibile sunt : 1 2 4 6 3 5, 2 1 4 5 3,
Pentru a reprezenta relaiile existente ntre soldai se va folosi un tablou
bidimensional n x n, ale crui elemente a[i,j] vor avea valorile 1 dac i este
superiorul lui j, 0 n caz contrar. Vectorul soluie va fi x=(x1,x2,,xn), x[k]
reprezint codificarea unui soldat, iar lementele sale or lua valori din mulimea
{1,,n}. Un element x[k] este valid dac sunt ndeplinite urmtoarele condiii
de continuare :
- este diferit de toate valorile determinate anterior
x[k]<>x[i], i={1,,k-1}
- nici un element anterior x[i] nu trebuie s fie subaltern
lui x[k]: a[x[k],x[i]]<>1, i={1,,k-1}
var a:array[1..20,1..20] of integer;
x,viz:array[1..20] of integer;
i,n,k,p,j:integer;f:text;
Function cont(k:integer):boolean;
Var i:integer;
Begin
Cont:=true;
for i:=1 to k-1 do
if a[x[k],x[i]]=1 then begin cont:=false;exit:end;
end;

procedure tipar;
var i:integer;
begin
for i:=1 to n do
write(f,x[i]);
writeln(f);
end;
5. La un concurs sunt prezentate 5 melodii notate
A,B,C,D,E. S se afieze toate posibilitile de a prezenta cele 5 melodii n
ipoteza c melodia B va fi prezentat naintea lui A.
Melodiile vor fi codificate prin numere de la 1 la 5. Elementele
vectorului soluie x=(x1,x2,x3,,x5) vor lua valori din mulimea {1,2,,5}.
Vectorul soluie trebuie s aib toate elementele distincte, valoarea 2 trebuie s
fie n vector naintea valorii 1. Astfel, condiiile de continuare sunt ndeplinite
dac :
- x[k]<>x[i], i={1,,k-1}
- dac x[k]=2 atunci x[i]<>1, i={1,,k-1}
Elementele vectorului soluie vor lua valori din mulimea
{A,B,C,D,E}. Vectorul viz ine evidena valorilor utilizate. Viz[i]=0
indic faptul c valoarea I nu a fost utilizat.
var x:array[1..5] of char;
viz:array[A..E]
of integer;
procedure tipar;
var i:integer;
begin
for i:= 1 to 5 do
write (x[i]);
writeln;
end;
function cont(k:integer):boolean;
var i:integer;
begin
cont:=true;
if x[k]=B then
for i:=1 yo k-1 do
if x[i]=A then begin cont:=false;brek;end;

end;
procedure back(k:integer);
var i:char;
bagin
for i:= A to E do
begin
x[k]:=i;
if viz[i]=0 then
if cont(k) then
begin
viz[i]:=1;
if k=5 then tipar
else
back(k+1);
viz[i]:=0;
end;
end;
end;
begin
back(1);
readln;end.
6. S se scrie un program care, citind n cuvnt i un numr natural
cuprins ntre 1 i lungimea cuvntului s se afieze toate anagramrile obinute
din acest cuvnt, dup eliminarea literei de pe poziia citit.
var x,viz:array[1..10] of integer;
cuv:strng;p:integer;
procedure tipar;
var i:integer;
bagin
for i:=1 to length(cuv) do
writw(cuv[x[i]]);
writeln;
end;
procedure back(k:integer);
var i:integer;
begin
for i:=1 to length(cuv) do
if viz[i]:=0 then

begin
x[k]:=i;
viz[i]:=1;
if k=length(cuv) then
tipar
else
back(k+1);
viz[i]:=0;
end;
end;
begin
write(dati cuvantul); readln(cuv);
reapeat
write(pozitia:);readln(p);
until p n [1..length(cuv)];
delete(cuv,p,1);
back(1);
readln;
end.

7. Figuri recursive
Dup cum am mai spus, recursivitatea are o mare arie de ntrebuinare i
de aplicabilitate. n continuare, voi prezenta o folosire a recursivitii n grafica
de sub Borland Pascal prin ncercarea de realizare a unor figuri recursive.
O astfel de figur recursiv este cea pe care o prezint mai jos.

Aceast figur o voi numi diamant. Observm forma recursiv a


acestui diamant. El este perfect caracterizat de coordonatele centrului su,
precum i de latura ptratului iniial. Ptratele imediat urmtoare, au laturile de
c ori mai mici, unde c este o constant real oarecare, c1. De fapt, acest
diamant se constituie dintr-un ptrat de centru (x,y) i de latur l i dintr-un cerc
cu acelai centru ca ptratul iar raza egal cu diferena dintre latura ptratului i
jumtate din diagonala sa. Ptratul are patru diamante n colurile sale. Aceasta
este o definiie recursiv a diamantului.
Astfel, vom putea scrie cu uurin o procedur care s-l deseneze.
Aceast procedur va desena un ptrat i un cerc, care au acelai centru, apoi se
va autoapela de patru ori, pentru cele patru diamante din colurile ptratului.
Trebuie s existe, ns, i o condiie de oprire deoarece programul ar afia
diamante din ce n ce mai mici de un numr infinit de ori, i astfel s-ar depi
stiva de memorie cu care lucreaz Borland Pascal. De aceea vom introduce o
condiia ca diamantele s fie desenate atta timp ct latura ptratului este mai
mare strict dect 0.
n program am folosit directivele de compilare {$S-} pentru a face
compilatorul s nu in seama de depirea stivei, i {$S+} pentru a reveni la
controlul normal al umplerii stivei.
Voi prezenta mai jos programul cu ajutorul cruia am realizat desenul
anterior, cu precizarea c singurele proceduri grafice pe care le-am folosit sunt:
Line i Circle. Nu voi insista asupra utilizrii graficii n Borland Pascal. Iat
programul:

program FiguraRecursiva;
var mg,er,d:integer;
procedure patratcerc(x,y,l:integer);
var l2:integer;
begin
l2:=round(l/sqrt(2));
line(x-l2,y,x,y-l2);
line(x,y-l2,x+l2,y);
line(x+l2,y,x,y+l2);
line(x,y+l2,x-l2,y);
circle(x,y,l-l2);
end;
{$S-}
procedure diamant(x,y,l:integer);
const c=2.7;
var l2,l3:integer;
begin

if l>0 then begin


patratcerc(x,y,l);
l2:=round(l/sqrt(2));
l3:=round(l/c);
diamant(x-l2,y,l3);
diamant(x,y+l2,l3);
diamant(x+l2,y,l3);
diamant(x,y-l2,l3);
end;
end;
{$S+}
begin
d:=detect;
initgraph(d,mg,'c:\bp\bgi');
er:=graphresult;
if er<>grok then
begin
writeln('Eroare grafica :',grapherrormsg(er));
halt;
end;
setcolor(blue);
setbkcolor(white);
diamant(GetMaxX div 2, GetMaxY div 2, GetMaxY div 3);
readln;
closegraph;
end.
Dac am prezentat o aplicaie grafic a recursivitii directe, trebuie s
prezentm i o aplicaie a recursivitii indirecte, realizat cu ajutorul cuvntului
cheie forward, despre care am vorbit n capitolele anterioare.
i aceast aplicaie se nscrie n seria figurilor recursive, i ilustreaz
totodat lucrul cu mouse-ul n modul grafic, dar nu voi insista asupra acestui
lucru. Precizez doar faptul c n program se folosete un unit pentru lucrul cu
mouse-ul, unit ce cuprinde unele proceduri realizate n limbaj de asamblare
(procedurile init, show, clear, done, getx, gety, etc.).
Astfel aciunea mouse-ului este urmtoarea: la apsarea butonului drept
se va afia o figur recursiv, iar la apsarea celuilalt buton, alt figur
recursiv.

Un posibil rezultat al programului pe care-l voi prezenta este urmtorul:

n acest exemplu am folosit de trei ori butonul drept al mouse-ului i de


patru ori pe cel stng. Se observ c acest diamant este o figur geometric (un
cerc ori un ptrat) care are la capetele unui diametru, respectiv unei diagonale,
cte un alt diamant care este de acelai tip cu el, iar la capetele diametrului
perpendicular pe el, respectiv a celeilalte diagonale, cte un diamant care nu
este de acelai tip cu el (diamantul realizat la apsarea celuilalt buton al mouseului).
Programul este urmtorul:
program DesenareCuMouse;
const n1=0;ns=1;nd=2;nt=3;
var am:tmouse;
x,y:integer;
d,mg,er:integer;
procedure romb(x,y,l:integer);
var l2:integer;
begin
l2:=round(l/sqrt(2));

line(x-l2,y,x,y-l2);
line(x,y-l2,x+l2,y);
line(x+l2,y,x,y+l2);
line(x,y+l2,x-l2,y);
end;
procedure diamantcercuri(x,y,l:integer); forward;
procedure diamantromburi(x,y,l:integer);
const c=2.3;
var l2,l3:integer;
begin
if l>0 then begin
romb(x,y,l);
l2:=round(l/sqrt(2));
l3:=round(l/c);
diamantcercuri(x-l2,y,l3);
diamantromburi(x,y-l2,l3);
diamantcercuri(x+l2,y,l3);
diamantromburi(x,y+l2,l3);
end;
end;
procedure diamantcercuri(x,y,l:integer);
const c=3;
var l2,l3:integer;
begin
if l>0 then begin
circle(x,y,l);
l2:=round(l/sqrt(2));
l3:=round(l/c);
diamantromburi(x-l2,y,l3);
diamantcercuri(x,y-l2,l3);
diamantromburi(x+l2,y,l3);
diamantcercuri(x,y+l2,l3);
end;
end;
{$S+}
begin
d:=detect;
initgraph(d,mg,'c:\bp\bgi');
er:=graphresult;
if er<>grok then
begin
writeln('Eroare grafica :',grapherrormsg(er));

halt;
end;
setcolor(blue);
setbkcolor(white);
am.init;
am.show;
repeat
x:=am.getx;
y:=am.gety;
if am.leftbutton then begin
am.clear;
diamantcercuri(x,y,50);
am.show;
end;
if am.rightbutton then begin
am.clear;
diamantromburi(x,y,50);
am.show;
end;
until (am.leftbutton and am.rightbutton) or keypressed;
end.

Cristea Valentin, Atanasiu Irina, Iorga Valeriu,


Kalisz Eugenia : ,,Tehnici de programare, Editura
Teora, Bucureti 1994;
Niculescu tefan, Cerchez Emanuela:
Bacalaureat i atestat n informatic, Editura L&S
Informat, Bucureti 1999;
Creu Vladimir Ioan, Rodica Pintea : Culegere
de probleme Pascal Editura Petrion, Timioara
1992 ;
Doina Rancea: Limbajul Pascal, vol I i II
Editura Libris, Cluj - 1994;
Carmen Popescu: Culegere de probleme de
informatic, Editura Donaris, Sibiu - 2002
Tudor Sorin: Tehnici de programare Editura
Teora, Bucureti - 1994;

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