Sunteți pe pagina 1din 53

MINISTERUL EDUCAIEI, CERCETRII I TINERETULUI

COLEGIUL TEHNIC MTSARI - GORJ


PROF. COORDONATOR:
SCEANU ION
ELEV:
Girjo! Cri"#i$
CLASA %II- &
Pro'i(: )#*)#i+,-i$'or)#i+,

MINISTERUL EDUCAIEI, CERCETRII I TINERETULUI
COLEGIUL TEHNIC MTSARI - GORJ
PROF. COORDONATOR:
SCEANU ION

ELEV:
Girjo! Cri"#i$
CLASA %II- &
Pro'i(: )#*)#i+,-i$'or)#i+,


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. Bibliografie50
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
Discutia se face pentru cazul implementarii recursivitii n
PASCAL, dar lucrurile sunt similare pentru C.
n PASCAL, exista doua tipuri de parametri formali (ce
apar n antetul unei proceduri sau functii) : valoare i variabila
(ultimii au numele precedat de cuvntul cheie var).
Apelul recursiv al unei proceduri (functii) face ca pentru
toti parametrii-valoare s se creeze copii locale apelului curent
(n stiva) , acestea fiind referite i asupra lor facndu-se
modificarile n timpul executiei curente a procedurii (functiei).
Cnd executia procedurii (functiei) se termina, copiile sunt
extrase din stiv, astfel incit modificarile operate asupra
parametrilor-valoare nu afecteaza parametrii efectivi de apel,
corespunzatori.
De asemenea pentru toate variabilele locale se rezerva
spatiu la fiecare apel recursiv. n cazul parametrilor-variabila,
nu se creaza copii locale, ci operarea se face direct asupra
spatiului de memorie afectat parametrilor efectivi, de apel.
De reinut:
-pentru fiecare apel recursiv al unei proceduri (functii) se
creaza copii locale ale parametrilor valoare i variabilelor
locale, ceea ce poate duce la risipa de memorie;
-orice parametru-variabila poate fi suprimat prin referirea
direct n procedura (functie) a variabilei ce figura ca
parametru de apel.
1.3 eri!icarea i simularea pro"ramelor recursive
Se face ca n cazul celor nerecursive, printr-o
demonstratie formala, sau testind toate cazurile posibile. Se
verifica intii dac toate cazurile particulare (ce se executa cind
se indeplineste conditia de terminare a apelului recursiv)
functioneaza corect.
Se face apoi o verificare formala a procedurii (functiei)
recursive, pentru restul cazurilor, presupunind ca toate
componentele din codul procedurii (functiei) functioneaza
corect. Verificarea e deci inductiva.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 corecta
-pentru n>1, presupunind corecta valoarea calculata pentru
predecesorul lui n de fact(n-1), prin inmultirea acesteia cu n se
obtine valoarea corect a factorialului lui n.
1.# $e%&ica elimi&rii recursivit'ii
Orice program recursiv poate fi transformat n unul
iterativ, dar algoritmul sau poate deveni mai complicat i mai
greu de inteles. De multe ori, solutia unei probleme poate fi
elaborata mult mai usor, mai clar i mai simplu de verificat,
printr-un algoritm recursiv.
Dar pentru implementare, poate fi necesara
transformarea algoritmului recursiv n unul nerecursiv, n
situatiile:
-solutia problemei trebuie scrisa intr-un limbaj nerecursiv; un
caz particularsuntcompilatoarele ce "traduc" un program
recursiv dintr-un limbaj de nivel inalt n cod masina
(nerecursiv)
-varianta recursiv ar duce la o viteza de executie i spatiu de
memorie prea mari, transformarea n una nerecursiv,
eliminind dezavantajele.
Se va prezenta una din metodele de eliminare a
recursivitii ce foloseste o structura de date de tip stiva. n
scrierea unei varianta nerecursive, trebuie parcursi toti paii
implicati n varianta recursiv, prin tehnici nerecursive.
Recursivitatea implica folosirea a cel putin unei stive. La
fiecare apel recursiv sunt depuse n stiv niste date,
caresuntextrase la revenirea din acel apel. E simplu dac
datele pentru un apel se organizeaza intr-un record, un apel
nsemnnd introducerea n stiv a unui record, revenirea,
extragerea lui.
Se prezint eliminarea recursivitii pentru un program
simplu, care citeste 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
*iniializeaza stiva
while not eoln do
begin
read(car);
push(car)
end;
while not stiva_goala do
begin
pop(car);
write(car)
end
end.
1.( )*emple +e al"oritmi recursivi
1.5.1 Algoritmi de traversare i inversare a unei
structuri
Traversarea i inversarea unei structuri inseamna
efectuarea unor operatii oarecare asupra tuturor elementelor
unei structuri n ordine direct, respectiv n ordine inversa.
Dei mai uzualesuntvariantele iterative, caz n care
inversarea echivaleaza cu doua traversari directe (o salvare n
stiva urmata de parcurgerea stivei), variantele
recursivesuntmai elegante i concise. Se pot aplica structurilor
de tip tablou, lista, fisier i pot fi o solutie pentru diverse
probleme (transformarea unui intreg dintr-o baza n alta, etc).
Intr-o forma 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_urmator)
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_urmator);
prelucrare(element)
end;
De observat importanta ca parametrul formal al celor doua
proceduri s fie de tip valoare, pentru a nu fi alterat de apelul
recursiv.
1.5.2 Algoritmi care implementeaz definiii
recursive
O definitie recursiv e cea n care un obiect se defineste
prin el insusi. Definitia contine o conditie de terminare,
indicnd modul de parasire a definitiei i o parte ce precizeaza
definirea recursiv propriu-zis.
Ca exemple: algoritmul lui Euclid de aflare a c.m.m.d.c.,
factorialul, ridicarea la o putere intreag (prin inmultiri
repetate), definirea recursiv a unei expreii aritmetice,
curbele recursive, un mod de a privi permutarile, 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 output-ului 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 a!a unui al"oritm#
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 adau"$nd 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 (!)
10
-- (101)
2
.
Reprezentarea binara a lui 2= reprezentarea binara a lui 2
div 2 adau"$nd 2 mod 2
(2)
10
"(10)
2
Reprezentarea binara a lui 5= reprezentarea binara a lui 5
div 2 adau"$nd & mod 2
(!)
10
"(101)
2
Implementarea (Borland) PASCAL a acestui algoritm
recursiv este programul binar.
#$O%$&M binar;
{Afiseaza echivalentul binar al ntregilor zecimali}
'&$ n:integer;
#$O(ED)$E binary(n:integer);
{Conversie recursiva a lui n zecimal n forma binara}
*E%IN
IF n<2 THEN write(n:2) ELSE
{aplica pasul inductiv:}
*E%IN
binary (n div 2);write(n +,d 2)
END-
END {binary};
*E%IN {principal}
.HILE NOT eof DO
*E%IN
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 pre"ateste
pentru editare o secventa de caractere (care intra) p$na c$nd
conditia eof este detectata 'i apoi, 'i numai apoi, tipareste
caracterele citite n ordine inversa.
#$O%$&M tipar;
{Citeste propozitiile pn la eof dupa care tipareste propozitia
n sens invers}
#$O(ED)$E flipcar;
{Inverseaza recursiv caracterele pn la eoln}
'&$ ch:char;
*E%IN
read(ch);
IF eoln THEN write(ch) ELSE
*E%IN {pasul inductiv}
flipcar;
write(ch)
END
END {flipcar};
*E%IN {principal}
.HILE NOT eof DO
*E%IN
writeln('Introduceti o propozitie pe o singura linie de input');
flipcar;
writeln
END
END {tipar}.
Rezultatele execuiei programului:
In/0t
&F&$& #LO)& LINISTIT
)NI'E$SIT&TE& DE 'EST ESTE 1N TIMISO&$&
&M FOST 1N *)()$ESTI
O0t/0t
TITSINIL &)OL# &$&F&
&$&OSIMIT NI ETSE TSE' ED &ET&TIS$E'IN)
ITSE$)()* NI TSOF M&
#r,b2e+a3 T0rn0ri2e din Han,i. Presupunem ca avem
cinci discuri (turnuri), gaurite n centru, ca n exemplul urmator
(numarul de ace este trei ntotdeauna, dar numarul de discuri
poate varia). Ce se doreste? S mutam discurile (turnurile)
unul cte unul, de la acul 1 la acul 3, folosind acul 2 ca...
gazda temporara, n conditiile n care la fiecare mutare se
deplaseaza un singur disc, i n nici o etapa nu este admis ca
un disc mai mare s stea pe un disc mai mic. Raspunsul dorit
este o lista de mutari, de genul: "Muta un disc de la acul 1 la
acul 3".
(,n4i50ratia /entr0 cinci disc0ri (t0rn0ri2e din Han,i)3
Desigur, va veti ntreba unde intervine recursivitatea?
Analiznd problema observam ca pentru cele 5 discuri, am fi
capabili s mutam ultimul disc numai daca, ntr-un mod
oarecare am putea manevra cele patru discuri de deasupra, pe
acul al doilea, lasnd acul al treilea lier pentru a primi discul
ramas (cel mai mare) de la primul ac. Alta prolema, de
aceeasi dimensiune, este mutarea celor patru discuri la acul
trei (dupa mutarea discului mai mare, conform descrierii
anterioare). (oi "enerali!am prolema, reali!$nd o procedura
move (n, a, , c) care, ntr)un fel, stie cum s* mute n discuri,
de la acul a la acul prin intermediul acului c 'i care listea!a
toate mutarile necesare pentru... atin"erea oiectivului. +aca
procedura move lucrea!a corect, solutia la prolema cu cinci
discuri este cea ilustrata n continuare.
MO'E(6717872)-
{Muta 4 discuri de la acul 1 la 3 prin intermediul acului 2}
Writeln('Muta un disc de la acul 1 la acul 3');
MO'E(6787271)-
{Muta 4 discuri de la acul 3 la acul 2 prin intermediul acului 1
pentru a completa solutia problemei cu 5 discuri}
Cum procedam s realizam primul i al treilea pas?
Recursivitatea directa: problema cu cinci discuri poate fi
rezolvata daca solutionam problema cu patru discuri i asa mai
departe, pna la problema care nu implica nici un disc.
Problema cu nici un disc este usor de rezolvat i furnizeaza
bootstrap-ul: pentru n=0, nu se face nimic!
Functia cheie move (ve!i pro"ramul de mai ,os) este
folosita n cadrul unui pro"ram care permite utili!atorului s*
introduca numarul de discuri ce treuie mutate. -estati functia
pentru valori mici, cum ar fi n./ dar, atentie la valori mari,
deoarece ele tind s* consume foarte mult timp!
#$O%$&M turnuri;
T9#E
In/0tdisk=integer;
In/0tac=1..3;
'&$
In/0tndisk:integer;
#$O(ED)$E MOVE(n:disk;a,b,c:ac);
{Muta n disk-uri de la acul a la acul b,via c}
*E%IN
In/0tIF n>0 THEN {se aplica pasul inductiv}
In/0t*E%IN
In/0tIn/0tMOVE(n-1, a,c,b);
In/0tIn/0twriteln('Muta un disc de la',a:2,'la',b:2);
In/0tIn/0tMOVE(n-1,c,b,a)
In/0tEND
END {MOVE};
*E%IN {principal}
In/0t.HILE NOT eof DO
In/0t*E%IN
In/0tIn/0twrite('Introduceti numarul de discuri ce trebuie
mutate:')
In/0tIn/0treadln(ndisk);
In/0tIn/0twriteln;
In/0tIn/0tMOVE(ndisk,1,3,2);
In/0tIn/0twriteln
In/0tEND
END {turnuri}.
Rezultatele executiei programului:
$e+arc!
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!
Intr,d0ceti n0+ar02 de disc0ri ce treb0ie +0tate38
M0ta 0n disc de 2a 1 2a 8
M0ta 0n disc de 2a 1 2a 2
M0ta 0n disc de 2a 8 2a 2
M0ta 0n disc de 2a 1 2a 8
M0ta 0n disc de 2a 2 2a 1
M0ta 0n disc de 2a 2 2a 8
M0ta 0n disc de 2a 1 2a 8
3. Funcii recursive
Una din cele mai simple functii matematice este, fara
ndoiala functia 4act,ria2.
Din moment ce (Borland) PASCAL-ul nu are o functie (de
biblioteca) standard pentru calculul factorialului, va trebui s
scriem noi una. Definirea lui n! (se citeste "n factorial") este
produsul:
n : (n-1) : (n-2) :;;;: 8 : 2 : 1 (pentru un ntreg mai mare
ca 0; 0!=1).
Aceasta definitie poate fi implementata n (Borland) PASCAL
prin functia descrisa n continuare#
E:e+/203
F)N(TION fact(n:integer):integer;
'&$ i,t:integer;
*E%IN
t:=1;
FO$ i:=n d,<nt, 2 DO t:=t*i;
fact:=t
END {fact};
Cnd vrem s subliniem ca o functie nu este recursiva
(dar ar fi putut fi !) noi o numim functie iterativa. Remarcati ca
enuntul iterativ folosit (o bucl FOR) nu este executat
niciodata pentru n mai mic ca 2 ) functia returnea!a valoarea 1
at$t pentru 1! c$t 'i pentru 0!. 0ariaila de control al uclei (i)
ia valori p$na la 2, nu p$na la 1 pentru a evita o nmultire
inutila cu 1 n final. 0ariaila (de stare) t este necesara pentru
a evita folosirea lui fact (numele functiei) n partea dreapta a
enuntului de atriuire t#.t1i. 2ompilatorul (3orland) 4A52A6
se asteapta ca un nume de functie s* apara numai n partea
dreapta a enuntului de atriuire, acela care lea"a numele
functiei de o valoare particulara. 7ata n exemplul urmator o
alternativa de definire a lui n! care este mai de"raa recursiva
dec$t iterativa.
IF n=0 THEN fact:=1
ELSE fact:=n*fact(n-1)
Clauza IF este extrem de importanta, din moment ce fara
ea secventa va... cur"e, indefinit#
;8!" 8:2!
;;;" 8:2:1!
;;;" 8:2:1:0!
;;;" 8:2:1:0:(-1)!
;;;" 8:2:1:0:(-1)!:(-2)!
;;;;;;
Testul care previne o asemenea recursivitate nedefinita se
numeste bootstrap condition 'i repre!inta un element
esential al oricarei rutine recursive. Aici, ootstrap condition
este 8IF n.0 THEN fact#.19 care opreste calculul lui n! de la
o rulare nedefinita. 7ata functia recursiva (3orland) 4A52A6
pentru calculul lui n!
F)N(TION fact(n:integer):integer;
{functia recursiva pentru calculul lui n!}
*E%IN
IF n=0 THEN fact:=1
ELSE fact:=n*fact(n-1)
END {fact};
Cele doua aparitii ale lui fact n partea st$n"a a
enunturilor de atriuire respecta re"ula prin care unei functii i
se atriuie o valoare particulara. 2eea ce face ca fact s* fie o
functie recursiva este pre!enta lui fact (n)1) n memrul drept
al enuntului 4act3"n=4act (n-1). Asocierea lui fact cu
ar"umentul n-1, presupune ca atunci cnd implicam functia
fact, ea se va apela pe ea nsasi.
&sa c0+ a treb0it s >nvata+ c0+ s scrie+ b0c2e
care se ter+ina d0/a 0n n0+ar 4init de iteratii7 treb0ie
s >nvata+ s c,nstr0i+ 40nctii rec0rsive care se
ter+ina c0 s0cces d0/a , serie 4inita de re4eriri 2a sine;
nvatarea modului de folosire a recursivitatii este mai
importanta dect ntele"erea modului cum lucrea!a. 4re!entam
doua re"uli simple, dar esentiale.
$e502i3
1) Orice functie sau procedura recursiva trebuie s aiba
cel putin o b,,tstra/ c,nditi,n, care specifica raspunsul
corect sau actiunea pentru cea mai simpla situatie imaginabila,
n general una corespunzatoare celei mai mici valori parametru
(cea de final);
2) Orice functie sau procedura recursiva trebuie s aiba
un pas inductiv (inductive step) care leaga problema ce trebuie
rezolvata de cea mai simpla versiune.
Pentru functia factorial (fact recursiva), ootstrap
condition este 0!.1, iar inductive step (pasul inductiv) lea"a
pe n! de (n)1)! care ram$ne nc:is la ootstrap.
La prima vedere, functia factorial - fact recursiva pare s*
aia nevoie de mai putina memorie dec$t omoloa"a s*
nerecursiva deoarece este folosita variaila nontemporara
(stare) t, dar aceasta este o ilu!ie. ;n spatele ... scenei, o
rutina recursiva treuie s* salve!e una sau mai multe valori
intermediare ori de c$te ori ea se apelea!a pe ea nsasi. Ea
salvea!a aceste valori n forma de stac<, o structura de date n
care ultimul item salvat este primul ce poate fi rec:emat.
$e+arc!
Alte nume pentru stack sunt pushdown stack i 2i4, list
(2i4, este prescurtarea de la "last n, first out").
Alta posibila operatie recursiva este a
n
) a ridicat la
puterea n (unde n 9. 0).
Ceea ce urmeaza este o solutie nerecursiva, bazata pe
multiplicarea lui a cu el nsusi de n ori.
F)N(TION putere (a:real; n:integer):real;
{O functie iterativa pentru calculul lui a la puterea n}
'&$ t:real;
i:integer;
*E%IN
t:=1;
FO$ i:=1 TO n DO t:=t*a;
putere:=t
END {putere};
Pentru n=0, bucla FOR nu se va executa, "ener$nd a
0
.1,
valoare evident corecta. 4entru n9.1, t devine n ordine a, a
2
,
a
=
'i tot asa p$na la a
n
.
Definirea recursiva a lui a
n
este#
IF n=0 THEN a
n
:=1; unde a
n
=a*a
n-1
Conditia bootstrap este a
0
.1. 4asul inductiv (inductive
step) a
n
.a1a
n)1
, lea"a prolema "enerala a
n
de prolema a
n)1
,
care ram$ne pe loc la ootstrap.
Traducerea (3orland) 4A52A6 a acestei definitii este
ilustrata n secventa urmatoare#
F)N(TION putere (a:real; n:integer):real;
*E%IN
IF n=0 THEN putere:=1
ELSE putere:=a*putere(a,n-1)
END {putere};
Exista ceva dezorganizat n ambele versiuni ale lui
putere. Ati calculat a
16
, fac$nd 1& nmultiri ? 4roail ca nu>
ati oservat ca a
16
.(a
?
)
2
'i ca a
?
.(a
@
)
2
'i tot asa mai departe.
Astfel, n realitate avem nevoie de @ nmultiri pentru a calcula
a
16
. Evident, aceasta n,umatatire maxima nu va lucra la fel,
daca n este impar. ;n consecinta, un al"oritm recursiv
munatatit treuie s* fie structurat astfel#
IF n=0 THEN a
n
=1
ELSE IF n is odd THEN a
n
=a*a
n-1

ELSE a
n
=(a
n/2
)
2

Aceasta definire are doi pasi inductivi, unul folosit pentru
n impar, celalalt utilizat pentru n par. Asa cum s-a cerut, ambii
pasi inductivi leaga problema de o dimensiune data, de una
care ramne nchisa la bootstrap. Programul (Borland) PASCAL
ce codifica acest algoritm mbunatatit este prezentat n
continuare:
E:e+/203
F)N(TION putere (a:real;n:integer):real;
*E%IN
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, aceasta versiune a lui putere
foloseste mai degraba un numar de nmultiri egal cu log
2
n
dec$t cu n)1, ca n versiunea precedenta. 4entru n.6@, unde
lo"
2
6@.6, aceasta repre!inta o economie n!ecita.
Observa?ie!
Remarcati ca ntruct exista o mica diferenta ntre
numarul de enunturi (Borland) PASCAL folosite pentru
versiunile recursiva, respectiv iterativa ale lui 4act sau pentru
primele doua versiuni (ineficiente) ale lui /0tere, este pe
undeva prea dificil s recodificam versiunea eficienta a lui
/0tere fara a folosi recursivitatea.
Implementarea recursiva a unui algoritm este adesea
mult mai naturala i mult mai lizibila dect implementarea
iterativa echivalenta.
Unul dintre cei mai cunoscuti algoritmi este algoritmul lui
Euclid, care calculeaza cel mai mare divizor comun (gcd) a doi
ntregi pozitivi, nenuli m i n. De exemplu, daca m este 45 i n
este 30, c.m.m.d.c. al lor este 15; daca 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. Daca m=n, atunci c.m.m.d.c. este m (sau n); n caz
contrar, se nlocuieste numarul mai mare cu diferenta celor
doua numere i procesul se repeta.
Functia iterativa (Borland) PASCAL care corespunde
acestei definitii este ilustrata de#
F)N(TION gcd1(m,n:integer):integer;
*E%IN
.HILE m<>n DO
IF m>n THEN m:=m-n
ELSE n:=n-m;
gcd1:=m
END {gcd1};
Versiunea recursiva, cu aceeasi logica, este prezentata n
continuare:
F)N(TION gcd2(m,n:integer):integer;
*E%IN
IF m=n THEN gcd2:=m ELSE
IF m>n THEN gcd2:=gcd2(m-n,n)
ELSE gcd2:=gcd2(m,n-m)
END {gcd2};
$e+arc!
Cele doua versiuni sunt foarte ineficiente cnd diferenta
dintre m i n este mare , deoarece determina un numar
considerabil de scaderi succesive pna cnd numerele sunt
aduse n acord. Dar o asemenea scadere repetata se constituie
ntr-un paravan; un algoritm recursiv mult mai bun poate fi
codificat folosind operatorul +,d.
F)N(TION gcd(m,n:integer):integer;
{Returneaza c.m.m.d.c. al lui m i n>0}
'&$ r:integer;
*E%IN
r:=m +,d 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
In acest capitol prezentam rutina de backtracking
recursiva. Procedurile si functiile folosite sunt in general
aceleasi ca la backtracking, cu doua mici exceptii:
-SUCCESOR nu mai este procedura ci functie booleana ;
-rutina backtracking se transforma in procedura,care se
apeleaza prin BACK(1)
Principiul de functionare al procedurii BACK,corespunzator
unui nivel k este urmatorul:
-in situatia in care avem o solutie,o tiparim si revenim pe
nivelul anterior
-in caz contrar se initializeaza nivelul si se cauta un
succesor
-cand am gasit unul verificam daca este valid;procedura
se autoapeleaza pentru (k+1) , in caz contrar urmand a se
continua cautarea succesorului;
-daca nu avem succesor,se trece pe nivel inferior (k-1)
prin iesirea din procedura BACK
Vom explica in continuare utilizarea backtrackingului
recursiv prin generarea permutarilor:
type stiva=array[1..9] of integer;
var st:stiva;
ev:boolean;n,k:integer;
procedure init(k:integer;var st:stiva);
begin
st[k]:=0;
end;
function succesor(var st:stiva;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:stiva;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 solutie(k:integer):boolean;
begin
solutie:=(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 solutie (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 problema care admite rezolvare
backtracking,poate fi rezolvata in acest mod.Insa,de multe ori,
aceeasi problema se poate rezolva scriind mai putin, daca
renuntam la standardizare.
5. Funcii Forward. Referine forward
O funcie sau o procedura nu poate fi recursiva numai
intrinsec, ea poate deveni de asemenea recursiva indirect prin
interactiunea cu alte proceduri sau functii care nu au fost nca
declarate. De exemplu, p1 'i p pot forma o perec:e recursiva
mutuala (mutuallA recursive pair, n lima en"le!a) daca p1
c:eama pe p 'i p c:eama pe p1, sau mai multe rutine pot
crea o recursivitate indirecta printr)un lant circular de apelari
cum ar fi p1)9 p2)9 p=)9 ...)9 pn)9 p1.
Consideram urmatorul exemplu de recursivitate mutuala.
S presupunem ca nu exista functiile (Borland) PASCAL de
biblioteca sin 'i cos 'i ca dorim s* implementam o perec:e
care s* se c:eme sine 'i cosine. 2onsideram identitatile
tri"onometrice cunoscute.
sin(:)"2 sin(:@2)c,s(:@2)
c,s(:)"c,s
2
(:@2)-sin
2
(:@2)
Pentru ca ambele identitati s constituie baza rutinelor
sine 'i cosine treuie s* oservam urmatoarele#
att sine c$t 'i cosine se apelea!a pe el nsele, deci sunt
recursive>
fiecare functie apeleaza pe cealalta, astfel ele formea!a o
perec:e mutuala recursiva>
conditiile bootstrap sunt necesare pentru a duce la bun
sfrsit programul;
indiferent de ordinea de scriere a rutinelor, compilatorul
(Borland) PASCAL va obiecta, n mod normal la ntlnirea
unei referiri la o functie al carei cod se afla mai departe
(n continuare).
Primele doua puncte sunt numai observatii. Ultimele doua
sunt probleme ce trebuie rezolvate.
Pentru nceput, s abordam problema conditiilor
bootstrap. ntruct sin(:) i c,s(:) folosesc ca argumente
unghiul pe jumatate care n interiorul... cuibului recursiv devin
din ce n ce mai mici, am putea avea propriile noastre
bootstrap-uri.
Pentru valori mici ale lui x este aproape adevarat ca sin x
i cos x au valorile definite de primii doi termeni: (x-x
=
B6),
respectiv 1)x
2
B2 dintr)o serie infinita.
sin: A :-:
8
@B
c,s: A 1-:
2
@2
Ne ntrebam: ct de mic trebuie s fie x pentru a ne
permite noua s ne bazam pe aceste aproximatii. Aceasta
depinde de c$t de multe !ecimale ne vom astepta la
raspunsurile date. Cn matematician ne)ar raspunde ca pentru
x 8 0.02 aproximarea lui cos x poate fi facuta cu ? !ecimale,
iar pentru sinx este c:iar mai una.
n rutinele pe care le vom pre!enta, valorile mai mici
dec$t 0.02 'i 0.01 servesc ca ootstrap)uri 'i sunt numite
e/si2,n. n fiecare rutina e/si2,n este declarat ca o constanta
astfel nct valoarea s poate fi usor modificata, n functie de
experiment .
Impedimentul final l constituie situatia "chicken-and-egg"
(gaina-i-oul) referitoare la ordinea relativa a lui sine 'i
cosine din interiorul codului sursa. +in fericire, un pas de
compilare n (3orland) 4A52A6 cere ca numai o procedura sau
o functie s* poata fi alimentate cu elementele pentru :eader)ul
rutinii apelate.
Cnd este definit un asemenea header, includerea
cuvntului rezervat for!ard va anunta compilatorul (3orland)
4A52A6 ca ntre" corpul lo"ic al rutinei mpreuna cu toate
declaratiile sale vor aparea mai t$r!iu n pro"ram. ;n ca!ul
nostru, vom scrie urmatorul :eader#
F)N(TION cosine(x:real): real; forward;
dupa care vom proceda la fel pentru functia sine.
F)N(TION cosine(x:real):real;forward;
F)N(TION sine(x:real):real;
Prezentam n cele ce urmeaza functiile mutuale complet
recursive cosine 'i sine#
F)N(TION cosine(x:real):real;forward;
F)N(TION sine(x:real):real;
(ONST epsilon=0.01;
*E%IN
IF abs(x)<epsilon THEN sine:=x*(1-x*x/6)
ELSE sine:=2*sine(x/2)*cosine(x/2)
END {sine};
F)N(TION cosine(x:real):real;
(ONST
epsilon=0.02;
*E%IN
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 in 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 tastatura 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
4 5
3 4 5
2 3 4 5
1 2 3 4 5
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, a=0 ai
ecuaiei: ax+bx+cx+d=0. Notm cu x
1
,x
2
,x
3
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: S
n
= x
1
n
+x
2
n
+x
3
n
S
0
=x
1
0
+x
2
0
+x
3
0
=3
S
1
=x
1
+x
2
+x
3
= -b/a
S
2
=x
1
2
+x
2
2
+x
3
2
= (x
1
+x
2
+x
3
)
2
-2(x
1
x
2
+x
1
x
3
+x
2
x
3
)=S
1
2
-2c/a
.
avem c aS
n
+bS
n-1
+cS
n-2
+dS
n-3
=0, adic
S
n
=-b/aS
n-1
- c/aS
n-2
- d/aS
n-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)=

=
=
= =
rest n b), mod a cmmdc(b,
0 b dac a,
0 a dac b,
0 b si 0 a dac exist, nu
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 C
k
n
,
utiliznd formula de recuren:
C
k
n
=
rest in , C + C
1 = k dac n,
0 = k dac 1,
1 - k
1 - n
k
1 - n


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 intregi 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 si b este: , prods(1));
readkey
end.
4. S se scrie un program care caut existena unui
element x citit de la tastatur ntr-un sir 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 minc 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 cautat: `);
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 in sir)
else writeln (`Elementul `,x, se gaseste in sir pe pozitia:
,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 gaseste in sir pe pozitia ,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#inte"er)#inte"er- calculeaz termenul n al
progresiei aritmetice.
- function fact(n#inte"er)#lon"int) calculeaz n!.
- function suma(n#inte"er)#inte"er) 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.
3. 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 multimea {1,.,v+c}. Vocalele vor fi elemente din
a din pozitiile {1,.,v} , iar consoanele elementele din a din
pozitiile {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.
4. 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 semnificatia ca i este superiorul lui j. se cere sa
se aseze soldatii intr-un rand, in mod ierarhic, astfel incat
fiecare soldat sa aiba subalternii sai situati dupa el.
Exemplu : pentru n=6, k=4 si perechile (1,5), (4,5),
(2,3), (1,4), iesirile posibile sunt : 1 2 4 6 3 5, 2 1 4 5 3, .
Pentru a reprezenta relatiile existente intre soldati se va
folosi un tablou bidimensional n x n, ale carui elemente a[i,j]
vor avea valorile 1 daca i este superiorul lui j, 0 in caz contrar.
Vectorul solutie va fi x=(x1,x2,.,xn), x[k] reprezinta
codificarea unui soldat, iar lementele sale or lua valori din
multimea {1,.,n}. Un element x[k] este valid daca sunt
indeplinite urmatoarele conditii 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 sa 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. Sa se afiseze toate posibilitatile de a prezenta cele 5
melodii in ipoteza ca melodia B va fi prezentata inaintea lui A.
Melodiile vor fi codificate prin numere de la 1 la 5.
Elementele vectorului solutie x=(x1,x2,x3,.,x5) vor lua valori
din multimea {1,2,.,5}. Vectorul solutie trebuie sa aiba toate
elementele distincte, valoarea 2 trebuie sa fie in vector
inaintea valorii 1. Astfel, conditiile de continuare sunt
indeplinite daca :
- x[k]<>x[i], i={1,.,k-1}
- daca x[k]=2 atunci x[i]<>1, i={1,.,k-1}
Elementele vectorului solutie vor lua valori din multimea
{`A,B,C,D,E}. Vectorul viz tine evidenta valorilor utilizate.
Viz[i]=0 indica faptul ca valoarea I nu a fost utilizata.
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. Sa se scrie un program care, citind in cuvant si un
numar natural cuprins intre 1 si lungimea cuvantului sa se
afiseze toate anagramarile obtinute din acest cuvant, dupa
eliminarea literei de pe pozitia citita.
var x,viz:array[1..10] of integer;
cuv:string;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 in [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, cl1. 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 mouse-ului).
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,
Kalis !ugenia " ,,Tehnici de programare, !ditura
#eora, $ucure%ti & '(()*
+iculescu ,te-an, Cerc.e !manuela"
Bacalaureat i atestat n informatic, !ditura /01
In-ormat, $ucure%ti & '(((*
Cre2u Vladimir Ioan, 3odica 4intea " Culegere
de probleme Pascal !ditura 4etrion, #imi%oara &
'((5 *

6oina 3ancea" imba!ul Pascal, 7ol I %i II
!ditura /ibris, Clu8 9 '(()*
Carmen 4o:escu" Culegere de probleme de
informatic, !ditura 6onaris, 1ibiu 9 5005
#udor 1orin" ;Tehnici de programare< !ditura
#eora, $ucure%ti 9 '(()*

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