You are on page 1of 179

Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica

Prof.Bogdan Constantin

Teme de specialitate pentru concursuri in informatica si


grade didactice
CONŢINUTUL PROGRAMEI
1. Arhitectura generală a sistemelor de calcul
- prezentare globală
- unitate centrală: componente, funcţii
- unitatea de memorie: structură şi funcţii
- dispozitive periferice
2. Sisteme de operare
- concepte de bază şi caracteristici ale sistemelor de operare (structură, funcţii,
elemente de interfaţă)
- tipuri de sisteme de operare
- (*) utilizarea unui sistem de operare
3. Algoritmi
- noţiunea de algoritm şi caracteristici
- structuri fundamentale( secvenţa, decizia, repetiţia)
- reprezentarea algoritmilor
- algoritmi iterativi şi recursivi
- algoritmi elementari: probleme care operează asupra cifrelor unui număr,
divizibilitate, numere prime, algoritmul lui Euclid, şirul lui Fibonacci, calculul unor
sume cu termenul general dat, determinare minim/maxim, metode de ordonare
(metoda bulelor, inserţie, selecţie, numărare), interclasare, metode de căutare
(secvenţială, binară)
- analiza complexităţii unui algoritm (considerând criteriile de eficienţă duratã de
executare şi spaþiu de memorie utilizat)
4. Limbaje de programare (Pascal sau C/C++)
- concepte generale (sintaxa unui limbaj de programare, medii de programare)
- (*) elementele de bază ale unui limbaj de programare (Pascal sau C, la alegere):
vocabularul limbajului, identificatori, constante, tipuri de dată, variabile, operatori,
structura programelor, comentarii, expresii, atribuire. Citirea/scrierea datelor.
Structuri de control (instrucţiunea compusă, structuri alternative şi repetitive)
- (*) tipuri de date structurate
- (*) fişiere; operaţii specifice
- (*) subprograme definite de utilizator: proiectarea modulară a rezolvării unei
probleme; declarare, definire şi apel subprograme; mecanismul de transmitere a
informaţiilor prin parametri; variabile globale şi variabile locale, domeniu de
vizibilitate; recursivitate
- concepte de bază ale programării orientată pe obiecte (principiile programării
orientată pe obiecte, încapsulare, moştenire, polimorfism, constructori şi destructori,
domeniul de vizibilitate a componentelor unui obiect)
5. Metode de programare
- metoda Backtracking: prezentare generală, probleme de generare, oportunitatea
utilizării metodei backtracking; aplicaţii specifice
5
- metoda Divide et Impera. Descriere şi aplicabilitate. Exemple. Sortarea prin
interclasare. Sortarea rapidă (quicksort)
- metoda Greedy. Descriere şi aplicabilitate. Exemple şi contraexemple
- algoritmi combinatoriali: generare permutări, aranjamente, combinări, produs
cartezian, submulţimile unei mulţimi, partiţii.
6. Implementarea metodelor numerice

1
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

- rezolvarea ecuaţiilor algebrice şi transcendente (metodele bisecţiei, coardei şi


tangentei)
- rezolvarea sistemelor de ecuaţii liniare (Gauss, Jacobi)
7. Alocarea dinamică a memoriei
- tipuri specifice alocării dinamice a memoriei
- structuri de date implementate dinamic (lista simplu şi dublu înlănţuită, stiva, coada,
arbore binar, arbore binar de căutare, operaţii specifice – creare, inserare, ştergere,
parcurgere, căutare)
8. Teoria grafurilor
- definiţie, metode de reprezentare
- noţiunea de graf parţial, subgraf, lanţ, drum, ciclu, circuit
- parcurgerea grafurilor (parcurgerea în lăţime şi în adâncime)
- conexitate/tare conexitate, determinarea componentelor conexe/tare conexe
- drumuri minime şi maxime (algoritmii Dijkstra şi Roy-Floyd)
- grafuri euleriene şi hamiltoniene
- arbori, arbori parţiali de cost minim
- arbori cu rădăcină: metode specifice de reprezentare în memorie. Arbori binari
9. Baze de date
- definirea bazei de date
- clasificarea bazelor de date (modelul relaţional, modelul reţea, modelul ierarhic)
- prezentarea conceptelor de bază ale unui sistem de gestiune a bazelor de date
- operaţii specifice prelucrării bazelor de date (creare, adăugare, modificare, ştergere,
sortare, căutare, vizualizare, interogare)
- relaţii între baze de date
10. Noţiuni de birotică
- editor de text (Microsoft Word)
- editor de foi de calcul (Microsoft Excel)
- editor prezentări (Microsoft PowerPoint)
11. Reţele. Internet
- reţele de calculatoare, clasificarea reţelelor, protocoale de reţea (noţiuni generale)
- reţeaua Internet – descriere generală, adresarea în Internet
- (*) serviciile reţelei Internet (transferarea fişierelor prin ftp, poşta electronică, www,
telnet)
- (*) căutarea informaţiei pe Internet – motoare de căutare
REZOLVARI:

3. Algoritmi
3.1 Noţiunea de algoritm şi caracteristici
ALGORITMI. DESCRIEREA ALGORITMILOR

Algoritmi
Orice activitate umană se desfăşoară, în general, pa baza unor principii logice sau, altfel spus,
a unui algoritm bine definit. Deşi nu se conştientizează acest lucru, omul acţionează conform unor
algoritmi, care reprezintă expresia regulilor impuse de parcurgerea logică a etapelor necesare pentru a
ajunge de la o situaţie iniţială la un anumit rezultat.
Funcţionarea calculatoarelor se aseamănă în mare măsură cu activitatea umană. În cazul
acestora, este obligatorie conştientizarea faptului că întreaga activitate a echipamentului de calcul se
bazează pe respectarea unor algoritmi, algoritmi ce sunt elaboraţi de factorul uman dotat cu raţiune şi
capacitate de analiză. Calculatorul nu dispune de calităţile omului, ca atare, în procesul de rezolvare a
unei probleme cu ajutorul echipamentului electronic de calcul este obligatorie parcurgerea unei etape
importante, şi anume elaborarea algoritmului de calcul. Succesul rezolvării problemei depinde de

2
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

calitatea algoritmului întocmit de către utilizator şi aplicat de echipamentul de calcul prin intermediul unui
program.
Calculatoarele numerice prelucrează informaţiile prin executarea unor operaţii simple. Deşi operaţiile
sunt elementare, prin înlănţuirea unei mulţimi de operaţii se poate ajunge la prelucrări deosebit de
complexe. Combinarea operaţiilor nu se face la întâmplare, ea supunându-se unor reguli bine
precizate. Studiul acestor reguli are la bază noţiunea de algoritm. Noţiunea de algoritm este strâns
legată de noţiunea de calcul.
Intuitiv un algoritm de calcul este o mulţime finită de operaţiuni cunoscute care executate într-o
ordine bine stabilită, pornind de la un set de valori, numite date de intrare, conduc într-un timp finit la un
set de valori, numite date de ieşire.
Algoritmul reprezintă o mulţime de asemenea calcule. Altfel spus, prin algoritm se înţelege
metoda de rezolvare a unei probleme într-un număr finit de paşi. Metoda de rezolvare este în esenţă un
şir de operaţii precise, care dacă sunt îndeplinite conduc la rezultatul dorit într-un număr finit de paşi.
Se poate spune că un algoritm constituie un sistem de reguli care, aplicat la o clasă de
probleme de acelaşi tip, conduce de la o situaţie iniţială la un rezultat final prin intermediul unor operaţii
succesiv ordonate, unic determinate.
O informaţie iniţială pentru care un algoritm de calcul este aplicabil, se numeşte informaţie admisibilă.
Totalitatea informaţiilor de acest gen constituie domeniul algoritmului.
Cunoscând faptul că orice algoritm conţine un anumit număr de etape numite şi paşii
algoritmului, se poate afirma că regulile algoritmului f aplicate asupra informaţiei iniţiale, care aparţine
domeniului D, determină întotdeauna obţinerea informaţiei finale corespunzătoare. Ca urmare, un
algoritm poate fi definit ca o funcţie:
f = D--> F unde: D= domeniul algoritmului (informaţiile iniţiale);
F= soluţia finală (informaţiile finale).
În general, un algoritm se caracterizează prin:
 unicitatea. regulile algoritmului determinând unicitatea ordinii în care au loc toate
transformările intermediare, dar şi obţinerea informaţiei finale, după care activitatea
algoritmului se opreşte.
 finalitate. Orice pas al algoritmului trebuie să se termine după un număr finit de paşi, şi
anume atunci când este obţinut rezultatul final, nu cel intermediar. Această proprietate se
mai numeşte şi realizabilitate potenţială.
 claritate (să fie definit). Fiecare pas al algoritmului trebuie să fie precis definit. Operaţiile
ce trebuie efectuate în cadrul fiecărui pas trebuie să fie specificate în mod riguros, precis,
astfel încât să nu apară ambiguităţi în interpretare lui de către cel care îl execută.
Totodată, trebuie riguros precizate toate etapele de calcul ce trebuie urmate pentru a
obţine soluţia finală;
 eficacitate. Orice algoritm trebuie să fie eficace. Aceasta înseamnă că toate operaţiile
algoritmului să poată fi efectuate de un individ cu creion şi hârtie într-un interval de timp
finit.
 generalitate (universal) - adică să permită rezolvarea oricărei probleme dintr-o
anumită clasă de probleme pentru care a fost stabilit.
Ca exemple de algoritmi cunoscuţi din matematică amintim: algoritmul lui Newton pentru aflarea
rădăcinii pătrate aritmetice a unui număr, algoritmul lui Euclid pentru aflarea celui mai mare divizor
comun a două numere etc .

Descrierea algoritmilor.
Transcrierea algoritmului într-un limbaj de programare, în vederea rezolvării lui cu ajutorul
calculatorului numeric poartă numele de program. Programele transmise calculatorului, ca o
reprezentare fidelă a algoritmului de calcul sunt transcrise într-un limbaj “înţeles” de calculator, nu
conţine ambiguităţi şi specifică precis şi clar doar operaţiile pe care calculatorul le poate executa.
Scrierea unui algoritm poate fi făcută rareori direct într-un limbaj de programare. Ca atare
realizarea unui program comportă, uzual nişte etape intermediare.
În vederea întocmirii unui algoritm de calcul şi utilizării acestuia la calculator, este necesară
realizarea următoarelor activităţi:
 definirea problemei;
 formularea modelului matematic al problemei;
 stabilirea algoritmului de rezolvare a problemei;
 reprezentarea algoritmului;

3
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

 scrierea programului corespunzător algoritmului, prin utilizarea unui limbaj de programare


adecvat;
 transpunerea programului pe un suport tehnic de memorie;
 testarea, depanarea şi execuţia programului;
 întreţinerea programului.
Calitatea programelor şi succesul execuţiei acestora depinde de calitatea algoritmilor utilizaţi,
de respectarea caracteristicilor specifice pentru orice algoritm, cât şi de mărimile şi operaţiile utilizate în
descrierea algoritmilor.
Exemple

1.Nu orice problemă poate rezolvată algoritmic.


a. Fiind dat un număr n să se determine toţi divizorii săi.
Pentru această problemă se poate scrie un algoritm foarte uşor.

b. Fiind dat un număr n să se determine toţi multiplii săi.


Pentru această problemă nu se poate scrie un algoritm deoarece nu cunoaştem un
criteriu de oprire a operaţiilor.

2.Un algoritm trebuie să funcţioneze pentru orice date de intrare.


Fiind date numerele a, b, c să se afişeze maximul dintre ele.
O posibilă soluţie ar fi:
se compară a cu b şi c şi dacă e mai mare se afişează a, iar apoi
se compară b cu a şi c şi dacă e mai mare se afişează b, iar apoi
se compară c cu b şi a şi dacă e mai mare se afişează c

Algoritmul nu funcţionează dacă 2 valori sunt identice şi de valoare maximă.

Exemple

3. Un algoritm trebuie sa se oprească.


Se consideră următoarea secvenţă de prelucrări:
Pas 1. Atribuie variabilei x valoarea 1;
Pas 2. Măreste valoarea lui x cu 2;
Pas 3. Daca x este egal cu 100 atunci se opreşte prelucrarea altfel se reia de la Pas 2.

Este usor de observat ca x nu va lua niciodată valoarea 100, deci succesiunea de


prelucrări nu se termină niciodată. Din acest motiv nu poate considerată un algoritm
corect.

4. Prelucrările dintr-un algoritm trebuie să fie neambigue.


Consideram următoarea secvenţă de prelucrări:
Pas 1. Atribuie variabilei x valoarea 0;
Pas 2. Fie se măreşte x cu 1 fie se micşorează x cu 1;
Pas 3. Daca x aparţine [-10; 10] se reia de la Pas 2, altfel se opreşte algoritmul.

4
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

5. Un algoritm trebuie să se oprească după un interval rezonabil de timp.


Fiind dat un număr n se cere să se determine de câte ori a apărut o cifră c în
reprezentarea tuturor numerelor naturale mai mici ca n.

O rezolvare simplă ar fi să luăm toate numere mai mici ca n şi să vedem de


câte ori apare cifra c în fiecare dinte ele. Soluţia e simplă şi pentru valori mici
ale lui n algoritmul se termină într-un interval de timp rezonabil, dar pentru valori
mari timpul de terminare al algoritmului creşte nepermis de mult.

Paşii realizării unui algoritm


1. Citirea cu atenţie a enunţului problemei.

2. Identificarea datelor de intrare şi a celor de ieşire.

3. Rezolvarea propriu-zisă a problemei pe cazuri particulare şi reprezentative. În acest


moment nu se încearcă scrierea programului ci doar determinarea metodei de
rezolvare, generalizarea şi înţelegerea acesteia.

4. Descrierea în limbaj natural a soluţiei problemei.


Dacă nu sunteţi capabili să descrieţi metoda folosită în limbaj natural e puţin probabil să
o puteţi face într-un limbaj de programare care e mai restrictiv decât limbajul natural.

5. Scrierea programului într-un limbaj de programare.

6. Testarea programului.
Testarea se face pe mai multe seturi de date care să acopere cazurile posibile ce pot
apărea.
3.2 Structuri fundamentale( secvenţa, decizia, repetiţia)

5
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Conform teoremei de structură, orice algoritm poate fi reprezentat ca o combinaţie a


trei structuri de control:

1. secventa ( succesiune de două sau mai multe atribuiri )

2. Decizia (if...then, sau if…then…else)

3. Ciclul cu test iniţ ial( whil …do…)

Programarea structurată admite şi utilizarea altor structuri de control, cum sunt:


• Selecţia(case… of…);
• ciclul cu test final(repeat…until…);
• ciclul cu contor(for…do…);
Regulile de bază
• 1.Structura oricărui program sau subprogram va fi concepută ca o combinaţie a structurilor de
control admise: secvenţa, decizia , selecţia, ciclul
• 2. structura datelor utilizate în program trebuie să corespundă specificului problemelor
rezolvate.
• 3. Lungimea maximă a unei funcţii sau proceduri este de 50-100 linii. Folosirea variabilelor
globale nu este încurajată.
• 4. Identificatorii folosiţi pentru constante, tipuri, variabile, funcţii, proceduri şi unităţi de program
trebuie să fie cît mai sugestivi.

Mărimile utilizate în cadrul algoritmilor pot fi clasificate astfel:


 după tipul datelor, respectiv din ce mulţime poate lua valori mărimea respectivă:
 date numerice;
 date alfanumerice;
 date logice;
 date calendaristice.
 după natura datelor:
 date constante;
 date variabile.
Operaţiile utilizate în descrierea algoritmilor sunt:
 operaţii de calcul aplicate asupra variabilelor. În cadrul acestora, se utilizează operatorii
aritmetici +, -, , /,* ce corespund operaţiilor de adunare, scădere, înmulţire, împărţire şi
ridicare la putere, care se împart pe trei nivele de prioritate:
 ridicarea la putere - prioritatea maximă;
 înmulţirea şi împărţirea;
 adunarea şi scăderea.

6
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

 operaţii de atribuire (x=(a+b)-c);


 operaţii de decizie (relaţionali , , , ,  sau logici , , )
Succesiunea operaţiilor din cadrul unui algoritm poate fi pusă în evidenţă prin intermediul a trei tipuri de
structuri de bază, elementare:
- structura liniară (secvenţială) – presupune executarea necondiţionată a operaţiilor din
cadrul unui algoritm, în ordinea logică a derulării acestora;

START

CITESTE
i
EITES
SUBRUTINA X
TE

PRINT i

STOP

- structura alternativă (de selecţie) necesită punerea în evidenţă a tuturor căilor de


rezolvare a problemei – cu descrierea operaţiilor specifice de realizare pe fiecare
variantă – ce apar ca urmare a existenţei unei condiţii date în cadrul algoritmului.
Pot fi utilizate trei tipuri de structuri alternative:
 Structura alternativă cu selecţie simplă (IF – THEN) – apariţia condiţiei C presupune
existenţa a două căi alternative de parcurgere în continuare a operaţiilor;

- STRUCTURA REPETITIVĂ (CICLICĂ) se bazează pe repetarea unei secvenţe din


algoritm, care poate să cuprindă una sau mai multe operaţii. Există următoarele tipuri de
operaţii repetitive:
- WHILE – DO presupune executarea unei anumite secvenţe din algoritm atâta timp cât
este îndeplinită condiţia C. Deoarece structura este condiţionată anterior, există
posibilitatea ca secvenţa respectivă să nu se execute niciodată.
- DO – UNTIL , condiţionare posterioară, secvenţa din program se execută cel puţin o dată,
întrucât decizia de reluare a secvenţei se ia după executarea acesteia.
- DO – FOR se execută atunci când se cunoaşte de câte ori trebuie repetată o anumită
secvenţă. Ea se caracterizează prin apariţia unei variabile numită contor, care evidenţiază
numărul de repetări a secvenţei.

V=Vi

A
A
C
NU V=V+r
C

DA
A V>Vr

WHILE - DO DO - UNTIL DO - FOR

Exemplu:
Se cere algoritmul şi schema logică pentru calculul lui n!
Paşii algoritmului de calcul sunt :
1. citeşte valoarea lui n;

7
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

2. atribuie lui P valoarea 1;


3. atribuie lui I valoarea 1;
4. atribuie lui P valoarea expresiei P * I;
5. atribuie lui I valoarea expresiei I + 1;
6. dacă I<N atunci treci la pasul 4;
7. scrie valoare lui P;
8. stop.
Schema logică corespunzătoare algoritmului:

START

Citeşte
n

p: = 1

i: = 1

p: = p * i

i: = i + 1

i< = n scrie STOP


p

Diagrama arborescentă
Diagrama arborescentă constituie o altă modalitate de reprezentare grafică a algoritmilor. Ca şi
în cazul schemelor logice, există mai multe convenţii de reprezentare a operaţiilor în cadrul algoritmilor.
IN PSEUDOCOD AVEM:
a) Secvenţa – este o structură realizată prin scrierea succesivă (în secvenţă) a comenzilor
componente.
Exemplu: citeşte A,B
atribuie C  A + B
scrie A , B , C
stop
Efectul execuţiei unei comenzi depinde de poziţia comenzii în cadrul secvenţei .
b) Decizia – este o structură care asigură alegerea pentru execuţie a unei secvenţe din două
alternative posibile.
Structura comenzii: dacă condiţie atunci
secvenţa1
altfel
secvenţa 2
[]
Începutul comenzii de decizie este marcat de cuvântul cheie “dacă” iar sfârşitul său de semnul []
Execuţia acestei comenzi comportă următoarele etape:
 se evaluează “ condiţia”;
 dacă rezultatul evaluării este adevărat (condiţie îndeplinită) se execută secvenţa 1;
 în caz contrar se execută secvenţa 2.
După executarea secvenţei 1 sau a secvenţei 2 se trece la următoarea comandă (cea după
semnul [] )
Observaţie: În cazul în care secvenţa care urmează după cuvântul cheie “altfel” lipseşte, se utilizează
forma simplificată a deciziei:

8
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

dacă condiţie atunci


secvenţa1
[]
În cazul în care condiţia nu este îndeplinită se trece direct la comanda ce urmează deciziei

Exemplul:
dacă A > B atunci
scrie A
altfel
scrie B
[]
Efectul execuţiei exemplului de mai sus este următorul:dacă valoarea variabilei A este mai
mare decât a variabilei B se scrie valoarea lui A în caz contrar se scrie valoarea variabilei B şi nu
valoarea variabilei A.
Exemplul: Decsrierea în Pseudocod a algoritmului de aflare a celui mai mare element
din 3 valori reale desemnate prin variabilele a,b,c.Variabila “x” va conţine cel mai mare element din cele
3 valori.Algoritmul de rezolvare a unei probleme nu este unic.Ca atare se dau două descrieri
Pseudocod pentru rezolvarea acestei probleme.
a) varianta 1
citeşte a,b,c
dacă a>b atunci
atribuie x  a
altfel
atribuie x  b
[]
dacă c > x atunci
atribuie x  c
[]
scrie x
stop
b) varianta 2
citeşte a,b,c
atribuie x  a
dacă x < b atunci
atribuie x  b
[]
dacă x < c atunci
atribuie x c
[]
scrie x
stop
O variantă simplificată : citeşte a,b,c,
atribuie x a
dacă x < b atunci atribuie x  b

9
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

dacă x < c atunci atribuie x  c


scrie x
stop
Observaţie: Ultima variantă a algoritmului are avantajul că poate fi uşor generalizată pentru aflarea
maximului unui şir.
c) Selecţia reprezintă o extindere a operaţiei de decizie, ea permitând alegerea unei alternative din
mai multe posibile.Forma generală a comenzii de selecţie este următoarea :
alege expresia dintre
c1 : secvenţa 1

c2 : secvenţa 2

.
.
cn : secvenţa n
rest : secvenţa n+1
[]
Unde c1 , c2 , ... cn sunt etichete şi se folosesc pentru identificarea secvenţelor.Sfârşitul comenzii este
marcat de _[] iar liniile textului selecţiei sunt marcate prin etichetele c.
Modul de execuţie al comenzii de selecţie este următorul:
 se evaluează expresia
 se identifică eticheta ci ce are aceeaşi valoare cu expresia ( în urma evaluării expresiei)şi
este selectată secvenţa corespunzătoare.Dacă nici o etichetă nu are valoarea expresiei
atunci este selectată secvenţa n+1, corespunzătoare etichetei rest.
 se execută secvenţa selecctată şi se sare la sfârşitul comenzii de selecţie adică după
semnul [].
Exemplu: Să se adune valoarea întreagă v la una din variabilele s 0,s1,s2 ,s3, după cum
restul împărţirii valorii v la 4 este 0,1,2 sau 3 .Descrierea în Pseudocod arată astfel:
citeşte v,s0,s1,s2,s3
alege v – int ( v/4)*4 dintre
0: atribuie s0  s0 + v
1: atribuie s1  s1 + v
2: atribuie s2  s2 + v
3: atribuie s3  s3 + v
[]
scrie s0,s1,s2,s3
stop
STRUCTURI REPETITIVE IN PSEUDOCOD
În acest caz , eticheta “rest” şisecvenţa respectivă lipseşte ,deoarece domeniul de valori ale expresiei
este mulţimea (0,1,2,3).
a) Ciclul cu test final – În rezolvarea unei probleme , nu de puţine ori apare situaţia executării
repetate a unei secvenţe de operaţii.O astfel de combinaţie , în care execuţia unui grup de
operaţii se repetă se numeşte ciclu sau iteraţie.Pentru reprezentarea ei se utilizează o comandă
de ciclare care specifică atâtoperaţiile care se repetă cât şi condiţia de repetare.
Forma generală a comenzii de ciclare cu test final este următoarea:

repetă
secvenţa
până condiţia

10
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

[]
Modul de execuţie al comenzii de ciclare este următorul:
1-se execută secvenţa
2-se evaluează condiţia şi dacă rezultatul este fals(condiţie neîndeplinită)se continuă cu etapa 1 , altfel
execuţia comenzii se termină şi se trece la comanda următoare.
Exemplu: Se dă algoritmul lui Euclid pentru afişarea celui mai mare divizor comun a
două numere întregi m,n(m>=n>0).
1. citeşte valorile lui m şi n
2. atribuie lui c valoarea lui n ( în variabila c se reţine cel mai mare divizor
comun )
3. atribuie lui r restul împărţirii întregi a lui m la n
4. dacă r diferit de 0 atunci treci la 7
5. scrie valoarea lui c
6. stop
7. atribuie lui m valoarea lui n
8. atribuie lui n valoarea lui r
9. treci la pasul 2
Se observă că operaţiile care se realizează calculul restului şiactualizarea valorilor c, m şi n se
repetă.
Folosind Descrierea în Pseudocod a algoritmului şi ciclul cu test final vom avea:
citeşte m,n
repetă
atribuie c  n , r  m-int(m/n)*n
atribuie mn , n  r
până r=0
_[]
scrie c
stop
Condiţia de terminare a ciclului poate fi orice expresie logică.Secvenţa de operaţii din ciclu
alcătuieşte corpul ciclului .Ea poate conţine oriceoperaţii, inclusiv iteraţii.
b) Ciclul cu test iniţial – În cazul ciclurilor sau iteraţiilor condiţia de
ciclare poate apare şi la începutul secvenţei de ciclare
Forma generală este :
cât timp condiţia execută
secvenţa
[]
Condiţia poate fi orice expresie logică , iar secvenţa poate conţine orice comenzi , inclusiv
comenzi de ciclare.
Modul de execuţie al ciclului cu test iniţial :
1-se evaluează condiţia;dacă rezultatul este fals(condiţie neîndeplinită) execuţia se termină,iar dacă
rezultatul este adevărat se continuă secvenţa(etapa 2)
2-se execută secvenţa,după care se continuă cu 1.
În cazul în care rezultatul evaluării condiţiei este fals încă de la început,secvenţa nu se
execută niciodată spre deosebire de ciclul cu test final,când secvenţa se executa cel puţin o dată.
Scrierea algoritmului lui Euclid în Pseudocod folosind ciclul cu test iniţial ne conduce la:
citeşte m,n
atribuie c  n , r  m-int(m/n)*n
cât timp r <> 0 execută
atribuie m  n , n  r, c  n
atribuie r  m-int(m/n)*n
[]

11
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

scrie c
stop
c) Ciclul de contor, cu forma generală:
pentru contor = val iniţială, val.finală,pas execută
secvenţa
[]
unde prin contor se înţelege o variabilă cu valori întregi:”valoarea iniţială, finală şi pas” pot fi expresii
aritmetice cu valori întregi.
Execuţia ciclului cu contor se explicitează astfel:
1) variabilei contor i se atribuie valoarea iniţială;
2) se verifică condiţia contor > val. Finală; dacă rezultatul este fals se continuă cu, astfel
execuţia ciclului se termină;
3) se execută secvenţa
4) se modifică valoarea contorului cu pasul p şi se continuă cu pasul 2)
Exemplu: aflarea lui n!
Observaţii: 1. Dacă pasul de ciclare este 1, se poate omite
2. Algoritmul a fost completat şi pentru cazul în care n = 0
citeşte n
atribuie p = 1
dacă n>0 atunci
pentru i=1,n execută
atribuie p=p*i
[]
[]
scrie p
stop

3.3 Reprezentarea algoritmilor


După cum am mai precizat, pentru că noţiunea de algoritm este dată printr-o descriere avem mai întâi
nevoie de metode de reprezentare a algoritmilor.:
1.O primă formă de reprezentare este desigur limbajul obişnuit (natural).
2.O altă formă de reprezentare a algoritmilor este limbajul pseudocod. Limbajul pseudocod,
faţă de limbajul natural, este o formă de reprezentare mai exactă, ajungându-se la nivel de detaliu. Nu
există un limbaj pseudocod standard care să permită reprezentarea algoritmilor, ci în funcţie de
experienţa celor care îl utilizează sau cărora li se adresează, limbajul pseudocod poate avea forme
diferite, influenţate chiar până şi de limbajul în care urmează a fi implementat algoritmul, dacă acest
lucru este imediat posibil.
Dacă un algoritm reprezentat în pseudocod, la un anumit grad de detaliu este o
secvenţă de blocuri, la un grad de detaliu superior, vom constata că parcurgerea
secvenţială este întreruptă prin întâlnirea structurilor alternative care, prin evaluarea
condiţiilor şi stabilirea valorii de adevăr a expresiei booleene asociate acestora, poate
decide care bloc să se execute sau nu, sau mai mult chiar, o structură repetitivă
determină execuţia unui bloc o dată sau de mai multe ori. Până la acest nivel de
detaliu, limbajul natural oferă o formă de reprezentare plastică, uşor de exprimat şi de
reţinut (memorat).
3. O formă grafică, intuitivă, de reprezentare a algoritmilor este schema logică.
Considerată ca prima formă de reprezentare sugestivă a unui algoritm, aceasta s-a
perfecţionat ajungând la un nivel care permite o standardizare acceptabilă. O schemă
logică are ca părţi constitutive, reprezentări grafice ale operaţiilor şi structurilor
prezentate la definirea unui limbaj pseudocod.

12
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

În 1966 s-a demonstrat că orice algoritm (imperativ) poate fi reprezentat


folosind numai structurile de control: secvenţială, alternativă şi repetitivă. Rezultatul
obţinut a condus la apariţia unei noi viziuni de proiectare a algoritmilor, proiectarea
modulară şi structurată.
Orice reprezentare trebuie să reflecte toate etapele, toate operaţiile conţinute de algoritmi, ceea ce
presupune existenţa unor convenţii de reprezentare a acestora. Algoritmii pot fi reprezentaţi grafic cu
ajutorul schemelor logice şi a diagramelor arborescente, iar reprezentarea textuală se efectuează cu
ajutorul limbajelor de tip pseudocod.

Scheme logice
Schemele logice reprezintă scrierea algoritmilor de calcul cu ajutorul unor simboluri (forme)
geometrice, care evidenţiază diferite tipuri de acţiuni.
Realizarea schemei logice corespunzătoare unui algoritm este utilă fie la depanarea
programelor, fie la lucrul în echipă, fie la schimbul de informaţii dintre diverse grupuri de
programatori,întrucât ea specifică precis şi clar ordinea de parcurgere a blocurilor (simbolurilor
geometrice).
Simbolurile uzuale utilizate în realizarea schemelor sunt cuprinse în tabelul de mai jos:

SIMBOL DENUMIREA UTILIZAREA


Uneşte componentele schemei logice, indicând
săgeată
succesiunea operaţiilor
Evidenţiază punctele de intersecţie a săgeţilor
Bloc conector dintre mai multe blocuri dispuse pe aceeaşi
pagină
Evidenţiază continuarea schemei logice pe o altă
Conector de
pagină; se menţionează în locurile de început /
pagină
sfârşit de pagină din cadrul schemei logice
Marchează începutul / sfârşitul schemei logice; în
Bloc terminal interior se menţionează START / STOP, iar în
cazul subrutinelor PRELUCRAE / REVENIRE
Marchează operaţiile de citire a variabilelor supus
Bloc de intrare /
prelucrării şi de scriere a rezultatelor: READ /
ieşire
WRITE sau CITEŞTE / SCRIE preced variabilele
Pune în evidenţă operaţiile de calcul şi atribuire
Bloc de calcul
(ex.: x=y+z, I=0)
Marchează ramificaţii, determinate de condiţia
Bloc de decizie înscrisă în bloc
Bloc de Se utilizeză pentru a marca începutul sau apelul
procedură unei proceduri.
Evidenţiază o subrutină (detalierea unor părţi din
Bloc de
algoritm separat de schema de bază) care
procedură
urmează a fi apelată.
Succesiunea operaţiilor din cadrul unui algoritm poate fi pusă în evidenţă prin intermediul a trei
tipuri de structuri de bază, elementare:
- structura liniară (secvenţială) – presupune executarea necondiţionată a operaţiilor din
cadrul unui algoritm, în ordinea logică a derulării acestora;

13
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

START

CITESTE
i
EITES
SUBRUTINA X
TE

PRINT i

STOP

- structura alternativă (de selecţie) necesită punerea în evidenţă a tuturor căilor de


rezolvare a problemei – cu descrierea operaţiilor specifice de realizare pe fiecare
variantă – ce apar ca urmare a existenţei unei condiţii date în cadrul algoritmului.
Pot fi utilizate trei tipuri de structuri alternative:
 Structura alternativă cu selecţie simplă (IF – THEN) – apariţia condiţiei C presupune
existenţa a două căi alternative de parcurgere în continuare a operaţiilor;
 Structura alternativă cu selecţie dublă (IF – THEN - ELSE) – dacă este îndeplinită condiţia
C, se execută operaţiile de pe ramificaţia notată cu DA, altfel se execută alte operaţii, total
diferite, evidenţiate pe ramura notată cu NU;
 Structura alternativă cu selecţie multiplă (CASE – OF) – permite selecţia între mai mult de
două posibilităţi de continuare în rezolvarea problemei.

STA STA
RT RT I
I
CITESTE CITESTE
I
i DA i DA I
A2
EITES EITES I
TE TE
A1 A3

PRINT i PRINT i

STOP STOP ii
CASE - OF I

IF - THEEN
- STRUCTURA REPETITIVĂ (CICLICĂ) se bazează pe repetarea unei secvenţe din
algoritm, care poate să cuprindă una sau mai multe operaţii. Există următoarele tipuri de
operaţii repetitive:
- WHILE – DO presupune executarea unei anumite secvenţe din algoritm atâta timp cât
este îndeplinită condiţia C. Deoarece structura este condiţionată anterior, există
posibilitatea ca secvenţa respectivă să nu se execute niciodată.
- DO – UNTIL , condiţionare posterioară, secvenţa din program se execută cel puţin o dată,
întrucât decizia de reluare a secvenţei se ia după executarea acesteia.
- DO – FOR se execută atunci când se cunoaşte de câte ori trebuie repetată o anumită
secvenţă. Ea se caracterizează prin apariţia unei variabile numită contor, care evidenţiază
numărul de repetări a secvenţei.

14
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

V=Vi

A
A
C
NU V=V+r
C

DA
A V>Vr

WHILE - DO
DO - UNTIL DO - FOR

Exemplu:
Se cere algoritmul şi schema logică pentru calculul lui n!
Paşii algoritmului de calcul sunt :
9. citeşte valoarea lui n;
10. atribuie lui P valoarea 1;
11. atribuie lui I valoarea 1;
12. atribuie lui P valoarea expresiei P * I;
13. atribuie lui I valoarea expresiei I + 1;
14. dacă I<N atunci treci la pasul 4;
15. scrie valoare lui P;
16. stop.
Schema logică corespunzătoare algoritmului:

START

Citeşte
n

p: = 1

i: = 1

p: = p * i

i: = i + 1

i< = n scrie STOP


p

Diagrama arborescentă
Diagrama arborescentă constituie o altă modalitate de reprezentare grafică a algoritmilor. Ca şi
în cazul schemelor logice, există mai multe convenţii de reprezentare a operaţiilor în cadrul algoritmilor.

Limbajul Pseudocod

15
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Spre deosebire de schemele logice, limbajele Pseudocod folosesc cuvinte cu înţeles


prestabilit (numite cuvinte cheie) şi câteva reguli simple de aliniere a textului scris.
Pseudocodul reprezintă un mijloc de exprimare naturală şi dezvoltare sistematică a
algoritmilor.
Pseudocodul are puţine reguli sintactice lăsând programatorului o mare libertarte în
exprimarea acţiunilor algoritmilor.
Pseudocodul permite specificarea algoritmilor prin două tipuri de enunţuri nestandard şi
standard.
Enunţurile nestandard sunt fraze în limbaj natural care pot fi utilizate de programator în
schiţarea formelor iniţiale ale algoritmilor şi sunt precedate de ***. În dezvoltarea algoritmilor, enunţurile
nestandard sunt înlocuite treptat cu enunţuri standard care exprimă operaţii cu corespondente directe
în limbajele de programare.
În forma standard fiecare comandă (operaţie) este reprezentată în limbajul Pseudocod printr-
un cuvânt care exprimă operaţia ce trebuie executată, însoţit de obicei, de elemente suplimentare care
îi particularizează efectul.
Limbajul pseudocod nu este un limbaj de programare, ci o modalitate textuală de reprezentare
a algoritmilor. El poate fi utilizat în locul reprezentărilor grafice, dar faţă de schemele logice este mult
mai puţin utilizat de către programatori.
Construcţia de bază a limbajului pseudocod este propoziţia, un algoritm fiind reprezentat printr-
o succesiune de propoziţii care pot fi:
- propoziţii simple care exprimă operaţii ce pot fi transpuse direct într-un limbaj de
programare;
- propoziţii complexe, notate cu simbolul #, care urmează să fie detaliate ulterior până la
nivelul propoziţiilor simple.
Fiecare propoziţie începe cu un verb care exprimă operaţia descrisă. Un exemplu de algoritm
reprezentat cu ajutorul limbajului pseudocod poate fi următorul:
citeşte var
atribuie var=expr
execută nume_proced
scrie var
stop
unde: var semnifică o variabilă;
expr reprezintă o expresie algebrică sau logică;
nume_proced este numele unei proceduri, care va fi detaliată ulterior.
Pentru a fi puse în evidenţă operaţiile, verbele sunt subliniate.
Cuvântul care identifică operaţia se numeşte cuvânt cheie. Enunţurile standard utilizate în
limbajele Pseudocod şi semnificaţia lor sunt următoarele:
d) operaţia de intrare (citire) - constă în transferul unor valori de pe mediul de intrare (eventual
de pe cartele sau de la un terminal) în locaţii de memorie specificate prin ‘lista de variabile’
Structura comenzii: citeşte lista de variabile
Exemplu: citeşte a,b,c
În locaţiile desemnate prin variabilele a,b,c se transferă valori de pe mediul de intrare.
e) Operaţia de ieşire (scriere) - constă în transferul unor valori din locaţiile de memori specificate
prin ‘lista de variabile’, pe mediul de ieşire (imprimantă, display etc.)
Structura comenzii: scrie lista de variabile
Exemplu: scrie x,a,d,g
Conţinutul locaţiilor de memorie desemnate prin variabilele x,a,d,g este transferat de mediul de
ieşire.
f) Operaţia de atribuire – constă în calculul valorii unei expresii, valoare ce se atribuie unei
variabile.
Structura comenzii: atribuie variabilă  expresie
Exemplu: atribuie D a*b+c
atribuie E  x /\ y \/ z
Variabilelor D,E li se atribuie valorile obţinute în urma calculului valorii expresiilor din dreapta
semnului 
g) Operaţia de oprire – are ca efect oprirea execuţiei comenzilor în calculator
Structura comenzii: stop

16
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

h) Secvenţa – este o structură realizată prin scrierea succesivă (în secvenţă) a comenzilor
componente.
Exemplu: citeşte A,B
atribuie C  A + B
scrie A , B , C
stop
Efectul execuţiei unei comenzi depinde de poziţia comenzii în cadrul secvenţei .
i) Decizia – este o structură care asigură alegerea pentru execuţie a unei secvenţe din două
alternative posibile.
Structura comenzii: dacă condiţie atunci
secvenţa1
altfel
secvenţa 2
[]
Începutul comenzii de decizie este marcat de cuvântul cheie “dacă” iar sfârşitul său de semnul []
Execuţia acestei comenzi comportă următoarele etape:
 se evaluează “ condiţia”;
 dacă rezultatul evaluării este adevărat (condiţie îndeplinită) se execută secvenţa 1;
 în caz contrar se execută secvenţa 2.
După executarea secvenţei 1 sau a secvenţei 2 se trece la următoarea comandă (cea după
semnul [] )
Observaţie: În cazul în care secvenţa care urmează după cuvântul cheie “altfel” lipseşte, se utilizează
forma simplificată a deciziei:
dacă condiţie atunci
secvenţa1
[]
În cazul în care condiţia nu este îndeplinită se trece direct la comanda ce urmează deciziei

Exemplul:
dacă A > B atunci
scrie A
altfel
scrie B
[]
Efectul execuţiei exemplului de mai sus este următorul:dacă valoarea variabilei A este mai
mare decât a variabilei B se scrie valoarea lui A în caz contrar se scrie valoarea variabilei B şi nu
valoarea variabilei A.
Exemplul: Descrierea în Pseudocod a algoritmului de aflare a celui mai mare element
din 3 valori reale desemnate prin variabilele a,b,c.Variabila “x” va conţine cel mai mare element din cele
3 valori.Algoritmul de rezolvare a unei probleme nu este unic.Ca atare se dau două descrieri
Pseudocod pentru rezolvarea acestei probleme.
a) varianta 1
citeşte a,b,c
dacă a>b atunci
atribuie x  a
altfel
atribuie x  b
[]
dacă c > x atunci

17
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

atribuie x  c
[]
scrie x
stop
b) varianta 2
citeşte a,b,c
atribuie x  a
dacă x < b atunci
atribuie x  b
[]
dacă x < c atunci
atribuie x c
[]
scrie x
stop
O variantă simplificată : citeşte a,b,c,
atribuie x a
dacă x < b atunci atribuie x  b
dacă x < c atunci atribuie x  c
scrie x
stop
Observaţie: Ultima variantă a algoritmului are avantajul că poate fi uşor generalizată pentru aflarea
maximului unui şir.
j) Selecţia reprezintă o extindere a operaţiei de decizie, ea permitând alegerea unei alternative din
mai multe posibile.Forma generală a comenzii de selecţie este următoarea :
alege expresia dintre
c1 : secvenţa 1

c2 : secvenţa 2

.
.
cn : secvenţa n
rest : secvenţa n+1
[]
Unde c1 , c2 , ... cn sunt etichete şi se folosesc pentru identificarea secvenţelor.Sfârşitul comenzii este
marcat de _[] iar liniile textului selecţiei sunt marcate prin etichetele c.
Modul de execuţie al comenzii de selecţie este următorul:
 se evaluează expresia
 se identifică eticheta ci ce are aceeaşi valoare cu expresia ( în urma evaluării expresiei)şi
este selectată secvenţa corespunzătoare.Dacă nici o etichetă nu are valoarea expresiei
atunci este selectată secvenţa n+1, corespunzătoare etichetei rest.
 se execută secvenţa selecctată şi se sare la sfârşitul comenzii de selecţie adică după
semnul [].
Exemplu: Să se adune valoarea întreagă v la una din variabilele s 0,s1,s2 ,s3, după cum
restul împărţirii valorii v la 4 este 0,1,2 sau 3 .Descrierea în Pseudocod arată astfel:
citeşte v,s0,s1,s2,s3
alege v – int ( v/4)*4 dintre
0: atribuie s0  s0 + v

18
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

1: atribuie s1  s1 + v
2: atribuie s2  s2 + v
3: atribuie s3  s3 + v
[]
scrie s0,s1,s2,s3
stop
În acest caz , eticheta “rest” şisecvenţa respectivă lipseşte ,deoarece domeniul de valori ale
expresiei este mulţimea (0,1,2,3).
k) Ciclul cu test final – În rezolvarea unei probleme , nu de puţine ori apare situaţia executării
repetate a unei secvenţe de operaţii.O astfel de combinaţie , în care execuţia unui grup de
operaţii se repetă se numeşte ciclu sau iteraţie.Pentru reprezentarea ei se utilizează o comandă
de ciclare care specifică atâtoperaţiile care se repetă cât şi condiţia de repetare.
Forma generală a comenzii de ciclare cu test final este următoarea:

repetă
secvenţa
până condiţia
[]
Modul de execuţie al comenzii de ciclare este următorul:
1-se execută secvenţa
2-se evaluează condiţia şi dacă rezultatul este fals(condiţie neîndeplinită)se continuă cu etapa 1 , altfel
execuţia comenzii se termină şi se trece la comanda următoare.
Exemplu: Se dă algoritmul lui Euclid pentru afişarea celui mai mare divizor comun a
două numere întregi m,n(m>=n>0).
10. citeşte valorile lui m şi n
11. atribuie lui c valoarea lui n ( în variabila c se reţine cel mai mare divizor
comun )
12. atribuie lui r restul împărţirii întregi a lui m la n
13. dacă r diferit de 0 atunci treci la 7
14. scrie valoarea lui c
15. stop
16. atribuie lui m valoarea lui n
17. atribuie lui n valoarea lui r
18. treci la pasul 2
Se observă că operaţiile care se realizează calculul restului şiactualizarea valorilor c, m şi n se
repetă.
Folosind Descrierea în Pseudocod a algoritmului şi ciclul cu test final vom avea:
citeşte m,n
repetă
atribuie c  n , r  m-int(m/n)*n
atribuie mn , n  r
până r=0
_[]
scrie c
stop
Condiţia de terminare a ciclului poate fi orice expresie logică.Secvenţa de operaţii din ciclu
alcătuieşte corpul ciclului .Ea poate conţine oriceoperaţii, inclusiv iteraţii.
l) Ciclul cu test iniţial – În cazul ciclurilor sau iteraţiilor condiţia de ciclare poate apare şi la
începutul secvenţei de ciclare
Forma generală este :
cât timp condiţia execută

19
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

secvenţa
[]
Condiţia poate fi orice expresie logică , iar secvenţa poate conţine orice comenzi , inclusiv
comenzi de ciclare.
Modul de execuţie al ciclului cu test iniţial :
1-se evaluează condiţia;dacă rezultatul este fals(condiţie neîndeplinită) execuţia se termină,iar dacă
rezultatul este adevărat se continuă secvenţa(etapa 2)
2-se execută secvenţa,după care se continuă cu 1.
În cazul în care rezultatul evaluării condiţiei este fals încă de la început,secvenţa nu se
execută niciodată spre deosebire de ciclul cu test final,când secvenţa se executa cel puţin o dată.
Scrierea algoritmului lui Euclid în Pseudocod folosindciclul cu test iniţial ne conduce la:
citeşte m,n
atribuie c  n , r  m-int(m/n)*n
cât timp r <> 0 execută
atribuie m  n , n  r, c  n
atribuie r  m-int(m/n)*n
[]
scrie c
stop
m) Ciclul de contor, cu forma generală:
pentru contor = val iniţială, val.finală,pas execută
secvenţa
[]
unde prin contor se înţelege o variabilă cu valori întregi:”valoarea iniţială, finală şi pas” pot fi expresii
aritmetice cu valori întregi.
Execuţia ciclului cu contor se explicitează astfel:
5) variabilei contor i se atribuie valoarea iniţială;
6) se verifică condiţia contor > val. Finală; dacă rezultatul este fals se continuă cu, astfel
execuţia ciclului se termină;
7) se execută secvenţa
8) se modifică valoarea contorului cu pasul p şi se continuă cu pasul 2)
Exemplu: aflarea lui n!
Observaţii: 1. Dacă pasul de ciclare este 1, se poate omite
2. Algoritmul a fost completat şi pentru cazul în care n = 0
citeşte n
atribuie p = 1
dacă n>0 atunci
pentru i=1,n execută
atribuie p=p*i
[]
[]
scrie p
stop
n) Proceduri şi funcţii
În rezolvarea unor probleme apar frecvent situaţii când un număr decomenzi se repetă
schimbându-se numai variabilele ce compun aceste comenzi,structura comenzilor rămânând aceeaşi.
Pentru a nu repeta acel număr de comenzi în mai multe locuri în cadrul descrierii algoritmului de
rezolvare a problemei se folosesc procedurile şi funcţiile.
Procedura – descrie în termeni generali un algoritm cu posibilitatea de a aplica acel algoritm în
diverse cazuri particulare concrete.

20
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Pentru a se identifica,procedurii i se asociază un nume.La definirea procedurii trebuie să se


asocieze un se de parametri , variabile care specifică mărimile ce se modifică la fiecare apelare a
procedurii.
Structura unei proceduri, în Pseudocod este :
Procedure nume (parametrii) este:
secvenţa
sfârşit
unde:
- nume = numele procedurii
- parametrii = parametrii formali ai procedurii
Apelul unei procedurei specifică numeleprocedurii,precum şi parametrii actuali prin care se
transmit valorile cu care se efectuează comenzile din procedură.
Structura apelului unei proceduri este :
execută nume ( parametrii )
unde : - nume = numele procedurii ce se apelează
- parametrii = parametrii actuali ( efectivi ),adică cei pentru care urmează a se
efectua comenzile din procedură.
Exemplu: Să se construiască o procedură pentru aflarea normei unui vector.Se ştie că
norma unui vector A de n componente se defineşte prin relaţia:

S=
Descrierea în Pseudocod a procedurii este :
Procedura norma (a, n; s) este :
atribuie s  0
pentru i=1,n,1 execută
atribuie s  s + |ai|
[]
sfârşit norma
Numele procedurii este “norma”.Parametrii de intrare necesari pentru a se realiza calculele din
procedură sunt vectorul a şi numărul de elemente ale vectorului n, iar parametrul de ieşire este S,prin
el se obţine rezultatul calculelor- norma . Separarea parametrilor de ieşire de cel de intrare se face prin
punct şi virgulă . Parametrii de intrare şi cei de ieşire specificaţi la definirea procedurii se numesc
parametrii formali.
Exemplu: Să se folosească procedura definită pentru a determina dacă norma vectorului x de l
componente este mai mare decât norma vectorului w de m componente.
Descrierea în Pseudocod a algoritmului de aflare a celei mai mari dintre normele vectorilor x şi
w este următoarea :
citeşte l ,(xi , i = 1, 1)
citeşte m,(xi , i = 1,m)
execută norma (x ,l ; s1)
execută norma (w,m; s2)
dacă s1>s2 atunci
scrie ‘norma vectorului x este mai mare’
altfel
scrie ‘norma vectorului w este mai mare’
[]
stop
În apelulprocedurii norma , parametrii x,l,s1,respectiv w,m,s2 sunt parametrii actuali.
Comanda “execută” urmată de numele procedurii are ca efect execuţia operaţiilor care
constituie procedura cu numele specificat , în care valorile parametrilor formali sunt înlocuite cu
valorile parametrilor efectivi corespunzători,adică parametrii a,n,s din procedura sunt înlocuiţi cu x,l,s1
respectiv w,m,s2 din apelul procedurii.

21
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Corespondenţa dintre parametrii efectivi şi parametrii formali este poziţională , adică


parametrul care ocupă poziţia p în lista parametrilor formali este înlocuit cu parametrul care ocupa
poziţia p în lista parametrilor efectivi.Aceasta substituţie se numeşte transferul parametrilor.Comanda “
execută” se termină odată cu terminarea execuţiei ultimei operaţii din procedură.
Funcţia
Atunci când procedura calculează o singură valoare se poate utiliza un tip particular de
procedură numit funcţie.Descrierea unei funcţii cuprinde :
- linia de definire a funcţiei
- secvenţa de operaţii ce constituie corpul funcţiei
- linia finală
Structura unei funcţii în Pseudocod este următoarea :
funcţia nume (parametrii ) este:
secvenţa
sfârşit
unde:
- nume reprezintă numele funcţiei
- parametrii sunt parametrii funcţiei şi trebuie să fie doar parametrii de intrare
Singurul parametru de ieşire în cazul funcţiei este considerat chiar numele funcţiei care este
utilizat în secvenţa de operaţii din corpul funcţiei ca orice parametru. Valoarea acestui parametru
reprezintă valoarea funcţiei.Secvenţa din corpul funcţiei trebuie să conţină o comandă de atribuire prin
care numelui funcţiei i se atribuie o valoare.
Exemplu: Să se definească o procedură pentru calculul lui n!.
Descrierea în pseudoco a funcţiei este :
funcţia fact(m) este :
atribuie p 1
dacă m>1 atunci
pentru i=1,m,1execută
atribuie p p*i
[]
[]
atribuie fact p
sfârşit fact
Apelul unei funcţii este considerat ca operand în cadrul expresiilor .Structura apelului unei funcţii în
Pseudocod este :
nume( parametri )
unde :
- nume -reprezintă numele funcţiei
- parametrii - reprezintă lista parametrilor actuali de intrare ai funcţiei
Exemplu:
Să se folosească funcţia descrisă mai sus pentru calculul combinărilor:

= =

Descrierea în Pseudocod a algoritmului este :


citeşte n,k
atribuie cnk  fact(n)/fact(n-k)*fact(k)
ank  cnk*fact(k)
scrie cnk,ank
stop
Execuţia unei funcţii intervine atunci când la evaluarea unei expresii este necesară valoarea sa
.În acest caz se face transmisia parametrilor efectivi,se execută secvenţa de operaţii corespunzătoare
corpului funcţiei, găsindu-se astfel valoare funcţiei.

22
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

3.4 Algoritmi iterativi si recursivi


IMPLEMENTAREA UNOR ALGORITMI NUMERICI ITERATIV
Să se calculeze valoarea lui PI din următoarea dezvoltare:
luând în considerare n termeni.
a) Descrierea algoritmului în limbaj natural:
Se consideră S valoarea sumeidin dreapta semnului egal,formată
dinînsumarea inverselor numerelor impare cu semne opuse.După
însumarea celor n termeni , valoarea PI se obţine prin înmulţirea lui S cu 4.
b) Descrierea şi semnificaţia structurilor de date folosite:
PI: variabila în care se va calcula valoarea numărului PI
S : variabila în care se păstrează sumele parţiale
T : termenul ce se adaugă
n : numărul de termeni ce se adună
i : contor
START
c) Descrierea în Pseudocod a algoritmului:
citeşte n {numărul de termeni} S:=0, T:=+1

T  - T atribuie S0,T+1
pentru i=1,n,1 execută i:=1
atribuie S  S + T*(1 / (2*i-1) )
T -T
NU DA
[] i<=n
atribuie PI  4 * S S := S + T*(1 / (2*i-1) )
scrie PI T := - T
stop i:=i+1
Variabila T asigură însumarea corectă
a termenilor cu semne contrare. T:=-T
d)Programul Pascal
Program calcul_pi; Scrie PI
var
i,n:integer; STOP
s,pi,t:real;
BEGIN{main}
writeln(‘introduceti valoarea lui
n:intreg’);
readln(n);
s:=0;t:=1;
for i:=1 to n do
begin
s:=s + t / (2 * i - 1);
t:= - t ;
end;
pi := 4 * s ;
writeln(‘valoarea lui PI=’,PI:10,8);
END.

IMPLEMENTAREA ALGORITMILOR RECURSIVI


Să se calculeze coeficienţi binomiali în care n şi p sunt întregi pozitivi daţi ( p <= n
), ştiind că există următoarea relaţie de recurenţă :

23
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Descrierea algoritmului în limbaj natural:


Se aplică relaţia de recurenţă pentru calculul coeficienţilor .Valorile calculate se vor afişa
pe măsura calculării lor , ele fiind păstrate pe rând în aceeaşi variabilă C.
Descrierea şi semnificaţia structurilor de date folosite
n,p : valorile înteregi pentru care se calculează combinaţiile
k : contor întreg
c : valoarea în care se calculează ,pe rând, combinările
Descrierea algoritmului în Pseudocod
citeşte n , p
scrie n,p
atribuie c 1
pentru k=1,p,1 execută
atribuie c c* (( n – k + 1 ) / k)
[]
scrie c
stop
Programul Pascal
Program comb;
var n,p,k,c:integer;
BEGIN{main}
write (‘n,p ?’) readln(n,p);
c:=1;
for k:=1 to p do
begin
c:=c*(n-k+1)div k;
writeln(‘combinari
de’,n,’luate
cate’,k,’=’,c);
end;
END.

Să se calculeze pentru un n dat , toţi termenii şirului lui Fibonacci, cunoscând relaţia de
recurenţă f k = f k-1+ f k-2 , pentru orice k >= 2 şi f0 =0, f1 = 1
a) Descrierea algoritmului în limbaj natural
Relaţia de recurenţă necesită două valori iniţiale f 0 şi f . Această relaţie va fi aplicată de n-2 ori ,
actualizând de fiecare dată pe f k-2 şi f k-1.Deci pentru calculul termenului curent f k sunt suficienţi 2
termeni consecutivi din şir. Vom nota cu “a” termenul f k-2 ,cu “b” f k-1 şi cu “c” termenul f k calculat.
b.) Descrierea algoritmului în pseudocod:
citeşte n
scrie n
{iniţializează primi 2 termeni ai şirului}
atribuie a 0, b 1
scrie a,b {primi doi termeni}
pentru k=3, n, 1 execută
atribuie c a+b {calculează termenul curent}

24
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

a b {actualizarea ultimilor doi}


b c {termeni din şir}
scrie c
stop
d.) Programul PASCAL:
program fibonacii;
var
a,b,c,k,n:integer;
BEGIN{main}
write('Introduceti nr. de
termeni:');
readln(n);
a:=0; b:=1;
write(a:3);
for k:=3 to n do
begin
c:=a+b;
a:=b; b:=c;
write(c:3)
end;
END.

Să se calculeze c.m.m.d.c. şi c.m.m.m.c a două numere întregi aplicând algoritmul lui


Euclid.
a.) Descrierea algoritmului în limbaj natural:
Se ştie că c.m.m.m.c a două numere A şi B este egal cu raportul dintre produsul celor două numere
şi c.m.m.d.c. al celor două numere. Ca atare în variabila p se va reţine produsul celor două numere.
Variabila CMMMC va reţine c.m.m.m.c, iar variabila CMMDC va reţine c.m.m.d.c. Conform
algoritmului lui Euclid de aflare a c.m.m.d.c se împarte cel mai mare număr (A) la cel mai mic (B) şi se
calculează restul împărţirii întregi (R). Dacă restul împărţiirii este 0 atunci c.m.m.d.c. este B. În caz
contrar se fac atribuirile: lui A i se atribuie B iar lui B i se atribuie R şi procesul se continuă până R=0.
Dacă la introducerea datelor B>A, se schimbă între ele cele două valori.
Dacă cel mai mic număr este 0 se va tipări mesajul ‘unul dintre numere este 0’ şi nu se va calcula
c.m.m.m.c.
Pentru calculul restului împărţirii se va folosi operatorul PASCAL ,,mod”.
b.) Descrierea şi semnificaţia structurilor de date folosite:
A,B : cele două numere întregi
CMMDC, CMMMC : variabile întregi pentru calculul c.m.m.d.c. şi c.m.m.m.c.
c)Descrierea şi semnificaţia structurilor de date folosite
a,b : cele două numere întregi
cmmdc,cmmmc : variabile xîntregi pt.calculul cmmdc şi cmmmc
p : produsul celor două numere ( pentru calculul cmmmc)
x : variabilă auxiliară
d)Descrierea algoritmului în Pseudocod
citeşte a,b
atribuie p  a * b { reţine produsul numerelor }

25
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

dacă a<b atunci


atribuie x  a {schimbă cele două valori între ele}
ab
bx
[]
dacă b<>0 atunci
atribuie r a mod b {restul împărţirii întregi }
cât timp r<>0 execută
atribuie a b {pregăteşte o nouă reluare
a algoritmului }
br
r  a mod b
[]
atribuie cmmdc  b
cmmmc  p / b
scrie cmmmc,cmmdc
altfel
scrie ‘ unul din termeni este zero’
[]
stop
c)Programul Pascal
Program Euclid;
var a,b,x,p,r,cmmdc,cmmmc:integer;
BEGIN{main}
write(‘introduceţi a si b : integer’);
readln(a,b);
p:=a*b;
if a<b then
begin
x:=a;
a:=b;
b:=x;
end;
if b<>0 then
begin
r:=a mod b;
while r<>0 do
begin
a:=b
b:=r;
r:=a mod b;
end;
cmmdc:=b;
cmmmc:=p div b;
writeln(‘cmmdc=’,cmmdc:8,
’cmmmc=’,cmmmc:9);
end
else writeln(‘unul din termeni este
zero’);
END.
3.5.1 Probleme care opereaza asupra cifrelor unui numar

26
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

1)Se citeste un numar natural n.Sa se end;


cunstruiasca numarul sau. writeln('in intervalul[',a,',',B,']
SUNT',NR,'NUMERE DEOSEBITE');
var m,n:word; readln;
begin end.
write('n='); readln(n); 4) Se citeste un numar natural mai mare
m:=0; strict decat 9 avand numar impar de
while (n<>0) do begin cifre (validare).Sa se afiseze numarul
m:=m*10+n mod 10;
n:=n div 10; obtinut prin eliminarea cifrei din
end; mijloc a numarului initial;.
write(m); Exemplu:
end. numarul initial:12345 numarul procesat:1245}
2) Se citeste un numar natural n,sa se calculeze var n,n1:0..maxlongint;
numarul cifrelor sale. cifre,i:byte;
ex:123 begin
=>3} repeat
write('Numarul dat:'); readln(n);
var n,nr:word; n1:=n; cifre:=0;
begin repeat
write('n='); readln(n); inc(cifre);
nr:=0; n1:=n1 div 10
while (n<>0) do begin until n1=0
nr:=nr+1; until (n>9) and odd(cifre);
n:=n div 10; i:=0;
end; repeat
write(nr); inc(i);
end. if i<>cifre div 2+1 then
3) Pentru a, b numere naturale date, 0<=a<b, sa se n1:=n1*10+n mod 10;
afiseze toate numerele n:=n div 10
deosebite din intervalul [a,b].Pentru fiecare numar until n=0;
deosebit se va afisa o repeat
singura descompunere.Sa se precizeze numarul n:=n*10+n1 mod 10;
lor.Un numar natural m este n1:=n1 div 10
deosebit daca exista un numar natural n astfel incat until n1=0;
m=n +s(n), unde s(n) writeln('Numarul obtinut:',n);
este suma cifrelor lui n. end.
Exemplu: 5) Pentru un numar intreg nr dat, cifra de control
In intervalul [30,100] sunt 64 numere deosebite.} (cifra de baza) se obtine
var a,b,m,n,n1,s,nr:word; astfel: se calculeaza suma cifrelor numarului dat,
begin apoi suma cifrelor acestei
write('a='); readln(a); sume,etc.Operatiile inceteaza cand suma obtinuta
write('b='); readln(b); este o cifra,numita cifra de
if b<=a then begin control (de baza) a numarului dat.Se citesc n>0
writeln('Data incorecta!'); readln; exit; end; numere intregi.Sa se afiseze
nr:=0; numerele cu cifra de control para.
for m:=a to b do Exemplu:
for n:=0 to m do begin n=8 (-35,567,-11,-56,23,0,65,635)
n1:=n; s:=0; Se vor afisa urmatoarele numere:
while n1>0 do begin -35 are cifra de baza 8;
inc(s,n1 mod 10); -56 are cifra de baza 2;
n1:=n1 div 10; end; 65 are cifra de baza 2;
if m=n+s then begin -11 are cifra de baza 2;
inc(nr); 0 are cifra de baza 0;
write(m,'este un numar deosebit.'); 535 are cifra de baza 4.}
writeln(' ',m,'=',n,'+',s); var n,i,s:byte;
if (m-a+1) mod 20=0 then nr,nr1:integer;
readln; begin
break repeat
end write('n='); readln(n);

27
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

until n>0; 0.
i:=0; Exemplu:
repeat Pentru n=4523, m=2 se va afisa 2, iar pt.
inc(i); write ('Numarul',i,':'); n=123 si m=4 se va afisa 0.}
readln(nr); nr1:=abs(nr); var n,m,cifra,k:word;
repeat begin
s:=0; write('n='); readln(n);
repeat write('pozitia='); readln(m);
inc(s,nr1 mod 10); cifra:=0; k:=0;
nr1:=nr1 div 10 while n<>0 do begin
until nr1=0; k:=k+1;
nr1:=s if k=m then
until nr1<10; cifra:=n mod 10;
if not odd(nr1) then n:=n div 10;
writeln(nr,'are cifra de baza',nr1) end;
until i=n; writeln; writeln('cifra:',cifra);
end. end.
6) Sa se calculeze ultima cifra a numarului a^n, 9) Sa se verifice daca numarul natural n este
unde a si n sunt numere bine ordonat.(n are cifrele fie
naturale mai mici ca 10000. in ordine crescatoare, fie in ordine
Exemplu: descrescatoare).ex:123 este
2^1000 are ultima cifra 6.} Solutie;
var a,n,i,p,r:word; Se pune problema in ce ordine are n cifrele:
begin crescatoare sau descrescatoare?
write('a='); readln(a); Ne dam seama de acest lucru comparand
write('n='); readln(n); ultimele doua cifre ale lui n.Dar daca
r:=a mod 10; p:=1; aceste sunt egale?Pentru a rezolva aceasta
for i:=1 to n do problema am facut un 'while' ce
begin elimina ultimele cifre din n. Apoi am facut o
p:=p*r; p:=p mod 10; conventie: daca n are cifrele
end; in ordine descrescatoare , t=0, iar daca le are
writeln('ultima cifra:',p); in ordine crescatoare t=1.}
end. var n,c,t,r:word;
7) Sa se genereze toate numerele naturale de ok:boolean;
patru cifre (abcd), ale caror begin
cifre sunt consecutive (cifra miilor este cea mai ok:=true;
mica), iar a*d=(bc)/2.Sa se write('n='); readln(n);
precizeze numarul lor. c:=n mod 10; n:=n div 10;
Observatie: while c= n mod 10 do
un singur numar indeplineste conditiile:4567} n:=n div 10;
var a,b,c,d,n:0..9; if c<n mod 10 then t:=0
nr:word; else t:=1;
begin r:=n mod 10; n:=n div 10;
n:=0; while n<>0 do begin
for a:=1 to 6 do c:=r;
begin if (c> n mod 10) and (t=0) then ok:=false;
b:=a+1; c:=b+1; d:=c+1; if (c< n mod 10) and (t=1) then ok:=false;
if a*d=(10*b+c) div 2 then begin r:=n mod 10; n:=n div 10;
nr:=1000*a+100*b+10*c+d; end;
write(nr:5); inc(n); end; if ok then writeln('bine ordonat')
end; else writeln('nu e bine ordonat');
writeln; end.
writeln(' numar de numere:',n); 10) Se dau doua numar natural x si y cu cel
end. mult zece cifre.Se cere sa se
8) Se citesc de pe mediul standard de intrare afiseze suma dintre produsul cifrelor lui x si
doua numere naturale n si m. Sa produsul cifrelor lui y.}
se afiseze cifra de pe pozitia m din numarul n. var
(cifrele vor fi numerotate de la x, y, px, py:longint;
dreapta la stanga).Daca nu exista o cifra pe begin
pozitia respectiva, se va afisa write ('x='); readln(x);

28
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

write ('y='); readln(y); readln;


px:=1; end.
while x<>0 do begin 12) Sa se determine cel mai mic nr. nat. care
px:=px*(x mod 10); se poate
x:=x div 10; forma cu cifrele unui nr nat. citit de la
end; tastatura.}
py:=1; var x,i,c,nr,ap,ap0,w:longint;
while y<>0 do begin begin
py:=py *(y mod 10); writeln('nr=');
y:=y div 10; readln(nr);
end; w:=0;
writeln (px+py); for c:=0 to 9 do begin
readln; x:=nr;
end. ap:=0;
11) Sa se determine cel mai mare numar care ap0:=0;
se poate forma cu repeat
cifrele unui numar natural citit de la tastatura.} if x mod 10=c then inc(ap);
var if x mod 10=0 then inc(ap0);
x,i,c ,nr , ap:longint; x:=x div 10;
begin until x=0;
writeln('dati numarul ');readln(nr); if(c<>0)and (ap>0)then begin
for c:=9 downto 0 do begin if w=0 then begin
x:=nr; write(c);
ap:=0; for i:=1 to ap0 do write(0);
repeat dec(ap); inc(w); end;
if x mod 10=c then inc(ap); for i:=1 to ap do
x:=x div 10; write(c);
until x=0; end;
for i:=1 to ap do write (c); end;
end; end.

3.5.2 Divizibilitate
1)Determinaţi toate numerele care sunt for i:=1 to n do begin
multipli de k, care depăşesc valoarea n. read(x);
program multipli2; if x mod 2 =0 then
var k,i,n:longint; nr_pare:=nr_pare+1;
begin end;
write('k=');readln(k) write(nr_pare);
; end.
write('n=');readln(n) 3) Se citeste un numar natural n Sa se numere
; divizorii sai (inclusiv 1 si
i:=k; el insusi)}
while i<=n do
begin var n,nr_div,i:integer;
write(i,' '); begin
inc(i,k); Write('n='); readln(n);
end; nr_div:=0;
end. for i:=1 to n do
2) Se citesc n numere naturale.Sa se numere if n mod i=0 then
cate din ele sunt pare. nr_div:=nr_div+1;
write(nr_div);
var n,i,x,nr_pare:integer; end.
begin 4) Sa se genereze toate numerele naturale de
Write('n='); readln(n); patru cifre de forma 1bcd care
nr_pare:=0;

29
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

indeplinesc simultan conditiile:d<c, b-c=1, iar b writeln('Cel mai mic numar natural cu
si d sunt divizibile cu 3 . exact',d,'divizori este',n);
Sa se precizeze numarul lor. write('Divizorii lui', n,' sunt:');
Exemplu: for i:=1 to n do
Sunt 6 numere:1320, 1650, 1653, 1980, 1983, if n mod i=0 then write(i:5);
1986} writeln;
var b,c,d,n:0..9; break end
nr:word; else inc(n)
begin until false;
n:=0; readln
for b:=3 to 9 do end.
for d:=0 to 6 do begin 7) SA se determine descompunerea in factori
c:=b-1; primi a unui numar natural n,
if (d<c) and (b mod 3=0) and (d mod 3=0) then citit de pe mediul standard de intrare.Afisarea
begin se va efectua ca in exemplul
nr:=1000+100*b+10*c+d; urmator.
write(nr:5); inc(n); Exemplu:
end; pentru n=12 avem:
end; 12|2
writeln; 6|2
writeln('sunt',n,'numere'); 3|3
end. 1|-}
5) Sa se verifice daca numarul natural n este var n,p:word;
perfect sau nu.( n este perfect begin
daca este egal cu suma divizorilor sai mai mici write('n='); read(n); p:=2;
ca el). while n>1 do
Exemplu: begin
n=6 este perfect deoarece 6=1+2+3.} while n mod p=0 do
var n,i,s:word; begin
begin writeln(n,'|',p);
write('n='); readln(n); n:=n div p;
s:=0; end;
for i:=1 to n div 2 do p:=p+1;
if n mod i=0 then s:=s+i; end;
if n=s then writeln(1,'|-');
writeln('numar perfect') end.
else 8) SA se determine suma numerelor naturale
writeln('numarul nu este perfect'); mai mici ca n, divizibile cu 5.}
end. var i,n,s:word;
begin
6) Sa se determine cel mai mic numar natural write('n='); readln(n);
nenul care are exact n divizori s:=0;
(inclusiv divizorii banali), d>=2 dat.Sa se for i:=5 to n do
afiseze acest numar impreuna cu if i mod 5=0 then s:=s+i;
divizorii sai. writeln('s=',s);
Exemplu: end.
d=10 : n=48 9) Sa se determine cifrele x si y astfel incat
Divizori: 1,2,3,4,6,8,12,16,24,48} numarul 1x2y sa fie divizibil
var d,nr:byte; cu 3.
n,i:word; Solutie:
begin Daca x si y sunt cifre atunci x,y apartin
repeat multimii{0,1,..,9) cu x<>0.Vom
write('d='); readln(d) verifica daca suma 1+x+2+y=3+x+y este
until d>=2; divizibila cu 3}
n:=2; var x,y:byte;
repeat begin
nr:=0; for x:=1 to 9 do
for i:=1 to n do for y:=0 to 9 do
if n mod i=0 then inc(nr); if (x+y+3) mod 3=0 then
if nr=d then begin writeln(1,x,2,y);

30
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

end. for i:=2 to n do begin writeln(' dati numarul al


9) Se citesc pe rand un numar prim x si n ',i,' lea ');
numere naturale.Fara a inmulti cele read(x);
n numere, sa se determine k maxim, pentru a:=d; b:=x;
care x^k divide produsul celor n while a<>b do
numere. if a >b then
Exemplu: a:=a-b
pentru n=4 si x=3 si numerele 23, 36, 4, 6 se else
va afisa k=3, deoarece 3^3 divide b:=b-a;
23*36*4*6} d:=a;
var n,x,k,i,nr:word; end;
begin writeln ;
write('n='); readln(n); write (' c.m.m.d.c=',d);
write('nr. prim:'); readln(x); readln;
k:=0; end.
for i:=1 to n do begin 12) Sa se calculeze cel mai mare divizor
write('nr='); readln(nr); comun a unui numar aleator de numere
while nr mod x=0 do begin (cu vectori)
k:=k+1; nr:=nr div x; ex:3
end; d
end; 6
writeln('k maxim:',k); d
end. 9
10) Se dau doua n numere naturale nenule n
(n<20) .Se cere sa se afiseze =>3}
media aritmetica a numerelor pare. Daca nu var a:array[1..20] of integer;n,i,j,di,x,y,t:integer;
exista numere pare se va afisa op:char;
mesajul "Nu exista numere pare ".} begin
var n,k,s,i,x: longint; writeln(' dati numerele');
begin n:=0;
write ('n='); readln (n); repeat
s:=0; k:=0; write('numar ');n:=n+1;readln(a[n]);
for i:=1 to n do begin write ('dati numarul ',i); write(' mai introduceti d / n ?');read(op);
readln (x); until op='n';
if x mod 2 =0 then di:=abs(a[1]);
begin for i:=2 to n do
s:=s +x; begin
k:=k+1; x:=abs(a[i]);
end; if di>x then begin
end; t:=x;x:=di;di:=t;end;
if k>0 then while x mod di <>0 do
write (s/k:0:2) begin t:=x;x:=di;di:=t mod di;end;end;
else writeln('c m m d c ',di);
write (' nu exista numere pare'); if di=1 then for i:=1 to n do
readln; for j:=i+1 to n do
end. begin
11) Se dau doua n numere naturale nenule x:=abs(a[i]);y:=abs(a[j]);
(n<40) .Se cere sa se afiseze if x>y then begin t:=x;x:=y;y:=t;end;
cel mai mare divizor comun.} while y mod x <>0 do
var n,a,b,d,i,x: longint; begin t:=y;y:=x;x:=t mod x; end;
begin if x=1 then writeln('(',a[i],',',a[j],')=1');
write ('n='); readln (n); end;
writeln(' dati primul numar '); readln;
readln(x); end.
d:=x;
3.5.2 Numere prime

1) Se citeste un numar natural n.Sa se verifice daca


el este prim.} var n,i:integer;

31
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

prim:boolean; t:=true;
begin for i:=2 to trunc(sqrt(x)) do
write('n='); readln(n); if x mod i=0 then t:=false;
prim:=true; if t then k:=k+1;
for i:=2 to trunc(sqrt(n)) do y:=x+2; t:=true;
if n mod i =0 then for i:=2 to trunc(sqrt(y)) do
prim:=false; if y mod i=0 then t:=false;
if prim then if t then k:=k+1;
write('Numarul este prim') if k=2 then write (x+1,' ');
else end;
write('Numarul nu este prim'); end.
end. 5) Se citeste un numar natural de cel mult 8 cifre.
2) Se citeste un numar natural n.Sa se afiseze Sa se afiseze cel
divizorii sai primi. mai apropiat numar prim fata de acesta.}
ex:n=9 VAR x,i,k,n1,n2: longint;
=>3} ok: boolean;
begin
var n,i,j:integer; writeln('dati numarul ');
prim:boolean; readln (x); n1:=x;
begin repeat
write('n='); read(n); inc(n1);
for i:=2 to n-1 do ok:=true;
if n mod i=0 then begin for i:=2 to trunc(sqrt(n1)) do
prim:=true; if n1 mod i =0 then ok:=false;
for j:=2 to trunc(sqrt(i)) do until ok;
if i mod j =0 then n2:=x+1;
prim:=false; repeat
if prim then write(i); dec(n2); ok:=true;
end; for i:=2 to trunc (sqrt(n2)) do
end. if n2 mod i=0 then ok:=false;
3) Sa se afiseze toate numerele prime mai mici sau until ok;
egale decat n, n>1 dat. if k-n2<n1-x then writeln (n2)
ex:n=10 else writeln(n1);
=>2 3 5 7} readln;
var n,i,j:byte; end.
prim:boolean; 6) Se da un numar natural n (0<n<1000000).Se cere
begin sa se afiseze toate
write('n='); readln(n); perechile de numere gemene (a,b), a,b<=n. Perechea
for i:=2 to n do begin (a,b) este o
prim:=true; pereche de numere gemene daca a si b sunt prime si
for j:=2 to trunc(sqrt(i)) do valoarea absoluta a
if i mod j=0 then begin diferenteia-b este 2.}
prim:=false; break; end; var
if prim then write(i:5); i,j,n,l:integer;
end; bec: boolean;
writeln; begin
end. write ('n='); readln(n);
4) Sa se afiseze toate numerele naturale x mai mici for i:=2 to n-2 do begin bec:=true;
decat n,natural, cu for j:=2 to trunc(sqrt(i)) do
proprietatea ca x-1 si x+1 sunt numere prime. if i mod j=0 then bec:= false;
Exemplu: if bec then begin
pentru n=15 se vor afisa: 4,6,12.} l:=trunc (sqrt(i+2));
var x,y,n,i,k:integer; for j:=2 to l do
t:boolean; if (i+2) mod j=0 then
begin bec:=false;
write('n='); readln(n); if bec then write ('(',i,',',i+2,') ');end;
for x:=2 to n-2 do end;
begin readln;
k:=0; end.

32
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

7) Dându-se un număr întreg N, să se afişeze toţi factorii primi ai acestuia precum şi ordinele lor de
multiplicitate.
a) Descrierea algoritmului în limbaj natural:
O soluţie posibilă ar fi aceea de a alege dintre numerele 2,3,4,5...d...[n/2] pe acelea care sunt
numere prime urmând a fi “extrase” din numărul n.Ordinul de multiplicare al fiecărui factor prim d va fi
egal cu numărul de împărţiri cu rest nul care se pot face succesiv cu el.Pentru a verifica că d este
număr prim trebuie cercetată divizibilitatea sa cu 2,3,4,...[sqrt(d)],ceea ce presupune un număr mare de
împărţiri.O serie de observaţii ce se vor face va conduce la reducerea numărului de calcule.Dintre toate
numerele pare, singurul număr prim este 2.Deci este suficient să căutăm factorii primi numai printre 2 şi
numerele impare ce satisfac condiţia 2k+1<=[n/2] (partea întreagă din n/2).
Dacă se scot din “n” divizorii săi în ordine crescătoare, un număr neprim nu va fi găsit divizor al
lui n, deoarece proprii săi factori primi au fost eliminaţi din n. De exemplu un număr nu se mai divide cu
25 după ce toţi divizorii 5 au fost eliminaţi. Deci nu este necesar să se verifice dacă un număr este prim.
Algoritmul ne asigură că dacă un număr este divizor al lui n atunci acesta este un divizor prim.
Căutarea divizorilor este o operaţie care se repetă ciclic necunoscându-se aprioric numărul de
repatări. Operaţia continuă până numărul mai admite divizori (n>1). Dacă n=1, el nu admite divizori, deci
ciclul nu se va efectua niciodată (se va folosi ciclu cu test iniţial).
Întrucât valoarea lui n se modifică prin extragerea divizorilor,este necesară afişarea sa înaintea
începerii procesului de căutare a acestora.
b) Descrierea şi semnificaţia structurilor de date folosite
n : numărul ce se descompune
d : divizorul (potenţial )
m : ordinul de multiplicare
c) Descrierea algoritmului în Pseudocod
O primă formă arată astfel:
citeşte n
scrie n
atribuie d 2
cât timp *n mai admite divizori execută
* determină multiplicitatea eventualului divizor şi extrage d din n
dacă *d a fost divizor atunci
afişează d şi ordinul de multiplicare
[]
trecere la următorul d
[]
stop
Acţiunea “*determină multiplicitatea eventualului divizor d şi îl extrage pe d din n” are un
caracter ciclic, necunoscându-se numărul de repetări ale ciclului.Această acţiune se poate realiza în
Pseudocod astfel:
atribuie m  0 {ordinul de multiplicitate}
cât timp *n estedivizibil cu d execută
*extrage d din n
atribuie m  m+1
[]
Deoarece divizorii se caută printre numerele 2,3,5,7.... acţiunea”*trecere la următorul d” se
realizează în Pseudocod astfel :
dacă d=2 atunci
atribuie d  3
altfel
atribuie d  d + 2
[]
Acţiunea “* îl extrage pe d in n” se cere realizează astfel:

33
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

atribuie n  n div d
Pentru valaorea maximă a lui d nu trebuiesc impuse condiţii , d va căpăta noi valori atât timp
cât n mai admite divizori.El nu va putea avea o valoare mai mare decât [ n / 2 ].
Având în vedere faptul că un număr n este prim dacă nu se divide cu 2,3,4,...[sqrt(n)]
algoritmul poate fi inductabil. Deci, trebuie căutaţi divizori ai lui n până la [sqrt(n)] şi nu până la [n/2]. În
final n va conţine iltimul divizor prim (cel mai mare) dacă acesta are multiplicitatea 1. În caz contrar, n va
fi 1. Algoritmul trebuie să facă distincţie între cele 2 situaţii.
Deoarece funcţia sqrt(n) oferă un rezultat de tip real, care poate fi afectat de erorile interne
operării cu numere reale, de exemplu sqrt(16) are valoarea 3,99999E+00, iar trunc(sqrt(16))=3, va
trebui introdusă corecţia sqrt(n+0.5), pentru ca algoritmul să lucreze corect.

Cu aceste observaţii algoritmul rafinat arată astfel:

citeşte n STAR
atribuie d  2 T
cât timp d<=(sqrt(n+0.5)) execută Citeste
atribuie m0 n
cât timp n mod d =0 execută
d := 2
atribuie n  n div d
mm+1 DA
d<=(sqrt(n+0.5))
[]
dacă m>0 atunci m:=0
scrie d , m
[] n mod d :=0
dacă d = 2 atunci
atribuie d  3 n :=n divd
altfel m := m + 1
atribuie d  d + 2 NU
NU DA
[] m>0
[]
Scrie d,m
dacă n > 1 atunci
scrie n
NU DA
[] d: = 2
n>1
stop
d := 3 d:= d + 2

Scrie n

STOP
d)Programul Pascal
Program divizorii ;{descompunere în factori primi}
var n,d,m:integer;
BEGIN{main}
write (‘introduceti n:integer’);
readln(n);
writeln(n:4,’are urmatorii factori primi’);
writeln(‘factor’,’‘:5,’multiplicitate’);
d:=2;{cel mai mic numar prim}
while d<= trunc(sqrt(n+0.5)) do
begin

34
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

m:=0;
while(n mod d)= 0 do
begin
n:=n div d;
m:=m+1;
end;
if m>0 then
writeln(d:5,’ ‘:9,m:2);
if d = 2 then d:=3
else d:=d+2;
end;
if n>1 then writeln(n:5,’ ‘:10,’1’);
END.
3.5.3 Algoritmul lui Euclid
1)Să se calculeze c.m.m.d.c. şi c.m.m.m.c a două numere întregi aplicând algoritmul lui
Euclid.
a.) Descrierea algoritmului în limbaj natural:
Se ştie că c.m.m.m.c a două numere A şi B este egal cu raportul dintre produsul celor două numere
şi c.m.m.d.c. al celor două numere. Ca atare în variabila p se va reţine produsul celor două numere.
Variabila CMMMC va reţine c.m.m.m.c, iar variabila CMMDC va reţine c.m.m.d.c. Conform
algoritmului lui Euclid de aflare a c.m.m.d.c se împarte cel mai mare număr (A) la cel mai mic (B) şi se
calculează restul împărţirii întregi (R). Dacă restul împărţiirii este 0 atunci c.m.m.d.c. este B. În caz
contrar se fac atribuirile: lui A i se atribuie B iar lui B i se atribuie R şi procesul se continuă până R=0.
Dacă la introducerea datelor B>A, se schimbă între ele cele două valori.
Dacă cel mai mic număr este 0 se va tipări mesajul ‘unul dintre numere este 0’ şi nu se va calcula
c.m.m.m.c.
Pentru calculul restului împărţirii se va folosi operatorul PASCAL ,,mod”.
b.) Descrierea şi semnificaţia structurilor de date folosite:
A,B : cele două numere întregi
CMMDC, CMMMC : variabile întregi pentru calculul c.m.m.d.c. şi c.m.m.m.c.
c)Descrierea şi semnificaţia structurilor de date folosite
a,b : cele două numere întregi
cmmdc,cmmmc : variabile xîntregi pt.calculul cmmdc şi cmmmc
p : produsul celor două numere ( pentru calculul cmmmc)
x : variabilă auxiliară
d)Descrierea algoritmului în Pseudocod
citeşte a,b
atribuie p  a * b { reţine produsul numerelor }
dacă a<b atunci
atribuie x  a {schimbă cele două valori între ele}
ab
bx
[]
dacă b<>0 atunci
atribuie r a mod b {restul împărţirii întregi }
cât timp r<>0 execută
atribuie a b {pregăteşte o nouă reluare

35
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

a algoritmului }
br
r  a mod b
[]
atribuie cmmdc  b
cmmmc  p / b
scrie cmmmc,cmmdc
altfel
scrie ‘ unul din termeni este zero’
[]
stop
c)Programul Pascal
Program Euclid;
var a,b,x,p,r,cmmdc,cmmmc:integer;
BEGIN{main}
write(‘introduceţi a si b : integer’);
readln(a,b);
p:=a*b;
if a<b then
begin
x:=a;
a:=b;
b:=x;
end;
if b<>0 then
begin
r:=a mod b;
while r<>0 do
begin
a:=b
b:=r;
r:=a mod b;
end;
cmmdc:=b;
cmmmc:=p div b;
writeln(‘cmmdc=’,cmmdc:8,
’cmmmc=’,cmmmc:9);
end
else writeln(‘unul din termeni este
zero’);
END.
2

3.5.4 Sirul lui Fibonacci


1)Să se calculeze pentru un n dat , toţi termenii şirului lui Fibonacci, cunoscând relaţia de
recurenţă f k = f k-1+ f k-2 , pentru orice k >= 2 şi f0 =0, f1 = 1
b) Descrierea algoritmului în limbaj natural
Relaţia de recurenţă necesită două valori iniţiale f 0 şi f . Această relaţie va fi aplicată de n-2 ori ,
actualizând de fiecare dată pe f k-2 şi f k-1.Deci pentru calculul termenului curent f k sunt suficienţi 2
termeni consecutivi din şir. Vom nota cu “a” termenul f k-2 ,cu “b” f k-1 şi cu “c” termenul f k calculat.
b.) Descrierea algoritmului în pseudocod:

36
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

citeşte n
scrie n
{iniţializează primi 2 termeni ai şirului}
atribuie a 0, b 1
scrie a,b {primi doi termeni}
pentru k=3, n, 1 execută
atribuie c a+b {calculează termenul curent}
a b {actualizarea ultimilor doi}
b c {termeni din şir}
scrie c
stop
d.) Programul PASCAL:
program fibonacii;
var
a,b,c,k,n:integer;
BEGIN{main}
write('Introduceti nr. de
termeni:');
readln(n);
a:=0; b:=1;
write(a:3);
for k:=3 to n do
begin
c:=a+b;
a:=b; b:=c;
write(c:3)
end;
END.
2) Calculul termenului de rang n din 3) Se citeste de la tastatura o
sirul Fibonacci, n>0 dat.Sirul lui valoare n intreaga, pozitiva. Sa se
Fibonacci este definit astfel: f(1)=0, verifice
f(2)=1, f(n)=f(n-1)+f(n-2). daca acest numar este un
Exemplu: termen in sirul lui Fibonacci. In caz
n=7 : 1, 1, 2, 3, 5, 8,13.} contrar, sa
var n,a,b,c,i,fibo:word;
begin
se descompuna intr-o suma de
write('n='); readln(n); termeni Fibonacci.
if n=0 then fibo:=0 ex:5=2+3}
else if n=1 then fibo:=1 Program Fibo;
else begin var n,x,y,z,nr,k:longint;
a:=0; b:=1; BEGIN
for i:=2 to n do begin write('Dati valoarea lui n ');
c:=a+b; a:=b; b:=c; end; readln(n);
fibo:=b; end; nr:=n;
writeln('Termenul de rangul',n,'din sirul lui k:=1;
Fibonacci:',fibo); repeat
end. x:=0;

37
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

y:=1; 2 nr m si n sunt termeni consecutivi ai


z:=x+y; sirului.Se va afisa pe ecran mesa-
while z<n do begin jul DA daca raspunsul este afirmativ,
x:=y; respectiv mesajul NU daca raspunsul
y:=z; este negativ.}
z:=x+y; program ddd;
end; var a,b,c:integer;
if z=n then begin begin
if k=1 then writeln(n,' este termen write('a='); readln(a);
Fibonacci') write('b='); readln(b);
else writeln(z, '=',nr,'scris ca suma if a>b then
de termeni Fibonacci'); begin
n:=0; c:=a; a:=b; b:=c;
end end;
else begin while b-a>1 do
k:=2; begin
write(y,'+'); c:=b-a; b:=a; a:=c;
n:=n-y; end;
end; if (a=2) and (b=3) or (a=1) and (b=1) or
until n=0; (a=0) and (b=1) then
readln; writeln('Da')
END. else
4) Sa se determine, fara a calcula writeln('Nu')
efectiv termenii sirului Fibonacci, daca end.

3.5.5 Calculul unor sume cu termen general


1)Determinarea sumei 1+2+...+n . end;
program suma1; writeln(' Suma
uses crt; totala: ',s);
var n,i,s:integer; readln;
begin end.
clrscr; 2) Sa se calculeze suma
writeln('Introduceti S=1+1*2+1*2*3+...+1*2*....*n, unde n este un
n:');readln(n); numar
s:=0; natural citit.
for i:=1 to n do ex:n=2
begin =>3
s:=s+i; }
writeln('Suma
primelor',i,'numere este',s); var p,n,s,i:integer;
end; begin
writeln('Suma totala Write('n='); readln(n);
este:',s); p:=1; s:=0;
readln; for i:=1 to n do begin
end. p:=p*i;
Varianta 2: Determinarea sumei s:=s+p;
a n numere folosind clauza downto . end;
program suma2; write(s);
var n,i,s:integer; end.
begin 3) Pentru n>0 dat, sa se evalueze
writeln('Introduceti expresia:
n:');readln(n); E=1+1*3+1*3*5+...+1*3*..*(2*n+1)
s:=0; Exemple:
for i:=n downto 1 do a)n=2 : E=19
begin b)n=3 : E=124
s:=s+i; c)n=4 : E=1069
writeln('Suma d)n=5 : E=11464}
ultimelor ',n-i+1,' numere este var n,i:byte;
',s); e,p:word;

38
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin inc(e,p);
write('n='); readln(n); end;
e:=1; p:=1; write('E=',e);
for i:=1 to n do begin end.
p:=p*(2*i+1);
3.5.6 Determinare maxim/minim
1)Sa se determine printr-o for j:=i+1 to n do
singura parcurgere a unui vector atit begin
distanta:=sqrt(sqr(x[i]-x[j])
elementul +sqr(ordonata[i]-ordonata[j]));
maxim cit si minim if distanta>max then max:=distanta;
ex:3 end;
123 writeln(' distanta maxima este ',max);
=>1 readln;
3 end.
}
program MAX_MIN; 3){Sa se determine maximul
uses crt; elementelor pare din vector.
type vector=array[1..100]of integer; ex:n=3
var v:vector; 124
max,min,n,i:integer; =>4}
var a:array[1..20] of integer;
begin i,n,k,max,j:integer;
clrscr; ok:boolean;
write('n=');readln(n); begin
for i:=1 to n do begin write write('n=');
('v[',i,']='); readln(n);
readln(v[i]); for i:=1 to n do
end; begin
max:=v[1];min:=v[1]; write('a[',i,']=');
for i:=1 to n do begin if max<v[i] readln(a[i]);
then max:=v[i]; end;
if min> v[i] then
min:=v[i]; i:=1;
end; ok:=false;
write('max=',max); while (i<=n) and (ok=false) do
write('min=',min); if a[i] mod 2=0 then ok:=true
readln else i:=i+1;
end. if ok=false then begin
writeln('nu sunt elemente pare');
2)Fie n puncte .Sa se determine distanta max:=-1;
maxima dintre acestea end
ex:2 else begin
11 max:=a[i];
22 for j:=i+1 to n do
=>dist 1.41 if (a[j] mod 2=0) and (a[j]>max) then
} max:=a[j];
var writeln('maximul elementelor pare
y,x,ordonata:array[1..50]of real; este',max);
i,n,j:byte; max,distanta:real;s,ma:real; end;
begin readln;
write('Numarul de end.
elemente:');readln(n); 4) Se numeste varf creasta un maxim
for i:=1 to n do begin care in stanga sa are elementele ordonate
write('abscisa x',i,' '); crescator iar in dreapta sa are
read(x[i]); elementele ordonate descrescator.
write('ordonata y',i,' '); ex:3
read(ordonata[i]);end; 132
max:=0; => da este}
for i:=1 to n-1 do

39
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

var i,n,m,p:integer; begin


v:array[1..20] of integer; write('n=');
s,d:boolean; readln(n);
begin for i:=1 to n do begin
write('n='); write ('x[',i,']=');
readln(n); readln (x[i]);end;
for i:=1 to n do begin max:=-maxint;
writeln('v[',i,']='); for i:=1 to n do
readln(v[i]); if x[i]<0 then
end; if max<x[i] then
m:=v[1]; max:=x[i];
p:=1; write ('max negat este:',max);readln;
for i:=2 to n do end.
if v[i]>m then begin 6) Sa se determine cea mai mica si cea
m:=v[i]; mai mare diferenta intre doi termeni
p:=i; consecutivi
end; la un vector
if (p=1) or (p=n) then ex:4
write('nu este un punct creasta') 1248
else begin =>4
s:=true; 1}
for i:=1 to p-1 do program zecetablouri;
if v[i]>v[i+1] then s:=false; type vector=array[1..100]of integer;
d:=true; var n,i,max,min:integer;
for i:=p to n-1 do v:vector;
if v[i]<v[i+1] then d:=false; begin
if s and d then write ('n=');readln (n);
write('da,este un punct creasta') for i:=1 to n do begin
else write('nu este un punct creasta'); write('v[',i,']='); readln(v[i]); end;
end; max:=v[1]-v[2];
readln; min:=v[1]-v[2];
end. for i:=1 to n do begin
5) Sa se determine maximul if max< v[i-1]-v[i] then
elementelor negative intr-un vector max:=v[i-1]-v[i];
ex:3
-1 -2 -3 if min>v[i-1]-v[i] then min:=v[i-
=>-1} 1]-v[i];
program maxim_nr_negat;
type vector=array[1..100]of real; end;
var x:vector; write('o diferenta este',abs( min),' iar
n,i:integer; alta diferenta ',abs(max));readln;
max:real; end.

3.5.7 Metode de ordonare


1)METODA INSERTIEI
teoria 1):
Sortarea prin insertie
Principiu: tabloul este vazut ca fiind format din doua subtablouri a[1], a[2],..., a[i-1] si
respectiv a[i], a[i+1],...,a[N] (i=2,N). Secventa a[1],...,a[i-1] este ordonata si urmeaza ca a[i] sa fie
inserat in aceasta secventa la locul potrivit, astfel incit secventa a[1],...,a[i-1],a[i] sa devina ordonata,
urmind ca in pasul urmator cele doua subtablouri considerate sa fie a[1],...,a[i] si a[i+1],...,a[N].
Pentru a gasi locul in care trebuie sa fie inserat a[i] se parcurge sirul a[1],...,a[i-1] de la
dreapta spre stinga, pina cind fie se gaseste un element cu cheia <= a[i].cheie, fie s-a atins capatul
sirului. Aici se poate utiliza metoda fanionului, extinzind tabloul spre stinga cu elementul a[0] care se
asigneaza initial cu a[i] (deci TipIndex=0..N).
Implementarea algoritmului in Pascal:
procedure Insertie;
VAR i,j : TipIndex;

40
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin
for i:=2 to N do begin
{insereaza a[i] la locul potrivit in sirul a[1]...a[i]}
a[0]:=a[i]; j:=i-1;
{cauta locul de inserare}
while a[j].cheie > a[0].cheie do begin
a[j+1]:=a[j]; j:=j-1
end;
a[j+1]:=a[0]
end;
end; {Insertie}
In cazul sortarii prin insertie C si M sint de ordinul N*N, avind valori minime cind tabloul e
ordonat si maxime cind tabloul e ordonat descrescator.
Aceasta metoda este stabila.
Teoria 2):
Sortarea prin insertie binara
Principiu: reprezinta o varianta a sortarii prin insertie, in care cautarea locului de inserare se
face aplicind cautarea binara, stiind ca secventa a[1],...,a[i-1] este deja ordonata.
Implementarea algoritmului in Pascal:
procedure InsertieBinara;
VAR i,j,s,d,m : TipIndex; x : TipElement;
begin
for i:=2 to N do begin
x:=a[i]; s:=1; d:=i-1;
while s<=d do begin
m:=(s+d) div 2;
if a[m].cheie > x.cheie then d:=m-1
else s:=m+1
end;
for j:=i-1 downto s do a[j+1]:=a[j];
a[s]:=x
end
end; {InsertieBinara}
In cadrul acestei metode, C este de ordinul N*log N, iar M de N*N.
Se obtin valori minime ale lui C pentru tablouri ordonate invers si valori maxime pentru tablouri
ordonate.
APLICATIA:

Sa se sorteze un vector prin metoda insertiei(adica fixez un numar de pe o anumita pozitie si


pornind de acolo stpre dreapta se compara doi vecini pina se gasesc doi care nu sunt in ordine dupa
care se merge spre stinga pina se gaseste locul potrivit a celui in cauza, in continuare se face la fel cu
pozitia la care s-a ramas
ex:3
213
=>1 2 3}
uses crt;
var x,i,j,n:integer;
a:array[1..20]of integer;
begin
clrscr;
write('n=');
readln(n);
for i:=1 to n do begin
write('a[',i,']=');
readln(a[i]);
end;
for j:=2 to n do
begin
x:=a[j];
i:=j-1;

41
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

while (i>=1) and (a[i]>x) do


begin
a[i+1]:=a[i];
i:=i-1;
end;
a[i+1]:=x;
end;
for i:=1 to n do
write(a[i]:4);
readln;
end.
2)Sortare prin numarare
Sa se sorteze un vector prin numarare( adica fixez o pozitie si compar
elementul de acolo cu toate celalte si in vectorul nr pe pozitia fixata
scriu de cite ori este mai mare numarul de pe pozitia fixata decit celelalte
,la fel cu urmatoarele ....)
ex:3
213
=>1 2 3}
uses crt;
var t,i,j,n:integer;
a,b,nr:array[1..20]of integer;
begin
clrscr;
write('n=');
readln(n);
for i:=1 to n do begin
write('a[',i,']=');
readln(a[i]);
end;
for i:=1 to n do nr[i]:=0;
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i]<a[j] then nr[j]:=nr[j]+1
else nr[i]:=nr[i]+1;
for i:=1 to n do
b[nr[i]+1]:=a[i];
for i:=1 to n do
write(b[i]:4);
readln;
end.
3)Sortare prin metoda selectiei
Teoria 1)
Sortarea prin selectie
Principiu: se considera subtabloul a[i],...,a[N], se cauta elementul cu cheia
minima din acest subtablou si apoi se interschimba acest element cu elementul a[i],
repetindu-se procedeul pentru valori ale lui i de la 1 la N-1.
Implementarea algoritmului in Pascal:
procedure Selectie;
VAR i,j,k : TipIndex; x : TipElement;
begin
for i:=1 to N-1 do begin
k:=i; x:=a[i];
for j:=i+1 to N do if a[j].cheie < x.cheie then begin
x:=a[j];
k:=j;
end;

42
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

a[k]:=a[i]; a[i]:=x
end
end; {Selectie}
In cazul sortarii prin selectie C este de ordinul N*N , iar M este de ordinul
N*ln N. Aceasta metoda este mai putin rapida pentru tablouri ordonate sau aproape
ordonate.
Teoria 2)
Sortarea prin selectie performanta
Principiu: reprezinta o varianta a sortarii prin selectie, in care determinarea elementului cu
cheia minima dintr-o portiune de tablou se reduce la determinarea pozitiei acestuia. In felul acesta se
poate renunta la asignarea x:=a[j] care apare in ciclul "for" controlat de j.
Implementarea algoritmului in Pascal:
procedure SelectiePerform;
VAR i,j,min : TipIndex; x : TipElement;
begin
for i:=1 to N-1 do begin
min:=i;
for j:=i+1 to N do if a[j].cheie<a[min].cheie then min:=j;
x:=a[min]; a[min]:=a[i]; a[i]:=x
end
end; {SelectiePerform}
APLICATIA:
Sa se sorteze un vector prin metoda selectiei (se interschimba numere care
sunt adiacente(cel mai mare merge catre ultima pozitie si la urmatoatea parcurgere
urmatorul catre penultima)
ex:3
213
=>1 2 3}
uses crt;
var t,i,j,n:integer;
a:array[1..20]of integer;
begin
clrscr;
write('n=');
readln(n);
for i:=1 to n do begin
write('a[',i,']=');
readln(a[i]);
end;
for i:=1 to n-1 do
for j:=i+1 to n do
if a[i]>a[j] then begin
t:=a[i];
a[i]:=a[j];
a[j]:=t;
end;
for i:=1 to n do
write(a[i]:4);
readln;
end.
4)Metoda bulelor
Teoria 1:
Sortarea prin interschimbare (bubblesort)
Principiu: se considera subtabloul a[i],...,a[N] care se parcurge de la dreapta spre stinga,
comparind si interschimbind perechile de elemente alaturate care nu satisfac relatia de ordine,
procedeul repetindu-se pentru i=2,N. Practic, la o parcurgere a subtabloului a[i],...,a[N] are loc
deplasarea elementului minim al acestui subtablou pina in pozitia a[i-1].
Implementarea algoritmului in Pascal:

43
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

procedure BubbleSort;
VAR i,j : TipIndex; x : TipElement;
begin
for i:=2 to N do
for j:=N downto i do
if a[j-1].cheie>a[j].cheie then begin
x:=a[j-1];
a[j-1]:=a[j];
a[j]:=x
end
end; {BubbleSort}
APLICATIA:
Sa se sorteze un vector prin metoda bulelor ( adica se compara permanent doi vecini
astfel incit in final cel mai mare merge spre dreapta)
ex:3
3 2 12
=>2 3 12
}
uses crt;
var t,i,q,n:integer;
a:array[1..20]of integer;
begin
clrscr;
write('n=');
readln(n);
for i:=1 to n do begin
write('a[',i,']=');
readln(a[i]);
end;
q:=0;
while q=0 do
begin
q:=1;
for i:=1 to n-1 do
if a[i]>a[i+1] then begin
t:=a[i];
a[i]:=a[i+1];
a[i+1]:=t;
q:=0;
end;
end;
for i:=1 to n do
write(a[i]:4);
readln;
end.
3.5.9 Metode de cautare
1)Metoda binara var i,n:byte;
Se da un vector cu n elemente ordonat a:array[1..20] of integer;
crescator si o valoare v.Sa se indice v,st,dr,m,k:integer;
daca aceasta valoare exista in sir ,daca ok:boolean;
da ,sa se precizeze pe ce pozitie se begin
afla ,folosind metoda cautarii binare . clrscr;
ex:3 write('n=');
123 readln(n);
p=2 for i:=1 to n do begin
=> pe pozitia a doua este} write('a[',i,']=');
program cautarebinara; readln(a[i]);
uses crt; end;
const Nmax=20; write('pe cine cautati');

44
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

readln(v); Se citesc n numre naturale intr-un


if v=a[1] then vector.sa se calculeze
write('valoarea este pe pozitia 1') media aritmetica a acestora
else ex:n=3
if v=a[n] then caut pe 2
write('valoarea este pe pozitia ',n) 123
else begin
st:=1; =>este 2}
dr:=n; program media;
ok:=false; uses crt;
while (dr-st>1) and not ok do begin var i,n:byte;
m:=trunc((st+dr)/2); a:array[1..50]of integer;
if v=a[m] then begin x,s:integer;m:real;
k:=m; begin
ok:=true; clrscr;
end else write('n=');
if v>a[m] then st:=m readln(n,x);
else dr:=m; for i:=1 to n do begin
end; write('a[',i,']=');
if ok then readln(a[i]);
writeln('valoarea cautata e in sir pe end;
pozitia ',k) for i:=1 to n do
else if x=a[i] then
writeln('valoarea cautata nu e in sir'); write('este',x)
end; else
readkey; write(' NU este',x)
end. readkey;
2)Cautare secventiala end.

3.5.8 Interclasarea
Sa se scrie un program pentru ordonarea prin interclasare a doua
siruri de
numere intregi a si b.
ex:n=3,a=(2,3,4),n=1 ,b=(1)}
program interclass;
var i,j,k,L,m,n:integer;
a,b,c:array[1..30] of integer;
BEGIN
write('n=');read(n);
write('m=');
readln(m);
for i:=1 to n do begin
write('a[',i,']=');readln(a[i]);
end;
for i:=1 to m do begin
write('b[',i,']=');readln(b[i]);
end;
i:=1;j:=1;k:=0;
while (i<=n) and (j<=m) do begin
if a[i]<b[j] then begin
k:=k+1;c[k]:=a[i];i:=i+1;end
else begin
k:=k+1;c[k]:=b[j];j:=j+1;end;
if i>n then for L:=j to m do begin
k:=k+1;c[k]:=b[L];end

45
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

else for L:=i to n do begin


k:=k+1;c[k]:=a[L];end;
for i:=1 to m+n do write(c[i],' '); end;
readln;
END.

3.6 Analiza complexitatii algoritmilor


Analiza eficientei algoritmilor

Vom dezvolta in acest capitol aparatul matematic necesar pentru analiza eficientei algoritmilor,
incercand ca aceasta incursiune matematica sa nu fie excesiv de formala. Apoi, vom arata, pe baza unor
exemple, cum poate fi analizat un algoritm. O atentie speciala o vom acorda tehnicilor de analiza a
algoritmilor recursivi.

Notatia asimptotica

In Capitolul 1 am dat un inteles intuitiv situatiei cand un algoritm necesita un timp in ordinul unei
anumite functii. Revenim acum cu o definitie riguroasa.

5.1.1 O notatie pentru “ordinul lui”

Fie N multimea numerelor naturale (pozitive sau zero) si R multimea numerelor reale. Notam prin N+
si R+ multimea numerelor naturale, respectiv reale, strict pozitive, si prin R multimea numerelor reale
nenegative. Multimea {true, false} de constante booleene o notam cu B. Fie f : N→R o functie
arbitrara. Definim multimea

O( f ) = {t : N→R | (c Є R+) (n0 Є N) (n <= n0) [t(n) <= cf (n)]}

Cu alte cuvinte, O( f ) (se citeste “ordinul lui f ”) este multimea tuturor functiilor t marginite superior de
un multiplu real pozitiv al lui f, pentru valori suficient de mari ale argumentului. Vom conveni sa
spunem ca t este in ordinul lui f (sau, echivalent, t este in O( f ), sau t Є O( f )) chiar si atunci cand
valoarea f (n) este negativa sau nedefinita pentru anumite valori n < n0. In mod similar, vom vorbi
despre ordinul lui f chiar si atunci cand valoarea t(n) este negativa sau nedefinita pentru un numar finit
de valori ale lui n; in acest caz, vom alege n0 suficient de mare, astfel incat, pentru n <= n0, acest lucru
sa nu mai apara. De exemplu, vom vorbi despre ordinul lui n/log n, chiar daca pentru n = 0 si n = 1
functia nu este definita. In loc de t Є O( f ), uneori este mai convenabil sa folosim notatia
t(n) Є O( f (n)), subintelegand aici ca t(n) si f (n) sunt functii.

Fie un algoritm dat si fie o functie t : N→R astfel incat o anumita implementare a algoritmului sa
necesite cel mult t(n) unitati de timp pentru a rezolva un caz de marime n, n Є N. Principiul invariantei
(mentionat in Capitolul 1) ne asigura ca orice implementare a algoritmului necesita un timp in ordinul
lui t. Mai mult, acest algoritm necesita un timp in ordinul lui f pentru orice functie f : N→R pentru
care t Є O( f ). In particular, t Є O(t). Vom cauta in general sa gasim cea mai simpla functie f, astfel
incat t Є O( f ).

Proprietatile de baza ale lui O( f ) sunt date ca exercitii (Exercitiile 5.1-5.7) si este recomandabil sa le
studiati inainte de a trece mai departe.

Notatia asimptotica defineste o relatie de ordine partiala intre functii si deci, intre eficienta relativa a
diferitilor algoritmi care rezolva o anumita problema. Vom da in continuare o interpretare algebrica a
notatiei asimptotice. Pentru oricare doua functii f , g : N→R, definim urmatoarea relatie binara: f <= g

46
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

daca O( f )  O(g). Relatia “<=” este o relatie de ordine partiala in multimea functiilor definite pe N si
cu valori in R (Exercitiul 5.6). Definim si o relatie de echivalenta: f  g daca O( f ) = O(g).

In multimea O( f ) putem inlocui pe f cu orice alta functie echivalenta cu f. De exemplu,


lg n  ln n log n si avem O(lg n) = O(ln n) = O(log n). Notand cu O(1) ordinul functiilor marginite
superior de o constanta, obtinem ierarhia:

O(1)  O(log n)  O(n)  O(n log n)  O(n2)  O(n3)  O(2n)

Aceasta ierarhie corespunde unei clasificari a algoritmilor dupa un criteriu al performantei. Pentru o
problema data, dorim mereu sa obtinem un algoritm corespunzator unui ordin cat mai “la stanga”.
Astfel, este o mare realizare daca in locul unui algoritm exponential gasim un algoritm polinomial.

In Exercitiul 5.7 este data o metoda de simplificare a calculelor, in care apare notatia asimptotica. De
exemplu,

n33n2n8 Є O(n3(3n2n8)) = O(max(n3, 3n2n8)) = O(n3)

Ultima egalitate este adevarata, chiar daca max(n3, 3n2n8)  n3 pentru 0 <= n <= 3, deoarece notatia
asimptotica se aplica doar pentru n suficient de mare. De asemenea,

     n33n2n8 Є O(n3/2(n3/23n2n8))      = O(max(n3/2, n3/23n2n8))


                                                                     = O(n3/2) = O(n3)

chiar daca pentru 0 <= n <= 6 polinomul este negativ. Exercitiul 5.8 trateaza cazul unui polinom
oarecare.

Notatia O( f ) este folosita pentru a limita superior timpul necesar unui algoritm, masurand eficienta
algoritmului respectiv. Uneori este util sa estimam si o limita inferioara a acestui timp. In acest scop,
definim multimea

Ω( f ) = {t : N→R | (c Є R+) (n0 Є N) (n <= n0) [t(n) <= cf (n)]}

Exista o anumita dualitate intre notatiile O( f ) si Ω( f ). Si anume, pentru doua functii oarecare
f, g : N→R, avem: f Є O(g), daca si numai daca g Є Ω( f ).

O situatie fericita este atunci cand timpul de executie al unui algoritm este limitat, atat inferior cat si
superior, de cate un multiplu real pozitiv al aceleiasi functii. Introducem notatia

 ©( f ) = O( f )  Ω( f )

numita ordinul exact al lui f. Pentru a compara ordinele a doua functii, notatia © nu este insa mai
puternica decat notatia O, in sensul ca relatia O( f ) = O(g) este echivalenta cu ©( f ) = ©(g).

Se poate intampla ca timpul de executie al unui algoritm sa depinda simultan de mai multi parametri.
Aceasta situatie este tipica pentru anumiti algoritmi care opereaza cu grafuri si in care timpul depinde
atat de numarul de varfuri, cat si de numarul de muchii. Notatia asimptotica se generalizeaza in mod
natural si pentru functii cu mai multe variabile. Astfel, pentru o functie arbitrara f : N  x  N→R
definim

O( f ) = {t : N  x  N→R | (c Є R+) (m0, n0 Є N) (m <= m0) (n <= n0)


     ∂t(m, n) <= cf (m, n)]}

Similar, se obtin si celelalte generalizari.

47
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

5.1.2 Notatia asimptotica conditionata

Multi algoritmi sunt mai usor de analizat daca consideram initial cazuri a caror marime satisface
anumite conditii, de exemplu sa fie puteri ale lui 2. In astfel de situatii, folosim notatia asimptotica
conditionata. Fie f : N→R o functie arbitrara si fie P : N→B un predicat.

O( f | P) = {t : N→R / (c Є R+) (n0 Є N) (n <= n0)


                            P(n) [  t(n) <= cf (n)] }

Notatia O( f ) este echivalenta cu O( f | P), unde P este predicatul a carui valoare este mereu true.
Similar, se obtin notatiile Ω( f | P) si ©( f | P).

O functie f : N→R este eventual nedescrescatoare, daca exista un n0, astfel incat pentru orice n <= n0
avem f (n) <= f (n1), ceea ce implica prin inductie ca, pentru orice n <= n0 si orice m <= n, avem
f (n) <= f (m). Fie b <= 2 un intreg oarecare. O functie eventual nedescrescatoare este b-neteda daca
f (bn) Є O( f (n)). Orice functie care este b-neteda pentru un anumit b <= 2 este, de asemenea, b-neteda
pentru orice b <= 2 (demonstrati acest lucru!); din aceasta cauza, vom spune pur si simplu ca aceste
functii sunt netede. Urmatoarea proprietate asambleaza aceste definitii, demonstrarea ei fiind lasata ca
exercitiu.

Proprietatea 5.1 Fie b <= 2 un intreg oarecare, f : N→R o functie neteda si t : N→R o functie
eventual nedescrescatoare, astfel incat

t(n) Є X( f (n) | n este o putere a lui b)

unde X poate fi O, Ω, sau ©. Atunci, t Є X( f ). Mai mult, daca t Є ©( f ), atunci si functia t este neteda.

Pentru a intelege utilitatea notatiei asimptotice conditionate, sa presupunem ca timpul de executie al


unui algoritm este dat de ecuatia

unde a, b Є R+ sunt constante arbitrare. Este dificil sa analizam direct aceasta ecuatie. Daca consideram
doar cazurile cand n este o putere a lui 2, ecuatia devine

Prin tehnicile pe care le vom invata la sfarsitul acestui capitol, ajungem la relatia

t(n) Є ©(n log n | n este o putere a lui 2)

Pentru a arata acum ca t Є ©(n log n), mai trebuie doar sa verificam daca t este eventual
nedescrescatoare si daca n log n este neteda.

Prin inductie, vom demonstra ca (n <= 1) [t(n) <= t(n1)]. Pentru inceput, sa notam ca

t(1) = a <= 2(ab) = t(2)

Fie n > 1. Presupunem ca pentru orice m < n avem t(m) <= t(m1). In particular,

t([n/2]) <= t([(n1)/2])

48
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

t([n/2]) <= t([(n1)/2])

Atunci,

t(n) = t([n/2])t([n/2])bn <= t([(n1)/2])t([(n1)/2])b(n1) = t(n1)

In fine, mai ramane sa aratam ca n log n este neteda. Functia n log n este eventual nedescrescatoare si

2n log(2n) = 2n(log 2  log n) = (2 log 2)n  2n log n
                              Є O(n  n log n) = O(max(n, n log n)) = O(n log n)

De multe ori, timpul de executie al unui algoritm se exprima sub forma unor inegalitati de forma

si, simultan

pentru anumite constante c, d Є R+, n0 Є N si pentru doua functii t1, t2 : N→R+. Notatia asimptotica ne
permite sa scriem cele doua inegalitati astfel:

                               t(n) Є t([n/2])  t([n/2])  O(n)
respectiv
                               t(n) Є t([n/2])  t([n/2])  Ω(n)

Aceste doua expresii pot fi scrise si concentrat:

t(n) Є t([n/2])  t([n/2])  ©(n)

Definim functia

Am vazut ca f Є ©(n log n). Ne intoarcem acum la functia t care satisface inegalitatile precedente. Prin
inductie, se demonstreaza ca exista constantele v <= d, u <= c, astfel incat

v <= t(n)/f (n) <= u

pentru orice n Є N+. Deducem atunci

t Є ©( f ) = ©(n log n)

Aceasta tehnica de rezolvare a inegalitatilor initiale are doua avantaje. In primul rand, nu trebuie sa
demonstram independent ca t Є O(n log n) si t Є Ω(n log n). Apoi, mai important, ne permite sa
restrangem analiza la situatia cand n este o putere a lui 2, aplicand apoi Proprietatea 5.1. Deoarece nu
stim daca t este eventual nedescrescatoare, nu putem aplica Proprietatea 5.1 direct asupra inegalitatilor
initiale.

49
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

5.2 Tehnici de analiza a algoritmilor

Nu exista o formula generala pentru analiza eficientei unui algoritm. Este mai curand o chestiune de
rationament, intuitie si experienta. Vom arata, pe baza exemplelor, cum se poate efectua o astfel de
analiza.

5.2.1 Sortarea prin selectie

Consideram algoritmul select din Sectiunea 1.3. Timpul pentru o singura executie a buclei interioare
poate fi marginit superior de o constanta a. In total, pentru un i dat, bucla interioara necesita un timp de
cel mult ba(ni) unitati, unde b este o constanta reprezentand timpul necesar pentru initializarea
buclei. O singura executie a buclei exterioare are loc in cel mult cba(ni) unitati de timp, unde c
este o alta constanta. Algoritmul dureaza in total cel mult

unitati de timp, d fiind din nou o constanta. Simplificam aceasta expresie si obtinem

(a/2)n2  (bca/2)n  (dcb)

de unde deducem ca algoritmul necesita un timp in O(n2). O analiza similara asupra limitei inferioare
arata ca timpul este de fapt in ©(n2). Nu este necesar sa consideram cazul cel mai nefavorabil sau cazul
mediu, deoarece timpul de executie este independent de ordonarea prealabila a elementelor de sortat.

In acest prim exemplu am dat toate detaliile. De obicei, detalii ca initializarea buclei nu se vor
considera explicit. Pentru cele mai multe situatii, este suficient sa alegem ca barometru o anumita
instructiune din algoritm si sa numaram de cate ori se executa aceasta instructiune. In cazul nostru,
putem alege ca barometru testul din bucla interioara,  acest test executandu-se de n(n1)/2 ori.
Exercitiul 5.23 ne sugereaza ca astfel de simplificari trebuie facute cu discernamant.

5.2.2 Sortarea prin insertie

Timpul pentru algoritmul insert (Sectiunea1.3) este dependent de ordonarea prealabila a elementelor de
sortat. Vom folosi comparatia “x < T[ j]” ca barometru.

Sa presupunem ca i este fixat si fie x = T[i], ca in algoritm. Cel mai nefavorabil caz apare atunci cand
x < T[ j] pentru fiecare j intre 1 si i1, algoritmul facand in aceasta situatie i1 comparatii. Acest lucru
se intampla pentru fiecare valoare a lui i de la 2 la n, atunci cand tabloul T este initial ordonat
descrescator. Numarul total de comparatii pentru cazul cel mai nefavorabil este

Є ©(n2)

Vom estima acum timpul mediu necesar pentru un caz oarecare. Presupunem ca elementele tabloului T
sunt distincte si ca orice permutare a lor are aceeasi probabilitate de aparitie. Atunci, daca 1 <= k <= i,
probabilitatea ca T[i] sa fie cel de-al k-lea cel mai mare element dintre elementele T[1], T[2], …, T[i]
este 1/i. Pentru un i fixat, conditia T[i] < T[i1] este falsa cu probabilitatea 1/i, deci probabilitatea ca sa
se execute comparatia “x < T[ j]”, o singura data inainte de iesirea din bucla while, este 1/i. Comparatia
“x < T[ j]” se executa de exact doua ori tot cu probabilitatea 1/i etc. Probabilitatea ca sa se execute
comparatia de exact i1 ori este 2/i, deoarece aceasta se intampla atat cand x < T[1], cat si cand
T[1] <= x < T[2]. Pentru un i fixat, numarul mediu de comparatii este

50
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

ci = 1×1/i  2×1/i * (i2)*1/i  (i1)*2/i = (i1)/2  1/i

Pentru a sorta n elemente, avem nevoie de  comparatii, ceea ce este egal cu

(n23n)/4  Hn Є ©(n2)

unde prin Hn= Є ©(log n) am notat al n-lea element al seriei armonice (Exercitiul 5.17).

Se observa ca algoritmul insert efectueaza pentru cazul mediu de doua ori mai putine comparatii decat
pentru cazul cel mai nefavorabil. Totusi, in ambele situatii, numarul comparatiilor este in ©(n2).

Algoritmul necesita un timp in Ω(n2), atat pentru cazul mediu, cat si pentru cel mai nefavorabil. Cu
toate acestea, pentru cazul cel mai favorabil, cand initial tabloul este ordonat crescator, timpul este in
O(n). De fapt, in acest caz, timpul este si in Ω(n), deci este in ©(n).

5.2.3 Heapsort

Vom analiza, pentru inceput, algoritmul make-heap din Sectiunea3.4. Definim ca barometru
instructiunile din bucla repeat a algoritmului sift-down. Fie m numarul maxim de repetari al acestei
bucle, cauzat de apelul lui sift-down(T, i), unde i este fixat. Notam cu jt valoarea lui j dupa ce se
executa atribuirea “j := k” la a t-a repetare a buclei. Evident, j1 = i. Daca 1 < t <= m, la sfarsitul celei
de-a (t1)-a repetari a buclei, avem j := k si k <= 2j. In general, jt <= 2jt-1 pentru 1 < t <= m. Atunci,

n <= jm <= 2jm-1 <= 4jm-2 <= … <= 2m-1i

Rezulta 2m-1 <= n/i, iar de aici obtinem relatia m <= 1  lg(n/i).

Numarul total de executari ale buclei repeat la formarea unui heap este marginit superior de

,  unde a = [n/2]                              ()

Pentru a simplifica aceasta expresie, sa observam ca pentru orice k <= 0

,  unde b = 2k  si  c = 2k+11

Descompunem expresia () in sectiuni corespunzatoare puterilor lui 2 si notam d = [lg(n/2)] :

Demonstratia ultimei inegalitati rezulta din Exercitiul 5.26. Dar d = [lg(n/2)] implica d1 <= lg n si
d1 <= lg(n/8). Deci,

51
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Din () deducem ca [n/2]3n repetari ale buclei repeat sunt suficiente pentru a construi un heap, deci
make-heap necesita un timp t Є O(n). Pe de alta parte, deoarece orice algoritm pentru formarea unui
heap trebuie sa utilizeze fiecare element din tablou cel putin o data, t Є Ω(n). Deci, t Є ©(n). Puteti
compara acest timp cu timpul necesar algoritmului slow-make-heap (Exercitiul 5.28).

Pentru cel mai nefavorabil caz, sift-down(T[1 .. i1], 1) necesita un timp in O(log n) (Exercitiul 5.27).
Tinand cont si de faptul ca algoritmul make-heap este liniar, rezulta ca timpul pentru algoritmul
heapsort pentru cazul cel mai nefavorabil este in O(n log n). Mai mult, timpul de executie pentru
heapsort este de fapt in ©(n log n), atat pentru cazul cel mai nefavorabil, cat si pentru cazul mediu.

Algoritmii de sortare prezentati pana acum au o caracteristica comuna: se bazeaza numai pe comparatii
intre elementele tabloului T. Din aceasta cauza, ii vom numi algoritmi de sortare prin comparatie. Vom
cunoaste si alti algoritmi de acest tip: bubblesort, quicksort, mergesort. Sa observam ca, pentru cel mai
nefavorabil caz, orice algoritm de sortare prin comparatie necesita un timp in Ω(n log n) (Exercitiul
5.30). Pentru cel mai nefavorabil caz, algoritmul heapsort este deci optim (in limitele unei constante
multiplicative). Acelasi lucru se intampla si cu mergesort.

5.2.4 Turnurile din Hanoi

Matematicianul francez Éduard Lucas a propus in 1883 o problema care a devenit apoi celebra, mai
ales datorita faptului ca a prezentat-o sub forma unei legende. Se spune ca Brahma a fixat pe Pamant
trei tije de diamant si pe una din ele a pus in ordine crescatoare 64 de discuri de aur de dimensiuni
diferite, astfel incat discul cel mai mare era jos. Brahma a creat si o manastire, iar sarcina calugarilor
era sa mute toate discurile pe o alta tija. Singura operatiune permisa era mutarea a cate unui singur disc
de pe o tija pe alta, astfel incat niciodata sa nu se puna un disc mai mare peste unul mai mic. Legenda
spune ca sfarsitul lumii va fi atunci cand calugarii vor savarsi lucrarea. Aceasta se dovedeste a fi o
previziune extrem de optimista asupra sfarsitului lumii. Presupunand ca in fiecare secunda se muta un
disc si lucrand fara intrerupere, cele 64 de discuri nu pot fi mutate nici in 500 de miliarde de ani de la
inceputul actiunii!

Observam ca pentru a muta cele mai mici n discuri de pe tija i pe tija j (unde 1 <= i <= 3, 1 <= j <= 3,
i  j, n <= 1), transferam cele mai mici n1 discuri de pe tija i pe tija 6ij, apoi transferam discul n
de pe tija i pe tija j, iar apoi retransferam cele n1 discuri de pe tija 6ij pe tija j. Cu alte cuvinte,
reducem problema mutarii a n discuri la problema mutarii a n1 discuri. Urmatoarea procedura descrie
acest algoritm recursiv.

procedure Hanoi(n, i, j)
     {muta cele mai mici n discuri de pe tija i pe tija j}
     if n > 0 then    Hanoi(n1, i, 6ij)
                            write i “-->“ j
                            Hanoi(n1, 6ij, j)

Pentru rezolvarea problemei initiale, facem apelul Hanoi(64, 1, 2).

Consideram instructiunea write ca barometru. Timpul necesar algoritmului este exprimat prin
urmatoarea recurenta:

Vom demonstra in Sectiunea 5.2 ca t(n) = 2n1. Rezulta t Є ©(2n).

Acest algoritm este optim, in sensul ca este imposibil sa mutam n discuri de pe o tija pe alta cu mai
putin de 2n1 operatii. Implementarea in oricare limbaj de programare care admite exprimarea
recursiva se poate face aproape in mod direct.

52
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

5.3 Analiza algoritmilor recursivi

Am vazut in exemplul precedent cat de puternica si, in acelasi timp, cat de eleganta este recursivitatea
in elaborarea unui algoritm. Nu vom face o introducere in recursivitate si nici o prezentare a metodelor
de eliminare a ei. Cel mai important castig al exprimarii recursive este faptul ca ea este naturala si
compacta, fara sa ascunda esenta algoritmului prin detaliile de implementare. Pe de alta parte, apelurile
recursive trebuie folosite cu discernamant, deoarece solicita si ele resursele calculatorului (timp si
memorie). Analiza unui algoritm recursiv implica rezolvarea unui sistem de recurente. Vom vedea in
continuare cum pot fi rezolvate astfel de recurente. Incepem cu tehnica cea mai banala.

5.3.1 Metoda iteratiei

Cu putina experienta si intuitie, putem rezolva de multe ori astfel de recurente prin metoda iteratiei: se
executa primii pasi, se intuieste forma generala, iar apoi se demonstreaza prin inductie matematica ca
forma este corecta. Sa consideram de exemplu recurenta problemei turnurilor din Hanoi. Pentru un
anumit n > 1 obtinem succesiv

 t(n) = 2t(n1) +1 = 22t(n2) +2 +1 = … 
= 2n-1t(1) 
 t

Rezulta t(n) = 2n1. Prin inductie matematica se demonstreaza acum cu usurinta ca aceasta forma
generala este corecta.

5.3.2 Inductia constructiva

Inductia matematica este folosita de obicei ca tehnica de demonstrare a unei asertiuni deja enuntate.
Vom vedea in aceasta sectiune ca inductia matematica poate fi utilizata cu succes si in descoperirea
enuntului asertiunii. Aplicand aceasta tehnica, putem simultan sa demonstram o asertiune doar partial
specificata si sa descoperim specificatiile care lipsesc si datorita carora asertiunea este corecta. Vom
vedea ca aceasta tehnica a inductiei constructive este utila pentru rezolvarea anumitor recurente care
apar in contextul analizei algoritmilor. Incepem cu un exemplu.

Fie functia f : N→N, definita prin recurenta

Sa presupunem pentru moment ca nu stim ca f (n) = n(n1)/2 si sa cautam o astfel de formula. Avem

si deci, f (n) Є O(n2). Aceasta ne sugereaza sa formulam ipoteza inductiei specificate partial IISP(n)
conform careia f este de forma f (n) = an2bnc. Aceasta ipoteza este partiala, in sensul ca a, b si c nu
sunt inca cunoscute. Tehnica inductiei constructive consta in a demonstra prin inductie matematica
aceasta ipoteza incompleta si a determina in acelasi timp valorile constantelor necunoscute a, b si c.

Presupunem ca IISP(n1) este adevarata pentru un anumit n <= 1. Atunci,

f (n) = a(n1)2b(n1)cn = an2(1b2a)n(abc)

53
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Daca dorim sa aratam ca IISP(n) este adevarata, trebuie sa aratam ca f (n) = an2bnc. Prin
identificarea coeficientilor puterilor lui n, obtinem ecuatiile 1b2a = b si abc = c, cu solutia
a = b = 1/2, c putand fi oarecare. Avem acum o ipoteza mai completa, pe care o numim tot IISP(n):
f (n) = n2/2n/2c. Am aratat ca, daca IISP(n1) este adevarata pentru un anumit n <= 1, atunci este
adevarata si IISP(n). Ramane sa aratam ca este adevarata si IISP(0). Trebuie sa aratam ca
f (0) = a0b0c = c. Stim ca f (0) = 0, deci IISP(0) este adevarata pentru c = 0. In concluzie, am
demonstrat ca f (n) = n2/2n/2 pentru orice n.

5.3.3 Recurente liniare omogene

Exista, din fericire, si tehnici care pot fi folosite aproape automat pentru a rezolva anumite clase de
recurente. Vom incepe prin a considera ecuatii recurente liniare omogene, adica de forma

a0tn  a1tn-1  ¼  aktn-k = 0                  ()

unde ti sunt valorile pe care le cautam, iar coeficientii ai sunt constante.

Conform intuitiei, vom cauta solutii de forma

tn = xn

unde x este o constanta (deocamdata necunoscuta). Incercam aceasta solutie in () si obtinem

 a0xn  a1xn-1  ...  akxn-k = 0

Solutiile acestei ecuatii sunt fie solutia triviala x = 0, care nu ne intereseaza, fie solutiile ecuatiei

 a0xk  a1xk-1  ...  ak = 0

care este ecuatia caracteristica a recurentei ().

Presupunand deocamdata ca cele k radacini r1, r2, ..., rk ale acestei ecuatii caracteristice sunt distincte,
orice combinatie liniara

este o solutie a recurentei (), unde constantele c1, c2, ..., ck sunt determinate de conditiile initiale. Este
remarcabil ca () are numai solutii de aceasta forma.

Sa exemplificam prin recurenta care defineste sirul lui Fibonacci (din Sectiunea 1.6.4):

tn = tn-1  tn-2               n <= 2

iar t0 = 0, t1 = 1. Putem sa rescriem aceasta recurenta sub forma

tn +tn-1 +tn-2 = 0

care are ecuatia caracteristica

x2 +x +1 = 0

cu radacinile r1,2 = (1 )/2. Solutia generala are forma

54
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Impunand conditiile initiale, obtinem

c1  c2      = 0         n = 0


r1c1  r2c2 = 1         n = 1

de unde determinam

c1,2 = 

Deci, . Observam ca r1 = ỹ = (1 )/2, r2 = ỹ-1 si obtinem

(ỹn(ỹ)-n)

care este cunoscuta relatie a lui de Moivre, descoperita la inceputul secolului XVI. Nu prezinta nici o
dificultate sa aratam acum ca timpul pentru algoritmul fib1 (din Sectiunea 1.6.4) este in ©(ỹn).

Ce facem insa atunci cand radacinile ecuatiei caracteristice nu sunt distincte? Se poate arata ca, daca r
este o radacina de multiplicitate m a ecuatiei caracteristice, atunci tn = rn, tn = nrn, tn = n2rn, ..., tn = nm-1rn
sunt solutii pentru (). Solutia generala pentru o astfel de recurenta este atunci o combinatie liniara a
acestor termeni si a termenilor proveniti de la celelalte radacini ale ecuatiei caracteristice. Din nou, sunt
de determinat exact k constante din conditiile initiale.

Vom da din nou un exemplu. Fie recurenta

tn = 5tn-1 +8tn-2  4tn-3               n <= 3

iar t0 = 0, t1 = 1, t2 = 2. Ecuatia caracteristica are radacinile 1 (de multiplicitate 1) si 2 (de multiplicitate
2). Solutia generala este:

tn = c11n  c22n  c3n2n

Din conditiile initiale, obtinem c1 = 2, c2 = 2, c3 = 1/2.

5.3.4 Recurente liniare neomogene

Consideram acum recurente de urmatoarea forma mai generala

a0tn  a1tn-1  ...  aktn-k = bnp(n)                        ()

unde b este o constanta, iar p(n) este un polinom in n de grad d. Ideea generala este ca, prin manipulari
convenabile, sa reducem un astfel de caz la o forma omogena.

De exemplu, o astfel de recurenta poate fi:

tn  2tn-1 = 3n

In acest caz, b = 3 si p(n) = 1, un polinom de grad 0. O simpla manipulare ne permite sa reducem acest
exemplu la forma (). Inmultim recurenta cu 3, obtinand

55
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

3tn +6tn-1 = 3n+1

Inlocuind pe n cu n1 in recurenta initiala, avem

tn+1 +2tn = 3n+1

In fine, scadem aceste doua ecuatii

tn+1 +5tn  +6tn-1 = 0

Am obtinut o recurenta omogena pe care o putem rezolva ca in sectiunea precedenta. Ecuatia


caracteristica este:

x2 +5x+  6 = 0

adica (x2)(x3) = 0.

Intuitiv, observam ca factorul (x2) corespunde partii stangi a recurentei initiale, in timp ce factorul
(x3) a aparut ca rezultat al manipularilor efectuate, pentru a scapa de parte dreapta.

Generalizand acest procedeu, se poate arata ca, pentru a rezolva (), este suficient sa luam
urmatoarea ecuatie caracteristica:

(a0xk  a1xk-1  ¼  ak)(xb)d+1 = 0

Odata ce s-a obtinut aceasta ecuatie, se procedeaza ca in cazul omogen.

Vom rezolva acum recurenta corespunzatoare problemei turnurilor din Hanoi:

tn = 2tn-1  1               n <= 1

iar t0 = 0. Rescriem recurenta astfel

tn  2tn-1 = 1

care este de forma () cu b = 1 si p(n) = 1, un polinom de grad 0. Ecuatia caracteristica este atunci
(x2)(x1) = 0, cu solutiile 1 si 2. Solutia generala a recurentei este:

tn = c11n  c22n

Avem nevoie de doua conditii initiale. Stim ca t0 = 0; pentru a gasi cea de-a doua conditie calculam

t1 = 2t0 +1

Din conditiile initiale, obtinem

tn = 2n +1

Daca ne intereseaza doar ordinul lui tn, nu este necesar sa calculam efectiv constantele in solutia
generala. Daca stim ca tn = c11n +c22n, rezulta tn Є O(2n). Din faptul ca numarul de mutari a unor
discuri nu poate fi negativ sau constant, deoarece avem in mod evident tn <= n, deducem ca c2 > 0.
Avem atunci tn Є Ω(2n) si deci, tn Є ©(2n). Putem obtine chiar ceva mai mult. Substituind solutia
generala inapoi in recurenta initiala, gasim

56
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

1 = tn  2tn-1 = c1  c22n2(c1  c22n-1) = c1

Indiferent de conditia initiala, c1 este deci 1.

5.3.5 Schimbarea variabilei

Uneori, printr-o schimbare de variabila, putem rezolva recurente mult mai complicate. In exemplele
care urmeaza, vom nota cu T(n) termenul general al recurentei si cu tk termenul noii recurente obtinute
printr-o schimbare de variabila. Presupunem pentru inceput ca n este o putere a lui 2.

Un prim exemplu este recurenta

T(n) = 4T(n/2)  n                n > 1

in care inlocuim pe n cu 2k, notam tk = T(2k) = T(n) si obtinem

tk = 4tk-1  2k

Ecuatia caracteristica a acestei recurente liniare este

(x4)(x2) = 0

si deci, tk = c14k  c22k. Inlocuim la loc pe k cu lg n

T(n) = c1n2  c2n

Rezulta

T(n) Є O(n2 | n este o putere a lui 2)

Un al doilea exemplu il reprezinta ecuatia

T(n) = 4T(n/2)  n2                n > 1

Procedand la fel, ajungem la recurenta

tk = 4tk-1  4k

cu ecuatia caracteristica

(x4)2 = 0

si solutia generala tk = c142  c2k42. Atunci,

T(n) = c1n2  c2n2lg n

si obtinem

T(n) Є O(n2log n | n este o putere a lui 2)

In fine, sa consideram si exemplul

57
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

T(n) = 3T(n/2)  cn               n > 1

c fiind o constanta. Obtinem succesiv

T(2k) = 3T(2k-1)  c2k

tk = 3tk-1  c2k

cu ecuatia caracteristica

(x3)(x2) = 0

tk = c13k  c22k

T(n) = c13lg n  c2n

si, deoarece

alg b = blg a

obtinem

T(n) = c1nlg 3  c2n

deci,

T(n) Є O(nlg 3 | n este o putere a lui 2)

In toate aceste exemple am folosit notatia asimptotica conditionata. Pentru a arata ca rezultatele
obtinute sunt adevarate pentru orice n, este suficient sa adaugam conditia ca T(n) sa fie eventual
nedescrescatoare. Aceasta, datorita Proprietatii 5.1 si a faptului ca functiile n2, n log n si nlg 3 sunt
netede.

Putem enunta acum o proprietate care este utila ca reteta pentru analiza algoritmilor cu recursivitati de
forma celor din exemplele precedente. Proprietatea, a carei demonstrare o lasam ca exercitiu, ne va fi
foarte utila la analiza algoritmilor divide et impera din Capitolul 7.

Proprietatea 5.2 Fie T : N→R+ o functie eventual nedescrescatoare

T(n) = aT(n/b)  cnk                n > n0

unde: n0 <= 1, b <= 2 si k <= 0 sunt intregi; a si c sunt numere reale pozitive; n/n0 este o putere a lui b.
Atunci avem

58
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Clasa P; alte clase deterministe

Unele probleme se pot rezolva, altele nu. De exemplu, o problemă notorie, a cărei imposibilitate este
riguros demonstrată în anii '30 de către matematicianul englez Alan Turing, este de a decide dacă un
program se va opri vreodată pentru o anumită instanţă a datelor de intrare.

Pe de altă parte, chiar între problemele care pot fi rezolvate, teoreticienii trag o linie imaginară între
problemele care au rezolvări ``rezonabil'' de rapide, şi restul problemelor, care se numesc ``intratabile''.

În mod arbitrar, dar nu ne-justificabil, o problemă se numeşte ``intratabilă'' dacă complexitatea ei este
exponenţială în mărimea datelor de intrare. (Nu uitaţi, este vorba de complexitate ``worst-case''
asimptotică.) O problemă este ``tratabilă'' dacă putem scrie complexitatea ei sub forma unui polinom,
de un grad oricît de mare.

Mulţimea tuturor problemelor de decizie (adică a problemelor la care răspunsul este da sau nu) cu
complexitate polinomială se notează cu P (de la polinom). De exemplu, problema de a găsi dacă o
valoare se află într-un vector este în clasa P; algoritmul exhibat mai sus este un algoritm în timp linear
(O(n)) pentru a răspunde la această întrebare.

Un exemplu de problemă cu complexitate exponenţială (ne-polinomială)? Iată unul: dacă se dă o


formulă logică peste numerele reale, cu cuantificatori existenţiali ( ) şi universali ( ), care foloseşte

numai operaţii de adunare, comparaţii cu < şi conectori logici ( ), este

formula adevărată? (Un exemplu de formulă: `` '').


Decizia se poate face numai într-un timp exponenţial în lungimea formulei (pentru anumite instanţe),
dar demonstraţia nu este de loc simplă.

(Ca o curiozitate: există şi probleme cu o complexitate ``ne-elementară'', care este mai mare decît
complexitatea oricărei probleme exponenţiale. O astfel de problemă este cea de decizie a adevărului
unei formule în teoria numită S1S, sau ``teoria monadică a succesorilor de ordinul 2''. Nu vă lăsaţi
intimidaţi de terminologie: aceasta este practic o teorie logică peste numerele naturale, în care avem
voie să scriem formule cu cuantificatori şi conectori logici, ca mai sus, dar avem şi dreptul să
cuantificăm peste mulţimi. Complexitatea deciziei unei formule logice într-o astfel de teorie este mai

mare decît pentru orice k natural!)

Clasa NP; algoritmi nedeterminişti; NP-completitudine

Algoritmii cu care suntem obişnuiţi să lucrăm zi de zi sunt determinişti. Asta înseamnă că la un


moment dat evoluţia algoritmului este unic determinată, şi ca instrucţiunea care urmează să se execute
este unic precizată în fiecare moment. Am văzut însă că limbajul pe care l-am folosit ne permite
scrierea unor algoritmi care au mai multe posibilităţi la un moment dat; construcţia if din limbajul cu
gărzi permite evaluarea oricărei instrucţiuni care are garda adevărată.

Acest tip de algoritmi este surprinzător de bogat în consecinţe cu valoare teoretică. Aceşti algoritmi nu
sunt direct aplicabili, însă studiul lor dă naştere unor concepte foarte importante.

Surprinzătoare este şi definiţia corectitudinii unui astfel de algoritm. Un algoritm nedeterminist este
corect dacă există o posibilitate de executare a sa care găseşte răspunsul corect. Pe măsură ce un

59
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

algoritm nedeterminist se execută, la anumiţi paşi se confruntă cu alegeri nedeterministe. Ei bine, dacă
la fiecare pas există o alegere, care făcută să ducă la găsirea soluţiei, atunci algoritmul este numit
corect.

Astfel, un algoritm nedeterminist care caută ieşirea dintr-un labirint ar arăta cam aşa:

do not iesire(pozitie_curenta) ->


if not perete(nord(pozitie_curenta)) ->
pozitie_curenta := nord(pozitie_curenta)
[] not perete(est(pozitie_curenta)) ->
pozitie_curenta := est(pozitie_curenta)
[] not perete(sud(pozitie_curenta)) ->
pozitie_curenta := sud(pozitie_curenta)
[] not perete(vest(pozitie_curenta)) ->
pozitie_curenta := vest(pozitie_curenta)
fi
od

Pe scurt algoritmul se comportă aşa: dacă la nord nu e perete mergi încolo, sau, poate, dacă la sud e
liber, mergi încolo, sau la est, sau la vest. În care dintre direcţii, nu se precizează (este ne-determinat).
Este clar că dacă există o ieşire la care se poate ajunge, există şi o suită de aplicări ale acestor reguli
care duce la ieşire.

Utilitatea practică a unui astfel de algoritm nu este imediat aparentă: în definitiv pare să nu spună nimic
util: soluţia este fie spre sud, fie spre nord, fie spre este, fie spre vest. Ei şi? Este clar că aceşti algoritmi
nu sunt direct implementabili pe un calculator real.

În realitate existenţa un astfel de algoritm deja înseamnă destul de mult. Înseamnă în primul rînd că
problema se poate rezolva algoritmic; vă reamintesc că există probleme care nu se pot rezolva deloc.

În al doilea rînd, se poate arăta că fiecare algoritm nedeterminist se poate transforma într-unul
determinist într-un mod automat. Deci de îndată ce ştim să rezolvăm o problemă într-un mod
nedeterminist, putem să o rezolvăm şi determinist! Transformarea este relativ simplă: încercăm să
mergem pe toate drumurile posibile în paralel, pe fiecare cîte un pas. (O astfel de tehnică aplicată în
cazul labirintului se transformă în ceea ce se cheamă ``flood fill'': evoluez radial de la poziţia de plecare
în toate direcţiile).

Clasa tuturor problemelor care se pot rezolva cu algoritmi nedeterminişti într-un timp polinomial se
notează cu NP (Nedeterminist Polinomial). Este clar că orice problemă care se află în P se află şi în NP,
pentru că algoritmii determinişti sunt doar un caz extrem al celor determinişti: în fiecare moment au o
singură alegere posibilă.

Din păcate transformarea într-un algoritm determinist se face pierzînd din eficienţă. În general un
algoritm care operează în timp nedeterminist polinomial (NP) poate fi transformat cu uşurinţă într-un
algoritm care merge în timp exponenţial (EXP). Avem deci o incluziune de mulţimi între problemele

de decizie: P NP EXP.

Partea cea mai interesantă este următoarea: ştim cu certitudine că P EXP. Însă nu avem nici o idee
despre relaţia de egalitate între NP şi P sau între NP şi EXP. Nu există nici o demonstraţie care să
infirme că problemele din NP au algoritmi eficienţi, determinist polinomiali! Problema P=NP este cea
mai importantă problemă din teoria calculatoarelor, pentru că de soluţionarea ei se leagă o grămadă de
consecinţe importante.

60
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Problema aceasta este extrem de importantă pentru întreaga matematică, pentru că însăşi demonstrarea
teoremelor este un proces care încearcă să verifice algoritmic o formulă logică (cum am văzut mai sus
de pildă); teoremele la care există demonstraţii ``scurte'' pot fi asimilate cu problemele din mulţimea
NP (la fiecare pas dintr-o demonstraţie putem aplica mai multe metode de inferenţă, în mod
nedeterminist; un algoritm trebuie să ghicească înşiruirea de metode aplicate pentru demonstrarea
enunţului); dacă orice problemă din NP este şi în P, atunci putem automatiza o mare parte din
demonstrarea de teoreme în mod eficient!

Problema P=NP este foarte importantă pentru criptografie: decriptarea este o problemă din NP (cel care
ştie cheia ştie un algoritm determinist polinomial de decriptare, dar cel care nu o ştie are în faţa o
problemă pe care nedeterminist o poate rezolva în timp polinomial). Dacă s-ar demonstra că P=NP
acest lucru ar avea consecinţe extrem de importante, iar CIA si KGB ar fi într-o situaţie destul de
proastă, pentru că toate schemele lor de criptare ar putea fi sparte în timp polinomial (asta nu înseamnă
neapărat foarte repede, dar oricum, mult mai repede decît timp exponenţial)!

Mai mult, în 1971 Cook a demonstrat că există o problemă specială în NP (adică pentru care se poate
da un algoritm eficient nedeterminist), numită problema satisfiabilităţii (notată cu SAT). Problema este
foarte simplă: dacă se dă o formulă booleană care cuprinde mai multe variabile, poate fi formula făcută

adevărată dînd anumite valori variabilelor? De pildă formula devine


adevărată pentru x1=adevărat şi x2 arbitrar. SAT este foarte importantă, pentru că Cook a demonstrat că
dacă SAT poate fi rezolvată în P (adică folosind un algoritm determinist polinomial), atunci orice
problemă din NP poate fi rezolvată în timp polinomial! Problema satisfiabilităţii este cumva ``cea mai
grea problemă'' din NP, pentru că rezolvarea oricărei alte probleme din NP se poate face ``mai repede''
decît a ei. Din cauza asta SAT se numeşte o problemă NP-completă.

De la Cook încoace s-au mai descoperit cîteva sute de probleme NP-complete. Unele probleme care se
ivesc foarte adesea în practică s-au dovedit NP-complete! Acesta este un alt motiv pentru care clasa atît
de abstractă NP a problemelor cu algoritmi nedeterminişti este atît de importantă: foarte multe
probleme practice au algoritmi polinomiali nedeterminişti, dar cei mai buni algoritmi determinişti iau
un timp exponenţial!

Iată cîteva exemple de probleme NP-complete:

 Problema comis-voiajorului (turneu Hamiltonian de cost minim): dîndu-se o reţea de oraşe, o reţea de
drumuri între oraşe şi o lungime k, există un traseu de cost mai mic decît k trecînd prin fiecare oraş o
singură dată şi revenind la punctul de plecare?
 Dîndu-se o mulţime de numere naturale, se poate împărţi în două mulţimi de numere de sume egale 2?
 ``Clica'': dîndu-se un graf G şi un număr k, are G un subgraf complet cu k vîrfuri (adică o mulţime de k
vîrfuri unite fiecare cu fiecare)?
 ``Acoperire'': dîndu-se un graf G şi un număr k, pot alege k vîrfuri în aşa fel încît toate muchiile din G au
un capăt ales?

O cantitate enormă de efort şi ingeniozitate a fost risipită pentru a încerca să se demonstreze că P=NP
sau opusul acestei afirmaţii, dar nici un rezultat concret nu a fost obţinut. Credinţa cvasi-unanimă este
că P=NP, dar numai matematica poate oferi vreo certitudine...

Din cauză că foarte multe probleme practice sunt în NP, şi ca aparent nu putem avea algoritmi
determinişti eficace pentru ele, cercetătorii şi-au îndreptat atenţia asupra unor clase noi de algoritmi,
care vor face obiectul secţiunilor următoare.

Algoritmi aproximativi

În secţiunile care urmează folosim tot timpul premiza nedemonstrată că PNP. Dacă P=NP, atunci
problemele pe care ne batem capul să le rezolvăm prin metode ciudate pot fi de fapt rezolvate exact şi
eficient.

61
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Optim şi aproximare

Foarte multe probleme de optimizare se dovedesc a fi NP-complete 3: probleme în care vrem să


calculăm maximumul sau minimumul a ceva. Bine, dar dacă de fapt mă mulţumesc să obţin o valoare
care nu este chiar optimă, dar este ``suficient de aproape''? Poate în acest caz complexitatea problemei
poate fi redusă, şi sunt în stare să scriu un algoritm eficient... (polinomial). Avem deci de a face cu un
compromis:

solutie optima; solutie sub-optima:


<-------------->
algoritm NP sau algoritm polinomial
algoritm exponential

Într-adevăr, această metodă se bucură de un oarecare succes, dar nu de unul general. Algoritmii care
rezolvă o problemă de optimizare în speranţa unui rezultat sub-optimal se numesc ``algoritmi
aproximativi''.

Există o sumedenie de rezultate în ceea ce priveşte problemele de optimizare şi aproximările lor. Se


demonstrează că unele probleme pot fi foarte bine aproximate (putem obţine soluţii cît dorim de
aproape de optim în timp polinomial), altele pot fi aproximate numai în anumite limite (de exemplu
putem obţine soluţii de 2 ori mai slabe, dar deloc mai bune), sau altele nu pot fi aproximate deloc (în
ipoteza că P<>NP).

Teoria algoritmilor aproximativi este relativ recentă (deşi ideea există de multă vreme), iar unele
rezultate sunt extrem de complicate. Ne vom mulţumi să dăm nişte exemple pentru a ilustra algoritmi
aproximativi în acţiune, şi tipul de rezultate care se pot obţine.

Vom ilustra două rezultate diferite din teoria algoritmilor aproximativi: algoritmi de aproximare
relativă, algoritmi de aproximare absolută a soluţiei (lămurim terminologia imediat).

Să notăm o instanţă a unei probleme cu I. Fie OPT(I) valoarea soluţiei optime pentru acea instanţă
(care există, dar pe care nu ştim s-o calculăm eficient), şi fie A(I) valoarea calculată de algoritmul
nostru aproximativ. Numim aproximaţia absolută dacă există un număr K, independent de instanţa I,
care are proprietatea că |OPT(I) - A(I)| < K. Numim aproximaţia relativă dacă există un R (numit
``performanţă'') astfel ca pentru orice instanţă I avem (A(I) / OPT(I)) < R (dacă problema caută un
maximum, atunci fracţia din definiţie trebuie inversată).

Problema rucsacului

Iată o variantă a problemei rucsacului care este NP-completă , dar pentru care se poate obţine cu foarte
mare uşurinţă un algoritm aproximativ relativ eficient.

Se dau o mulţime (mare) de rucsaci de capacitate egală (cunoscută, un număr natural). Se mai dă o
mulţime finită de obiecte, fiecare de un volum cunoscut (număr natural). Întrebarea este: care este
numărul minim de rucsaci necesari pentru a împacheta toate obiectele?

Problema rucsacului are un algoritm de aproximare relativă cu performanţă 2.

Algoritmul este banal: metoda ``greedy'': pune de la stînga fiecare greutate în primul rucsac liber:

Date de intrare: nrobiecte, capacitate, marime[1..nrobiecte]

Initializari:
o, folositi := 1, 0
do o <= nrobiecte -> liber[o] := capacitate od

Algoritm:

62
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

o := 1
do o <= nrobiecte ->
r := 1
do (liber[r] < marime[o]) -> r := r+1
od
folositi, liber[r], o :=
max(r, folositi), liber[r] - marime[o], o+1
od

Cum demonstrăm că performanţa relativă este 2? Foarte simplu: să observăm că la sfîrşitul


algoritmului nu pot exista doi rucsaci folosiţi pe mai puţin de jumătate amîndoi, pentru că atunci
conţinutul celui de-al doilea ar fi fost vărsat în primul. Cu alte cuvinte, la terminare avem: liber[r] < 1/2
capacitate. Dar dacă însumăm pentru toţi rucsacii, vom avea că spaţiul liber este mai puţin de jumătate
din cel disponibil, deci cel ocupat este mai mult de jumătate. Dar dacă obiectele au mărime totală M,
atunci orice-am face nu putem folosi mai puţin de M spaţiu total pentru a le împacheta. Dar noi am
folosit mai puţin de M + M = 2M, deci algoritmul are performanţă 2. QED.

Performanţa absolută; un rezultat negativ

Vom folosi o altă problemă NP-completă, pentru care avem imediat un algoritm de aproximare relativă
de performanţă 2, dar pentru care vom demonstra că nu există nici un algoritm de aproximare absolută.

Problema este cea a acoperirii unui graf, enunţată mai sus. Ca problemă de optimizare, ea se enunţă
astfel: ``care este numărul minim de vîrfuri care trebuie ``acoperite'' astfel ca toate muchiile dintr-un
graf să fie atinse?''

Pentru această problemă algoritmul greedy nu face multe parale ca algoritm de aproximare. Există însă
un algoritm relativ simplu, cu performanţă 2, care se foloseşte însă de un alt algoritm clasic, cel al
``cuplării'' (matching). Fără a intra în detalii, există un algoritm polinomial relativ sofisticat pentru a
calcula cuplări maximale pe grafuri4. Calculăm o cuplare maximală, după care luăm capetele tuturor
muchiilor care o formează: astfel obţinem o acoperire (uşor de demonstrat) care e cel mult dublă ca
mărime faţă de optim (pentru că în optim trebuie să se găsească cel puţin cîte un vîrf pentru fiecare
muchie din cuplare, iar noi am luat cîte două).

Iată şi un rezultat negativ interesant: pentru orice K fixat, nu există nici un algoritm care să dea pentru
problema acoperirii o soluţie aproximativă absolută la distanţa K de cea optimă pentru orice instanţă.
Demonstraţia este foarte simplă, odată ce ai văzut ideea, şi se bazează pe ``tehnica amplificării''. Iată
cum se face, prin reducere la absurd:

Să presupunem că avem un algoritm A care calculează pentru orice graf o acoperire care este cu cel
mult K noduri mai mare ca cea optimă (K e fixat). Cu alte cuvinte |OPT(G) - A(G)| < K. Să luăm o
instanţă arbitrară a problemei cuplării, G. Formăm un nou graf G 1 din G, care nu este conex, şi care
constă din K+1 copii ale lui G, alăturate. Aceasta este o instanţă perfect corectă a problemei acoperirii,
aşa că rulăm pe ea algoritmul nostru A. Acesta va oferi o acoperire care are cel mult cu K noduri mai
mult decît acoperirea optimă. (Vă reamintesc notaţiile: OPT(G) este valoarea optimă: numărul minim
de noduri pentru a acoperi muchiile, iar A(G) este valoarea calculată de algoritmul nostru.

Datorită faptului că cele K+1 copii ale lui G sunt neconectate, optimumul pentru G 1 este reuniunea a
K+1 optimumuri pentru G. Din cauza asta avem relaţia OPT(G 1) = (K+1) OPT(G). Fie acum H copia
lui G pe care A a marcat cele mai multe vîrfuri; atunci A(G 1) <= (K+1) A(H). Dar din proprietăţile lui
A avem: |OPT(G1) - A(G1)| < K, sau |(K+1) OPT(H) - (K+1) A(H)| < K, ori |OPT(H) - A(H)| <
K/(K+1) < 1. Însă ştim că OPT(H) şi A(H) sunt numere naturale, deci am obţinut OPT(H) = A(H)!

63
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Asta înseamnă că dacă avem un algoritm aproximativ absolut pentru problema acoperirii, putem
imediat construi un algoritm exact la fel de rapid. Ori asta ar însemna că P=NP, ceea ce am presupus
fals.

Exemplele pe care le-am ales sunt în mod deliberat simple; teoria algoritmilor aproximativi este în
plină dezvoltare şi are rezultate foarte spectaculoase şi în general complicate. În orice caz,
aplicabilitatea ei este imediată, pentru că multe probleme practice care nu pot aştepta au numai
rezolvări aproximative.

Algoritmi Monte Carlo

O tehnică foarte spectaculoasă pentru rezolvarea problemelor este cea a folosiri numerelor
aleatoare. Practic algoritmii aleatori sunt identici cu cei obişnuiţi, dar folosesc în plus o nouă
instrucţiune, care s-ar putea chema ``dă cu banul''. Această instrucţiune generează un bit arbitrar ca
valoare.

În mod paradoxal, incertitudinea ne poate oferi mai multă putere...

La ce se foloseşte aleatorismul? Să ne amintim că în general complexitatea unei probleme este


definită luînd în considerare cea mai defavorabilă instanţă. De exemplu, pentru problema comis
voiajorului, faptul că această problemă este NP-completă nu înseamnă că nu putem rezolva nici o
instanţă a ei, ci că există instanţe pentru care algoritmii cunoscuţi nu au prea multe şanse să termine în
curînd.

Acest lucru este adevărat şi pentru alte clase de algoritmi; de pildă algoritmul quicksort are
pentru majoritatea vectorilor de intrare o comportare O(n log n). Dacă însă datele de intrare sunt prost
distribuite, atunci quicksort poate face n2 comparaţii. Pentru n=100 asta înseamnă de 10 ori mai mult!
Numărul de instanţe pentru care quicksort este slab este mult mai mic decît numărul de instanţe pentru
care merge bine. Ce te faci însă dacă într-un anumit context lui quicksort i se dau numai date rele?
(Datele preluate din măsurători reale sunt foarte rar complet uniform distribuite). O soluţie paradoxală
constă în a amesteca aleator vectorul înainte de a-l sorta.

Complexitatea medie (average case) a lui quicksort este O(n log n). Complexitatea în cazul cel
mai rău (worst case) este O(n 2). Dacă datele vin distribuite cu probabilitate mare în zona ``rea'', atunci
amestecîndu-le putem transforma instanţe care pică în zona ``worst-case'' în instanţe de tip ``average-
case''. Fireşte, asta nu înseamnă ca nu putem avea ghinion, şi ca amestecarea să producă tot o instanţă
``rea'', dar probabilitatea ca acest lucru să se întîmple este foarte mică, pentru că quicksort are puţine
instanţe rele5.

Acesta este un caz de folosire a aleatorului pentru a îmbunătăţi performanţa medie a unui algoritm.

Cîteodată cîştigul este şi mai mare, pentru că putem rezolva probleme NP-complete foarte rapid
folosind aleatorismul. De obicei avem însă un preţ de plătit. Cînd folosim algoritmi din clasa prezentată
mai jos, putem risca să nu primim răspunsul corect.

Algoritmi Las Vegas

64
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Evoluţia unui algoritm care foloseşte numere aleatoare nu mai depinde numai de datele de intrare, ci şi
de numerele aleatoare pe care le generează. Dacă are ``noroc'' algoritmul poate termina repede şi bine;
dacă dă prost cu zarul, ar putea eventual chiar trage o concluzie greşită. (În cazul quicksort de mai sus
răspunsul este întotdeauna corect, dar cîteodată vine mai greu. Aceasta este diferenţa dintre algoritmii
Monte Carlo, mereu corecţi, şi cei Las Vegas, care pot uneori, rar, greşi.)

Vom defini acum algoritmii probabilişti pentru probleme de decizie (ţineţi minte, la care răspunsul este
Da sau Nu). Majoritatea problemelor pot fi exprimate în forma unor probleme de decizie, deci
simplificarea nu este prea drastică.

Există două clase de algoritmi probabilişti, dar ne vom concentra atenţia numai asupra uneia dintre ele,
pentru care vom da şi două exemple simple şi spectaculoase. Vom defini totodată clasa problemelor
care pot fi rezolvate probabilist în timp polinomial, numită RP (Random Polinomial).

Observaţi că dacă indicăm de la început care sunt numerele aleatoare care vor fi generate, evoluţia
algoritmului este perfect precizată.

Definiţie: O problemă de decizie este în RP dacă există un algoritm aleator A care rulează într-un timp
polinomial în lungimea instanţei (nc pentru un c oarecare), şi care are următoarele proprietăţi:

 Dacă răspunsul la o instanţă I este ``Da'', atunci cu o probabilitate mai mare de 1/2 algoritmul va
răspunde ``Da''.
 Dacă răspunsul la o instanţă I este ``Nu'', atunci cu probabilitate 1 algoritmul va răspunde ``Nu''.

De cine este dată ``probabilitatea'' de mai sus? De numărul de şiruri aleatoare. Cînd rulăm un
algoritm aleator pentru o instanţă I avem la dispoziţie 2 nc şiruri aleatoare de biţi; pentru unele dintre ele
algoritmul răspunde ``Da'', pentru celelalte răspunde ``Nu''. Ceea ce facem este să numărăm pentru cîte
şiruri algoritmul ar răspunde ``da'' şi să facem raportul cu 2nc. Aceasta este probabilitatea ca algoritmul
să răspundă ``da''. Opusul ei este probabilitatea să răspundă ``nu''.

O tehnică foarte simplă de amplificare poate creşte nedefinit această probabilitate: dacă
executăm algoritmul de 2 ori pe aceleaşi date de intrare, probabilitatea de a greşi pentru răspunsuri
``nu'' rămîne 0. Pe de altă parte, ajunge ca algoritmul să răspundă măcar odată ``da'' pentru a şti că
răspunsul este ``da'' cu siguranţă! Din cauza asta, dacă probabilitatea de eroare este p pentru algoritm,
executînd de k ori probabilitatea coboară la p k (nu uitaţi ca p este subunitar, ba chiar sub 1/2). Această
metodă se numeşte ``boost'' în engleză, şi face dintr-un algoritm probabilist slab ca discriminare o sculă
extrem de puternică!

Pentru a scădea probabilitatea de eroare a unui algoritm care poate greşi cu probabilitatea p
pînă sub o limită dorită siguranta, se procedează astfel:

raspuns, probabilitate = nu, 1


do (raspuns = nu) and (probabilitate > siguranta) ->
raspuns, probabilitate := executa(algoritm), probabilitate * p
od

Iată un exemplu şi o aplicaţie al algoritmilor aproximativi.

Rădăcinile unui polinom

Fie un polinom de mai multe variabile, x1, x2, ... xn. Acest polinom poate fi descris printr-o
formulă aritmetică, de pildă: (x1 + 1) (x2 + 1) ... (xn + 1). Întrebarea este: este acest polinom identic nul
sau nu?

Desigur, o posibilitate este de a ``expanda'' acest polinom în formă canonică (sumă de


produse), şi de a compara fiecare coeficient cu 0. Dar în general această operaţie poate lua un timp
exponenţial! (De exemplu polinomul anterior generează 2n termeni!).

65
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Soluţia este să ne bazăm pe două proprietăţi elementare ale polinoamelor:

 Un polinom identic nul este 0 pentru orice combinaţie de valori a variabilelor;


 Un polinom ne-nul are ``puţine'' rădăcini într-un corp6.

De aici rezultă că:

 Dacă polinomul este nul, atunci evaluarea lui în orice punct va da 0;


 Dacă polinomul este ne-nul, atunci probabilitatea de a obţine valoarea 0 într-un punct (v 1, v2, ... vn) ales
arbitrar din Sn este < d/|S|.

Pentru polinomul de mai sus gradul este n, şi putem alege pentru K de exemplu Z p, unde p este
un număr prim relativ mare în raport cu n (de două ori mai mare ajunge!).

Alegînd arbitrar numerele v1, v2, ..., vn în Zp şi evaluînd q(v1, v2, ..., vn) mod p, putem imediat
afirma cu probabilitate mare > 1 - n/p despre q dacă este nul sau nu! Observaţi că evaluarea
polinomului nu este prea costisitoare, putîndu-se face în timp polinomial în lungimea expresiei care
descrie polinomul.

Folosind metoda de ``boost'' putem creşte rapid siguranţa noastră despre rezultatul algoritmului.

Izomorfismul arborilor

Iată şi o aplicaţie imediată a acestei proprietăţi.

Se dau doi arbori, cu rădăcina precizată. Sunt aceşti doi arbori ``izomorfi'' (identici prin re-ordonarea
fiilor)? Această problemă este surprinzător de dificilă pentru un algoritm determinist (am impresia
chiar că este NP-completă). Iată însă o soluţie aproape imediată: construim pentru fiecare arbore cîte un
polinom care nu depinde de ordinea fiilor unui nod, în aşa fel încît dacă şi numai dacă arborii sunt
izomorfi polinoamele sunt egale. Apoi pur şi simplu testăm ca mai sus dacă polinomul diferenţă este
nul.

O metodă de a asocia recursiv un polinom unui arbore este de pildă următoarea: fiecărui nod îi
asociem o variabilă xk, unde k este înălţimea nodului (distanţa pînă la cea mai depărtată frunză).
Frunzele vor avea toate asociate variabila x 0. Apoi asociem nodului v de înălţime k cu fii v 1, ... vl
polinomul fv = (xk - fv1) (xk - fv2) ... (xk - fvl). Se arată uşor că polinoamele sunt egale pentru arbori
izomorfi, bazîndu-ne pe unicitatea descompunerii în factori a unui polinom. Gradul polinomului asociat
unui nod este egal cu suma gradelor fiilor, care la rîndul ei este egală cu numărul de frunze care se află
sub acel nod (cum se demonstrează imediat prin inducţie după înălţime). Şi asta-i tot!

Pentru a încheia secţiunea, să observăm că singurul algoritm eficient cunoscut pentru a


verifica primalitatea unui număr este tot probabilist7! Pentru că numerele prime mari stau la baza
criptografiei cu cheie publică în sistemul RSA (probabil cel mai răspîndit la ora actuală), iată că unele
dintre cele mai importante aplicaţii se bazează indirect pe algoritmi probabilişti. Nimeni nu va putea
obiecta asupra utilităţii lor!

Algoritmi on-line

Adesea trebuie luate decizii cu informaţii incomplete. Un caz particular este luarea de decizii
pe măsură ce datele devin disponibile. Deciziile afectează viitorul, dar sunt luate fără a avea cunoştinţe
despre datele viitoare. Sa vedem în acţiune un exemplu foarte simplu:

66
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Problema schiorului

Se pune problema: ce este mai bine: să închiriezi sau să cumperi schiuri? (Vom presupune că preţul
schiurilor este constant de-a lungul timpului, ca să simplificăm problema). Dilema constă din faptul că
în fiecare sezon, nu ştii dacă te vei mai duce odată. Dacă le cumperi şi nu te mai duci, ai dat banii
degeaba. Dacă le tot închiriezi şi te duci des, s-ar putea să le plăteşti de mai multe ori. Totuşi, trebuie să
iei o decizie. Pe care?

Există un răspuns foarte simplu, care promite nu că dă rezultatul cel mai ieftin în orice circumstanţă, ci
doar că nu vei cheltui de două ori mai mult decît în cazul în care ai face decizia perfectă (decizia
perfectă este cea care ştie precis dacă te vei mai duce, şi de cîte ori; ea nu este accesibilă decît ``post-
factum'', deci este pur teoretică).

Algoritmul este: închiriezi schiuri pînă ai dat pe chirie costul schiurilor. După aceea dacă mai vrei să
mergi le cumperi. Voi demonstra rapid că în felul ăsta orice s-ar întîmpla nu pierzi mai mult de jumate
din banii pe care i-ai fi cheltuit în cazul ideal.

Avem 3 posibilităţi:

1. Te opreşti înainte de a le cumpăra: în cazul ăsta ai jucat perfect, pentru că ai schiat şi nu puteai ieşi mai
ieftin nicicum;
2. Te opreşti imediat după ce le-ai cumpărat. În cazul ăsta ai dat de două ori preţul (odată pe închirieri, şi
odată pe cumpărare), dar ai schiat cît ai fi putut schia dînd numai odată preţul (mai ieftin de odată nu
puteai ieşi);
3. Te opreşti mai tîrziu: în cazul ăsta cel mai ieftin era tot să le cumperi din prima zi, deci iar ai cheltuit
dublu.

Orice altă schemă foloseşti pentru a decide cumpărarea, există un scenariu în care poţi cheltui mai mult
de dublu faţă de optim.

Algoritmii on-line apar foarte natural într-o mulţime de situaţii: de exemplu în reţele de calculatoare,
algoritmii care decid traseul unui pachet cu informaţii sunt algoritmi on-line; dacă decid trasee proaste,
reţeaua poate deveni supra-aglomerată în viitor; astfel de algoritmi nu au idee despre cererile viitoare,
aşa că acţionează cu informaţie incompletă.

Un alt exemplu este în sistemele de operare: algoritmii după care cache-urile (sau sistemele de
memorie virtuală) aleg paginile care trebuie înlocuite. Alegerea aceasta nu poate fi optimă în absenţa
informaţiilor despre viitoarele cereri. Cu toate acestea, anumite alegeri sunt mai bune decît altele.

Un al treilea exemplu, tot din contextul sistemelor de operare, este al algoritmilor de planificare, care
trebuie să stabilească în ce moment se execută fiecare proces pe un calculator (paralel). Acolo unde
minutul de rulare costă o grămadă de bani, deciziile trebuie să risipească cît mai puţin timp. Însă job-uri
pentru prelucrare sosesc dinamic, aşa că algoritmii trebuie să facă faţă unui mediu în continuă
schimbare.

Algoritmii on-line sunt în general analizaţi comparîndu-i cu algoritmii off-line, care ar avea înainte de a
face deciziile informaţii perfecte despre toate cererile viitoare. Este clar că informaţia aceasta este un
mare avantaj, aşa că în general algoritmii on-line au performanţe mult mai proaste decît cei
corespunzători off-line.

Cercetările în acest domeniu sunt doar la început; se explorează şi variante de algoritmi hibrizi on/off-line, în care
algoritmul are o idee despre viitor, dar nu neapărat o vedere completă.

67
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

3.5 Agoritmi elementari


3.5.1 Probleme care opereaza asupra cifrelor unui numar

1)Se citeşte un număr natural n. Să se calculeze suma cifrelor sale.


Exemplu: pentru n = 213, se va tipări 6 (2 + 1 + 3).
Pentru calculul acestei sume, trebuie să găsim o modalitate de a separa cifrele unui număr. Între
operatorii care se pot aplica numerelor naturale sunt doi care ne folosesc în acest caz. Aceştia sunt operatorii DIV
şi MOD. Aplicând operatorul DIV pentru două numere naturale a şi b sub forma a DIV b obţinem câtul întreg al
împărţirii lui a la b.
Exemplu: 24 DIV 5 = 4.
Prin aplicarea operatorului MOD la două numere naturale a şi b (a MOD b) obţinem restul împărţirii lui a
la b.
Exemplu: 24 MOD b 7 = 3.
Dacă vom considera un număr natural n, n MOD 10 va da restul împărţirii la 10 a numărului, deci ultima
cifră a sa, iar n DIV 10 va avea ca rezultat câtul împărţirii la 10 a numărului (acesta nu este altceva decât numărul
format prin suprimarea ultimei cifre a numărului n).
Presupunem că am citit numărul 425. Procedăm astfel:
 iniţializăm suma (s = 0);
 calculăm ultima cifră a numărului 425 MOD 10 = 5 şi o adunăm la s (s =5);
 reţinem numărul fără ultima cifră (425 DIV 10 = 42);
 pentru numărul nou format reţinem ultima cifră şi o adunăm la s (4 MOD 10 = 4, s := 7 + 4 = 11);
 reţinem numărul fără ultima cifră (4 DIV 10 = 0).
Întru-cât numărul a devenit 0, algoritmul se încheie prin tipărirea lui s (s = 11).
Algoritmul scris în pseudocod:
INTEGER n, s;
READ n
S := 0;
WHILE n < > 0

s := s + n MOD 10
n := n DIV 10
START
REPEAT
WRITE s;
STOP. Cit. s

S := 0

DA NU
Tip. S

S := S + n MOD 10
STOP

N := N DIV 10
Cit. n

2) Se citeşte n un număr natural. Să se tipărească numărul obţinut prin


inversarea cifrelor lui n.
Exemplu: n := 412. Se va tipări 214.

68
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

În problema anterioară am văzut cum putem izola cifrele unui număr. De menţionat că algoritmul
propus anterior izola cifrele numărului n în ordine inversă.
Exemplu: pentru numărul 162 se izolau pe rând cifrele 2, 6, şi 1. Pe de altă parte, dacă cunoaştem cifrele
unui număr putem calcula numărul respectiv.
Exemplu: din cifrele 2, 6 şi 1 putem obţine numărul 261. Aici nu este vorba de alăturarea cifrelor, cum
am fi tentaţi să credem, ci de calculul numărului sub forma:
2 * 102 + 6 * 101 + 1 * 100,
aşa cum cunoaştem din teoria bazelor de numeraţie. Cum procedăm pentru rezolvarea acestei probleme?
Considerăm o variabilă (notată ninv., care iniţial va avea valoarea 0). Pentru fiecare cifră noua valoare a lui niv va
fi vechea valoare înmulţită cu 10 la care se va adăuga cifra:
niv : = 0 * 10 + 2;
niv : = 2 * 10 + 6;
niv : = 26 * 10 + 1 = 261.
În concluzie, izolăm pe rând cifrele în ordine inversă (aşa cum am arătat în problema anterioară) şi cu
fiecare nouă cifră construim numărul cerut.
În pseudocod, algoritmul arată astfel:
Integer n, ninv;
READ n
ninv := 0;
WHILE n < > 0
ninv := ninv * 10 + n MOD 10;
n .= n DIV 10
REPEAT
WRITE ninv
STOP.

START

Cit. N

NINV := 0

NU
N0 Tip. NINV

DA
STOP
NINV := NINV * 10 + N MOD 10

3.5.3 Probleme CU NUMERE PRIME


1)Se citeşte n număr natural. Să se precizeze dacă este prim sau nu.
Să presupunem că dorim să verificăm dacă numărul 1000 este prim. Primul divizor posibil (2) divide
acest număr. Cu toate acestea, în loc să se afişeze rezultatul imediat, se verifică şi ceilalţi divizori posibili. Trebuie
găsită o modalitate prin care, la găsirea unui divizor, să se tipărească faptul că numărul nu este prim. Prezentăm
acest nou algoritm:
INTEGER n, i
READ n

69
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

i := 2
WHILE (i < n) AND (n MOD i < > 0)
i := i +1
REPEAT
IF i := n THEN WRITE ’numarul este prim’
ELSE WRITE ’numarul nu este prim’
ENDIF
STOP.

2) Să se scrie un algoritm care tipăreşte primele numere prime (numărul se citeşte).


În problema anterioeră am văzut cum putem stabili dacă un număr este prim. Acum, se pune problea să
asigurăm un contor în care să se caute numerele prime printre numerele 1, 2, ş. a. m. d., până se tipăresc numerele
cerute.
În pseudocod, algoritmul arată asrfel:
INTEGER n, i, j, nr
BOOLEAN prim;

READ nr
N := 1
J := 0;
DO
prim := true
FOR i := 2, ∂ 
IF n MOD i = 0 THEN prim := false
ENDIF
REPEAT
IF prim THEN
WRITE n
j := j + 1
ENDIF
n := n + 1
UNTIL j = nr
STOP.

3) Se citeşte n, număr natural, să se descompună în factori primi.


Algoritmul constă în următoarele:
 se citeşte n;
 se iniţializează ptrimul diviyor (i = 2);
 secvenţa următoare se repetă până când n = 1;
 se iniţializează fm cu 0 (factor de multiplicitate, arată puterea la care se găseşte factorul prim);
 atâta timp cât i îl divide pe n, se execută următoarele:
- se măreşte cu 12 factorul de multiplicitate;

70
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

- se împarte n la I;
 dacă fm este diferit de 0 (deci s-a găsit divizor al lui n) se tipăresc I şi fm;
 se adun 1 la i (se incrementează).
Să presupunem că am citit n = 12. Algoritmul decurge astfel:
 se iniţializează I cu 2;
 se iniţializează fm cu 0;
 întrucât 2 divide pe 12, fm va lua valoarea 1 iar n valoarea 6;
 întrucât 2 divide pe 6, fm va lua valoarea 2 şi n valoarea 3;
 n nu divide pe 3, deci se trece mai departe;
 fm este diferit de 0, se tipăreşte 2 la puterea 2;
 se măreşte i cu 1;
 n nu este 1, deci secvenţa se reia;
 fm va lua valoarea 0;
 3 divide pe 3 (i divide pe n) deci fm va lua valoarea 1 şi n va deveni 1;
 3 nu divide 1, deci se trece mai departe;
 fm este diferit de 0, deci se tiopăreşte 3 la pueterea 1;
 i devine 4;
 n este 1 şi algoritmul se încheie.
În continuare se prezintă schema logică şi algoritmul realizat în pseudocod:
INTEGER n, i, fm;
READ n
i := 2;
DO
fm := 0;
WHILE n MOD i = 0
fm := fm + 1;
n := n DIV i
REPEAT
IF fm < > 0 THEN
WRITE I, ’la puterea’ fm
ENDIF
i := i + 1
UNTIL n = 1
STOP.

3.5.5 Calculul unor sume cu termen general dat


1)Pentru n citit ( n natural mai mare sau egal cu 1) să se calculeze suma
S = 1 +1 * 2 + 1 * 2 * 3 + . . . + 1 * 2 * . . . * n.
Pentru rezolvare, observăm că putem adăuga o sumă s (care are iniţial valoarea 0) pe rând
valorile calculate 1, 1 * 2 *, . . ., 1 * 2 * . . . n (adică n valori). Aceasta nu înseamnă că trebuie calculată de
fiecare dată valoarea 1 * 2 * . . . i. Dacă calculat 1v2 * . . . . * I, valoarea următoare care trebuie adăugată
este 1 * 2 * . . . i * (i +1) şi se poate obţine înmulţind valoarea calculată cu i + 1.

71
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Pentru calculul acestor valori se utilizează se utilizează variabila p. din cele arătate rezultă
schema logică de mai jos:

START

Cit. n

S := 0

P := 1

i := 1

P := p * i

S := s + p

i := i + 1

DA NU
I<N Tip. S STOP

În pseudocod, algoritmul propus arată astfel:

INTEGER n, i, s, p;
READ n
s := 0
p := 1
FOR i := 1, n
p := * i
s := s + p
REPEAT

WRITE s
STOP.
2) Se consideră şirul de numere naturale:
1, 4, 7, 10, 13, . . .
Să se calculeze suma primelor n termeni, cu n dat de la tastatură

72
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Program Problema_1;

Var s, suma : Word; { s reprezintă termenul curent al şirului }


n, i : integer;
Begin
Suma := 1;
s :=1;
write (’n =’); readln (n);
for i := 1 to n –1 do
begin
s := s + 3;
suma := suma + s;
end;
writeln (’Suma este: ’, Suma)
End.

2. Se consideră şirul: 2, 7, 12, 17, . . .


cu n termeni (n > 1). Să se calculeze suma termenilor pari.
Program Problema _2;
Var s, suma : Word; { s reprezintă termenul curent al şirului }
n, i : Integer;
Begin
Suma : 2;
s :=2;
write (’n =’);
readln (n);
for i := 1 to n –1 do
begin
s := s + 5;
if not odd (s) {verificarea parităţii termenului curent }
then Suma := Suma + s;
end;
writeln (’Suma este: ’, suma)
End.
4. Limbaje de programare

4.1. Concepte generale


Despre limbajul Pascal
Limbajul Pascal apărut la începutul anilor ’70 şi a fost elaborat de către
matematicianul Niklaus Wirth. Iniţial, limbajul a fost conceput pentru predarea
sistematică a disciplinei de programare a calculatoarelor, deci ca limbaj de tip
pseudocod. Cu timpul, limbajul a început să fie folosit şi în activitatea practică de
programare a calculatoarelor. La ora actuală, există mai multe implementări ale
limbajului Pascal Standard, dintre care una dintre cele mai utilizate aparţine firmei
americane Borland, variantă denumită Turbo Pascal. Această implementare include
toate elementele limbajului Pascal standard, dar oferă şi facilităţi suplimentare.

4.2. Sintaxa unui limbaj de programare


Descrierea sintaxei cu ajutorul diagramelor de sintaxă
Orice limbaj de programare se caracterizează prin sintaxă şi semantică.
Sintaxa limbajului este dată de totalitatea regulilor de scriere corectă(însensul
acceptării sale de programul traducător(compilator) care are rolul de a converti
programul în cod maşină pentru a fi executat). Dar un program corect din punct de
vedere sintactic nu este neapărat un program bun. Certitudinea sintactică este numai

73
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

o cerinţă a programelor, tot aşa cum pentru a fi campion mondial la alergări este
necesar să nu ai picioarele amputate. Cel mai greu este ca programul să execute
întocmai ce şi-a propus cel ce l-a realizat. Prin semantica unui limbaj se înţelege ce
anume realizează fiecare instrucţiune a sa.
Sintaxa este formalizată perfect din punct de vedere matematic dar nu acelaşi
lucru se întâmplă şi cu semantica. Sintaxa poate fi descrisă cu ajutorul diagramelor de
sintaxă. Aceasta nu reprezintă singura formă de descriere a sintaxei unui limbaj(mai
există de exemplu, forma BNF), dar se remarcă prin faptul că sunt sugestive. În ce
constă o descriere cu ajutorul diagramelor de sintaxă? Să presupunem că dorim să
descriem riguros cum arată un număr în baza 16. dacă folosim o descriere în genul un
număr în baza 16 are în componenţa sa cifre şi litere, cifrele pot fi de la 0 la 9 iar
literele a,b,c,d,e,f,A,B,C,D,E,F şi dăm câteve exemple, nu suntem suficient de riguroşi.
Imediat pot apărea întrebări de genul: A reprezintă un număr în baza 16? Mai mult
dacă dorim să facem un program care să recunoască dacă un număr citit este sau nu
în bază 16, situaţia se complică.
Se observă că o astfel de schemă are un nume(în cazul nostru cifra
hexazecimală). Pentru a putea obţine o cifră trebuie să urmez un drum prin acest
desen(în matematică se numeşte graf orientat), de la intrare(din dreptul numelui) până
la ieşire, urmând sensul săgeţilor. Problema se poate pune şi invers: fiind dat un
caracter oarecare să se precizeze dacă este sau nu cifră. Caracterul este cifră dacă
în diagrama prezentată există un drum care trece printr-un cerculeţ ce reprezintă
caracterul. Acum am definit riguros cifraÎn noua diagramă apare un dreptunghi în care
este scris cuvântul cifră. Dreptunghiul se utilizează atunci când se foloseşte o noţiune
ce a fost definită printr-o diagramă de sintaxă. Orice drum folosit în acest desen(de la
intrare la ieţire) obţinem sau o cifră sau una din literele care pot face parte din
structura unui număr hexa:

În esenţă, într-o diagramă de sintaxă putem întâlni următoarele simboluri grafice:


 cercuri – încadrează anumite simboluri speciale;
 elipse – încadrează cuvinte rezervate(nu pot fi folosite în alt context);
 dreptunghiuri – încadrează elemente definite prin alte diagrame de
sintaxă.
 Săgeţi – indică sensul de parcurgere a diagramei.
Orice drum de la intrare la ieşire din diagramă reprezintă o construcţie sintactică
corectă.
Ne-am putea întreba care este motivul unei descrieri atât de riguroase? Un
program scris într-un limbaj de programare trebuie tradus de programul numit
compilator în cod maşină. În primul rând programul trebuie să fie corect din punct de
vedere sintactic(altfel nu poate fi tradus). Verificarea corectitudinii nu este un lucru
simplu (există foarte multe forme de programe). Din acest motiv, verificarea se face
după reguli care trebuie descrise foarte clar, iar această descriere este realizată de
diagramele de sintaxă.
4.2 Elemente de bază ale limbajului Pascal
4.2.1 Vocabularul limbajului
Vocabularul oricărui limbaj este format din:
 setul de caractere;
 identificatori;
 separatori;
 comentarii.

74
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Setul de caractere Reprezintă ansamblul de caractere cu ajutorul cărora se


poate realiza un program Pascal. Acesta este alcătuit din:
 litere mari şi mici ale alfabetului englez(A=Z,a-y);
 cifrele sistemului de numeraţie zecimal(0-9);
 caractere speciale: +,-,*,/,=,^,<,>,(,),[,],{,},., ,,:,;,#,$,@,_, şi blank(spaţiu).
4.2.2 Identificatori
Un identificator este o succesiune de litere sau cifre sau caracterul special’_’ din
care primul caracter nu poate fi cifră. Cu ajutorul identificaorilor se asociază nume
constantelor, variabilelor, procedurilor etc.
Exemple de identificatori: a1, tasta, un_numar.
Exemple eronate: 4ar, mt& (primul începe cu o literă , al doilea conţine un
caracter nepermis). O categorie specială de identificatori este dată de cuvintele cheie
ale limbajului(au un înţeles bine definit şi nu pot fi folosite în alte context).
Acestea sunt:
AND,ARRAY,BEGIN,CASE,CONST,DIV,DO,DOWNTO,ELSE,END,FILE,FOR,FUNCT
ION,GOTO,IF,IN,LABEL,MOD,NILL,NOT,PROCEDURE,PROGRAM,RECORD,REPE
AT,SET,OF,OR,ORIGIN,OTHERWISE,PACKED,THEN,TO,TYPE,UNTIL,
VAR,WHILE,WITH.

Citiri, scrieri
Să analizăm programul de mai jos, care citeşte un număr întreg(pe care noi îl
introducem de la tastatură) şi îl tipăreşte:
program c1;
var a:integer;
begin
read(a);write(a)
end.
În cazul în care introducem numărul 10, calculatorul va tipării 10, dacă
introducem 16, calculatorul va tipării 16 ş.a.m.d.
Citirea datelor se face cu ajutorul procedurii READ şi READLN. În acest
paragraf sunt prezentate aceste proceduri într-o formă mult simplificată. Pentru
amănunte, vezi fişier text. Procedura READ are forma READ(var), unde var are
semnificaţia de variabilă(variabile de tip boolean şi enumerare nu se citesc). Se citeşte
de la tastatură o dată care se depune în variabila var. Procedura READLN se
foloseşte exact ca READ, cu deosebirea că, după citire, cursorul sare pe linia
următoare a ecranului.
Scrierea datelor se face cu ajutorul procedurii WRITE şi WRITELN. În ambele
cazuri se scrie începând cu poziţia curentă a cursorului pe ecran. Diferenţa între
WRITE şi WRITELN este aceea că, după scriere, prin utilizarea procedurii WRITE
cursorul rămâne după ultimul caracter scris, iar prin utilizarea procedurii WRITELN el
sare pe prima poziţie a liniei următoare.
Exemple:
WRITE (a), unde a este o variabilă care conţine numărul 3 - scrie 3 începând din
poziţia curentă a cursorului.
WRITE (a,b), unde a şi b sunt variabile întregi care au conţinuturile 2, respectiv 3
- va avea ca efect scrierea numărului 2 urmat de numărul 3 (apare 23).
WRITE (‘a=’,a) - are ca rezultat scrierea şirului de caractere ‘a=’urmat de data
reţinută de variabila întreagă a.
Presupunem că b este o variabilă reală (care reţine numere reale) şi conţine
numărul 3.25 WRITELN (b:4:2) va determina apariţia pe monitor a numărului 3.25.

75
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Cifra 4 are semnificaţia de număr total de poziţii pe care să se scrie numărul real, iar
cifra 2 numărul de poziţii pe care să se scrie partea zecimală (în absenţa acestor
parametri, data reală se va scrie într-o formă greu inteligibilă).În situaţia in care partea
întreagă a datei reale nu încape în formatul prestabilit, nu se mai ţine cont de acest
format.
O utilizare specială o au instrucţiunile readln şi writeln fără parametri. Să
analizăm programul de mai jos.Acesta tipăreşte numărul 6 (se poate tipări un număr în
acest mod). Observăm că programul se termină cu instrucţiunea readln. Ce rol are ea?
După ce un program îşi încheie execuţia, se revine în mod automat în mediul în care
se găseşte textul sursă. Rezultatele se pot vizualiza tastând ALT + F5. Pentru ca
revenirea să nu se facă automat (să avem timp să vedem rezultatul), vom utiliza
instrucţiunea readln fără parametri. Efectul? Se va aştepta să se tasteze Enter. În
acest timp, avem posibilitatea să vedem ce s-a tipărit.
program c2
begin
writeln(6)
readln;
end.
Programul de mai jos tipăreşte numerele 6 şi 7. Între cele două numere există un
rând liber. De ce? Pentru că am utilizat writeln. Instrucţiunea writeln fără parametri are
rolul de a determina saltul cursorului pe rândul următor.
program c3;
begin
writeln(6);
writeln; {se sare un rând}
writeln (7)
end.
4.2.3 Constante
Constante
Constantele Pascal reprezintă valori care pot fi conţinute de un program scris în
acest limbaj (nu sunt citite de program). Ele folosesc în cadrul diverselor expresii
(numerice, logice, şiruri de caractere) sau pentru scrierea unor mesaje. Exemplu: În
program trebuie realizată atribuirea y:=2*x+1. În acest caz, 2 şi 1 sunt constante.

Constantele corespunzătoare tipurilor standard sunt:


constante întregi;
-constante reale;
constante şir de caractere;
constante simbolice.
Diagrama de sintaxă care descrie noţiunea de constantă este:

Constantă întreagă

Constantă reală
Constantă
Sir caractere
Constantă simbolică

76
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Constante întregi. Sunt alcătuite dintr-o submulţime a numerelor întregi care pot
fi reprezentate în memoria calculatorului.
Observaţie: Nu se pot reprezenta în calculator numere oricât de mari sau oricât
de mici (orice număr ocupă un spaţiu în memoria internă a calculatorului). Prin
utilizarea limbajului Turbo Pascal se pot reprezenta numere întregi cuprinse în
intervalul [-2.147.483.648, 2.147.483.647].
Numerele se pot reprezenta în baza 10 sau în baza 16 (mai rar utilizată). Pentru
baza 16, numărul este precedat de caracterul special ‘$’.
Exemple: 32, -164, +131, $a1.
Cifră
Constantă
întreagă
Cifră
hexazecimală

Constante reale. Sunt alcătuite dintr-o submulţime a numerelor reale (mai precis
a numerelor raţionale) care pot fi reprezentate în calculator. Numerele se găsesc în
intervalul [3.4*10-4932, 1,1*104932]. În locul virgulei se foloseşte punctul Exemple: 2.34, -
45.26, 512E+23, -45.1E-3.
Ultimele două numere folosesc o scriere neîntâlnită în matematică. Ele
reprezintă numerele 512*10 23 şi -45.1*10-3.

Constantă
reală cifră cifră

cifră

Constante şir de caractere. După cum reiese şi din denumire, cu ajutorul lor se
reprezintă şiruri de caractere. Caracterele de şir pot fi specificate enumerându-le între
apostrofuri sau se pot preciza prin codul lor ASCII, precedat de caracterul #.
Exemplu: #1$2 sau, echivalent (în baza 16), #$1#$2
‘abc’
‘abc’#10#13

caracter
Sir
caracter
e Constantă
întreagă

77
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Constante simbolice. Acestea sunt constante care au n program un anumit


nume. Numele dat acestor constante poate fi standard (de exemplu: false, true,
maxint) sau dat de utilizator atunci când defineşte constantele.
Definirea constantelor simbolice precede definirea tupurilor utilizator şi se
realizează astfel

const
identificator = expresie;
identificator = expresie;

Observaţie. Expresiile care intervin în definirea constantelor trebuie să poată fi


evaluate la momentul compilării programului.

Exemplu.
const NrMaxValori = 30;
Dim = NrMax Valori*2-1;
Mesaj = ‘Nu exista solutie’#10#13'
PI = 3.14;

Prin utilizarea constantelor simbolice, programatorul are posibilitatea de a asocia


nume sugestive unor valori, ceea ce măreşte considerabil lizibiltatea programului. În
plus, în cazul în care o astfel de valoare trebuie modificată (de exemplu: în cazul în
care beneficiarului programului îşi schimbă cerinţele), actualizarea programului se
reduce doar la modificarea valorii din declaraţia constantei simbolice şi nu presupune
înlocuirea vechii valori din întreg programul.

4.2.4 Tipuri de date


Tipuri de date, tipuri standard

În paragraful anterior am văzut faptul că o variabilă poate reţine date de un anumit tip. De
exemplu, anumite variabile pot reţine numere întregi, altele numere reale (la informatică asta
înseamnă numere cu zecimale). Se pune întrebarea: cum are programatorul posibilitatea să
stabilească natura datelor care pot fi memorate de variabile? Mecanismul este următorul: atunci
când se declară o variabilă se precizează tipul ei.
Prin tip de date se înţelege:
mulţime de valori;
regulă de codificare a lor (modul în care se reprezintă în memorie);
mulţime de operaţii definite pe mulţimea valorilor.
Spunem că variabilele au un tip standard dacă acesta este recunoscut de către compilator, fără a
fi definiti în prealabil de programator. Vom vedea ulterior că există posibilitatea ca programatorul
să-şi definească propriile tipuri, pentru ca apoi să declare variabile de tipul definit de el. Limbajul
Turbo Pascal conţine următoarele tipuri de standard:
1. tipuri întregi;
2. tipul caracter;
3. tipul logic;
4. tipuri reale.
Acestea vor fi studiate în continuare.

Tipuri întregi

Tipul shortint.
Mulţimea valorilor este dată de numerele întregi cuprinse între -128, 127. Pentru memorare, se
foloseşte un singur octet, iar un număr se memorează în cod complementar. Operaţiile sunt cele
de la tipul integer. Datele sunt memorate în cod complementar.

78
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Tipul integer.
Mulţimea valorilor este dată de numerele întregi cuprinse între - 32768, 32767. Pentru memorare,
se folosesc doi octeţi, iar un număr se memorează în cod complementar. Datele sunt memorate
în cod complementar.
Tipul longint (întreg lung).
Mulţimea valorilor este dată de numerele întregi cuprinse între -2l47483648 şi 2147483647.
Pentru memorare, se folosesc 4 octeţi iar un număr se memorează în cod complementar. Datele
sunt memorate în cod complementar.
Tipul byte.
Mulţimea valorilor este dată de numerele naturale cuprinse între 0 şi 255. Pentru memorare, se
foloseşte un octet, iar un număr se memorează în binar. Datele sunt memorate în binar.
Tipul word.
Mulţimea valorilor este dată de numerele naturale cuprinse între 0 şi 65535. Pentru memorare se
folosesc doi octeţi, iar un număr se memorează în binar. Datele sunt memorate în binar.
Declararea variabilelor de unul din tipurile întregi se face ca mai jos:
var a,b:integer;
c:word;
d,e,f:longint;
Variabilelor (operanzilor) de tip întreg li se pot aplica mai mulţi operatori.
Operanzilor de tip întreg li se pot aplica şi operatorii pe biţi (lucrează asupra biţilor din
reprezentarea internă a numărului). Aceştia sunt tot cei logici, dar acţionează de această dată
altfel.
Operatorul NOT.
Acţionează asupra variabilelor în felul următor:
toţi biţii care reţin 1, vor reţine 0;
toţi biţii care reţin 0, vor reţine 1.
Exemplu: O variabilă de tip byte a reţine valoarea 11110000. După atribuirea a:=not a; variabila a
va reţine valoarea 00001111.
Operatorul SHL.
Este binar (are doi operanzi).
Are rolul de a deplasa la stânga conţinutul biţilor primului operand cu un număr de poziţii dat de
al doilea operand. Conţinutul primilor biţi se pierde, iar ultimii biţi vor reţine 0.
Exemplu. O bariabilă de tip byte a reţine valoarea 10000110. După operaţia a shl 2; se obţine
00011000.
Observaţie. În cazul în care primul bit este 0, prin deplasare la stânga cu o poziţie (a shl 1)
valoarea se înmulţeşte cu 2.
Exemplu. O variabilă de tip byte a reţine valoarea 00000110(2)=6(10). După operaţia a shl 1; se
obţine valoarea 00001100(2) = 12(10).
Operatorul SHR.
Este binar şi are rolul de a deplasa la dreapta conţinutul biţilor primului operand cu un număr de
poziţii dat de al doilea operand. Conţinutul primilor biţi se pierde, iar ultimii biţi vor rămâne 0.
Exemplu. O variabilă de tip byte a reţine valoarea 10000110. După operaţia a shr 2; variabila a va
reţine valoarea 00100001.
Observaţie. Prin deplasare la dreapta cu o poziţie (a shr 1) se efectuează împărţirea întreagă la 2
(a div 2).
Exemplu. O variabilă de tip byte a reţine valoarea 00000110(2)=6(10). După atribuirea a:-a shr 1;
variabila a va reţine valoarea 00000011(2)=3(10).
Tipul caracter.

Calculatoarele nu lucrează numai cu numere. Ele reţin şi caractere. Din ce este alcătuită
mulţimea caracterelor?
Mulţimea caracterelor conţine:
literele mari şi mici ale alfabetului (a,b,...z, A,B,...Z);
cifrele sistemului zecimal (0,1,2,..9);
caractere speciale (!,$,%,?,. şi altele);
alte caractere.
În Turbo Pascal un caracter se notează între apostrofuri.
Exemple:’a’, ‘A’, ‘1’ (caracterul ‘1’ nu trebuie confundat cu numărul 1).

79
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

O variabilă de tip caracter reţine, la un moment dat, un singur caracter. Declaraţia unei variabile
de tip caracter se face ca în exemplul următor în care se declară două variabile a şi b de acest
tip:
Var a, b: char; (char înseamnă caracter).
Se citeşte variabila ch (de tip caracter) care, apoi, se tipăreşte. De asemenea se tipăreşte şi
caracterul 7. Cele două caractere sunt separate de un alt caracter şi anume caracterul spaţiu (şi
acesta este un caracter).
program c;
var ch: char;
begin
write(‘ch=’); readln (ch);
writeln (ch,’ ‘.’7')
end.
Tipuri reale
Variabilele de un tip real reţin numere cu zecimale. Exemple de astfel de numere: 6, 82, 9, 3, -8, 6.
În locul virgulei, în informatică se foloseşte punctul. Astfel, numerele de mai sus, vor fi
notate:6.82, 9.3, -8.6.
În Turbo Pascal există mai multe tipuri reale. O variabilă de un tip real reţine datele codificate în
virgulă mobilă (vezi anexa 2).
Tipul REAL.
Se reţin numerele reale care aparţin domeniului:
[-1,7*1038,-2,9*10-29]  [2,9*10-29, 1,7*1038]

Pentru memorare sunt folosiţi 6 octeţi şi se reprezintă cu precizie 11-12 cifre.

Tipul SINGLE.
Se reţin numere reale care aparţin domeniului:
[-3,4*1038,-1,5*10-45]  [1.5*10-45, 3,4*1038]

Pentru memorare sunt folosiţi 4 octeţi şi se reprezintă cu precizie 7-8 cifre.


Tipul DOUBLE.
Se reţin numere reale care aparţin domeniului:
[-1,7*10308,-5*10-324]  [5*10-324, 1,7*10308]

Pentru memorare sunt folosiţi 8 octeţi şi se reprezintă cu precizie 15-16 cifre.


Tipul EXTENDED.
Se reţin numere reale care aparţin domeniului:
[-1,1*104932,-3,4*10-4932]  [3.4*10-4932, 1,1*104932]

Pentru memorare sunt folosiţi 10 octeţi si se reprezintă cu precizie 19-20 cifre.


Tipul COMP.
Se reţin numere reale care aparţin domeniului:
[-9,2*1018,9,2*1018].

Pentru memorare sunt folosiţi 8 octeţi şi se reprezintă cu precizie 19-20 cifre.


Exemple:
var a, b: real;
c:comp;
d, e, f: extended;
Observaţie. Turbo Pascal admite două modele de lucru cu numere reale. Pentru a utiliza tipurile
reale single, double, comp şi extended trebuie să utilizaţi modelul 80x87 floating point. Deoarece
acesta nu este implicit, pentru a specifica utilizarea acestui model selectaţi din meniul Options al
mediului Turbo Pascal opţiunea Compiler, apoi activaţi cu tasta spaţiu opţiunea 8087/80287.
Acelaşi efect îl obţineţi incluzând la începutul programului directiva de compilare {$N+}.
Operatorii care acţionează asupra operanzilor de tip real sunt cei cunoscuţi:+,-.(,/ (ultimul este
pentru împărţire). Vezi 6.4. Programul de mai jos care citeşte o variabilă reală şi o tipăreşte în
două moduri:
program r;
var v: real;

80
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin
write (‘v’); readln (v);
writeln (‘v=’,v);
writeln (‘v=’,v:3:2);
end.
Să presupunem că citim numărul 3.35 (3,35 cum suntem obişnuiţi). Programul va tipări prima
dată 3.35000000000E+00 iar a doua oară 3.35. De fapt, de fiecare dată se tipăreşte acelaşi număr
însă înscris în forme diferite. Prima formă se numeşte formă normalizată sau formă ştiinţifică.
Pentru a regăsi numărul se procedează astfel: se înmulţeşte numărul aflat înaintea literei E cu 10
la puterea care este dată de numărul care urmează lui E (3.350...0x100 = 3.35).
Totuşi ne-am putea întreba care este logica faptului că există această formă (la prima vedere
chiar stupidă)? Trebuie ţinut seama de faptul că, în general, numerele reale nu se pot reţine
întotdeauna cu precizie în calculator (chiar numerele aflate între două valori). De exemplu, nu pot
fi reţinute cu precizie nici măcar numerele aflate între 1 şi 2. De ce? Fie numărul
1.6272625729383973235...9. Are prea multe zecimale. Există numere cu şirul zecimalelor infinit.
Atunci cum poate fi memorat un astfel de număr?
Se reţine o aproximaţie a sa. Acum putem răspunde la întrebare: forma normalizată tipăreşte
numărul cu precizia cu care a putut fi reţinut de calculator. Acesta este motivul existenţei sale.
Renunţând la ea, vom comanda calculatorului precizia cu care va fi tipărită valoarea respectivă.
Cum? Se poate utiliza formatul nr.:lg: zec, unde nr este numărul real pe care îl tipărim, lg este
numărul total de poziţii pe care se va tipări valoarea respectivă, iar zec reprezintă numărul de
zecimale care vor fi tipărite.
În program, am solicitat ca numărul să fie tipărit pe 3 poziţii din care ultimile două să fie
zecimale. S-a tipărit 3.35. Aţi observat, probabil, că numărul a fost tipărit pe 4 poziţii (şi punctul
ocupă o poziţie). Apare o neconcordanţă între cele afirmate. De ce?
Calculatorul va proceda astfel: va tipări întotdeauna numărul de zecimale cerut. În cazul în care
nu mai există poziţii care să permită tipărirea numărului întreg (ca în exemplu) nu se ţine cont de
lg. În cazul în care numărul poziţiilor pe care va fi tipărit numărul este mai mare decât cel
necesar, numărul va fi tipărit cu un număr de spaţii în faţă. Testaţi!

Tipul logic
Variabilele de acest tip pot reţine numai două valori: TRUE (adevărat) şi FALSE (fals). Pentru
declaraţie se foloseşte cuvântul boolean.

Exemplu: var gasit:boolean;

Reţinem următorul amănunt: conţinutul variabilelor de acest tip poate fi tipărit, dar nu poate fi
citit.
Tipuri ordinale
Am arătat că un tip de date conţine,în primul rând, o mulţime de valori(date).
Spunem că un tip de date este ordinal dacă:
 datele pot fi ordonate (crescător);
 fiecare dată din şirul ordonat al valorilor are:
o un succesor – valoarea care îl urează în şir (excepţie face ultima
dată din şir);
o un predecesor – valoarea aflată imediat înainte în şirul ordonat
(excepţie face prima dată din şir).
Tipurile întregi sunt tipuri ordinale. Fie tipul integer ‚. Să considerăm o valoare a
sa, numărul 123. succesorul acestuia este numărul 124, iar predecesorul său este
numărul 122. Evident, pentru fiecare valoare din şir putem face un astfel de
raţionament. De asemenea, pentru fiecare tip întreg (byte,longint etc.) se poate face
un astfel de raţionament.

Tipul caracter(char) este un tip ordinal. Am învăţat modul în care se memorează


caracterele(pe un octet, fiecare caracter se reprezintă printr-un număr natural, scris în

81
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

baza 2, între 0 şi 255). Întrucât mulţimea numerelor cu ajutorul cărora se memorează


caracterele îndeplinesc condiţiile de mai sus, rezultă afirmaţia făcută. Exemplu. Fie
caracterul ’b’. Succesorul lui ’b’ este ’c’, iar predecesorul său este caracterul ’a’.
Tipul logic este un tip ordinal. Tipul logic are numai două valori true şi false. Este
adevărată relaţia: false<true. Prin urmare, succesorul valorii false este true, iar
predecesorul valorii true este false.
Tipurile reale nu sunt tipuri ordinale. Evident, mulţimea valorilor acestui tip poate
fi ordonată crescător. A doua condiţie nu este îndeplinită. Să vedem de ce. Să
considerăm o valoare oarecare(de exemplu, 0). Care este valoarea reală care
urmează şi este mai mare ? dacă veţi spune că această valoare este1, vă amintesc că
este vorba de valori reale (0<0.5<1). Atunci care? Orice valoare veţi găsi, vă arăt că
există întotdeauna alta care este mai mare ca 0 şi mai mică decât valoarea găsită de
voi. Fie valoarea 0,00001. atunci găsesc valoarea 0,000001, care este mai mică decât
0,00001 şi mai mare decât 0.
Pentru a obţine succesorul unei valori aparţinând unui tip ordinal se foloseşte
funcţia succ cu forma generală:
SUCC(valoare)
Pentru a obţine predecesorul unei valori aparţinând unui tip ordinal se foloseşte
funcţia pred cu forma generală:
PRED(valoare)
Analizaţi şi rulaţi programul de mai jos:
program ordinal1;
var a:integer;b:char;
begin
a:=0;
writeln(succ(a)); writeln(pred(a));
b:=’b’;
writeln(succ(b)); writeln(succ(a));
writeln(succ(false)); writeln(pred(true));
end.
O întrebare posibilă: care este succesorul celei mai mari valori din şir şi care este
predecesorul celei mai mici valori din şir? Răspunsul la această întrebare diferă în
funcţie de tipul ordinal şi chiar de varianta compilatorului.
De exemplu pentru tipul integer avem:
succ(32767)=-32768;
pred(-32768)= 32767.
Pentru tipul boolean avem:
succ(true)= true;
pred(false)=true.
Concluzia? În mod normal nu are sens problema pusă (oricum, este absurd să
căutăm succesorul celei mai mari valori din şir, la fel cum este absurd să căutăm
predecesorul celei mai mici valori). Din acest motiv, rezultatele prezentate nu sunt
coerente.
Funcţia ord returnează numărul asociat unei valori a unui tip ordinal oarecare şi
are forma generalăl:
ORD(valoare)
Ce înţelegem prin numărul asociat unei valori a unui tip ordinal? Răspunsul este
diferenţiat de la un tip ordinal la altul.
 pentru o valoare care aparţine unuia din tipurile întregi, funcţia ord
returnează chiar numărul. Astfel, ord(6)=6, rod(-5)=-5.

82
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

 pentru o valoare care aparţine tipului char, funcţia ord returnează codul
caracterului respectiv.
 În cazul tipului boolean funcţia ord returnează următoarele valori:
o 0, pentru false;
o 1, pentru true.
Convingeţi-vă de cele prezentate rulând programul de mai jos:
program ordin;
var a:integer;
b:char;
begin
a:= -13;b;= ’a’;
writeln(ord(a));writeln(ord(b));
writeln(ord(false));writeln(ord(true));
end.

Tipuri ordinale definite de utilizator


Utilizatorul are posibilitatea să definească două tipuri de date ordinale:
 tipul enumerare;
 tipul subdomeniu.
Pentru definirea unui tip propriu se foloseşte următoarea declaraţie:
type nume_tip=definitie tip
unde:
 prin nume_tip înţelegem numele tipului;
 definiţia tipului este specificată fiecărui tip în parte.
Declaraţia tipurilor este plasată după declaraţiile de constante simbolice(dacă
există)şi precede declaraţiile de variabile.
Tipul enumerare.
A fost prevazut în limbaj în ideea de a scrie programe clare(care să fie uşor
înţelese de o persoană care le analizează). Ce-i drept, se pot scrie toate genurile de
programe şi fără a-l folosi. toate genurile de programe şi fără a-l folosi.
Un tip ordinal, se se defineşte prin scrierea mulţimilor din care este alcătuit.
Numele valorilor pot fi formate din litere şi cifre, dar orice nume trebuie să înceapă cu
o literă.

În programul următor definim tipul timp. Acesta este format din 4 valori numite:
dimineaţa, prânz, seara şi noaptea. Tot aici, am declarat o variabilă de tip timp, căreia
i-am atribuit o valoare.
program ordinal3;
type timp= (dimineaţa, prânz, seara, noaptea);
var a:timp;
begin
a:= dimineaţa;
end.
Observaţii:
 Valorile unui tip enumerare nu se citesc şi nu se tipăresc.
 Ordinul primei valori din şir este 0, următoarea valoare din şir are ordinul
1, următoarea are ordinul 2 ş.a.m.d.
Tipul subdomeniu. Fiind dat un tip ordinal – numit tip părinte, putem construi un
alt tip ordinal numit tip subdomeniu al părintelui. Tipul subdomeniu conţine o

83
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

submulţime de valori consecutive(în şirul crescător al valorilor tipului părinte).


Precizarea valorilor tipului subdomeniu se face după formatul următor:
valoare1..valoare2
unde:
 valoarea1 reprezintă prima valoare din submulţime(cu ordinul cel mai
mic);
 valoarea2 reprezintă a doua valoare din submulţime(cu ordinul cel mai
mare);
În programul de mai jos am definit următoarele tipuri de subdomeniu:
 TreiValori – subdomeniu al tipului enumerare Valori (definit mai sus)
care conţine valorile a,b,c;
 CifreNenule – subdomeniu al unui tip întreg şi conţine numerele
naturale 1,2…9;
 Litere – subdomeniu al tipului char şi conţine caracterele ‘c’,’d’,…,’k’.
De asemenea , am declarat câteva variabile din fiecare tip şi i-am atribuit câte o
valoare a tipului respectiv.
program test;
type Valori =(a,b,c,d);
TreiValori= a..c;
CifreNenule =1..9;
Litere = ‘c’..’k’;
var x: TreiVAlori; z: CifreNenule; z: Litere;
i: integer;
begin
i:=9;y:= i;z:= ‘e’; x:= b
end.
Observaţie. În cazul unui tip subdomeniu, ordinul oricărei valori este acelaşi cu
ordinul în tipul părinte. Să analizăm programul de mai jos:
program test;
type Litere = (a,b,c,d);
Lit = b..d;
var l:Lit;
begin
1:= b;
writeln(ord(1));
end.

Tipul Lit este un tip subdomeniu al tipului Litere. Ordinul valorii b este 1(acesta
este ordinul ei din tipul Litere.       
4.2.5 Variabile
Variabile. Declararea variabilelor

In lectiile precedente am definit si vehiculat deja cu ideea de variabila.


Prin variabila se intelege o informatie (o data) a carei valoare se poate modifica
pe parcursul executiei unui program. Fiecarei variabile i se asociaza un identificator.
Multimea de valori pe care o poate lua acea variabila reprezinta tipul acelei variabile.
O variabila se declara astfel: var identif_var : identif_de_tip;.
Cand avem mai multe variabile de acelasi tip, putem scrie: var v_1, v_2, v_3:
tip;, iar cand avem si tipuri mai multe, vom scrie ceva de genul:

84
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

var v_1, v_2, v_3: tip_1;


w_1, w_2, w_3: tip_2;
...................

Diagrama de sintaxa este data mai jos.

VA identificator : tip ;
R
:

 Atentie! In limbajul Pascal trebuie sa se declare toate variabilele si inainte de a fi


folosite (in textul programului). Exista cazuri cand variabilele pot fi declarate in
unituri utilizate de un program, dupa cum veti invata mai tarziu, in clasa a-X-a.
Fiecarei variabile declarate in program i se aloca un spatiu de memorie,
dependent de tipul ei. Aceasta alocare se face odata cu compilarea programului.
Cand am vorbit despre tipuri de date standard simple am dat exemple de
declaratii de variabile.

 Atentie! Se pot defini si variabile initializate cu ajutorul lui const.


4.2.6 Operatori
Operatori – reguli de prioritate si evaluare
LIMBAJUL PASCAL

Prioritate Operator Evaluare


1 () s→d
2 not+-sizeof( ) d→s
3 */div mod s→d
4 +- s→d
5 < <= > >= s→d
6 = <> s→d
7 and (si logic) s→d
8 xor s→d
9 or (sau logic) s→d
10 :=(atribuire) s→d

4.2.7 Structura programelor


Structura programelor Pascal
Să vedem cum arată cel mai simplu program Pascal:
program usor;
begin
end.
Programul de mai sus este corect, cu toate acestea el nu face nici o operaţie. Dacă îl analizăm, putem
trage primele concluzii:
 Orice program Pascal începe cu cuvântul program, uramat de numele programului (nume pe care
l-am ales pentru a-l ’boteza’);
 Orice program Pascal conţine cuvintele begin şi end;
 După numele programului punem ’;’(caracterul punct şi virgulă);

85
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

 Orice program Pascal se termină cu ’.’ (caracterul punct).


În exemplul nostru, programul se numeşte uşor.
Observaţie 1. La scrierea unui program nu are importanţă dacă folosim litere mari sau mici. De
exemplu, programul de mai sus ar putea arăta şi astfel(deşi nu este o formă elegantă de prezentare):
PrograM uSoR;
BeGin
End.
Observaţie 2. Nu are importanţă nici plasarea cuvintelor pe linie, nici spaţiile dintre ele.
Programul de mai sus poate fi scris şi aşa:
pRogrAm usor;BeGin End.

Aceasta nu înseamnă că este bine să procedăm astfel. Să ne imaginăm că avem în faţă un program
mare scris aşa. El poate fi rulat, dar care programator va mai înţelege ceva, dacă îl priveşte?
Observaţie 3. Versiunea Borland a limbajului permite ca secvenţa program nume să lipsească. De
exemplu putem scrie şi aşa:
begin
end.
Dacă suntem ordonaţi nu procedăm astfel. Un program scris în Pascal (oricât de complex ar fi) are
structura următoare:
program nume;
 definiţii de constante;
 definiţii de tipuri;
 declaraţii de variabile;
 declaraţii de subprograme;
begin
 instrucţiuni
end.
Nu este obligatoriu ca într-un program să figureze toate acestea, dar dacă figurează, trebuie să apară în
această ordine.

4.2.8 Comentarii
Separatori şi comentarii. Cele mai simple elemente alcătuite din caractere cu
semnificaţie lingvistică poartă denumirea de unităţi lexicale. Acestea se repetă între
ele, după caz, prin unul sau mai multe blancuri, caracterul CR, sfârşit de linie sau
caracterul ’;’. Pentru ca un program să fie uşor de înţeles se folosesc comentariile.
Acestea se plasează oriunde în program. Un comentariu poate fi scris în două feluri:
 între acolade, exemplu: {un comentariu}
 între paranteze rotunde urmate de *, exemplu (*un comentariu*).

4.2.9 Expresii
Expresii

O expresie este fie o constanta, fie o variabila, fie un apel de functie, fie o combinatie
corecta (din punct de vedere sintactic) de expresii mai simple.
“Combinarea” se realizeaza cu ajutorul operatorilor. Elementele care se combina se
numesc operanzi. In general, se lucreaza cu expresii algebrice, in care regulile de formare sunt
aceleasi ca si in matematica, insa, dupa cum am mai spus, expresiile se scriu liniarizat. Pot
exista,de asemenea,si expresii nenumerice,cum ar fi de pilda:’Turbo’+’Pascal’,aici simbolul +
reprezentand alipirea (concatenarea) celor doua siruri de caractere.Rezultatul este sirul
‘TurboPascal’.

 Atentie! Expresiile sunt foarte importante in instructiunile de atribuire, despre care am


vorbit deja. Vom reveni asupra instructiunii de atribuire la inceputul urmatorului capirol.
In cadrul expresiilor algebrice, o mare importanta o au prioritatile operatorilor:

Prioritate Operator

86
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

1 (maxima) NOT, +, - (operatori unari)

2 AND, *, /, DIV, MOD, SHR, SHL (operatori multiplicativi)

3 OR, XOR, +, - (operatori aditivi)

4 (minima) =, <>, >, <, <=, >=, IN (operatori relationali)

 Atentie! In cazul in care am dori ca intr-o expresie sa schimbam ordinea de executie a


operatiilor, se pot folosi paranteze rotunde (nu si patrate sau acolade!).
Se pot folosi oricate perechi de paranteze rotunde.
Astfel, de exemplu se scrie 1/(2*a), si nu ½*a, pentru expresia care ar fi echivalenta cu
expresia 1/2/a.

 Atentie! O alta eroare ce poate surveni in scrierea unei expresii este urmatoarea: daca a, b
si c sunt valori intregi, de pilda, expresia (a>b) and (b<c) nu este echivalenta cu expresia a>b
and b<c, deoarece aceasta din urma este incorecta, fiindca mai intai se efectueaza operatia pe
biti: b and b si expresia isi pierde sensul!

In continuare prezentam diagramale de sintaxa pentru notiunea de expresie.

expresie
+

termen operator aditiv


-
termen

termen
factor operator multiplicativ

factor

Un factor este fie un numar fara semn, fie o constanta sau o variabila, fie un identificator
de functie avand ca argument o alta expresie (intre paranteze), fie un alt factor precedat de
operatorul unar NOT.
4.2.10 Atribuirea
Sintaxa instructiunii de atribuire
LIMBAJUL PASCAL
id_variabila:=valoare/expresie;
Precizare: Tipul variabilei trebuie sa coincida
cu tipul valorii/expresiei.

4.2.11 Citirea /scrierea datelor


Citirea si scrierea datelor

Ajutati de profesor, editati un prim program in mediul Turbo/Borland Pascal, care se porneste
prin comanda turbo sau bp. In construirea unui program, tineti cont de cerintele prezentate in Anexa 2.
Fisierul executabil este, cel mai adesea:C:\BP\BIN\turbo.exe sau C:\BP\BIN\bp.exe. lansarea in

87
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

executie a programului editat si corectat se face prin actionarea simultana a tastelor Ctrl si F9. De fapt,
capitolul 7 din manual prezinta modul de lucru cu mediul limbajului.
Programul nostru va calcula aria unui cerc in functie de lungimea razei cercului:

program CalculArie;

const pi=3.1415926;
var raza, aria: Real;
begin
raza:=2;
aria:=pi*Sqr(raza;
end.

El are doua parti: primele trei randuri reprezinta zona declaratiilor, iar instructiunile dintre
begin si end. zona actiunilor, adica partea operativa.
Daca pornim in executie acest program (in mediul Turbo Pascal), vom observa ca palpaie
putin ecranul, dar nu se intampla nimic. E si normal. Calculatorul a atribuit valoarea 2 variabilei raza.
A calculat aria (obtinand o anumita valoare) si gata. Noi nu am precizat prin nimic sa ni se comunice
rezultatul. De aceea va trebui sa folosim o procedura de extragere a datelor, de scriere a lor pe ecran.
Dar, chiar daca am dispune de o asemenea procedura, rezultatul programului ar fi acelasi la
orice executare a sa. De aceea, ar fi bine sa putem introduce de la tastatura raze de diferite valorui; deci
am avea nevoie de o procedura de citire a datelor. Aceste proceduri exista in limbajul Pascal:

a) Proceduri de citire a datelor (eu scriu – calculatorul citeste):

 ReadLn (v1, v2, . . . , vn) – citeste variabilele v1, . . . , vn, introduse de la tastatura. Variabilele
pot fi de orice tip invatat pana acum, mai putin Boolean sau un tip enumerare (sau un subdomeniu
al unui astfel de tip). Introducerea mai multor variabile se poate face daca acestea se separa prin
spatii sau <Enter>. La sfarsit trebuie apasata tasta <Enter>. Cursorul trece pe randul urmator.
Procedura ReadLn va citi si sfarsitul de linie (caracterul Enter).
 Read(v1, v2, . . . , vn) – la fel ca ReadLn, doar ca nu citeste sfarsitul de linie.

Atentie! Datele citite se depun, de fapt, intr-o zona tampon, inainte de a fi date variabilelor.
Aceasta zona tampon se goleste cand apare ReadLn. De aceea, un apel simplu ReadLn (fara
argumente) va avea drept efect golirea acestei zone tampon. Astfel, apelul ReadLn (x, y, . . . ) este
echivalent cu secventa Read (x, y, . . . ); ReadLn.
Daca variabilele ar fi avut alte valori inaintea apelului procedurii de citire, ele se pierd.
Valorile citite ale acestor variabile raman neschimbate pana la rpima atribuire sau (re)citire a lor.

b) Proceduri de scriere a datelor (calculatorul scrie – eu citesc):

 Write(e1,e2, . . .,en) – evalueaza si apoi afiseaza valorile expresiilor e1, e2, . . ., en. Expresiile
pot fi inclusiv de tipul Boolean, caz in care se afiseaza unul din cele doua cuvinte (False sau True),
dar nu pot fi de tip enumerare. Dupa afisarea valorilor unor expresii, acestea nu se pierd si nici nu
se schimba.
 WriteLn(e1,e2, . . .,en) – face acelasi lucru, dar la sfarsitul intregii afisari, muta cursorul pe
randul urmator. De exemplu, pentru a citi raza vom scrie: ReadLn(raza), iar, dupa calculul ariei,
aceasta se afiseaza prin: Write(aria). Putem scrie direct Write(pi*Sqr(raza)), efectul fiind acelasi.
Observatie

In lista argumentelor procedurilor Write si WriteLn, expresiile pot fi urmate de un format de


afisare, astfel: e:m:n, unde e este expresia de afisat, iar m si n sunt expresii cu valori intregi:
 m reprezinta numarul de pozitii ecran pe care sa se afiseze; daca valoarea de afisat necesita mai
mult de m pozitii, atunci m este ignorat;
 n reprezinta numarul de zecimale cu care se doreste scrierea valorii expresiei e (daca este de tip
real), in reprezentarea fara exponent.
Daca valoarea de afisat necesita mai putin de m pozitii, afisarea se va face cu spatii in fata, pana la
ocuparea tuturor celor m pozitii.
Un exemplu este dat in programul urmator.

88
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Exemple:

Fie declaratiile de variabile: var a: Integer; s: String;. Fie urmatoarea secventa de program:
a:=20; ReadLn(a,s); WriteLn(a,s); Write(s+’s’); in cazul introducerii valorilor 3 si alfa, se realizeaza
urmatoarele: a primeste valoarea 20; dupa citire, a isi pierde valoarea initiala (20) si devine 3.

Erori frecvente:

Unii incepatori sau cunoscatori ai limbajului BASIC cred ca se poate face o citire in felul
urmator: ReadLn(‘Dati n=”,n); iar altii nu sesizeaza diferenta intre un sir si valoarea identificatorului
corespunzator: ReadLn(‘n’).
Sa rescriem programul nostru folosind noile proceduri invatate:

program CalculArie;

const pi=3.1415926;
var raza, aria: Real;
begin
ReadLn(raza);
aria:=pi*Sqr(raza;
WriteLn(aria)
end.

Pornind de la acest program se intampla urmatoarele:


 apare cursorul si noi introducem o valoare, de exemplu 2;
 se afiseaza foarte rapid o alta valoare, insa sub o forma ciudata:1.25663704000035E+0001.
(??!!??) (pentru a vedea ce s-a afisat, se va apasa Alt+F5.). Este vorba despre formatul
stiintific de afisare a valorilor reale; valoarea de mai sus se interpreteaza ca fiind
1.25 . . . . .x101. Pentru a afisa o expresie de m pozitii, din care n pozitii pentru partea
zecimala, vom scrie: Write(e:m:n). De exemplu Write(aria:7:3) va afisa, cu un spatiu in fata:
12.566. O pozitie a fost ocupata de punctul zecimal, trei de cele trei zecimale cerute, doua de
partea intreaga (12), iar un spatiu a fost pus in fata pentru a obtine totalul de 7 pozitii.

 Atentie! Daca se afiseaza un numar intreg sau un sir de caractere, n trebuie sa lipseasca.

Cu aceasta inlocuire programul devine mai “bun”, dar tot nu satisface urmatoarele cerinte:
 sa se ceara explicit sa introducem raza;
 sa se spuna ca rezultatul pe care il afiseaza este aria cercului de raza data.
De aceea vom scrie programul de mai jos.

program CalculArie;
{ acest program calculeaza aria unui cerc in functie de raza sa }
const pi=3.1415926;
var raza, aria: Real;
begin
WriteLn(‘Program de calculat aria cercului’);
WriteLn(‘********************************’);
Write(‘Dati raza=’);ReadLn(raza);
aria:=pi*Sqr(raza);
WriteLn(‘Aria este=’, aria:7:3)
end.
Acum lucrurile stau mai bine, insa ne mai deranjeaza doua lucruri:
 trebuie sa apasam Alt-F5 pentru a vedea rezultatul programului;
 raman pe ecran “urme” care deranjeaza, de la executia programelor anterioare.
Pentru a solutiona prima problema se va folosi un apel al procedurii ReadLn fara parametri,
inainte de instructiunea end finala. Aceasta instructiune va astepta sa apasam Enter, apoi va reveni in
mediul Turbo Pascal.

Observatie

89
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Limbajul Pascal dispune de functia EoLn care testeaza daca s-a ajuns la citirea sfarsitului de
linie, caz in care returneaza True, sau nu, cind returneaza False. O astfel de functie se poate folosi
atunci cand se doreste prelucrarea de linii de caractere, cu dimensiuni variabile.

Program demonstrativ
Sa se citeasca mai multe linii de caractere de la tastatura si sa se afiseze fiecare linie, inlocuind
caracterele mici cu majusculele corespunzatoare. Prelucrarea se va incheia la aparitia caracterului ‘$’.
Pentru a transforma literele mici in litere mari se va folosi functia UpCase.

Program ConversieMinusculeMajuscule;
Var linie_vida,gata: Boolean; c:Char;
begin
Gata:=False;
While not gata do
begin
Write(‘Dati linia: ‘);
While not EoLn do
begin
Read(c);Write(UpCase(c));

linie_vida:=False;
if c=’$’ then gata:=True
end;
if linie_vida then WriteLn(‘Linia este vida!’)
else WriteLn
end.

Tipuri de constante / definirea constantelor si a variabilelor

LIMBAJUL PASCAL LIMBAJUL C/C++

Tipuri de constante

-intregi – numere intregi pozitive care nu pot -intregi – numere intregi pozitive cu valori
depasi valoarea 32767, valoare identificata de intre 0 si 4.294.967.295 si care sunt de trei
compilator sub numele de MAXINT;valorile tipuri:
intregi pot fi numere: -zecimale (baza 10);
-zecimale (baza 10); Exemple:43,152,7564.
Exemple:43,187,2001. -octale (baza 8),care sunt precedate de un
-hexazecimale (baza 16),care sunt zero nesemnificativ;
precedate de caracterul special $ Exemplu:0354→345(8)
Exemplu:$2F4 sau $2F4→ 2F4(16). -hexazecimale (baza 16),care sunt
-reale – numere reale cu valori absolute precedate de Ox sau OX.
cuprinse intre 5.9×10(la puterea -39) si 3.4×10(la Exemplu:0×2F4 sau 0X2F4 sau
puterea 38);atat partea intreaga,cat si cea 0×2f4-→2F4(16).
zecimala trebuie sa contina cel putin o -reale – orice valoare reala
cifra,chiar daca aceasta este 0. Exemple:32.45,0.5.
-caracter – orice caracter scris intre apostrofuri. -caracter- orice caracter scris intre
Exemplu:’A’ apostrofuri.
-siruri de caractere – o succesiune de Exemplu:’A’
caractere,delimitata tot prin apostrofuri. -siruri de caractere – o succesiune de
Exemple:true/false,MAXINT. caractere,delimitata tot prin ghilimele.
-constante definite prin cuvinte-cheie
Exemplu:NULL

90
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Definirea constantelor si a variabilelor

const id_constanta=valoare; const [tip] id_constanta=valoare;


var id_variabila:tip standard; tip standard id_variabila;
Exemplu: Exemplu:
const pi=3.14; const unu=’1’; const pi=3.14; const unu=’1’;
var s: integer; int s;
p:real; float p;

Tipuri de date

Tipuri întregi Tipurile intregi sunt:


 unsigned char→caracter fara semn, ocupa
Tipul shortint. 8 biti si ia valori intre 0 si 255;
Mulţimea valorilor este dată de numerele întregi  char→caracter, ocupa 8 biti si ia valori
cuprinse între -128, 127. Pentru memorare, se intre -128 si 127;
foloseşte un singur octet, iar un număr se  unsigned int→intreg fara semn,ocupa 16
memorează în cod complementar. Operaţiile biti si ia valori intre 0 si 65535;
sunt cele de la tipul integer. Datele sunt  short int→intreg scurt, ocupa 16 biti si ia
memorate în cod complementar. valori intre -32768 si 32767;
Tipul integer.  int→intreg, ocupa de regula 16 biti si ia
Mulţimea valorilor este dată de numerele întregi valori intre -32768 si 32767;
cuprinse între - 32768, 32767. Pentru memorare,  unsigned long→intreg lung fara semn,
se folosesc doi octeţi, iar un număr se ocupa 32 de biti si ia valori intre 0 si
memorează în cod complementar. Datele sunt 4.294.967.295;
memorate în cod complementar.
 long→intreg lung cu semn, ocupa 32 de
Tipul longint (întreg lung).
biti si ia valori intre -2.147.483.648 si
Mulţimea valorilor este dată de numerele întregi
2.147.483.647.
cuprinse între -2l47483648 şi 2147483647.
Variabilele de tip intreg folosesc pentru
Pentru memorare, se folosesc 4 octeţi iar un
memorarea datelor codul
număr se memorează în cod complementar.
complementar.Caracterele se memoreaza prin
Datele sunt memorate în cod complementar.
codul ASCII.
Tipul byte.
Mulţimea valorilor este dată de numerele
TIPURI
naturale cuprinse între 0 şi 255. Pentru
REALE
memorare, se foloseşte un octet, iar un număr
se memorează în binar. Datele sunt memorate
Variabilele de tip real retin numere cu
în binar.
zecimale.Tipurile reale sunt:
Tipul word.
Mulţimea valorilor este dată de numerele  float→ocupa 32 de biti si ia valori intre
naturale cuprinse între 0 şi 65535. Pentru 3.4x10-38 si 3.4x1038;
memorare se folosesc doi octeţi, iar un număr  double→ocupa 64 de biti si ia valori intre
se memorează în binar. Datele sunt memorate 1.7x10-308 si 1.7x10308;
în binar.  long double→ocupa 80 de biti si ia valori
Tipul REAL. intre 3.4x10-4932 si 1.1x104932.
Se reţin numerele reale care aparţin pentru memorare datelor se foloseste reprezentarea
domeniului: in virgula mobila.

[-1,7*1038,-2,9*10-29]  [2,9*10-29, 1,7*1038]

Pentru memorare sunt folosiţi 6 octeţi şi se


reprezintă cu precizie 11-12 cifre.

Tipul SINGLE.
Se reţin numere reale care aparţin domeniului:
[-3,4*1038,-1,5*10-45]  [1.5*10-45, 3,4*1038]

Pentru memorare sunt folosiţi 4 octeţi şi se


reprezintă cu precizie 7-8 cifre.
Tipul DOUBLE.

91
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Se reţin numere reale care aparţin domeniului:


[-1,7*10308,-5*10-324]  [5*10-324, 1,7*10308]

Pentru memorare sunt folosiţi 8 octeţi şi


se reprezintă cu precizie 15-16 cifre.
Tipul EXTENDED.
Se reţin numere reale care aparţin domeniului:
[-1,1*104932,-3,4*10-4932]  [3.4*10-4932, 1,1*104932]

Pentru memorare sunt folosiţi 10 octeţi si se


reprezintă cu precizie 19-20 cifre.
Tipul COMP.
Se reţin numere reale care aparţin domeniului:
[-9,2*1018,9,2*1018].

Operatori – reguli de prioritate si evaluare


LIMBAJUL PASCAL LIMBAJUL C/C++

Prioritate Operator Evaluare Prioritate Operator Evaluare


1 () s→d 1 () s→d
2 not+-sizeof( ) d→s 2 !~+-++ –sizeof() d→s
3 */div mod s→d 3 */% s→d
4 +- s→d 4 +- s→d
5 < <= > >= s→d 5 < <= > >= s→d
6 = <> s→d 6 (egal)== ! s→d
=(diferit)
7 and (si logic) s→d 7 & (si pe biti) s→d
8 xor s→d 8 ^(XOR pe biti) s→d
9 or (sau logic) s→d 9 │ (OR pe biti) s→d
10 :=(atribuire) s→d 10 && (si logic) s→d
11 ¦¦ (sau logic) s→d
12 =(atribuire) d→s

Operatii cu dispozitivele standard


LIMBAJUL PASCAL LIMBAJUL C/C++
Citirea de la intrarea standard (tastatura) se face cu:
Procedurile read si readln functia cin
read(id_v1[,idv2,..,id_vn]); #include<iostream.h>;
readln(id_v1[,idv2,..,id_vn]); cin>>id_v1[>>id_v2>>..>>id_vn];
unde id_v1,id_v2,…,id_vn sunt identificatori unde id_v1,id_v2,…,id_vn sunt identificatori
de variabile elementare de orice tip,cu de variabile elementare de orice tip.
exceptia celor logice.
Procedura readln are acelasi rol cu cel al
procedurii read,cu diferenta ca,la terminarea
citirii,cursorul este pozitionat pe linia
urmatoare a ecranului.

Scrierea (afisarea) la iesirea standard (ecran) se face cu:


Procedurile write si writeln functia cout
write(id1[,id2,…,idn]); #include<iostream.h>;
writeln(id1[,id2,…,idn]); cout<<id_v1[<<id_v2<<..<<id_vn];
unde id1,id2,…,idn sunt identificatori de unde id_v1,id_v2,..,id_vn sunt identificatori de

92
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

variabile elementare de orice tip sau de variabile elementare de orice tip sau de
constante. constante.
La terminarea scrierii (afisarii),cu
procedura writeln,cursorul este adus pe
prima pozitie a randului urmator.

Operatori cu fisiere de text


LIMBAJUL PASCAL LIMBAJUL C/C++

Citirea datelor din fisiere text are urmatoarele etape:


-definirea identificatorului de fisier #include<fstream.h>
var id_f:text; -implementarea fisierelor de tip text:
-asocierea dintre fisierul fizic si identificator: fstream id_f([cale\\]nume_f,ios::in);
assign(id_f’,nume_f’); sau
-deschiderea fisierului pentru citire: ifstream id_f(’’nume_f’’);
reset(id_f); Prin implementare,fisierul este deschis pentru
-citirea variabilelor din fisier se face cu citire.
ajutorul procedurilor:read si readln. -citirea se face astfel:
read(id_f,id_v1[,idv2,…,id_vn]); id_f>>id_v1[>>id_v2>>…>>id_vn];
readln(id_f,id_v1[,idv2,…,id_vn]); unde id_v1,id_v2,…,id_vn sunt identificatori de
Unde id_v1,id_v2,…,id_vn sunt identificatori variabile elementare de orice tip.
de variabile elementare de orice tip,cu -inchiderea fisierului:
exceptia celor logice. id_f.close();
-inchiderea fisierului:
close(id_f).
Scrierea in fisiere text are urmatoarele etape:

-definirea identificatorului de fisier #include<fstream.h>


var id_f:text; -implementarea fisierelor de tip text:
-asocierea dintre fisierul fizic si identificator: fstream id_f([cale\\]nume_f,ios::aut);
assign(id_f’,nume_f’); sau
-deschiderea fisierului pentru scriere: ofstream id_f([cale\\]’’nume_f’’);
rewrite(id_f); Prin implantare,fisierul este deschis pentru
-scrierea variabilelor in fisier se face cu scriere.
ajutorul procedurilor write writeln: -scrierea in fisier se face astfel:
write(id_f,id1[,id2,…,idn]); id_f<<id_v1[<<id_v2<<..<<id_vn];
writeln(id_f,id1[,id2,…,idn]); unde id_v1,id_v2,..,id_vn sunt identificatori de
unde id1,id2,…,idn sunt identificatori de variabile elementare de orice tip sau de
variabile elementare de orice tip sau de constante.
constante. -inchiderea fisierului:
-inchiderea fisierului: id_f.close();
close(id_f);

Functii matematice
LIMBAJUL PASCAL LIMBAJUL C/C++

abs:R→R+ abs(x)-modulul lui x #include<math.h> abs(x)-modulul lui x


abs:Z→N abs:Z→N(vezi labs,fabs)
sqr:R→R+ sqr(x)-x la puterea a-2-a pow:R→R+ pow(x,2)-x la puterea a doua)
sqrt:R+→R+ sqrt(x)-radical din x sqrt:R+→R+ sqrt(x)-radical din x
sin:R→[-1,1] sin(x),cos(x),arctan(x)-functii sin:R→[-1,1] sin(x),cos(x),arctan(x)-functii
cos:R→[-1,1] trigonometrice cos:R→[-1,1] trigonometrice
arctan:R→R atan:R→R log(x)-logaritm natural (ln x)
ln:R+→R ln(x)-logaritm natural log:R+→R log10(x)-logaritm in baza
exp:R→R+ exp(x)-ex(e=2,71 constanta log10:R+→R 10 (lg x)
int:R→Z Euler) exp:R→R+ exp(x)-ex(e=2,71 constanta
trunc:R→Z int(x)-partea intreaga din x ceil:R→Z Euler)

93
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

round:R→Z trunc(x)-rotunjeste la cel mai ceil(x)-rotunjeste la cel mai


frac:R→(-1,1) apropiat intreg mai mic decat floor:R→Z apropiat intreg mai mare
x pow:RxR→R decat x
round(x)-rotunjeste la cel mai floor(x)-rotunjeste la cel mai
apropiat intreg mai mare apropiat intreg mai mic decat
decat x x
frac(x)-returneaza partea pow(x,y)-calculeaza xy
fractionara a lui x

Sintaxa instructiunii de atribuire


LIMBAJUL PASCAL LIMBAJUL C/C++
id_variabila:=valoare/expresie; Id_variabila=valoare/expresie;
Precizare: Tipul variabilei trebuie sa coincida Precizare:Atribuirea este precedata de
cu tipul valorii/expresiei. conversia implicita a valorii/expresiei la tipul
variabilei.
Sintaxa instructiunii de selectie
LIMBAJUL PASCAL LIMBAJUL C/C++
case selector of switch(selector)
v11[,v12..v1n]:s1; {case v1:s1;break;
v21[,v22..v2n]:s2; case v2:s2;break;
… …
vm1[,vm2..vmn]:sm case vm:sm;break;
else s default:s;
end; }
unde:selector este o expresie de tip integer sau unde:selector este o expresie de tip int sau
char char
v11,..vmn sunt expresii constante de acelasi tip v1,..vm sunt expresii constante de acelasi tip
cu expresia selector cu expresia selector
s1,..sm,s reprezinta secvente de instructiuni s1,..sm,s reprezinta secvente de instructiuni
clauza else este optionala clauza default este optionala

EXEMPLU:
LIMBAJUL PASCAL LIMBAJUL C/C++
var a,b,selector:integer; #include<iostream.h>
begin void main()
write(’a=’);readln(a);write(’b=’);readln(b); {int a,b,selector;
writeln(’Tastati una din cifre’); cout<<’’a=’’;cin>>a;cout<<’’b=’’;cin>>b;
writeln(’1-suma/2-diferenta/3-produs/4-cat’); cout<<’’Tastati una dintre cifre’’<<end1;
write(’selector=’);readln(selector); cout<<’’1-suma/2-diferenta/3-produs/4-cat’’;
case selector of cout<<’’selector=’’;cin>>selector;
1:write(’suma = ’,a+b); switch(selector)
2:write(’diferenta = ’,a-b); {case 1:cout<<’’suma=’’<<a+b;break;
3:write(’produsul = ’,a*b); case2:cout<<’’produsul=’’<<a*b;break;
4:write(’catul impartirii intregi=’,a div b); case3:cout<<’’diferenta=’’<<a-b;break;
else write(’Ati tastat o optiune inexistenta’); case4:cout<<’’catul=’’<<a/b;break;
end; default:cout<<’’Ati tastat o optiune inexistenta’’;
end. }}

Sintaxa instructiunii repetitive cu test initial


LIMBAJUL PASCAL LIMBAJUL C/C++
while(cond_logica) do while(cond_logica)
S; S;
Secventa (S) se executa numai in cazul in care Secventa (S) se executa numai in cazul in care
conditia logica este adevarata(expresia conditia logica este adevarata(expresia
genereaza valoarea logica true). genereaza o valoare nenula).

94
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Daca secventa contine mai multe Daca secventa contine mai multe
instructiuni,atunci acestea sunt cuprinse intre instructiuni,atunci acestea sunt cuprinse intre
begin si end. acolade {}.
Exemplu:

LIMBAJUL PASCAL LIMBAJUL C/C+


var x,s:word; #include<iostream.h>
begin void main()
write(’x=’);readln(x); {unsigned int x,s=0;
s:=0; cout<<’’x=’’;cin>>x;
while(x<>0)do while (x!=0)
begin {s=s+x%10;x=x/10;
s:=s+x mod 10;x:=x div 10; }
end; cout<<’’Suma cifrelor=’’<<s<<end1;
writeln(’Suma cifrelor =’,s); }
end.

Sintaxa instructiunii repetitive cu test final


LIMBAJUL PASCAL LIMBAJUL C/C++

repeat do
S; {S;
until (cond_logica); }while(cond_logica);
Secventa (S) se executa pana cand conditia Secventa (S) se executa cat timp conditia logica
logica este adevarata (expresia genereaza este adevarata (expresia genereaza o valoare
valoarea logica true). nenula).
Secventa se executa cel putin o data,chiar Secventa se executa cel putin o data,chiar deca
daca conditia logica este indeplinita conditia logica nu este indeplinita.
(adevarata).

Cel mai mare divizor comun a doua numere naturale


LIMBAJUL PASCAL LIMBAJUL C/C++
var a,b,r:integer; #include<fstream.h>
f,g:text; void main()
begin { int a,b,r;
assign(f,’euclid.in’);reset(f); ifstream f(’’euclid.in’’);
assign(g,’euclid.out’);rewrite(g); ofstream g(’’euclid.out’’);
readln(f,a,b); f>>a>>b;
while(a mod b<>0) do while(a%b)
begin {r=a%b;a=b;b=r; }
r:=a mod b;a:=b; b:=r; g<<b;
end; f.close();
writeln(g,b); g.close();
close(f);close(g); }
end.
Numere prime
LIMBAJUL PASCAL LIMBAJUL C/C++
var n,x,i,j:word; #include<iostream.h>
prim:boolean; #include<math.h>
begin void main()
write(’n= ’);readln(n); {unsigned int n,i,j,x,prim;
for i:=1 to n do cout<<’’n= ’’;cin>>n;

95
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin for(i=1;i<=n;i++)
write(’numarul=’);readln(x); {cout<<’’numarul=’’);cin>>x;
if(x=1) then prim:=false if(x==1)prim=0;
else else
begin {prim=1;j=2;
prim:=true;j:=2; while (prim && j<=sqrt(x))
while(prim and (j<=trunc(sqrt(x)))) do if(x%j==0)prim=0;
if(x mod j=0 ) then prim:=false else j++;
else inc(j); }
end; If(prim) cout<<x<<end1;
if(prim) then writeln(x) }
end;end. }

Elemente de sintaxa specifice tablourilor unidimensionale


LIMBAJUL PASCAL LIMBAJUL C/C++
Declararea tabloului
var numetablou:array[1..nrmax]of tipelement tipelement numetablou [nrmax]
Declararea indicelui de adresa
var numeindice:tipindice tipindice numeindice
Adresarea unui element din tablou
numetablou [numeindice] Numetablou [numeindice]

Determinarea mediei.profesorul diriginte doreste sa afle media generala a clasei.


LIMBAJUL PASCAL LIMBAJUL C/C++
Se pastreaza declaratiile din exemplul 1
Var medii:array[1..10] of real; #include<iostream.h>
m:real;i,n:integer; #include<math.h>
begin void main()
read(n); {
m:=0; Float medii[10];
for i:=1 to n do float m=0;int i,n;
m:=m+medii[i]; cin>>n;
{se calculeaza media clasei,in cazul general se for (i=0;i<n;i++)
testeaza n<>0} m=m+medii[i];
m:=m/n; //se calculeaza media clasei,in cazul general se
{se afiseaza media clasei} testeaza n<>0}
Writeln (’media clasei este’,m); m=m/n;
end cout<<’’media clasei este’’;
cout<<m;
}

Compararea valorilor.Profesorul diriginte doreste sa afle cea mai mare medie a clasei

LIMBAJUL PASCAL LIMBAJUL C/C++


Se pastreaza declaratiile din exemplul 1
Var #include<iostream.h>
medii:array[1..10] of real; i,n:integer; #include<math.h>
max:real; void main()
begin {
readln(n); Float medii[10];
for i:=1 to n do int i,n;
readln(medii[i]); float max;
max:=medii[1]; cin>>n;
for i:=2 to n do for (i=1;i<n;i++)
if medii[i]>max then cin>>medii[i];
max:=medii[i]; max=medii[0];
{se afiseaza cea mai mare medie} for (i=1;i<n;i++)
writeln (’media este’,max); if(medii[i]>max)

96
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

end. max=medii[i];
//se afiseaza cea mai mare medie
cout<<’’media este’’<<max;
}

Elemente de sintaxa specifice tablourilor bidimensionale


LIMBAJUL PASCAL LIMBAJUL C/C++
Declararea tabloului
var numetablou:array[1..nrmax1,1..nrmax2]of tipelement numetablou [nrmax1][nrmax2]
tipelement
Declararea indicelui de adresa
var numeindice:tipindice1, tipindice1 tipindice numeindice1, tipindice2
Adresarea unui element din tablou
numetablou [numeindice1, tipindice2] Numetablou [numeindice1][ tipindice2]

Determinarea mediei.profesorul diriginte doreste sa afle media generala a clasei.


LIMBAJUL PASCAL LIMBAJUL C/C++
Se pastreaza declaratiile din exemplul 1
var m:real; #include<iostream.h>
medii:array[1..10,1..10] of real; i,n:integer; #include<math.h>
begin void main()
m:=0; {
readln(n); float medii[10][10];
for i:=1 to n do int i,n;
for j:=1 to n do float m=0;
read(medii[i,j]); cin>>n;
for i:=1 to n do for (i=1;i<n;i++)
for j:=1 to n do for (i=1;i<n;i++)
m:=m+medii[i,j]; cin>>medii[i][j];
{se calculeaza media clasei,in cazul general se for (i=0;i<n;i++)
testeaza n<>0} for (j=0;i<n;J++)
m:=m/n; m=m+medii[i][j];
{se afiseaza media clasei} //se calculeaza media clasei,in cazul general se
Writeln (’media clasei este’,m); testeaza n<>0}
end . m=m/n;
cout<<’’media clasei este’’;cout<<m;
}

Subprograme

Noţiunea de subprogram
Prin subprogram vom înţelege un ansamblu alcătuit din tipuri de date, variabile şi
instrucţiunii scrise în vederea unei anumite prelucrări (calcule, citiri, scrieri) şi care poate fi utilizat
(rulat) doar dacă este apelat de un program sau de alt subprogram.

Până în prezent am fost doar utilizatori de subprograme. Exemple de subprograme folosite:

■ matematice: sin, cos, exp, log.

■ de prelucrare a şirurilor de caractere:in Pascal avem pos,length …,iar in C++ strlen, strcpy, strncat.

■ chiar citirile şi scrierile se fac sub controlul unor subprograme speciale.

În acest capitol învăţăm să le creăm. Pentru a înţelege noţiunea de subprogram, vom porni de
la două exemple:

97
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

□ Se citeşte n, număr natural. Să se scrie programele care tipăresc valoarea calculată a expresiilor:

E1=1+1/2+1/3+1/4+…+1/n

E2=(1+1/2+1/3+1/4+…+1/n)ⁿ

Ce observăm? A doua expresie, se poate obţine din prima. Relaţia este:

E₂=E₁ⁿ

Cerinţa este de a scrie programe separate. Cum procedăm? Prin utilizarea cunoştinţelor
dobândite până în prezent, scriem cele două programe separat, iar în al doilea program, secvenţa care
calculează prima expresie, se copiază din primul.

Oare nu se poate lucra mai eficient? Răspunsul este afirmativ. Se scrie un program care
calculează E₁ şi care este apelat de ambele programe. Primul program va tipări valoarea transmisă de
subprogram, al doilea va ridica la putere această valoare şi va afişa rezultatul.

□ Se citeşte n, număr natural. Se citeşte un vector cu n componente numere reale. Se cere să se


tipărească vectorul sortat.

Desigur, ştim să rezolvăm această problemă şi clasic, în mai multe feluri, pentru că am studiat
mai mulţi algoritmi de sortare. De această dată vom rezolva problema prin utilizarea subprogramelor.

Vom scrie un subprogram care citeşte un vector, unul care tipăreşte un vector şi un al treilea
care sortează vectorul, după una din metodele cunoscute.

În acest caz, programul ar arăta astfel:

Pasul 1 apelează subprogramul care citeşte vectorul;


Pasul 2 apelează subprogramul care sortează vectorul;
Pasul 3 apelează subprogramul care tipăreşte vectorul.

Faţă de scrierea clasică, aici problema a fost descompusă în altele mai mici (citire, sortare,
tipărire). În general, o problemă complexă se rezolvă mai uşor dacă o descompunem în altele mai
simple. Apoi, şansele de a greşi la scrierea unui subprogram sunt cu mult mai mici decât acelea de a
greşi la scrierea unui program mare. Acesta din urmă rezultă din “asamblarea” subprogramelor la care
se adaugă, eventual, câteva linii scrise în programul principal. Putem acum enumera avantajele
utilizării subprogramelor:

■ reutilizarea codului –o dată scris, un subprogram poate fi utilizat de mai multe programe;

■ elaborarea algoritmilor prin descompunerea problemei în altele mai simple. În acest fel, rezolvăm cu
mult mai uşor problema;

■ reducerea numărului de erori car pot apărea la scrierea programelor;

■ depistarea cu uşurinţă a erorilor –verificăm la început subprogramele, apoi modul în care le-am
asamblat (le-am apelat din cadrul programului).
 Parametrii care se găsesc în antetul funcţiei se numesc parametrii formali.

Atunci când scriem o funcţie nu cunoaştem valoarea propriu-zisă a parametrilor. Funcţia trebuie să
întoarcă rezultatul corect, oricare ar fi valoarea lor. Din acest punct de vedere ei se numesc formali.

 Parametrii care se utilizează la apel se numesc parametrii afectivi.

98
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare aceştia se cunosc
parametrii efectivi.
În esenţă, o funcţie este alcătuită din:

 Antet – acesta conţine mai multe informaţii importante necesare compilatorului, numele funcţiei,
lista parametrilor formali, tipul rezultatului.
O funcţie poate fi apelată de sine stătător (prin nume şi lista parametrilor efectivi), dar poate fi inclusă şi în cadrul
expresiilor, caz în care, la evaluarea expresiei este apelată.

 Sistemul de operare alocă fiecărui program trei zone distincte în memoria internă în care se găsesc
memorate variabilele programului.

Segment de date

Segment de stivă

Heap

De asemenea, există posibilitatea ca variabilele să fie memorate într-un anumit registru al


microprocesorului. În acest caz timpul de acces la astfel de variabile este foarte mic, deci se pot obţine
programe optimizate.

 În general o variabilă se caracterizează prin 4 atribute. Acestea sunt:

1. Clasa de memorare.
2. Vizibilitate.
3. Durata de viaţă.
4. Tipul variabilei, singurul pe care l-am studiat până în prezent.

1. Clasa de memorare – precizează locul unde este memorată variabila respectivă. O variabilă poate
fi memorată în segmentul de date, în cel de stivă, în heap sau într-un registru al microprocesorului.

2. Vizibilitatea – precizează liniile textului sursă din care variabila respectivă poate fi accesată. Astfel
avem:

a. Vizibilitate la nivel de bloc (instrucţiune compusă);

b. Vizibilitatea la nivel de fişier – în cazul în care programul ocupă un singur fişier sursă,
singurul caz pe care îl tratăm acum.

c. Vizibilitatea la nivel de clasă – este în legătură cu programarea pe obiecte, pe care o veţi


studia în anul următor.

3. Durata de viaţă – reprezintă timpul în care variabila respectivă are alocat spaţiu în memoria
internă. Astfel avem:

a. Durata statică – variabila are alocat spaţiu în tot timpul execuţiei programului.

b. Durata locală - variabila are alocat spaţiu în timpul în care se execută instrucţiunile
blocului respectiv.

c. Durata dinamică – alocarea şi dezalocarea spaţiului necesar variabilei respective se face


de către programator prin operatori sau funcţii speciale.

Variabile globale
Acestea se declară în afara corpului oricărei funcţii
La declarare, variabilele globale sunt iniţializate cu 0.

99
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Atributele variabilelor globale sunt:

1. Clasa de memorare – segmentul de date.

2. Vizibilitatea – În cazul în care declaraţiile acestora sunt înaintea tuturor funcţiilor, acestea sunt
vizibile la nivelul întregului program (fişier). Dacă anumite funcţii se află plasate înaintea
declaraţiilor acestor variabile, atunci ele sunt vizibile doar pentru funcţiile care sunt plasate după
aceste declaraţii.

3. Durata de viaţă a variabilelor globale este statică. Ele au spaţiu rezervat în tot timpul execuţiei
programului.
Variabile locale
Acestea sunt declarate în corpul funcţiilor. Mai precis, pot fi declarate în orice bloc (instrucţiune
compusă) al acestora
1. Clasa de memorare a variabilelor locale este, implicit, segmentul de stivă. Există posibilitatea ca
acestea să fie alocate în registrele microprocesorului, caz în care declaraţia lor trebuie precedată de
cuvântul cheie register.

1. Variabilele locale nu sunt iniţializate implicit cu 0. În ipoteza în care acestea nu sunt iniţializate
explicit de programator, reţin o valoare oarecare, numită valoare reziduală.

2. Vizibilitatea variabilelor locale este la nivelul blocului la care au fost declarate.


3.În cazul în care, într-un anumit bloc sunt vizibile (se pot accesa) mai multe variabile, toate au acelaşi
nume, dar au domenii de vizibilitate diferite, se accesează variabila cu vizibilitatea cea mai mică.
. Există posibilitatea ca, un ciclu for să conţină declaraţia unei variabile locale.
5. Durata de viaţă a variabilelor locale este atât timp cât durează execuţia blocului respectiv.

Transmiterea parametrilor

Aşa cum am arătat, parametrii care se găsesc în antetul funcţiei se numesc parametrii formali,
iar cei care se găsesc în instrucţiunea de apel se numesc parametrii efectivi.
După fiecare apel al funcţiei se tipăreşte suma obţinută. Între parametrii formali şi cei efectivi trebuie
să existe o anumită concordanţă, care este descrisă prin regulile următoare:

Numărul parametrilor formali trebuie să coincidă cu numărul parametrilor efectivi. La această regulă
există o excepţie care va fi prezentată într-un paragraf separat.
Tipul parametrilor formali trebuie să coincidă cu tipul parametrilor efectivi sau tipul parametrilor efectivi
să poată fi convertit implicit către tipul parametrilor formali la fel ca în cazul atribuirii
Observaţie: Nu este obligatoriu ca numele parametrilor formali să coincidă cu numele parametrilor
efectivi.

Vom analiza modul în care sunt memoraţi parametrii transmişi, în momentul lansării în
execuţie a funcţiei.

 Pentru memorarea parametrilor subprogramele folosesc segmentul de stivă, întocmai ca pentru


variabilele locale.

 Memorarea parametrilor transmişi se face în ordinea în care aceştia figurează în antet: de la stânga
la dreapta.

 În cadrul subprogramului, parametrii transmişi şi memoraţi în stivă sunt variabile. Numele lor este
cel din lista parametrilor formali.

 Variabilele obţinute în urma memorării parametrilor transmişi sunt variabile locale.


Există două mecanisme de transmitere a parametrilor, transmiterea prin valoare şi transmiterea prin
referinţă. Acestea vor fi tratate în continuare:

100
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

A. Transmiterea prin valoare se utilizează atunci când suntem interesaţi ca subprogramul să lucreze
cu acea valoare, dar, în prelucrare, nu ne interesează ca parametrul efectiv (cel din blocul apelant)
să reţină valoarea modificată în subprogram.

Se pot transmite prin valoare:

1. Valorile reţinute de variabile.


2. Expresii (acestea pot conţine şi funcţii).

1. Valorile reţinute de variabile. În acest caz, parametrii efectivi trebuie să fie numele
variabilelor.
2. Parametrii efectivi sunt expresii, care mai întâi se evaluează.
Aşa cum am arătat, transmiterea parametrilor prin valoare se utilizează atunci când nu ne
interesează ca, la întoarcerea din subprogram, parametrul efectiv să reţină valoarea modificată
acolo. Întrebare: dacă n-ar exista decât transmiterea prin valoare, ar fi posibil să modificăm
valoarea anumitor variabile care sunt declarate în blocul aparent?

Răspunsul este afirmativ daca lucram cu variabile pointer.


B. Transmiterea prin referinţă. Parametrii sunt transmişi prin referinţă atunci când de interesează
ca la revenirea din subprogram variabila transmisă să reţină valoarea stabilită în timpul execuţiei
subprogramului.

 În cazul transmiterii prin referinţă, parametrii efectivi trebuie să fie referinţe la variabile (vezi
tipul referinţă prezentat în capitolul anterior).

 În cazul transmiterii prin referinţă subprogramul reţine în stivă, adresa variabilei.

În acest caz ne putem întreba care este mecanismul prin care, deşi pentru o variabilă transmisă se
reţine adresa ei, în subprogram putem adresa variabila normal (nu indirect)? La compilare, orice
referinţă la variabila respectivă, este “tradusă” ca adresare indirectă.

Programul următor utilizează o funcţie care interschimbă valorile reţinute de două variabile.
Acestea sunt transmise prin referinţă.
Definirea şi declararea unui subprogram
Deşi aparent asemănătoare, cele două noţiuni diferă. Buna înţelegere a lor ne ajută să evităm
anumite erori. Mai mult, aceste noţiuni sunt utilizate de orice limbaj de programare.

□ A defini un subprogram, înseamnă a-l scrie efectiv, după structura anterior prezentată. O problemă
importantă este locul unde se defineşte subprogramul.

□ A declara un subprogram, înseamnă a-l anunţa. Un subprogram nedeclarat nu poate fi folosit.


Definiţia unui subprogram ţine loc şi de declaraţie!

FUNCTII
LIMBAJUL PASCAL LIMBAJUL C/C++
declaratiile
FUNCTION tip_returnat_de_functie
nume_functie(parametrii:tip):tip_returnat_de_functie; nume_functie(tip parametrii)
Var variabile_locale:tip; {
Begin tip variabile_locale;

Nume_functie:=expresie_calculata_aici; return expresie_calculata_aici;


End; }

exemplu
Var s,i,n:integer; #Include<iostream.h>
Function ss(n:integer):integer; int i,n;

101
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Var s:integer; int ss(int n)


Begin { int s=0;
S:=0; for (i=0;i<n;i++)
For i:=1 to n do s=s+i;
S:=s+i; return s
Ss:=s; }
End; void main()
Begin {
Readln(n); cin>>n;
Write(ss(n)); cout<<ss(n);
End. }
PROCEDURI
LIMBAJUL PASCAL LIMBAJUL C/C++
declaratiile
PROCEDURE nume_procedura(parametrii_intrare:tip;VAR VOID nume_procedura(tip
parametrii_iesire:tip);
Var variabile_locale:tip;
parametrii_intrare,tip &
Begin parametrii_iesire )
…….. {
End; tip variabile_locale;

}
Exemplu
LIMBAJUL PASCAL LIMBAJUL C/C++
declaratiile
Var s, i,n:integer; #Include<iostream.h>
procedure ss(n:integer;var s:integer); int s=0,i,n;
Begin void ss(int n, int& s)
S:=0; {
For i:=1 to n do for (i=0;i<n;i++)
S:=s+i; s=s+i;
End; }
Begin void main()
Readln(n); {
ss(n,s); cin>>n;
Write(s); ss(n,s);
End. cout<<s;
}
RECURSIVITATE
Introducere in recursivitate

Prezentare generala

Recursivitatea este una din notiunile fundamentale ale informaticii. Utilizarea frecventa a recursivitatii
s-a facut dupa anii 80.Multe din limbajele de programare evaluate si mai mult utilizate -Fortran, Cobol-
nu permiteau scrierea programelor recursive.

● Recursivitatea este un mechanism general de elaborare a programelor .Ea consta in posibilitatea


ca un subprogram sa se autoapeleze.

Recursivitatea a aparut din necesitati practice date de transcrierea directa a formulelor matematice
recursive.In timp. Acest mecanism a fost extins, fiind utilizat in elaborarea multor algoritmi.

Mecanismul recursivitatii

102
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

▫ Sa se calculeze recursiv n!.

A) Pentru a scrie o functie recursiva care efectueaza acelasi calcul, vom porni de la o
definitie recursiva a lui n !. Aceasta este :

n !=fact(n)= 1, n=0
n€N
n * fact(n-1), astfel

De exemplu, pentru a calcula 3!, procedam astfel :

3 !=fact(3)=3 x fact(2)=3 x 2 x fact(1)=3 x 2 x 1 x fact(0)=3 x 2 x 1 x 1=6.


Observati ca functia fact se autoapeleaza. Autoapelul se realizeaza prin: return n*fact(n-1).

Care este mecanismul prin care subprogramele se pot autoapela? Sa ne amintim modul in care
subprogramele memoreaza parametrii transmisi:

● Pentru memorarea parametrilor, subprogramele folosesc o zona de memorie numita stiva (mai
exact, aceasta zona se numeste segment de stiva).

● Memorarea parametrilor transmisi se face in ordinea in care acestia figureaza in atent: de la


stanga la dreapta.

● Pentru parametrii transmisi prin valoare, se memoreaza valoarea transmisa, iar pentru cei
transmisi prin referinta se memoreaza adresa variabilei.

● In cadrul subprogramului, parametrii transmisi si memorati in stiva sunt variabile.Numele lor este
cel di lista parametrilor formali.

In capitolul anterior am studiat proprietatile structurii numita stiva. Exact aceleasi proprietati le are si
segmental de stiva.Singura diferenta este data de faptul ca gestiunea segmentului de stiva este facuta
automat de catre calculator.Mai exact, codul in limbaj masina, obtinut in urma compilarii, contine
secvente prin care se gestioneaza segmentul de stiva.

● La apelul subprogramului se depun in stiva, in ordine, parametrii transmisi. DE asemenea, tot in


stiva se rezerva spatiu pentru variabilele locale.(cele declarate in subprogram).Acesta este un prim
nivel al stivei.

● In cazul in care subprogramul se autoapeleaza pe un al doilea nivel se depun din nou parametrii
transmisi si se rezerva un nou spatiu pentru variabilele locale.

In continuare prezentam grafic modul in care functioneaza recursivitatea in cazul functiei fact a
programului anterior. Aceasta functie nu are variabile locale, deci in stiva se depune doar parametrul
n.

n→3 La primul apel al functiei fact se creeaza in segmental de stiva o


variabila numita n, care retine 3- valoarea parametrului formal.

n→2
n→3 Functia se autoapeleaza. De aceasta data parametrul n ia valoarea 2

103
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

.In stiva se creeaza un nou nivel, care retine n cu valoarea 2.

n→1 Functia se autoapeleaza. De aceasta data parametrul n ia


n→2 valoarea 1. In stiva se creeaza un nou nivel, care retine n cu
n→3 valoarea 1.

n→0 Functia se autoapeleaza.Parametrul n ia valoarea 0.In stiva se


n→1 creeaza un nou nivel, care retine n cu valoarea 0.Functia ia
n→2 valoarea 1, autoapelul nu mai are loc.Se revine pe nivelul 3.
n→3

n→1 Pe nivelul 3 se efectueaza calculul 1*1=1.Se revine apoi pe


n→2 nivelul 2.
n→3

n→2 Pe nivelul 2 se efectueaza calculul 2 * 1=2.Se revine apoi


n→3 pe nivelul 1.

n→3 Pe nivelul 1 se efectueaza calculul 3 * 2=6.Se revine apoi in


main( ).

Aici se afiseaza 6, adica s-a calculat 3 !.

LIMBAJUL PASCAL LIMBAJUL C/C++


FUNCTII CARE SE AUTOAPELEAZA
VAR N:INTEGER; #include <iostream.h>
Function fact(n:integer):integer; int fact(int n)
Begin { if (!n) return 1;
If n=0 then fact:=1 else return n* fact(n-1);
Else }
Fact:=n*fact(n-1); main( )
End; { int n;
Begin cout<<”n=”; cin>>n;
Readln(n); cout<<fact(n) ;
Write(fact(n); }
End.
PROCEDURI CARE SE AUTOAPELEAZA

Var n:integer;
Procedure fact( val:integer;var prod:integer); #include <iostream.h >
Begin void fact(int val, int n,int& prod)
If (val<=n) then { if (val<=n)
Begin { prod*=val;
Prod=prod*val; fact(val+1,n,prod);
fact(val+1,n,prod); }
} }
begin main( )
readln(n); { int val,n,p=1;
p=1; cout<<”n=”; cin>>n;
fact(1,n,p); fact(1,n,p) ;
write(p); cout<<p ;
end. }

104
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

B)Sa analizam si pentru acest exemplu modul in care se efectueaza calculul,pentru


n=3.Functia are trei parametri : doi transmisi prin valoare, unul prin referinta.

Iata continutul variabilelor dupa primul apel :

1 3 Referinta catre
p
1

p val n prod
Pentru ca val este mai mic sau egal ca n se efectueaza : prod :=prod*val ;Intrucat
variabila p a fost transmisa prin referinta, programul lucreaza cu aceasta variabila, in
loc de prod.In concluzie, se efectueaza p :=p*val ;.Apoi, functia se autoapeleaza :

2 3 Referinta catre p
1 1 3 Referinta catre p
p val n prod

Pentru ca val este 2 –mai mic ca 3 - 3 3 Referinta catre p


se efectueaza prod :=prod*val ; dupa 2 3 Referinta catre p
1 3 Referinta catre p
care functia se autoapeleaza.

2
p val n prod

Pentru ca val este 3 –mai mic sau egal cu 3 – se efectueaza prod :=prod*val, deci p
ia valoarea 6, dupa care se revine pe nivelul 2, apoi 1, apoi in programul principal.

Observatii :

▫Dupa cum rezulta din aceste exemple, subprogramul lucreaza cu datele aflate pe un
anumit nivel al stivei pentru variabilele transmise prin valoare si variabilele locale
ale sale, dar si cu variabilele functiei main( ) , daca acesteav sunt transmise prin
referinta.

▫Exista posibilitatea ca subprogramul sa lucreze direct cu variabilele globale far aca


acestea sa fie transmise prin referinta.Dupa cum stim variabilele globale pot fi
accesate din orice subprogram , daca sunt declarate la inceputul textului sursa.In
exemplu, am preferat varianta de a trece ca parametru variabila transmisa prin

105
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

referinta din motive didactice si pentru a asigura independenta


subprogramului.Dezavantajul este dat de faptul ca stiva va fi incarcata suplimentar cu
adresa acestei variabile.

▫In cazul unui numar mare de autoapelari , exista posibilitatea ca segmentul de stiva
sa se ocupe total, in caz in care programul se va termina cu eroare.

▫Recursivitatea presupune mai multa memorie(ma refer la stiva), aceasta este oricum
rezervata.

Cum gandim un algoritm recursiv

Pentru a ne familiariza cu rationamentul recursiv vom porni de la cateva exemple


intuitive.

1.Wirth.O camera de luat vederi are in obiectiv un televizor care transmite imaginile
primite de la camera.Evident, in televizor se va vedea un televizor, iar in acesta
un televizor...s.a.m.d

Pe scurt :
▪ in orice televizor, se vede un televizor.

2.Anunt. In anumite restaurante am intalnit anuntul : Azi nu se fumeaza !.

3.Constatare. Intr-o tara cu nivel de trai scazut, orice partid care ajunge la putere
afirma:de vina nu suntem noi, sunt cei de la care am preluat puterea!.

4.Logica. Orice militar aflat in ciclu 2 de instruire afirma :cand eram in ciclu 1, cei
din ciclu 2 ‘m-au chinuit inutil’.Asa fac si eu cu cei din ciclu 1.

Lasand gluma la o parte, constatam ca, in general, o gandire recursiva exprima


concentrat o anumita stare, care se repeta la infinit. Aceasta gandire se aplica in
elaborarea algoritmilor recursivi, dar cu o modificare esentiala :adaugarea conditiei
de terminare.In absenta acestei conditii, nu poate fi vorba de algoritm, intrucat
algoritmul trebuie sa fie finit.

→In elaborarea algoritmilor recursivi se aplica rationamentul : ce se intampla la un


nivel, se intampla la orice nivel.

106
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

→Subprogramul care se autoapeleaza trebuie sa contina instructiunile


corespunzatoare unui nivel.

→Starea tratata de subprogram se gaseste pe un anumit nivel al stivei (variabilele


rezultate in urma transmiterii parametrilor si variabilele locale ale subprogramului).

Observatii

▪Un algoritm recursiv se elaboreaza utilizand acest tip de gandire, nu o gandire


precum cea folosita pana acum, cand am elaborat algoritmi iterativi.

▪Pentru orice algoritm recursiv exista unul iterativ care rezolva aceeasi problema.

▪Nu intodeauna alegerea unui algoritm recursiv reprezinta un avantaj.

▪Numeroase exemple care urmeaza va vor lamuri asupra celor afirmate


Proceduri recursive cu vectori

LIMBAJUL PASCAL LIMBAJUL C/C++


Recursiv sa se determine cel mai mare element dintr-un vector

Type v=array[1..100] of integer; #include <iostream.h>


var b,i,n:integer; int n;
a:v; int max (int x[ ],int n)
function m(var f:integer;i:integer):integer; {
begin int j,k;
if i>n then m:=f if (n==1) k=1;
else if (x[j]>x[n]) k=j;
begin else k=n;
if f<a[i] then }
f:=a[i]; return k;
m:=m(f,i+1);end; }
end; void citire(int x[],int i)
{
procedure afis(a:v;lung:byte); if (i<n+1)
var k:byte; {
begin cin >>x[i];
for k:=1 to lung do citire(x,i+1);
write(a[k],' '); }
end; }
begin void tipar (int x[ ],int i)
write('cite elemente aveti');readln(n); {
for i:=1 to n do if (i<n+1)
begin {
write('a[',i,']'); cout<<x[i]<<’ ‚;
readln(a[i]); tipar (x,i+1);
end; }
b:=a[1]; }
writeln('maximul este',m(b,2));{DE LA AL DOILEA ELEMENT main( )
INCOLO CAUT MAXIMUL} {
readln; int a[100],maxi;
end. cin>>n;
citire(a,1);
tipar (a,1);
maxi=max(a,n);
cout<<a[maxi];

107
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

}
Recursiv indirect sa se calculeze sirurile date prin:a0:=a;b0=b;
an:=(A[n-1]+B[n-2])/2
si bn:=sqrt(a[n-1]*b[n-1])
LIMBAJUL PASCAL LIMBAJUL C/C++
sursele
var n,a0,b0:word; #include <iostream.h>
function a(n:word):real;forward; #include <math.h>
function b(n:word):real; double a,b;
begin int n;
if n=0 then b:=b0
else double bn (int n);
b:=sqrt(a(n-1)*b(n-1)); double an (int n);
end; { if (!n) return a;
function a; else return (an(n-1)+bn(n-1))/2;
begin }
if n=0 then a:=a0
else double bn (int n)
a:=(a(n-1)+b(n-1))/2; { if (!n) return b;
end; else return sqrt(an(n-1)*bn(n-
begin 1));
writeln('valoarea initiala a sirului a ');readln(a0); }
writeln('valoarea initiala a sirului b ');readln(b0);
write('rangul sirurilor ');readln(n); main( )
writeln('b= ',b(n):6:2,' a= ',a(n):6:3); { cout<<”a=”;cin>>a;
readln; cout<<”b=”;cin>>b;
end. cout<<”n=”;cin>>n;
cout<<an(n)<<’ ‘<<bn(n) ;
}

DIVIDE ET IMPERA
o Se citeste un vector cu n componente,numere naturale.Se cere sa se
tipareasca valoarea maxima.
Problema de mai sus este binecunoscuta.Cum o rezolvam utilizand metoda divide et
impera?
Trebuie tiparita valoarea maxima dintre numerele retinute in vector de la i la j(initial
i=1,j=n).Pt acesta procedam astfel:
 Daca i=j,valoarea amxima va fi v[i];
 Contrar vom imparti vectorul in doi vectori(primul vector va contine
componentele de la i la (i+j) div 2,al doilea va contine componentele de la
(i+j)div 2+1 la j),rezolvam subproblemele(aflam maximul pentru fiecare
dintre ele) iar solutia problemei va fi data de valoarea maxima dintre
rezultatele celor doua subprobleme.

LIMBAJUL PASCAL LIMBAJUL C/C++


Maximul dintr-un vector
type sir=array[1..20] of integer; #include<iostream.h>
var x, y,xx:sir;k1,n,i,ss:integer; int v[10],n;
ssss:boolean;
function afis11111(x:sir;k,p:integer); int max(int i,int j)
var s1,s2:integer; { int a,b;
begin if (i==j) return v[i];
if k=p then afis11111:=x[k] else
else { a=max(i,(i+j)/2);
begin b=max((i+j)/2+1,j);

108
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

s1:=afis11111(x,k,trunc((k+p) div 2)); if (a>b) return a;


s2:=afis11111( x,trunc( ( k+p ) div 2 else return b;
+1 ),p ); }
if s1>s2 then afis11111:=s1 else }
afis11111:=s2; main ( )
end;end; { cout<<”n=”;cin>>n;
begin for (int i=1;i<=n;i++)
writeln('n=');readln(n); {cout<<”v[“<<i<<”]=”;cin>>v[i];}
for i:=1 to n do cout<<”max=”<<max(1,n);
begin }
writeln('xx[',i,']=');
readln(xx[i]);
end;
write(afis11111(xx,1,n readln;
end.

o Sortare prin interclasare.Se considera vectorul a cu n componente numere intregi(sau


reale).Sa se sorteze crescator,utilizand sortarea prin interclasare.
Algoritmul de sortare prin interclasare se bazeaza pe urmatoarea idée:pentru a sorta un vector cu n
elemante il impartim in doi vectori care,odata sortati,se interclaseaza.

Conform strategiei generale Divide et impera,problema este descompusa in alte doua subprobleme de
acelasi tip si,dupa rezolvarea lor,rezultatele se combina(in particular se interclaseaza).Descompunerea
unui vector in alti doi vectori care urmeaza a fi sortati are loc pana cand avem de sortat vetori de una
sau doua componente.
In aplicatie,functia sort sorteaza un vector cu maximum doua elemente;interc interclaseaza
rezultatele ;divimp implementeaza strategia generala a metodei studiate

LIMBAJUL PASCAL LIMBAJUL C/C++


INTERCLASARE A DOI VECTORI
type vector=array[1..10] of integer; #include <iostreAm.h>
var a:vector; int a[10],n;
n,i:integer; void sort(int p,int q,int a[10])
procedure sort(xxx1,xxx2:integer;var {
a:vector); int m;
var m:integer; if (a[p]>a[q])
begin {
if a[xxx1]>a[xxx2] then m=a[p];
begin a[p]=a[q];
m:=a[xxx1]; a[q]=m;}
a[xxx1]:=a[xxx2]; }
a[xxx2]:=m; void interc(int p,int q,int m,int a[10])
end {
end; int b[10],I,j,k;
i=p;j=m+1;k=1;
procedure interclasare(xxx1,xxx2,m:integer;var while (i<=m && j<=q)
a:vector); if (a[i]<=a[j])
var b:vector; {
i,j,k:integer; b[k]=a[i];
begin i=i+1;
i:=xxx1;j:=m+1; k=k+1;
k:=1; }
while (i<=m) and (j<=xxx2) do else
if a[i]<=a[j] then {
begin b[k]=a[j];
b[k]:=a[i]; j=j+1;
i:=i+1; k=k+1;
k:=k+1;
}
end
if (i<=m)
else

109
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin for (j=i;j<=m;j++)


b[k]:=a[j]; {
j:=j+1; b[k]=a[j];
k:=k+1; k=k+1;
end; }
if i<=m then else
for j:=i to m do for (i=j;j<=q;j++)
begin {
b[k]:=a[j]; b[k]=a[i];
k:=k+1; k=k+1;
end }
else k=1;
for i:=j to xxx2 do for (i=p;i<=q;i++)
begin {
b[k]:=a[i]; a[i]=b[k];
k:=k+1; k=k+1;
end; }
k:=1; }
for i:=xxx1 to xxx2 do void divimp (int p,int q,int a[10])
begin {
a[i]:=b[k]; int m;
k:=k+1; if ((q-p)<=1) sort(p,q,a);
end;end; else
procedure divimp(xxx1,xxx2:integer;var { m=(p+q)/2;
a:vector); divimp(p,m,a);
var m:integer; divimp(m+1,q,a);
begin interc(p,q,m,a);
if (xxx2-xxx1)<=1 then
}
sort(xxx1,xxx2,a)
}
else
main( )
begin
{ int i;
m:=(xxx1+xxx2) div 2;
cout<<”n=”;cin>>n;
divimp(xxx1,m,a);
for (i=1;i<=n;i++)
divimp(m+1,xxx2,a);
{
interclasare(xxx1,xxx2,m,a);
cout<<”a[“<<i<<”]=”;cin>>a[i];}
end;end;
divimp(1,n,a);
begin
writeln('n=');readln(n); for (i=1;i<=n;i++)
for i:=1 to n do cout<<a[i]<<” “;
begin }
writeln('a[',i,']=');
readln(a[i]);
end;
divimp(1,n,a);
for i:=1 to n do
write(a[i]);
readln;
end.

o Sortare rapida.Fie vectorul a cu n numere intregi(sau reale).Se


cere ca vectorul sa fie sortat crescator.

Pentru rezolvare este necesara o functie poz care trateaza o portiune din vector
cuprinsa intre indicii dati de li (limita inferioara) si ls(limita superioara).Rolul acestei
functii este de a pozitiona prima componenta a[li] pe o pozitie k cuprinsa intre li si
ls,astfel incat toate componentele vectorului cuprinse intre li si k-1 sa fie mai mici sau
egale decat a[k] si toate componentele vectorului cuprinse intre k+1 si ls sa fie mai
mari sau egale decat a[k].
In aceasta functie exista doua moduri de lucru:

110
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

a) i ramane constant,j scade cu 1;


b) i creste cu 1,j ramane constant.
Functia este conceputa astfel:
 initial,i va lua valoarea li,iar j va lua valoarea ls (elemental care initial
se afla pe pozitia li se va gasi mereu pe o pozitie data de i sau de j);
 se trece in modul de lucru a);
 atata timp cat i<j,se executa:
-daca a[i] este strict mai amre decat a[j],atunci se inverseaza cele doua
numere si se schimba modul de lucru;
-i si j se modifica corespunzator modului de lucru in care se afla
programul;
-k ia vlaoraea comuna a lui i si j.
 Dupa aplicarea functiei poz,este evident ca elementul care se afla initial
in pozitia li va ajunge pe o pozitie k si va ramane pe acea pozitie in
cadrul vectorului deja sortat,fapt care reprezinta esenta algoritmului.
Functoa quick are parametrii li si ls(limita inferioara si limita superioara).In cadrul ei
se utilizeaza metoda Divide et impera,dupa cum urmeaza:
-se apeleaza poz;
-se apeleaza quick pentru li si k-1;
-se apeleaza quick pentru k+1 si ls.

LIMBAJUL PASCAL LIMBAJUL C/C++


SORTAREA RAPIDA
{Fie a un vector cu n componente intregi #include<iostream.h>
Scrieti o functie care sa plaseze primul element din
vectorul a pe pozitia care acesta int a[100],n,k;
ar ocupao fara sa ordonati vectorul in stinga sa fiind
plasate numai elemente mai mici decit el iar in void poz(int li,int ls,int& k,int a[100])
dreapta numai elemente mai mari decit el {
Functia sa returneze pozitia pe care a fost plasat
primul element int i=li,j=ls,c,i1=0,j1=-1;
OBS:cu metoda divide et impera(Quick sort) while (i<j)
ex:3 { if (a[i]>a[j])
1 3 2
=>1 2 3
{
c=a[j];
} a[j]=a[i];
const nmax=100;type indice=1..nmax; a[i]=c;
tipelement=integer;
var a:array[indice] of tipelement;
c=i1;
n:indice; i1=-j1;
procedure citire; j1=-c;
var I:indice; }
begin
writeln('n=');readln(n); i=i+i1;
for i:=1 to n do j=j+j1;
begin }
writeln('a[',i,']='); k=i;
readln(a[i]);
end;end; }
procedure afisare;
var i:indice; void quick (int li,int ls)
begin
writeln('vectorul sortat este');
{ if (li<ls)
for i:=1 to n do { poz (li,ls,k,a);
write(a[i]);writeln;readln; quick(li,k-1);
end; quick(k+1,ls);
function divide (p,q:indice):indice; }
var st,dr:indice;x:tipelement; }
begin main( )
st:=p;dr:=q;x:=a[p]; { int I;
while st<dr do
begin cout<<”n=”;cin>>n;
while (st<dr) and (a[dr]>=x) do dec(dr); for (i=1;i<=n;i++)

111
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

a[st]:=a[dr]; { cout<<”a[“<<i<<”]=”;cin>>a[i];}
while (st<dr) and (a[dr]>=x) do dec(dr);
quick(1,n);
a[st]:=a[dr]; for (i=1;i<=n;i++) cout <<a[i]<<endl;
while (st<dr) and (a[st]<x) do inc(st); }
a[dr]:=a[st];
end;
a[st]:=x;divide:=st;
end;

procedure rapida(p,q:indice);
var m:indice;
begin
m:=divide(p,q);
if m-1>p then rapida(p,m-1);
if m+1 <q then rapida(m+1,q);
end;
begin
citire;
rapida(1,n);
afisare;
readln;
end.

o Cautare binara.Se citeste un vector cu n componente numere intregi,unde numerele se


presupun ordonate crescator si o valoare intreaga(nr).Sa se decida daca nr se gaseste
sau nu printer numerele citite,iar in caz afirmativ sa se tipareasca indicele componentei
care contine acea valoare.
Problema este de a decide daca valoarea cautata se gaseste printer numerele de indice cuprins intre i
si j (initial i=1,j=n).Pt aceasta vom proceda astfel:
 Daca nr coincide cu valoarea de indice (i+j)/2 (valoarea de la mijloc),se tipareste indicele si se
revine din apel(problema a fost rezolvata);
Contrar,daca i<j (ni s-a cautat peste tot) problema se descompune astfel:
 Daca numarul este mai mic decat valoarea testate(din mijloc),inseamna ca avem sanse sa-l
gasim intre componentele cu indicele intre i si (i+j)/2-1,caz in care reapelam functia cu acesti
parametrii
 Daca numarul este mai amre decat valoarea testate(din mijloc),inseamna ca avem sanse sa-l
gasimb intre componentele cu indicele intre (i+j)/2+1 si j,caz in care reapelam functia cu acesti
parametrii.
LIMBAJUL PASCAL LIMBAJUL C/C++
CAUTAREA BINARA
{S-a se gaseasca pozitia unui element intr-un vector prin #include <iostream.h>
metoda cautari binare int v[100],n,nr;
OBS:Aplicati divide et impera
ex: void caut(int i,int j)
n=3 { if (nr==v[(i+j)/2])
123 cout<<”gasit”<<’
caut pe 2 ‘<<”indice”<<(i+j)/2;
=>e pe pozitia 2} else
type indice=1..100; if(i<j)
if (nr<v[(i+j)/2])
var a:array[indice] of integer; caut(i,(i+j)/2-1);
nr,n:indice; else caut ((i+j)/2+1,j);
procedure citire; };
var I:indice; main( )
begin { cout<<”n=”;cin>>n;
writeln('n=');readln(n); for (int i=1;i<=n;i++)
for i:=1 to n do { cout<<”v[“<<i<<”]=”;cin>>v[i];}
begin cout<<”nr=”;cin>>nr;
writeln('a[',i,']='); caut(1,n);
readln(a[i]); }
end;end;
procedure afisare;
var i:indice;
begin

112
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

writeln('vectorul sortat este');


for i:=1 to n do
write(a[i]);writeln;readln;
end;
procedure caut(i,j:integer);
begin
if nr=a[(i+j) div 2 ]
then writeln('l-am gasi la pozitia ',(i+j) div 2)
else
if i<j then
if nr<a[(i+j) div 2 ]
then caut (i,(i+j) div 2-1)
else caut ((i+j) div 2+1,j)
end;
begin
citire;
write('pe cine cautai ');
readln(nr);
caut(1,n);
readln;
end.

o Turnurile din Hanoi.Se dau 3 tije simbolizate prin a,b,c.Pe tija a se gasesc discuri de
diameter diferite,asezate in orine descrescatoare a diametrelor private de jos in sus.Se
cere sa se mute discurile de pe tija a pe tija b,utilizand ca tija intermediara tija
c,respectand urmatoarele reguli:
 La fiecare pas se muta un singur disc;
 Nu este permis sa se aseze un disc cu diametrul mai mare peste un disc cu diametrul mai mic.
Rezolvare:
Daca n=1 se face mutarea ab,adica se muta discul de pe tija a pe tija b.
Daca n=2 se fac mutarile ac,ab,cb.
In cazul in care n>2 problema se complica.Notam cu H(n,a,b,c) sirul mutarilor celor n discuri de pe tija a
pe tija b,utilizand ca tija intermediara,toja c.

Conform strategiei Divede et impera incercam sa descompunem problema in alte doua subprobleme
de acelasi tip,urmand apoi combinarea solutiilor.In acest sens,observam ca mutarea celor n discuri de
pe tija a pe tija b,utilizand ca tija intermediara tija c,este echivalenta cu:
 Mutarea a n-1 discuri de pe tija a pe tija c,utilizand ca tija intermediara tija b;
 Mutarea discului ramas pe tija b;
 Mutarea a n-1 discuri de pe tija c pe tija b,utilizand ca tija intermediara tija a.

a b, daca n=1
H(n,a,b,c)=
H(n-1,a,c,b),ab,H(n-1,c,b,a), daca n>1
Pentru n=2 avem: H(2,a,b,c)=H(1,a,c,b),ab,H(1,c,b,a)=ac,ab,cb.
Pentru n=3 avem:
H(3,a,b,c)=H(2,a,c,b),ab,H(2,c,b,a)=H(1,a,b,c),ac,H(1,b,c,a),ab,H(1,c,a,b),cb,H(1,a,b,
c)=ab,ac,bc,ab,ca,cb,ab.

LIMBAJUL PASCAL LIMBAJUL C/C++


TURNURILE DIN HANOI
var a,b,c:string;n:integer; #include <iostream.h>
procedure discurile(n:integer;a,b,c:string); char a,b,c;
begin int n;
if n=1 then
writeln(a,' --se pune pe--> ',b) void han(int n,char a,char b,char c)
else {
begin if (n==1) cout<<a<<b<<endl;

113
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

discurile(n-1,a,c,b); else
writeln(a,'-----se pune pe---> ',b); {
discurile(n-1,c,b,a); han(n-1,a,c,b);
end; cout<<a<<b<<endl;
end; han(n-1,c,b,a);
begin }
write('n=');readln(n); }
a:='mic';b:='mijlociu';c:='mare'; mian ( )
discurile(n,a,b,c); {
readln; cout<<”N=”;cin>>n;
end. a=’a’;b=’b’;c=’c’;
han(n,a,b,c);
}

o Se da o bucata dreptunghiulara de tabla de lungime 1 si inaltimea h,avand pe


suprafata ei n gauri de coordinate numere intregi.Se cere sa se decupeze din ea
o bucata de arie maxima care nu prezinta gauri.Sunt premise numai taieturi
verticale si orizontale.
Coordonatele gaurilor sunt retinute in doi vectori xv si yv.Dreptunghiul initial,precum
si dreptunghiurile care apar in procesul taierii sunt memorate in program prin
coordonatele coltului din stanga-sus (x,y),prin lungime si inaltime (L,H).

Pentru un dreptunghi (initial pornim cu toata bucata de tabla),verificam daca avem


sau nu o gaura in el(se cauta practice prima din cele n gauri).In situatia cand acesta
prezinta o gaura,problema se descompune in alte patru probleme de acelasi tip.Daca
bucata nu prezinta gauri,se compara aria ei cu aria unei alte bucati fara gaura,gasita in
fazele precedente.

Mentionam ca dreptunghiul de arie maxima fara gauri este retinut prin aceiasi
parametric ca si dreptunghiul cu gauri,in zonele XF,YF,LF,HF

In concluzie,problema initiala se descompune in alte patru probleme de acelasi tip,mai


usoare,intrucat fiecare nou dreptunghi are cel mult n-1 gauri,daca dreptunghiul initial
avea n gauri.La aceasta problema compararea solutiilor consta in a retine dreptunghiul
cu aria maxima dintre cele fara gauri.

Fie dreptungiul cu o gaura : h


 xv(i),yv(i)
x,y
Pentru a se afla in interiorul dreptunghiului,gaura trebuie sa indeplineasca simultan
conditiile:
1) xv(i)>x;
2) xv(i)<x+1;
3) yv(i)>y;
4) yv(i)<y+h.
Daca facem o taietura verticala prin aceasta gaura,obtinem doua dreptunghiuri:
1) x,y,xv(i)-x,h;
2) xv,yv(i),1+x-xv(i),h.
In urma unei taieturi pe orizontala se obtin cele doua dreptunghiuri:
1) x,y,1,yv(i)-y;
2) x(i),yv(i),1,h+y-yv(i).
LIMBAJUL PASCAL LIMBAJUL C/C++

114
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

TABLA DREPTUNGHIULARA
TABLA #include <iostream.h>
{SE DAU COORDONATELE COLTURILOR UNEI TABLE int 1,h,I,n,xf,yf,lf,hf,xv[10],yv[10];
DREPTUNGHIULARE SI N GAURI IN EA
Stiind ca se permit numai taieturi orizontale si verticale sa se void dimp(int x,int y,int l,int h,int&
decupeze xf,int&yf,int& lf,int& hf,int xv[10],int yv[10])
o bucata de arie maxima} { int gasit=0,i=1;
type vector=array[1..100] of integer; while (i<=n && !gasit)
var x,y:vector; if (xv[i]>x && xv[i]<l && yv[i]>y &&
n:integer; yv[i]<y+h)
function max(i,j:integer):integer; gasit=1;
begin else i++;
if i<j then max:=j if (gasit)
else { dimp(x,y,xv[i]-x,h,xf,yf,lf,hf,xv,yv);
max:=i; dimp(xv[i],y,l+x-xv[i],h,xf,yf,lf,hf,xv,yv);
end; dimp(x,y,l,yv[i]-y,xf,yf,lf,hf,xv,yv);
function arie(x1,y1,x2,y2:integer):integer; dimp(x,yv[i],l,h+y-yv[i],xf,yf,lf,hf,xv,yv);
var i:integer;nusereducelaunpunct:boolean; }
begin else
i:=1;nusereducelaunpunct:=false; if (l*h>lf*hf)
repeat { xf=x;yf=y;
nusereducelaunpunct:=(x1<x[i]) and(x[i]<x2) and(y1<y[i]) and lf=l;hf=h;
(y[i]<y2);i:=i+1; }
until nusereducelaunpunct or(i=n+1); }
i:=i-1; main ( )
if not nusereducelaunpunct then { cout<<”n=”;cin>>n;
arie:=(x2-x1)*(y2-y1) for(int i=1;i<=n;i++)
else { cout<<”x[“<<i<<”]=”;cin>>xv[i];
arie:=max( max(arie(x1,y1,x[i],y2),arie(x[i],y1,x2,y2)),max(arie(x1,y1,x cout<<”y[“<<i<<”]=”;cin>>yv[i];
2,y[i]),arie(x1,y[i],x2,y2))); }
end; cout<<”l=”;cin>>l;cout<<”h=”;cin>>h;
begin dimp(0,0,l,h,xf,yf,lf,hf,xv,yv);
n:=6; cout<<”x=”<<xf<<”y=”<<yf<<”l=”<<”h=”<<hf
x[1]:=5;x[2]:=7;x[3]:=10;x[4]:=12;x[5]:=13;x[6]:=17; ;
y[1]:=3;y[2]:=4;y[3]:=5;y[4]:=13;y[5]:=16;y[6]:=22; }
writeln(arie(0,0,20,20));readln;
end.

BACKTRACKING
Aspecte teoretice
Aceasta tehnica se foloseste in reezolvarea problemelor care indeplinesc simultan urmatoarele conditii:
 solutia lor poate fi pusa sub forma unui vector S=x1,x2,..,xn,cu x1 apartine de de A1,x2
apartine de A2,…,xn apartine de An;
 multimile A1,A2,…,An sunt multimi finite,iar elementele lor se considera ca se afla intr-o relatie
de ordine bine stabilita;
 nu se dispune de o alta metoda de rezolvare,mai rapida.
Observatii:
 nu pentru toate problemele n este cunoscut de la inceput;
 x1,x2,…,xn pot fi la randul lor vectori;
 in multe probleme,multimile A1,A2,…,An coincide.
Observatie: tehnica Backtracking are ca rezultat obtinerea tuturor solutiilor problemei.In cazul in care se
cere o singura solutie,se poate forta oprirea,atunci cand a fost gasita.
 Pentru usurarea intelegerii metodei,vom prezenta o rutina unica(aplicabila oricarei
probleme),rutina care este elaborate folosind structura de stiva.Rutina va apela functii care au
intotdeauna acelasi nume si care,din punct de vedere al metodei,realizeaza acelasi
lucru.Sarcina rezolvitorului este sa scrie explicit,pentru fiecare problema in parte,functiile
apelate de rutina backtracking.
 Evident o astfel de abordare conduce la programe lungi.Nimeni nun e opreste ca,dupa
intelegerea metodei,sa scriem programe scurte,specifice fiecarei probleme in parte(de

115
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

exemplu,scurtam substantial textul doar daca renuntam utilizarea unor functii,scriind


instructiunile lor chiar in corpul rutinei).
Aplicatii rezolvate iterativ
o Generarea permutarilor.Se citeste un numar natural n.Sa se genereze toate permutarile
multimii {1,2,..,n}.
Generarea permuatrilor se va face tinand cont ca orice permutare va fi alcatuita din elemente distincte
ale multimii A={1,2…,n}.
Prezentam algoritmul corespunzator cazului n=3;
1 2 3

1 2 2 2 2

1 1 1 1 1 1

1 2 3

3 3 3 3 1

1 1 1 1 2 2

1 2 3 1

1 1 1 2 3 3

2 2 2 2 2 2

 se incarca in stiva pe nivelul 1 valoarea 1;


 incarcarea valorii 1 pe nivelul al 2-lea nu este posibila,intrucat aceasta valoare se gaseste sip e
nivelul 1 al stivei;
 incarcarea valorii 2 pe nivelul al 2-lea este posibila,deoarece aceasta valoare nu mai este
intalnita;
 valoarea1 din nivelul al 3-lea se regaseste pe nivelul 1;
 valoarea 2 din nivelul al 3-lea se regaseste pe nivelul al 2-lea;
 valoarea 3 pe nivelul al 3-lea nu e intalnita pe nivelurile anterioare;intrucat nivelul 3 este
completat corect,afisam 1 2 3

Algoritmul continua pana cand stiva devine vida.
o Problema celor n dame.Fiind data o tabla de sah n xn,se cer toate solutiile de aranjare a n
dame,astfel incat san u se afle doua dame pe aceeasi linie,coloana sau diagonala(damele san
u se atace reciproc).
Exemplu:Presupunand ca dispunem de o tabla de dimensiune 4X4,o solutie ar fi urmatoarea:
D

116
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

A doua dama nu poate fi asezata decat in coloana a 3-a.

Observam ca a treia daman u poate fi plasata in linia a 3-a.Incercam atunci plasarea celei de-a doua
dame in coloana a 4-a.
D

A treia daman u poate fi plasata decat in coloana a 2-a.

In aceasta situatie dama a patra nu mai poate fi asezata.Incercand sa avansam cu dama a


treia,observam ca nu este posibil sa o plasma nici in coloana a 3-a,nici in coloana a 4-a,deci o vom
scoate de pe tabla.Dama a doua nu mai poate avansa,deci si ea este scoasa de pe tabla.Avansam cu
prima dama in coloana a 2-a.
D

A doua dama nu poate fi asezata decat in coloana a-4-a.

D
D

117
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Dama a treia se aseaza in prima coloana.

D
D
D

Acum este posibil sa plasam a patra dama in coloana a-3-a si astfel am obtinut o solutie a problemei.

D
D
D
D

Algoritmul continua in acest mod pana cand trebuie scoasa de pe tabla prima dama.

Pentru reprezentarea unei solutii putem folosi un vector cu n componente (avand in vedere ca pe
fiecare linie se gaseste o singura dama).Exemplu:pentru solutia gasita avem vectorul st ce poate fi
asimilat unei stive.
Doua dame se gasesc pe aceeasi diagonala daca si numai daca este indeplinita conditia:l st(i)-st(j) l=li-
jl: diferenta, in modul, intre linii si coloane este aceeasi).

ST(4)
ST(3)
ST(2)
ST(1)

In general ST(i)=k semnifica faptul ca pe linia i dama ocupa pozitia k.

Exemplu: in tabla 4x4 avem situatia:


D st(1)= 1 i=1
st(3)=3 j=3
D l st(1) – st(3) l = l 1-3 l=2
l i-j l = l 1-3 l= 2

sau situatia:

D st(1) = 3 i = 1
st(3) = 1 j=3
D | st(i) – st(j) l|= | 3-1 | = 2
| i-j | = |1-3 | = 2

Intrucat doua dame nu se pot gasi in aceeasi coloana, rezulta ca o solutie este sub forma de permutare.
O prima idee ne conduce la generarea tuturor permutarilor si la extragerea solutiilor pentru
3 problema ( ca doua dame sa nu fie plasate in aceeasi diagonala).A proceda astfel, inseamna
1 ca nu lucram conform strategiei backtracking.
4
2
LIMBAJUL PASCAL LIMBAJUL C/C++
GENERARE PERMUTARI
type sir =array[1..100] of integer; #include <iostream.h>
int st[10],n,k;
var x:sir;
p,i,j,k,n,k1:integer; void Init( )

118
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

as,ev:boolean; { st[k]=0;}
v:string[20];
int Am_Succesor( )
procedure succesor(var x:sir;k:integer;var { if st[k]<n)
as:boolean); { st[k]++;
begin return 1;
if (x[k]<n) then begin }
as:=true; x[k]:=x[k]+1; else return 0;
}
end int E_Valid( )
else { for (int i=1;i<k;i++)
as:=false; if (st[i]==st[k]) return 0;
end; return 1;
}
procedure valid(x:sir;k:integer;var ev:boolean);
var i:integer; int Solutie ( )
begin { return k==n;}
ev:=true;
for i:=1 to k-1 do void Tipar( )
if v[x[k]]=v[x[i]] then ev:=false; {
for (int i=1;i<=n;i++)
end; cout<<st[i];
cout<<ebdl;
}
procedure afis(x:sir;k:integer);
var i:integer; void back( )
begin {int AS;
for i:=1 to n do
k=1;
write(v[x[i]],' ');
Init( );
while (k>0)
writeln;
{ do {}
end;
while ((AS=Am_Succesor( ))
&& !E_Valid( ));
begin
if (AS)
READLN(N);
if (Solutie( ))
write('dati vectorul ');
Tipar( );
readln(v);
for i:=1 to n do else
read(v[i]; {
k:=1; k++;
x[k]:=0; Init( );
while(k>0) do }
begin else k--;
repeat }
succesor(x,k,as); }
if as then valid(x,k,ev) main ( )
until (as and ev) or (not as); { cout<<””n=;cin>>n;
if as then back( );
if (k=n) then }
afis(x,k)
else
begin
k:=k+1;
x[k]:=0;
end
else
k:=k-1 ;
end;
readln;
end.

119
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

LIMBAJUL PASCAL LIMBAJUL C/C++


PROBLEMA DAMELOR
type sir =array[1..100] of integer; #include <iostream.h>
#include <math.h>
var x:sir; int st[100],n,k;
p,i,k,n,s:integer;
as,ev:boolean; void init( )
{ st[k]=0; }
procedure succesor(var x:sir;k:integer;var
as:boolean); int Am_Succesor ( )
begin { if (st[k]<n)
if (x[k]<n ) then begin { st[k]++;
as:=true; x[k]:=x[k]+1; return 1;
}
end else return 0;
else }
as:=false; int E_Valid ( )
end; { for (int i=1; i<k; i++)
if (st[k]= =st[i] l l abs(st[k] –
procedure valid(x:sir;k:integer;var ev:boolean); st[i])= =abs(k-i) ) return 0;
var i:integer; return 1;
begin }
ev:=true;
for i:=1 to k-1 do int Solutie( )
if (x[k]=x[i]) OR (K-i =ABS(X[K]-X[I])) then { return k= =n;}
ev:=false;
void Tipar( )
end; { for (int i=1; i<=n; i++)
cout<<st[i];
cout<<endl;
procedure afis(x:sir;k:integer);
}
var i,j:integer;
void back( )
begin p:=p+1;
{ int AS; k=1;
for i:=1 to n do
Init( );
begin
While (k>0)
{
for j:=1 to n do
do { } while ((AS=Am_Succesor( ))
if x[i]=j then
&& !E_Valid( ));
write('1 ',' ')
else if (AS)
write('0 ',' '); if (Solutie( )) Tipar ( );
else {k++; Init( );}
writeln;end; writeln('------------------'); else k- - ;
}
end; }

begin main( )
{ cout<<”n=”; cin>>n;
write('dati numarul n= '); back( );
readln(n); }
k:=1; p:=1;
x[k]:=0;

while(k>0) do
begin
repeat
succesor(x,k,as);
if as then valid(x,k,ev)
until (as and ev) or (not as);
if as then
if k=n then begin

120
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

writeln('solutia
',p);writeln('==============');
afis(x,k);
end
else
begin
k:=k+1;
x[k]:=0;
end
else
k:=k-1 ;
end;
readln;
end.

LIMBAJUL PASCAL LIMBAJUL C/C++


Tipul enumerare(record)
Type nume_inregistrare=record Struct nume_inregistrare
Camp1:tip1; {
… Camp1:tip1;
campN:tipN; …
end; campN:tipN
var v:nume_inregistrare; } v;
begin MAIN void main()
readln(v.camp1); { struct nume_inregistrare v1;
… cin>>v1.camp1;
readln(campN); …
end. cin>>v1.campN;

cin>>v.camp1;

cin>>v.campN
}

LIMBAJUL PASCAL LIMBAJUL C/C++


Tipul interval( subdomeniu)
Type Nume_inteval=val_minima..valoare_maxima; Nu exista in C++
Var v:Nume_interval;
Begin
Readln(v);
End.

LIMBAJUL PASCAL LIMBAJUL C/C++


Tipul multime

121
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Type nume_multime=set of tip_ordinal; Nu exista in C++


Var v: nume_multime;
Begin
Readln(v);
End.

ALTE TEHNICI DE ELABORARE A ALGORITMILOR

GREEDY

Sa considaram o multime A cu n elemente.Se cere o submultime a sa, eventual


m<=n elemente, astfel incat sa fie indeplinite anumite conditii(acestea difera de la o problema
la alta).
Se considera o multime de n enumere reale..Se cere o submultime a sa astfel incat
suma elemetelor ei sa fie maxima.Pentru rezolvare vom alege un prim element al multimii de
numere reale.Daca este posibil acesta va fi adaugat solutiei,initial vide.Posibilitatea ca acesta
sa fie edagat este data de semnul numarului(acesta trebuie sa fie mai mare ca 0).Se alege un
al doilea numar cu care se procedeaza in mod asemanator.
Algoritmul se incheire cand au fost alese si, 4eventual ,adaugate toate elementele
multimi.
Pentru a rezolva o problema cu Greedy ,solutiia se construieste ,dupa algoritmul de mai jos.
Pentru fiecare element care urmeaza sa fie adaugat solutiei finale, se efectueaza oalegere a
sa dintre elementele multimi A(dupa un mecanism specific fiecarei probleme in parte),iar daca
este posibil,acesta este adaugat.Alghoritmul se termina,fie cand a fost gasita solutia ceruta ,fie
cand afost gasita solutia ceruta fie cand s-a constatat inexistenta acesteia.
Intuitiv,alegem un element,al doilea,.... pana cand obtinem ce dorim sau pana cand au fost
testate toate elementele multimii.De aici provine si numele metodei(greedy=lacom.)
Cel care elaboreaza un algoritm greedy trebuie sa stie faptul ca, procedand in modul ales de
el, se ajunge la rezultatul dorit.Pentru fiecare problema in parte,dupa ce se identifica un
algoritm,este onbligatoriu sa se demonstreze ca acesta conduce la solutia optima.
In general,numarul de operatii de baza efectuate de un algoritm greedy este o expresie
polinomiala -algoritmi sunt performanti
De multe ori este necesar ca elementele multimii A sa fie sortate,pentru ca apoi sa slegem din
acestea.
Intr-o zi trebuie planificate n spectacole.Pentru fiecare spectacol se cunoaste intervalul in care
se desfasoara:[st,sf(.Se cere sa se planifice un numar maxim de spectacole astfel incat sa nu
se suprapuna.
Vom construi o solutie dupa urmatorul algoritm:
P1 Sortam spectacolele dupa ora terminarii lor;
P2 Primul spectacol programat este celo care se termina cel ma devreme;
P3 Alegem primul spectacol dintre cele care urmeaza in sir ultimului spectacol programat care
indeplineste conditia ca incepe dupa ce s-a terminat ultimul spectacol programat;
P4 Daca tentativa de mai sus a esuat (nu am gasit un astfel de spectacol) algoritmul se
termina,astfel se progreameaza spectacolul gasit si algoritmul se reia de la P3

LIMBAJUL PASCAL LIMBAJUL C/C++


SPECTACOLE

122
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

{Dindu-se n spectacole fiecare avind ora de inceput si de sfirsit sa se stabileasca o #include <iostream.h>
ordine a lor ca sa aiba loc un numar maxim de spectacole int s[2][10],o[10],n,i,h1,m
Varianta 1:se dau n compozitori fiecare cu durata lui de viata void sortare( )
Se cere sa se scrie un numar maxim de compozitori contemporani {
VARIANTA 2:Fiind date n intervale sa se determine multimea maxima de intervale int gata,m,i;
disjuncte do{ gata=1;
VARIANTA 3:FIIND DATE DURATA DE INCEPUT SI SFIRSIT LA N MELODII for (i=1;i<=n-1;i++);
CUM LE ORGANIZEZ CIT MAI MULTE PE O BANDA if (s[i][o[i]] s[1][o[i+1]])
} {m=o[i];o[i]=o[i+1];
type spectacol=array[1..2,1..10] of integer; o[i+1]=m;
ordine=array[1..10] of integer; gata=0;
var s:spectacol; }
o:ordine; }
n,i,oradeinceputaspectacoluluicurent,siciteminutearespectacolulcurent, while (!gata)
oradesfirsitaspectacoluluiurmator,siciteminutearespectacolulurmator:integer; }
procedure sortare; main( )
var gata:boolean; { cout<<"n=";cin"n;
variabiladeschib,i:integer; for (i=1;i<=n;i+=)
begin {o[i]=i;
repeat cot<<"ora de inceput pen
gata:=true; spectacolul"<<i<<"( h h)
for i:=1 to n-1 do cin >>h1>m1;
if s[2,o[i]]>s[2,o[i+1]] then s[0][i]=h1*60+m1;
begin cout <<"oradesfarsit pen
variabiladeschib:=o[i]; "<<i<,"(hh mm)=";
o[i]:=o[i+1]; cin>>h2>>m2;
o[i+1]:= variabiladeschib; s[1][i]=h2*60+m2;
gata:=false; }
end; sortare( );
until gata; cout,<<ordinea spectaco
end; este"<<end1<<0[1]<<end
begin ora=s[1][o][1]];
write(' nr de spectacole n='); for (i=2;i<=n;i++)
readln(n); { if (s[0][o[i]]>=ora{cout<
for i:=1 to n do ora=s[1][o[i]];}
begin }
o[i]:=i; }
write ('ora de inceput pentru spectacolul ',i); readln(oradeinceputaspectacoluluicurent);
write ('si cite minute ',i); readln(siciteminutearespectacolulcurent);
write ('ora de sfirsit pentru spectacolul ',i); readln(oradesfirsitaspectacoluluiurmator);
write ('si cite minute ',i); readln(siciteminutearespectacolulurmator);
s[1,i]:=oradeinceputaspectacoluluicurent*60+siciteminutearespectacolulcurent;
s[2,i]:=oradesfirsitaspectacoluluiurmator*60+siciteminutearespectacolulurmator;
end;
sortare;
write('primul este ',o[1]);
for i:=2 to n do
if s[1,o[i]]>=s[2,o[i-1]] then

writeln( 'spectacolul cu numarul de ordine ',o[i]:6);


readln;
end.

 persoana are un rucsac cu ajutorul caruia poate transporta o greutate maxima


G.Persoana are la dispozitie n obiecte si cunoaste pentru fiecare obiect greutatea si
castigul care se obtine in urma transportului sau la destinatie.Se cere sa se precizeze ce
obiecte trebuie sa transporte persoana in asa fel incat castigul sa fie maxim.
O precizare in plus transforma aceasta problema in alte doua probleme distincte.Aceasta
precizare serefera la faptul ca obiectele pot fi sau taiate pentru transportul la destinatie.In

123
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

prima situatie,problema poarta numele de problema continua a rucsacului ,iar in a doua avem
problema discreta a rucsacului.Aceste doua probleme se rezova diferit,mpotiv pentru care ele
sunt prezentate separat .Varianta continua a probelmei rucsacului este tratata in acest
paragraf.Algoritmul este urmatorul:
-se calculeaza,pentru fiecare obiect in parte,eficienta de transport rezultata prin impartirea
castigului la greutate(de fapt,acesta reprezinta castigul optinut din transportul unitatii de
greutate);
-obiectele se sorteaza in ordine descrescatoare a eficintei de transport si se preiau in calcul in
aceasta ordine;
-castigul initial va fi 0 iar greutatea ramasa deincarcat va fi G
-atat timp cat nu a fost completata greuatatea maxima a rucsacului si nu a fost luate un
considerare toate obiectele se procedeaza astfel:
-dintre obiectele neincarcate se selecteaza acela cu cea mai mica eficienta de transport si
avem doua posibilitati:
-acesta incape in totalitate in rucsac.deci se scade din greutatea ramasa de incarcat
greutatea obictului,la castig se cumuleaza castigul datorat transportului acestui obiect;
-se tipareste 1 in sensul ca intregul obiect a fost incarcat;
-obiectul nu incape in totalitate in rucsac,caz in care se calculeaza ce parte din el poate fi
transportata se cumuleaza castigul obtinut cu transportul aceste plati din obiect iar greutatea
ramasa de incarcat devine 0.

LIMBAJUL PASCAL LIMBAJUL C/C++

PROBLEMA RUCSACULUI
{Dindu-se un rucsac de o anumita capacitate si n obiecte care au un cost #include<iostream.h>
si o greutate si stiind ca se poaate lua si double c[9],g[9],ef[9],gv,man,castig;
o parte din fiecare obiect sa se gaseasca o modalitate de cistig maxim int n,i,man1,inv,ordine[9];
transportat cu rucsacul} main( )
type vector=array[1..9] of real; {cout<<''Greutatea ce poate fi transportata='';cin
var i,n,auxiliara1:integer; ef,c,greutateaobiectului :vector; cout<<''Numar de obiecte='';cin>>n;
capacitatearucsacului,auxiliara,cistig:real; for(i=1;i<=n;i++)
inv:boolean; {
ordine:array[1..9] of integer; cout<<''c[''<<i<<'']='';cin>>c[i];
begin cout<<''g[''<<i<<''];cin>>g[i];
write('greutatea ce poate fi transportata in sac '); ordine[i]=i; ef[i]=c[i] /g[i];
readln(capacitatearucsacului); }
writeln(' cite obiecte sunt'); do
readln(n); {
for i:=1 to n do inv=0;
begin for(i=1;i<=n-1;i++)
write('costul obiectului ',i);readln(c[i]); if(ef[i]<ef[i+1])
write('greutatea obiectului ',i);readln(greutateaobiectului[i]); { man=ef[i];ef[i]=ef[i=1];ef[i=1]=man;
ordine[i]:=i; man=c[i]; c[i]=c[i=1]; c[i=1]=man;
ef[i]:=c[i]/greutateaobiectului[i]; man=g[i];g[i]=g[i+1]=man;
end; inv=1;
repeat man1=ordine[i];ordine[i]=ordine[i+1];ordine[i+1]
inv:=false; }
for i:=1 to n-1 do }
if ef[i]<ef[i+1] while (inv);
then i=1;
begin while(gv>o && i<=n)
auxiliara:=ef[i]; {
ef[i]:=ef[i+1]; if (gv>g[i])
ef[i+1]:=auxiliara; { cout <<''Obieclul ''<<ordine[i]<< ' '<<1<<endl;
auxiliara:=greutateaobiectului[i]; gv-=g[i];castig+=+c[i];
greutateaobiectului[i]:=greutateaobiectului[i+1]; }
greutateaobiectului[i+1]:=auxiliara; else
auxiliara:=c[i]; {cout<<''Obiectul ''<<ordine[i]<<' ' <<gv /g[i]<<en

124
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

c[i]:=c[i+1]; castig+c[i]*gv /g[i];


c[i+1]:=auxiliara; inv:=true; gv=0;
auxiliara1:=ordine[i]; }
ordine[i]:=ordine[i+1]; i++;
ordine[i+1]:=auxiliara1; }
end; cout<<''Castig total=''<<castig;
until not inv; }
cistig:=0;
i:=1;
while (capacitatearucsacului>0) and (i<=n) do
begin
if capacitatearucsacului>greutateaobiectului[i] then
begin
writeln('obiectul cu numarul de ordine ',ordine[i],' ',1);
capacitatearucsacului:=capacitatearucsacului-greutateaobiectului[i];
cistig:=cistig+c[i];

end
else
begin
writeln('obiectul cu numarul de ordine ',ordine[i],' intra din el
',capacitatearucsacului/greutateaobiectului[i]:1:2);
cistig:=cistig+c[i]*capacitatearucsacului/greutateaobiectului[i];
capacitatearucsacului:=0;
end;
i:=i+1;
end;
writeln('cistigul maxim este ',cistig:3:2);
readln;
end.

PROGRAMARE DINAMICA
Alaturi de Greedy,programarea dinamica este o tehnica ce conduce, de cele mai
multe ori, la un timp de calcul polinomial.Mai mult, ea furnizeaza in totdeauna solutia
optima .Din nefericire, programarea dinamica nu se poate aplica tuturor problemelor, ci
numai care indeplinesc anumite conditii.
Se considera o problema in care rezultatul se obtine ca urmare a unui sir de decizii D1,
D2,......Dn. In urma decizei D1 sistemul evolueaza din starea S0 in starea S1,in urma
decizei D2 sistemul evolueaza din starea S1 in starea S2,....,in urma decizei Dn sistemul
evolueaza din starea Sn-1 in stareaSn.
Daca D1, D2,....Dn este un sir de decizii care comduce sistemul in mod optim din S0 in
Sn,atunci trebuie indeplinita una din conditiile urmatoare (principiul de optimalitate):
1)Dk...Dn este un sir de decizii ce conduce optim sistemul din starea Sk-1 in starea
Sn,Ak,1<=k<=n;
2)D1....Dk este un sir de decizii ce conduce optim sistemul din starea S0 in
stareaDk,Ak,1<=K<=;
3)Dk+1...Dn,D1...Dk sunt siruri de decizii care conduc optim sistemul starea Sk in starea
Sn, respectiv din starea D0 in starea Sk,Ak,1<=k<=n.
=>Daca principiulde optimalitate se verifica in forma 1,spunem ca se aplica programarea
dinamica metoda inainte.
=>Daca principul de oplimalitate se verifica in forma 2, spunem ca se aplica programarea
dinamica inapoi.
=>Daca primcipiul de optimalitate se verifica in forma 3, spunem ca se aplica programarea
dinamica metoda mixta.

125
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Programarea dinamica se poate aplica problemelor la care optimul general implica optimul
partial.
Faptulca optimul general determina optimul partial, nu inseamna ca optimul partial determina
optimul general.
cu toate acestea, faptul ca potimul general impune optimul partial ne este de mare
ajutor:cautam optimul general,intre optimele partiale, pe care le retinem la fiecare
pas.Oricum,cautarea se reduce considerabil.
Problema triunghiului.Se considera un triunghi de numere naturale format din n
linii.Prima linie contine un numar,a doua doua numere,........ultims n numere naturale.Cu
ajutorul acestuoi triunghi se pot forma sume ne numer naturale in felul urmator:
-se porneste cu numarul din linia unu;
-succesorul unui numar se afla pe linia urmatoare plasat sub el(acees coloana) sau pe
diagonala la dreapta(coloana creste cu 1).
Care este cea mai mare suma care se poate forma astfel si care sunt numerele care o
alcatuiesc:
Exemplu:n=4;
2
3 5
6 3 4
5 6 1 4
Se pot forma mai multe sume:
S1=2+3+6+5=16;
S2=2+5+4+1=12;
Sk=2+3+6+6=17 (care sete[i suma maxim').
Saq observam ca se pot forma 2 la puterea n-1 sume de acest fel.A le lua in considerare pe
toate pentru a gasi valoarea maxima nu este eficient.
Pentru etapa i se trateza linia i a triunghiului.Fie un sir de n numere care respecta conditile
problemei si care formeaza suma maxima.In acest sir,consideram numarul care a fost preluat
de pe linia i.Numerele intre i+1 si n,formeaza o suma maxima in raport cu sumele care se pot
forma incepand cu nu,marul preluat de pe linia i,contrar,se contrazice ipoteza.In aceasta
situatie se poate aplica programarea dinamica,metoda inainte.

Vom forma un triunghi,de la baza catre varf,cu sumele maxime care se pot forma cu fiecare
numar.Daca am citit triunghiul de numere intr-o matrice T si calculam sumele intr-o matrice C
vom avea relatiile urmatoare:
C[n][1]:=T[n][1];
C[n][2]:=T[n][2];
C[n][n]:=T[n][n];
Pentru linia i (i<n), cele i sume maxime care se obtin aqstfel:
C[i][j]=max{T[i][j]+C[i+1][j],T[i][j]+C[i+1][j+1]},i apatine multimii {1,2,....,n-1) iar j apartine multimii
{1,.....,i}.
Sa rezolvam problema propusa ca exemplu:
Linia 4 a matricei C va fi linia n a matricei T:5 6 1 4;
Linia 3 se calculeaza astfel:
C[3][1]=max{6+5,6+6}=12;
C[3][2]=max{3+6,3+1}=9;
C[3][3]=max{4+1,4+4}=8;
Linia 2:
C[2][1]=max{3+12,3+9}=15;
C[2][3]=max{5+9,5+8}=14;
Linia 1
C[1][1]=max{2+15,2+14}=17.
Aceasta este si cea mai mare suma care se poate forma.

126
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Pentru a tipari numerele luate in calcul se foloseste o matrice numita DRUM in care pentru
fiecare i apartinand multimii mai sus mentionate si j la fel apartinand multimii mentionate mai
sus se retine coloana in care se gaseste succesorul lui T[i][j].

LIMBAJUL PASCAL LIMBAJUL C/C++


Problema triunghiului
{Fie un triunghi care are pe prima linie un numar pe a doua doua .... #include<iostream.h>
Sa se calculeze cea mai mare dintre sumele ce aparpe drumurile ce pleaca int t[50][50],c[50][50],drum[50]
din virf si ajung la baza} [50].n,i,j;
const dimmax=100; main()
type numar=0..9;
{ cout<<"n=";cin>>n;
var celcareretinesumamaximademomentpelinie:array[1..dimmax,1..dimmax] of
numar; for (i=1;i<=n;i++)
t,celcareretinepozitiadinliniepentrusumamaxima:array[1..dimmax,1..dimmax] of for (j=1;j<=n;j+=)
numar; { cout <<"t["<<i<<','<<j<<"]=";
d,n,i,j:integer; cin>>t[i][j];}
begin for (j=1;j<=n;j++) c[n][j]=t[n][j];
writeln('cite linii avem in triunghi ');readln(n); for (i=n-1;i>=1;i--)
for i:=1 to n do {for (j=1;j<=i;i++
for j:=1 to i do { for (j=1;j<=n;j++)
begin if (c[i+1][j]<c[i+1][j+1])
writeln('t[',i,',',j,' ]=');
{ c[i][j]=t[i][j]+c[i+1][j+1];drum[i]
readln(t[i,j]);
end; [j]=J+1;
for i:=1 to n do }
begin else
celcareretinepozitiadinliniepentrusumamaxima[n,j]:=j; { c[i][j]=t[i][j]+c[i+1][j];
celcareretinesumamaximademomentpelinie[n,j]:=t[n,j]; drum[i][j]=j;}
end; }
for i:=n-1 downto 1 do cout<<"suma maxima="<<c[1]
for j:=1 to i do [1]<<end1;
if celcareretinesumamaximademomentpelinie[i+1,j] i=1;j=1;
+t[i,j]>celcareretinesumamaximademomentpelinie[i+1,j+1]+t[i,j]
while (i<=n)
then
begin { cout<<t[i][j]<<end1;
celcareretinepozitiadinliniepentrusumamaxima[i,j]:=j; j=drum[i][j];
i++;
celcareretinesumamaximademomentpelinie[i,j]:=celcareretinesumamaximademo }
mentpelinie[i+1,j]+t[i,j]; }
end
else
begin
celcareretinepozitiadinliniepentrusumamaxima[i,j]:=j+1;

celcareretinesumamaximademomentpelinie[i,j]:=celcareretinesumamaximademo
mentpelinie[i+1,j+1]+t[i,j] ;
end;
writeln('suma este ',celcareretinesumamaximademomentpelinie[1,1]);
d:=celcareretinepozitiadinliniepentrusumamaxima[1,1];
writeln(1);
for i:=1 to n-1 do
begin
writeln(celcareretinepozitiadinliniepentrusumamaxima[i,d]);
d:=celcareretinepozitiadinliniepentrusumamaxima[i,d];
end;
readln;
end.

127
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Subsir crescator de lungime maxima.Se considera un ve ctor cu n elementeintregi.Se cere


sa se tipareasca cel mai lung subsir crescator al acestuia.
Exemplu:Pentru n=5 se da V=(4,1,7,6,7).In acest caz subsirul tiparit va fi :4,7,7.
Problema se poate rezolva pornind de la idee a de a calcula ,pentru fiecare element al
vectorului lungimea celui mai lung subsir crescator care se poate forma incepand cu el.In final
este selectat elementul din vector cu care se poate forma cel mai lung subsir crescator si
acesta este listat,
L(k)={1+max L{i}/V{i}>=V(k). i apartine multimii {k+1,...,n} iar k apatrtine multimii {1,2,....,n}.
In practica,folosim un vector L cu n componente,unde L(k) are semnificatia explicata.Pentru
examenul nostru vom avea:
L=(3,3,2,2,1).
Componentele vectorului L au fost calculate astfel:
-cel mai lung subsir care se poate forma cu elementul 7,aflat pe ultima pozitie,are lungimea 1;
-cel mai lung subsir care se poate forma cu elementul 6 aflat pe pozitia 4 are lungimea
(1+L(5)), pentru ca pe pozitia 5se gaseste elementul 7 care este mai mare decat 6;
-cel mai lung subsir care se poate forma cu elementul aflat pe pozitia 3 are lungimea2(1+L(5))
pentru ca 7 este egal cu 7;
-algoritmul continua in acest mod pana se completeazaL(1).
Dupa aceasta se calculeaza maximul dintre componentele luiL,iar cel mai lung subsir
crescator format din elementele vectoruluiV vaavea lungimea data pe acest maxim. Pentru a
lista efectiv acel subsir de lungime maximala se procedeaza astfel:
-se cauta mazimul din vectorulL precum si indicele t,la care se gaseste acest maxim;
-se afiseazaV(t);
-se gaseste si se listeaza primul element care este mai mare sau egel cu V(t) si are lungimea
mai mica cu 1(max-1), se actualizeaza valoarea max cu max-1;
-algoritmul continua pana cand se epuizaza toate elementele subsirului.

LIMBAJUL PASCAL LIMBAJUL C/C++


SUBSIR OPTIM
{Sa se calculeze cit e lungimea unui subsir crescator al #include<iostream.h>
unui sir initial int v[20],1[20],n,i,k,max,t;
in cazul in care este maxima} main()
var v:array[0..20] of integer; {
n,i:integer;
cout<<''n=''; cin>>n; for(i=1;i<=n;i++)
function lungime(k:integer):integer;
var max,i:integer; {cout<<''v[''<<i<<'']='';cin>>v[i];}
begin 1[n]=1;
if k=n then lungime:=1 else for(k=n-1;k>=1;k--)
begin {max=0;
max:=0; for(i=k+1;i<=n;i++)
for i:=K+1 to n do if (v[i]>=v[k]&& 1 [i]>max)
if (max<lungime(i)) and (v[i]>=v[k]) then max=1[i];
max:=lungime(i); 1[k]=1+max;
Lungime:=max+1; }
end;
max=i[1]; t=1;
end;
begin for(k=1; k<=n;k++)
write('cite elemente are sirul ');readln(n); if (i[k]>max)
v[0]:=0; {max=i[k]; t=k;}
for i:=1 to n do cout<<''lungimea
begin maxima:''<<max<<end1<<v[t]<<end1
writeln('v[',i,']='); ;
readln(v[i]); for(i=t+1;i<=n;i++)
end; if (v[i]>v[t]&& 1 [i] ==max-1)
writeln(' lungimea maxima este ',lungime(0)-1); {cout<<v[i] << end1;
readln;
max--;
end.
}

128
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Inmultirea optima a unui sir de matrice


Presupunem ca avem inmultiti doua matrice:An,p cu Bp,m.In mod evident, rezultatul
va fi o matrice Cn,m.Se pune problema de a afla cate inmultiri au fost facute pentru a obtine
matricea C. Prin inmultirea liniei 1 cu coloana 1 se fac p inmultiri, intrucat au p elemente. Dar
linia 1 se inmulteste cu toate cele m coloane, deci se fac m*p inmultiri.In mod analog se
procedeaza cu toate cele n linii ale matricei A,deci se fac n*m*p inmultiri.Retinem acest
rezultat.

Sa consideram produsul de matrice A1xA2x....xAn (A1(d1,d2),A2(d2,d3)...,An(dn,dn+1)).Se


cunoaste ca legea de compozitie produs de matrice nu este comutativa in schimb este
asociativa.De exemplu ,daca avem de inmultit trei m atrice A,B,C produsul se poate face in
doua moduri:(AxB) xC; Ax(BxC).Este interesant de observat ca nu este indiferent modul de
inmultire a celor n matrice.Sa considera ca avem de inmultit patru matrice
A1(10,1),A2(1,10),A3(10,1),A4(1,10).
Pentru inmultirea lui A1 cu A2 se fac 100 de inmultiri si se obtine o matrice cu 10 lini si 10
coloane.Prin inmul tirea acesteia cu A3 se fac 100 de inmultiri si se obtine o matrice cu 10 linii
si o coloana.daca aceasta matrice se inmulteste cu A4 se fac 100 inmultiri. In concluzie, daca
acest produs se efectueaza in ordine naturala,se efectueaza 300 inmultiri.
Sa efectuam acelas produs in ordinea care rezulta din expresia A1x((A2XA3) x A4).Efectuand
produsul A2 cu A3 se efectueaza 10 inmultiri si se obtine o matrice cu o linie si cu o
coloana.aceasta matrice se inmulteste cu A4 se fac 10 inmultiri si se obtine o matrice cu 1 linie
si 10 coloane.Daca o inmultim pe aceasta cu prima, efectuam 100 inmtltiri , obtinand rezultatul
final cu numai 120 de inmultiri.
In concluzie,apare o problema foarte interesanta si anume de a afla modul in care trebuie sa
se inmulteasca cele n matrice,astfel incat nr de inmultiri sa fie minim.Pt rezolvare vim aplica
principiul 3 al programari dinamice.

In vederea rezolvari problemei,retinem o matrice A cu n linii si n coloane.Elementul A(i,j)


i<j,reprzinta nr minim de inmultiri pt efectuarea produsului AixAi+1x....xAj.De asemenea,nr
liniilor si al coloanelor celor n matrice sunt retinute intrun vector DIM cu n+1 componente.Pt
exemplu nostru DIM retine urmatoarele valori:10,1,10,1,10.
Pt rezolvare se tine cont de urmatoarele relatii existente intre cimponentele matricei A:
1)A(i,i)=0;
2)A(i,i+1)=DIM(i)xDIM(i+1)xDIM(i+2);
3)A(i,j)=min{A(i,k)+A(k+1,j)+DIM(i)xDIM(k+1)xDIM(j+1)}.
i<=k<j
Justificarea acestor relati este urmatoarea:
1)o matrice nu se inmulteste cu ea insasi,deci se efectueaza 0 inmultiri;
2)liniile si coloanele matricei A1 se gasesc in vectorul DIM pe pozitiile i si i+1, iar ale matricei
Ai+1-pe pozitiile i+1 si i+2;
3)
-inmultind matriceleAi x Ai+1 x Ak se obtine o matrice cu un nr de linii egal cu acela al matricei
Ai (DIM(i)) si cu un nr de coloane egal cu acela al matricei Ak (DIM(k+1));
-inmultind matricele Ak+1 x.....x Aj se obtine o matrice cu un nr de linii egal cu acela al
matricei Ak+1 (DIM(k+1)) si cu un nr de coloane egal cu acela al matricei Aj (DIM(j+1));
-prin inmultirea celor doua matrice se obtine matricea rezultat al inmultirii Aix....xAj, iar pt
aceasta inmultire de matrice se efectueaza DIM(i) xDIM(k+1) xDIM(j+1) inmultiri;
~Relatia sintetizeaza faptul ca pt a obtine nr de inmultiri optim pt produsul Aix....xAj se
inmultesc doua matrice, una obtinuta ca produs optim intre Aix....xAk si cealalalta obtinuta ca
produs optim intre Ak+1x....xAj, in ipoteza in care cunoastem nr de inmultiri necesar efectuarii
acestor doua produse orucare ar fi k, cuprins intre limitele date.

129
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

~Aceasta observatie este o consecinta directra a programarii dinamice si anume ca produsul


efectuat optim intre matricele prezentate se reduce in ultima istanta la a efectua un produs
intre 2 matrice cu conditia ca acestea sa fie calculate optim(produsul lor sa aiba un numar
minim de inmultit).
Se pune problema cum putem efectua acest calcul utilizand relatiile prezentate.Pentru
exemplificare vom utiliza exemplul dat la inceputul acestui capitol.Datorita relatiei 1, diagonala
pricipala a maricei A( cu 4 lini si 4 coloane) va fi alcatuita numai din elemente avand valoarea
0. s
Initial se pot calcula numai elemente A(i,i+1),adica A(1,2),A(2,3),A(3,4)-elemente situate pe o
paralela la digonala principala a matricei A.Este cazul sa observam ca portiunea din matrice
situata sub diagonala principala este neeutilizata.In concluzie,avem
A(1,2)=100,A(2,3)=10,A(3,4)=100.Matricea A va arata astfel:

0 100 x x
x 0 10 x
A= x x 0 100
x x x 0

In continuare calculam:
A(1,3)=min{A(1,k)
+A(k+1,3)+DIM(1)*DIM(k+1)*DIM(4)}=min{0+10+10*1*1,100+0+10*10*1}=20;
A(2,4)=min{A(2,k)
+A(k+1,4)+DIM(2)*DIM(k+1)*DIM(5)}=min{0+100+1*10*10,10+0+1*1*10}=20;
A(1,4)=min{A(1,k)
+A(k+1,4)+DIM(1)*DIM(K+1)*DIM(5)}=min{0+20+10*1*10,100+100+10*10,20+0+10*1*10}=12
0;

.
0 100 20 120
x 0 10 20
A= x x 0 100
x x x 0
In concluzie,pt. exemplul nostru, se fac minim 120 de inmultiri,rezultat luat din matricea A si anume
A(1,4).
LIMBAJUL PASCAL LIMBAJUL C/C++
Inmultiri optimale de matrice
#include<iostream.h>
{Prin programare dinamica sa se determine numarul minim de int i,n,dim[10]
inmultiri care sa se faca long a[10] [10];
cind se dau dimensiunile matricelor
ex:n=4 void costopt(int n,int dim[10],long
10 1 10 1 10} a[10] [10])
{int k,i,j,l;
program inm_optima; long m;
const nmax=20; for (i=1;i<=n;i++) a[i] [i]=0;
type vector=array[1..nmax] of word; for (k=1;k<=n-1;K++)
tabl=array[1..nmax,1..nmax] of word; for (i=1;i<=n-k;i++)
var p:vector; { j=i+k;
m:tabl;n,i,j,k,imin:integer;min,v:word; a[i] [j]=100000;
procedure paranteze(i,j:integer); for(l=i;l<=j;l++)
var k:integer; {m=a[i] [l] +a[l+1] [j]
begin +dim[i]*dim[l+1]*dim[j+1];
if i<j then begin if (a[i] [j]>m)
k:=m[j,i]; {
if i<>k then begin a[i] [j]=m;;
write('('); a[j] [i]=l;

130
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

paranteze(i,k); }
write(')'); }
end }
else paranteze(i,k); cout<<"cost optim:"<<a[1]
write('x'); [n]<<end1;
if k+1<>j then begin
write('('); }
paranteze(k+1,j); main()
write(')') {cout<<"n=";cin>>n;
end for (i=1;i<=n+1;i++)
else paranteze(k+1,j); { cout<<"d=";cin>>dim[i];}
end costopt(n,dim,a);
else write('A',i) }
end;
begin
write('Nr. de matrici:');
readln(n);
writeln('Dimensiuni matricelor:');
for i:=1 to n+1 do read(p[i]);
for i:=n downto 1 do
for j:=i+1 to n do
begin
min:=m[i,i]+m[i+1,j]+p[i]*p[i+1]*p[j+1];
imin:=i;
for k:=i+1 to j-1 do
begin
v:=m[i,k]+m[k+1,j]+p[i]*p[k+1]*p[j+1];
if min>v then begin
min:=v;
imin:=k
end;
end;
m[i,j]:=min;
m[j,i]:=imin;
end;
writeln('Numarul minim de inmultiri este:',m[1,n]);
writeln('Aceasta se obtine pentru urmatoarea ordine a
inmultirilor');
paranteze(1,n);
readln;
end.

LIMBAJUL PASCAL LIMBAJUL C/C++


Tipul pointer
Atribuirea functioneaza numai pentru aceleasi tipuri de pointer in dreapta si stanga atribuirii
Type nume_pointer= ^ tip; Tip *nume_pointer;
Var v:nume_pointer; Exemplu:
Exemplu: Main void main()
Type adr=^integer; {
Var a1,a2:adr; Int *a1,*a2;
Begin a1=a2;
a1:=a2; }
End.
LIMBAJUL PASCAL LIMBAJUL C/C++
Adresa pentru tipul pointer

131
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Var x:integer; Void main void()


A:^integer; { int x,*a=&x;
Begin x=10;
X:=10; cout<<*a;
A=@x; }
Write(a^);
End.

Alocare dinamica
Memoria interna poate fi privita ca o succesiune de octeti.Numarul de ordine
al unui octet se numeste adresa lui.Adresa unei variabile nu trebuie confundata cu
valoarea pe care aceasta o memoreaza.
Definitie: Adresa primului octet al variabilei se numeste adresa variabilei.
Adresele variabilelor se memoreaza cu ajutorul variabilelor de tip pointer.
LIMBAJUL PASCAL LIMBAJUL C/C++
Alocarea spatiului pentru variabila poiter p si elberarea lui
Procedure new(var p:pointer); P=new p;
Procedure dispose (var p :pointer); Delete p;
Ex: Ex:
Var adr1:^integer; Void main ()
New(adr1);adr^:=7; {
Writeln(adr1);dispose(adr1); int * adr1;
End; adr1=new int;
adr =7;cout<<*adr1;
delete adr1;
}
Tipul enumerare
LIMBAJUL PASCAL LIMBAJUL C/C++

Type Nume_enumerare=(v0,v1,…,v n-1); Enum nume_enumerare {v0,v1,…,


Type zile=(sambata,dumineca,luni); vn-1 }
Var azi:zile; Exemplu:
Begin Void main()
Azi:=luni; {
Write(azi); enum zile
End. {
sambata,
dumineca,
luni
} azi;
enum zile azi1;
azi1=dumineca;
azi=luni;
cout<<azi;
}
Tipul inregistrare cu structura variabila
LIMBAJUL PASCAL LIMBAJUL C/C++

union nume_enumerare
{
tip v0;
tip v1;

tip vn-1;
};
Exemplu:
#include< iostream.h>

132
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

union test
{ int a;
char b[10];
double c;
};
main()
{
test var;int I;
cin>>var.c;cout<<var.c<<endl;
cin>>var.c;cout<<var.c<<endl;

}
Siruri de caractere
LIMBAJUL PASCAL LIMBAJUL C/C++

SINTAXA: SINTAXA:
TYPE NUME=string[dimensiune]; Char nume[dimensiune] ;
Var variabila:nume; Char nume[dimensiune] =”sirul”;
Sau: Ex:
Var variabila:string[dimensiune]; #Include<iostream.h>;
Variabila[0] este lungimea sirului main()
Are maxim 255 de caractere {
Ex: char a[20];
Var a:string[3]; cin>>a;
Begin cout<<a;
A:=”cal”; }
Write(a); obs:
End. a[0] reprezinta prima componenta
a sirului
Functii care lucreaza cu siruri de caractere
LIMBAJUL PASCAL LIMBAJUL C/C++
LUNGIMEA UNUI SIR DE CARACTERE
Sintaxa: Sintaxa:
Variabila :=Length(sir); #include<string.h>
Ex: Variabila:= strlen (sir);
Var s: string; Ex:
Begin #include<iostream.h>
Readln(s); #include<string.h>
Writeln(length(s); main()
End. {
char a[100];
cin.get(a,100);
cout<<”sirul este de lungimea
“<<strlen (a);
}

LIMBAJUL PASCAL LIMBAJUL C/C++


CONCATERNARE(ALATURAREA) ADOUA SIRURI DE CARACTERE
Sintaxa: Sintaxa:
SIRdestinatie:=CONCAT(SIRsursa,SIR2); #include<string.h>
Ex: STRCAT (sirDESTINATIE,sirSURSA);
Var s1,S2,S3: string; Ex:
Begin #include<iostream.h>
Readln(s2); #include<string.h>
READLN(S3); main()
S1:=CONCAT(s2,S3); {
Writeln (s1); char a[100]=”MAMA”,B[100]=”TATA”;
End. strcat(a,b);
SAU: cout<<”sirul este “<<a;

133
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Var s1,S2,S3: string; }


Begin
Readln(s2);
READLN(S3);
S1:= s2+S3;
Writeln (s1);
End.

LIMBAJUL PASCAL LIMBAJUL C/C++


COPIEREA UNUI SIR DE CARACTERE de la sursa LA DESTINATIE
Sintaxa: Sintaxa:
SIRdestinatie:=COPY(SIRsursa,POZITIA_initialadecopiat,POZITIA_finala); #include<string.h>
Ex: STRCPY (sirDESTINATIE,sirSURSA);
Var s1,S2: string; Ex:
Begin #include<iostream.h>
Readln(s2); #include<string.h>
S1:=copy(s2,1,length(s2)-2); main()
{
Writeln (s1); char a[100]=”MAMA”,B[100]=”TATA”;
End. strcpy(a,b);
cout<<”sirul este “<<a;
}
LIMBAJUL PASCAL LIMBAJUL C/C++
CAUTAREA UNUI SIR DE CARACTERE
Sintaxa: Sintaxa:
VARIABILA_de_tip_intreag:=pos(SIRsursa,CINE_se_cauta); #include<string.h>
Ex: STRSTR(sirDESTINATIE,sir_DE_cautat
Var s1,S2: string;p:integer; ;
Begin Ex:
Readln(s2); #include<iostream.h>
Readln(s1); #include<string.h>
p:=pos(s1,s2); main()
Write(p); {
End; char a[100]=”MAMA”,B[100]=”M”;
strchr(a,b);
cout<<”sirul este “<<strchr(a,b);
}

LIMBAJUL PASCAL LIMBAJUL C/C++


COMPARAREA A DOUA SIRURI DE CARACTERE
Sintaxa: Sintaxa:
VARIABILA_logica:=SIR1 operator_relational SIR2; #include<string.h>
Ex: STRCMP(sir1,sir2);
Var s1,S2: string;p:boolean; Ex:
Begin #include<iostream.h>
Readln(s2); #include<string.h>
Readln(s1); main()
p:=s1<s2; {
if p then write(“mai mare”) int s;
else write(“mai mic”);; char a[100]=”MAMA”,B[100]=”M”;
End. s=strcmp(a,b);
if (s<0)
cout<<”sirul este s1< s2 “;
else
if (s>0)
cout<<”sirul este s1>s2 “;
else
cout<<”sirul este s1=s2 “
}

134
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

LIMBAJUL PASCAL LIMBAJUL C/C++


STREGEREA DINTR-UN SIR
Sintaxa:
DELETE(SIRsursa,DE_UNDE_STERG,pana_in_ce_pozitie);
Ex:
Var s1: string;
Begin
Readln(s1);
delete(s1,1,length(s1)-2);
Write(s1);
End.

LIMBAJUL PASCAL LIMBAJUL C/C++


INSERAREA INTR-UN SIR A ALTUI SIR
Sintaxa:
INSERT(SIRsursa_UNDE_inserez,pe_cine_inserez,pozitia_de_unde_fac_ins
erarea);
Ex:
Var s1,S2: string;
Begin
Readln(s1);readln(s2);
insert(s1,s2,3);
Write(s1);
End.

LIMBAJUL PASCAL LIMBAJUL C/C++


CONVERSII LA SIRURI DE CARACTERE DIN NUMAR IN STRING
Sintaxa: Sintaxa:
STR(NUMAR:cate_zecimale,cate_unitati,SIRUL_string); #include<string.h>
Ex: #INCLUDE<STDLIB.H>
Var s1: string;p:integer; ITOA(NUMAR,sir2,BAZA);
Begin Ex:
Readln(p); #include<iostream.h>
Str(p:10,s1); #include<string.h>
Write(s1); #INCLUDE<STDLIB.H>
End. main()
Ex: {
Var s1: string;p:real; char a[100],*AA;
Begin long v;
Readln(p); cin>>a;
Str(p:10:2,s1); v=strtol(a,@aa,10);
Write(s1); cout<<v;
End. }

LIMBAJUL PASCAL LIMBAJUL C/C++


CONVERSII LA SIRURI DE CARACTERE DIN STRING IN NUMAR
INTREG SI IN REAL
Sintaxa: Sintaxa:
VAL(SIRUL_string ,NUMAR,INDICATOR_NUL_DACA_E_bine); #include<string.h>
Ex: #INCLUDE<STDLIB.H>
Var s1: string;p,k:integer; STRTOI(sir1);
Begin STRTOL(sir1);
Readln(s1); STRTOF(sir1);
val(s1,p,k); STRTOLD(sir1);
if k=0 then STRTOD(SIR1);
Write(p); STRTOD(SIR1);
End. Ex:
#include<iostream.h>
#include<string.h>
#INCLUDE<STDLIB.H>

135
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

main()
{
int s;
char a[100]=”11.2001”;
s=strtoi(a);
cout<<p;
}
#include<iostream.h>
#include<string.h>
main()
{
FLOAT s;
char a[100]=”11.2001”;
s=strtof(a);
cout<<p;
}

Structura de tip stivă

Stiva este o listă pentru care singurele operaţii permise sunt:

● Adăugarea unui element în stivă;


● Eliminarea, consultarea, sau modificarea ultimului element introdus în stivă.

Stiva funcţionează pe principiul LIFO (Last In First Out) – “ultimul intrat, primul ieşit”.

Pentru a înţelege modul de lucru cu stiva, ne imaginăm un număr n de farfurii identice, aşezate
una peste alta (o “stivă” de farfurii). Adăugarea sau scoaterea unei farfurii se face, cu uşurinţă, numai în
vârful stivei. Oricât ar părea de simplu principiul stivei, el are consecinţe uriaşe în programare.

Stivele se pot aloca secvenţial (ca vectori). Fie ST[i] un vector. ST[1], ST[2], … , ST[n] pot reţine numai
litere sau numai cifre. O variabilă k indică în permanenţă vârful stivei, adică ultimul element introdus.

În stivă iniţial vidă se introduce litera A, vârful stivei va fi la nivelul 1,


(k=1);
A
B
A
Introducem în stivă litera B, deci k va lua valoarea 2.

Scoatem din stivă pe B (A nu poate fi scos deocamdată); k=1

Scoatem din stivă pe A; stiva rămâne vidă k=0

Observaţii:

În mod practic, la scoaterea unei variabile din stivă, valoarea variabilei ce indică vârful stivei scade cu 1, iar atunci
când scriem ceva în stivă, o eventuală valoare reziduală se pierde.

136
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Pe un anumit nivel se reţine, de regulă, o singură informaţie (literă sau cifră), însă este posibil, aşa cum va rezulta
din exemplele prezentate în lucrare, să avem mai multe informaţii, caz în care avem stive duble, triple, etc.

În cazul stivei, alocarea secvenţială nu prezintă mari dezavantaje, ca în cazul mai general, al listelor, pentru că nu
se fac operaţii de inserare sau ştergere în interiorul stivei. Singurul dezavantaj, în comparaţie cu alocarea dinamică
înlănţuită este dat de faptul că numărul de noduri care pot fi memorate la un moment dat este mai mic – depinde de
gradul de ocupare al segmentului de date.

În literatura de specialitate veţi întâlni termenul PUSH pentru operaţia de adăugare în stivă a unei înregistrări şi
POP, pentru extragere.

Exemple:

137
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

□ Funcţia Manna-Pnueli. Se citeşte xЄZ. Se cere programul pentru calculul funcţiei:

F(x)= x-1, x≥12


F(F(x+2)), x<12

Vom începe prin a studia modul de calcul al funcţiei pentru x=15 şi x=8.

f(15)=14;
f(8)=f(f(10))=f(f(f(12)))=f(f(11))=f(f(f(13)))=f(f(12))=f(11)=f(f(13))= f(12)=11.
Algoritmul va folosi o stivă ST şi o variabilă k, ce indică în permanenţă vârful stivei. Algoritmul se
bazează pe următoarele considerente:
■ la o nouă autoapelare a funcţiei f, se urcă în stivă (k se incrementează cu 1) şi se pune noua valoare.

■ în situaţia în care pentru valoarea aflată pe nivelul k se poate calcula funcţia, se coboară în stivă, punându-se pe
acest nivel noua valoare.

■ algoritmul se încheie când se ajunge în stivă la nivelul 0.

Pentru exemplul dat, prezentăm schematic funcţionarea sa:

12 13

10 10 11 11
8 8
8 8 8

12 13
11 12
8 11
f=11

□ Programul următor calculează funcţia Manna-Pnueli, utilizând


stiva alocată dinamic. Lucrul cu stiva se face prin utilizarea funcţiilor
PUSH (PUNE) şi POP (SCOATE).
LIMBAJUL PASCAL LIMBAJUL C/C++
STIVA-MANNA PNUELI
{ Functia lui MaNa-Pnueli.calculati f(x)=x- STATIC
1 daca x>=12 #include <iostream.h>
alfel f(x)=f(f(x+2)) daca x<12 int st[100], n, k;
ex:x=8 main( )
=>11} { cout<<”n=”; cin>>n;
program stiva1; k=1; st[1]=n;
const nmax=5; while (k>0)
type stiva=array[1..nmax] of byte; if st([k]<12)
var a: stiva; { k++;
dim,n,i:byte; st[k]=st[k-1]+2;
x,y:byte; }

138
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

function vida(x:stiva;dim:byte):boolean; else


begin { k--;
if dim >0 then vida:=false else vida:=true; if (k>0) st[k]=st[k+1]-1;
end; }
cout<<”n=”<<st[1]-1;
function plina(x:stiva;dim:byte):boolean; }
begin
if dim <nmax then plina:=false else DINAMIC
plina:=true; #include <iostream.h>
end; struct Nod
procedure adaug(var x:stiva;var { int info;
dim:byte;y:byte); Nod* adr_inap;
begin };
inc(dim); Nod* v;
x[dim]:=y; Int n;
end; Void Push(Nod*& v, int n)
{ Nod* c;
function elimin(var x:stiva;var if (!v)
dim:byte):byte; { v= new Nod; v->info=n; v-
begin >adr_inap=0;}
elimin:=x[dim] ; else
dec(dim); { c= new Nod; c->info=n; c-
end; >adr_inap=v;
v=c;
begin }
write('x=');readln(x); }
adaug(a,dim,x); void Pop (Nod*& v)
while not vida(a,dim) do
{ Nod* c;
begin
if (!v) cout<< ”stiva este vida”;
y:=elimin(a,dim);
else
for i:=1 to dim do
{ c=v;
writeln(a[i]);writeln;
cout<<” am scos”<<c-
if y>=12 then {writeln('valoarea functiei
>info<<end1;
se poate calcula direct') }
v=v->adr_inap;
if not vida(a,dim) then a[dim]:=y-1
delete c;
else
}
else
begin }
adaug(a,dim,y); main( )
for i:=1 to dim do { int Man;
writeln(a[i]); writeln; cout<<”n=”; cin>>n;
adaug(a,dim,y+2); Push(v,n);
for i:=1 to dim do While (v)
writeln(a[i]); If (v->info<12)
end; Push(v, v->info+2);
end; Else
write('manna pnueli(',x,')=',y-1); { Man=v->info;
end. Pop(v);
DINAMIC If (v) v->info=Man-1;
{Sa se simuleze formula lui manna pnueli cu stive pentru a se }
pune cout<<”f=”<<Man-1;
in evidenta operatiile in stiva f(x)=x-1 dacax>=12 alfel
f(x)=f(f(x+2))
ex:n=8}
program stiva;
type adresa=^nod;
nod=record
info:integer;
adr_inap:adresa;
end;
var v:adresa;

139
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

n,man:integer;
procedure push(var v:adresa;n:integer);
var c:adresa;
begin
if v=nil then
begin
new(v);
v^.info:=n;
v^.adr_inap:=nil;
end
else
begin
new(c);
c^.info:=n;
c^.adr_inap:=v;
v:=c;
end;
end;
procedure pop(var v:adresa);
var c:adresa;
begin
if v=nil then writeln('stiva este vida')
else
begin
c:=v;
v:=v^.adr_inap;
dispose(c)
end;
end;
procedure tipar(v:adresa);
var c:adresa;
begin
c:=v;
while c<> nil do
begin
writeln(c^.info);c:=c^.adr_inap;
end;
end;
begin
write('n=');
readln(n);
push(v,n);
while v<>nil do
if v^.info <12 then
begin
push(v,v^.info+2);
tipar(v); readln;
end
else
begin man:=v^.info;
pop(v);
tipar(v);
readln;

if v<>nil then v^.info:=man-1;


end;
writeln('f=',man-1) ;
readln;
end.

140
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

DINAMIC IN GENERAL
{Sa se creeze o stiva.
Scrieti doua proceduri diferite care
elimina elemente in stiva}
type ref=^inr;
inr=record
nr:integer;
urm:ref;
end;
var p:ref;
i,n:integer;
procedure b(var p:ref);
var c:ref;
begin
new(c);
writeln(' pe cine pui in stiva
');readln(c^.nr);
c^.urm:=p;
p:=c;
end;
procedure s(var p:ref);
var c:ref;
begin
if p=nil then
writeln(' goala ')
else
begin
writeln(' scot din stiva pe');
writeln(p^.nr);
c:=p;
p:=p^.urm;
dispose(c);
end;
end;
procedure s1(var p:ref);
var q:ref;
begin
q:=p;
p:=q^.urm;
dispose(q);
end;

begin
write('dati un numar n>=3 ');
readln(n);
for i:=1 to n do
b(p);
writeln('-----------elimin elementul din
virful stivei');
s1(p);
for i:=1 to n do
s(p);

readln;
end.

□ Funcţia lui Ackermann. Se dă funcţia următoare, definită pe produsul cartezian NXN.. Se citesc m şi
n. Să se calculeze Ack(m, n).

141
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

| n+1, m=0
Ack(m,n)= | Ack(m-1, 1), n=0
| Ack(m-1, Ack(m, n-1)), altfel

Pentru a elabora algoritmul, studiem un exemplu numeric:

ack(2,1)=ack(1,ack(2,0))=ack(1, ack(1,1))=ack(1, ack(0, ack(1,0))= ack(1, ack(0, ack(0,1))=ack(1,


ack(0,2))=ack(1,3)=ack(0, ack(1,2))= ack(0, ack(0, ack(1,1))=ack(0, ack(0, ack(0, ack(1,0))))= ack(0,
ack(0, ack(0, ack(0,1))))=ack(0, ack(0, ack(0,2)))=ack(0,,ack(0,3))= ack(0,4)=5.

Pentru calculul acestei funcţii, folosim o stivă dublă, ST. Iniţial, valorile m şi n se reţin la nivelul 1. Pe
nivelul k al stivei se reţin valorile curente m şi n. În funcţie de valorile acestora se procedează astfel:

■ pentru m şi n diferite de 0, este necesar un nou calcul de funcţie, caz în care se urcă în stivă şi pe noul
nivel se pun argumente m şi n-1.

■ pentru cazul n=0, se rămâne pe acelaşi nivel în stivă, punând în locul lui m valoarea m-1, iar în locul
lui n valoarea 1.

■ în situaţia în care m=0, funcţia se poate calcula; se coboară în stivă şi se înlocuieşte valoarea lui m cu
m-1, valoarea lui n cu valoarea calculată anterior.

În continuare, prezentăm grafic modul de funcţionare a algoritmului pentru exemplul ack(2,1):

10 01
20 11 11 11
21 21 21 21 21

10
01 11 11
11
02 02 13 12 12
12
21 12
13 03
12 13 13
13 13 13 04

ack(2,1)=5.

LIMBAJUL PASCAL LIMBAJUL C/C++


AKERMAN
VAR ST:ARRAY[0..1000,0..2] OF INTEGER; int st[10000] [2];
M,n,k:integer; main( )
Begin { int m, n, k;
Readln(m,n); cout<<”m=”; cin>>m;
K:=1; cout<<”n=”; cin>>n;
st[k,0]: =m; st[k,1] :=n; k=1; st[k] [0] =m; st[k] [1] =n;

142
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

while (k>0) do while (k>0)


if (st[k,0]>0 and st[k,1]>0) if (st[k] [0] && st[k] [1])
begin {
k:=k+1; k++;
st[k,0] =st[k-1,0]; st[k] [0] =st[k-1] [0];
st[k,1] =st[k-1,1] – 1; st[k] [1] =st[k-1] [1] – 1;
end }
else else
if (st[k,1]<>0) if (!st[k] [1])
begin {
st[k,0] =st[k,0] – 1; st[k] [0] =st[k] [0] – 1;
st[k,1] = 1; st[k] [1] = 1;
end }

else else
begin {
k:=k-1; k--;
if (k>0) if (k>0)
{ st[k,0] =st[k,0] – 1; { st[k] [0] =st[k[] [0] – 1;
st[k,1] =st[k+1,1] +1; st[k] [1] =st[k+1] [1] +1;
end; }
end; }
write(”ac(“m, n”) = ”,st[1,1] +1); cout<<”ac(“<<m<<’, ‘<<n<<”) =
end. ”<<st[1] [1] +1;
}
dinamic
#include <iostream.h>
struct Nod
{
int info;
Nod* adr_inap;
};

Nod* v;
int n;

void Push( Nod*& v, int n)


{
Nod* c;
If (!v)
{v= new Nod; v->info=n; v-
>adr_inap=0;}
else
{c= new Nod; c->info=n; c-
>adr_inap=v;
v=c;
}
}

void Pop(Nod*& v)
{
Nod* c;
If (!v) cout<<”stiva este vida”;
Else
{
c=v;
cout<<”am scos”<< c-
>info<<end1;
v=v->adr_inap;
delete c;

143
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

}
}

main( )
{ Push(v,1); Push(v,2); Push(v,3);
Pop(v); Pop(v); Pop(v); Pop(v);
}

Structura de tip coadă



 O coadă este o listă pentru care toate inserările sunt făcute la unul din capete, toate ştergerile
(consultările, modificările) la celălalt capăt.

Coada funcţionează pe principiul FIFO (First In First Out) – “primul intrat, primul ieşit”.

Este cu totul nerecomandabilă alocarea secvenţială a cozii, deoarece în această situaţie,


are loc un fenomen de migraţie a datelor către ultimele componente ale vectorului (cele de indice
mare).

Să presupunem că simulăm o coadă cu ajutorul unui vector cu zece componente, care


reţin numere întregi. Introducem în coadă, pe rând, numerele 1, 2, 3, 4.

1 2 3 4

Dacă scoatem din coadă pe 1 şi introducem în coadă pe 5, coada va arăta astfel:

2 3 4 5

Scoatem din coadă pe 2 şi introducem pe 6:

3 4 5 6

Se observă acest fenomen de “migraţie”.

Alocarea dinamică înlănţuită a cozii. O variabilă v va reţine adresa elementului care


urmează a fi scos (servit). O alta, numită sf, va reţine adresa elementului introdus în coadă.
Figura următoare prezintă o coadă în care primul element care urmează a fi scos are adresa în v,
iar ultimul introdus are adresa sf.

v sf

7 3 5 2

LIMBAJUL PASCAL LIMBAJUL C/C++


COADA
{Considerind in doua fisiere niste numere ordonate crescator #include <iostream.h>
in fiecare struct Nod
sa se preia numarele in ordine descrescatoare si sa se puna {

144
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

intr-o lista simplu int info;


inlantuita care sa fie COADA pentru ca la listare sa fie afisate Nod* adr_urm;
in }
ordine crescatoare
Sa se puna datele ordonate in alt fisier din lista creata Nod* v, *sf;
anterior} int n;
type po=^nod;
nod=record void Pune( Nod*& v, Nod*& sf,
info:integer; int n)
leg:po; {
end; Nod* c;
var p,q,d,u:po; If (!v)
f,g:text; { v= new Nod; v->info=n; v-
procedure o; >adr_inap=0;
var a,b:integer; sf=v;
begin }
p:=nil; else
assign(f,'f1.pas'); { c= new Nod;
assign(g,'f2.pas'); sf->adr_urm=c;
reset(f); c->info=n;
reset(g); c->adr_urm=0;
read(f,a);read(g,b); }
while (not eof(f) and not eof(g)) do }
begin
new(q); void Scoate(Nod*& v)
if a<b then begin { Nod* c;
q^.info:=a;read(f,a); if (!v) cout<<”coada este
end vida”<<end1;
else else
if (a=b) then begin { cout<<”Am scos”<<v-
q^.info:=a; >info<<end1;
read(f,a);read(g,b); c=v; v=v->adr_urm;
end delete c;
else }
begin }
q^.info:=b;
read(g,b); void Listare(Nod* v)
end; { Nod* c=v;
IF (P=NIL) THEN BEGIN while ( c )
{ cout<<c->info<<” “;
q^.leg:=p; c=c->adr_urm;
p:=q; }
u:=p; cout<<end1;
end }
else main( )
begin { Pune(v, sf, 1); Pune(v, sf, 2);
q^.leg:=nil;u^.leg:=q;u:=q; Pune(v, sf, 3); Listare(v);
end; Scoate(v); Listare(v);
end; Scoate(v); Listare(v);
while (not eof(f)) do begin Scoate(v); Listare(v);
new(q);q^.info:=a;q^.leg:=nil; Scoate(v); Listare(v);
u^.leg:=q;u:=q; }
read(f,a);
end;

while (not eof(g)) do


begin
new(q);q^.info:=b;q^.leg:=nil;u^.leg:=q;
u:=q;
read(g,b);

145
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

end;
close(f);close(g);
end;
procedure L;
var c:po;
begin
c:=p;
while(c<>nil) do
begin
write(c^.info, ' ');
c:=c^.leg;
end;
end;
procedure li;
var H:text;
var c:integer;
begin
assign(h,'ff.pas');rewrite(h);
d:=p;c:=0;
while d<>nil do
begin
writeln(d^.info);writeln(h,d^.info);
inc(c);d:=d^.leg;
end;
writeln(' am atitea inregistrari',c);

close(h);
end;
begin
o; {L;
writeln;}
Li;
readln;
end.
CU LISTE DUBLU INLANTUITE
{ Sa se creeze o structura de coada}
type ref=^inr;
inr=record
nr:integer;
as,ad:ref;
end;
var p,u:ref;i,n:integer;
procedure b(var u:ref);
var c:ref;
begin
new(c);
writeln(' pe cine pui in coada
');readln(c^.nr);
c^.ad:=nil;
c^.as:=nil;
if u<>nil then u^.ad:=c else
p:=c;
u:=c;
end;
procedure s(var p:ref);
var c:ref;
begin
if p=nil then writeln(' e goala ') else
begin
writeln(' pe cine scot ');
writeln(p^.nr);

146
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

c:=p;p:=p^.ad;
p^.as:=nil;
dispose(c);
end;
end;

begin
writeln(' cite elemente dai
n>=3');readln(n);
for i:=1 to n do
b(u);
for i:=1 to n do
s(p);

readln;
end.

Structura de tip listă liniară

Prezentarea structurii

 O listă liniară este o colecţie de n≥0 noduri, X₁, X₂, … , Xn aflate într-o relaţie de ordine.
Astfel, X₁ este primul nod al listei, X₂ este al doilea nod al listei … Xn este ultimul nod.
Operaţiile permise sunt:

□ Accesul la oricare nod al listei în scopul citirii sau modificării informaţiei conţinute de acesta.

□ Adăugarea unui nod, indiferent de poziţia pe care o ocupă în listă.

□ Ştergerea unui nod, indiferent de poziţia pe care o ocupă în listă.

□ Schimbarea poziţiei unui nod în cadrul listei.

Există două metode de alocare a unei liste liniare: alocarea secvenţială şi alocarea
înlănţuită.

Liste alocate secvenţial

Nodurile listei ocupă poziţii succesive în memorie. Acest tip de alocare l-am întâlnit des,
de câte ori am utilizat vectori.

Exemplu: un vector are n componente de tip real. Se cere să se sorteze vectorul crescător.
Algoritmul are ca dată de intrare o listă liniară, cu n noduri de tip real. Ieşirea este tot o listă
liniară, cu aceleaşi noduri, dar în altă ordine. Să presupunem că utilizăm sortarea prin

147
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

interschimbare. O interschimbare a nodurilor i şi j se reduce la următoarele operaţii, premise în


listă:

■ man = v[i]; - se citeşte nodul i şi se memorează – accesez nodul i în vederea citirii;

■ v[i] v[i+1]; - accesez nodul i+1 în vederea citirii (operaţie permisă) şi accesez nodul i în vederea
modificării informaţiei reţinute (operaţie permisă).

■ v[i+1] = man; - accesez nodul i+1 în vederea modificării informaţiei reţinute de el.

În concluzie, sortarea se realizează prin utilizarea operaţiilor permise asupra unei liste
liniare.

 Avantajul alocării secvenţiale este dat de faptul că programatorul are acces direct la oricare din
nodurile listei, la fel ca la componentele unui vector.

 Dezavantajul alocării secvenţiale este dat de faptul că operaţiile de adăugare, eliminare sau
schimbare de poziţie a unui nod necesită un efort mare de calcul, ca în exemplul următor, în care
se elimină un nod:

Fie lista alocată secvenţial:


7 3 1 2 8 9 5 8 3 2 6 ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙

Eliminăm al doilea nod –conţinut 3.


7 1 2 8 9 5 8 3 2 6 ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙
◄▬▬▬▬▬▬▬▬▬▬▬▬
Este obligatoriu ca nodurile următoare să fie deplasate către stânga:
7 1 2 8 9 5 8 3 2 6 ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙ ∙∙∙

Liste alocate înlănţuit


Există două feluri de alocare înlănţuită: alocare simplu înlănţuită şi alocare înlănţuită. În
acest paragraf prezentăm principiile alocării înlănţuite, urmând ca în paragraful următor să
arătăm modul în care implementăm listele alocate înlănţuit.

1. O listă liniară simplu înlănţuită este o structură de forma:

in₁ adr₂ in₂ adr₃ inn nil

adr₁ adr₂ adrn

Semnificaţia notaţiilor folosite este următoarea:

■ adr₁, adr₂, adr₃, … , adrn reprezintă adresele celor n înregistrări;

■ in₁, in₂, in₃, … , inn reprezintă informaţiile conţinute de noduri, de altă natură decât cele de
adresă;

■ nil – are semnificaţia “nici o adresă” – elementul este ultimul în listă.

După cum observăm, fiecare nod, cu excepţia ultimului, reţine adresa nodului următor.

148
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

2. Alocarea dublu înlănţuită. Alocarea simplu înlănţuită permite parcurgerea listei într-un
singur sens (de la stânga la dreapta). În cazul în care se doreşte ca lista să poată fi parcursă
în ambele sensuri se utilizează alocarea dublu înlănţuită. Aici fiecare nod reţine adresele
predecesorului şi succesorului său, aşa cum se vede în figura următoare:

nil in₁ adr₂ adr₁ in₂ adr₃ adrn-1 inn nil

adr₁ adr₂ adrn

 Dezavantajele alocării înlănţuite sunt:


1. Accesul la un nod al listei se face prin parcurgerea nodurilor care în preced. Aceasta necesită
un efort de calcul.
2. Informaţiile de adresă, prezente în cadrul fiecărui nod, ocupă memorie.

 Avantajele alocării înlănţuite sunt date de faptul că operaţiile de adăugare sau eliminare a unui
nod se fac rapid. Exemplele sunt date pentru lista liniară simplu înlănţuită, dar bine înţelese, ne
permit să deducem singuri modul de efectuare a operaţiilor respective pentru liste dublu
înlănţuite.

a) Adăugarea unui nod.

Fie lista:

3 adr₂
7 adr₃ 9 nil

adr₁ adr₂ adrn

Dorim să adăugăm după nodul cu informaţia 3, un altul cu informaţia 5.

Etapele sunt:

□ Se alocă spaţiu în memorie pentru un nou nod – indiferent unde:

3 adr₂
7 adr₃
9 nil

adr₁ adr₂ adrn

adrt

149
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

□ Se completează informaţiile pentru nodul creat – câmpul de adresă trebuie să conţină adresa
nodului care trebuie să-i urmeze în listă:

3 adr₂
7 adr₃
9 nil

5 adr₂
adrt

□ Se modifică adresa nodului care precede nodul nou creat. Adresa trebuie să fie a nodului nou
creat:

3 adrt 7 adr₃ 9 nil

5 adr₂
adrt

De acum, putem “privi” lista aşa cum am fost obişnuiţi:

3 adrt 5 adr₂ 7 adr₃ 9 nil

adr₁ adrt adr₂ adrn

b) Ştergerea unui nod. Pentru a exemplifica operaţiile efectuate în acest caz vom folosi a de mai
sus, la care ştergem al doilea nod (cel cu informaţia 5). Iată etapele:

150
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

□ Informaţia de adresă a nodului care îl precede trebuie să reţină adresa nodului următor:

3 adr₂ 9 nil
5 adr₂ 7 adr₃
adr₁ adrt adr₂ adrn

□ Memoria ocupată de nodul care urmează a fi şters este eliberată:

7 adr₃ 9 nil

3 adr₂
adr₁ adr₂ adrn

De acum, putem privi lista aşa cum am fost obişnuiţi.

7 adr₃ 9 nil

3 adr₂

adr₁ adr₂ adrn

Observaţii:
În cazul alocării înlănţuite, adresele de memorare ale nodurilor consecutive nu sunt neapărat
consecutive. Pentru a realiza acest lucru este suficient să analizaţi cazul ştergerii unui nod (sau
acela al adăugării unui nod).

 Prin alocarea memoriei pentru un nod înţelegem rezervarea spaţiului necesar memorării
informaţiilor conţinute de acesta. Evident, se poate aloca memorie doar dacă există memorie
disponibilă, adică nu este ocupată de alte variabile.

151
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

 Pentru eliberarea memoriei ocupate de un nod înţelegem că spaţiul ocupat de acesta devine
disponibil – este pus la dispoziţia programatorului, pentru ca, eventual, acesta să fie din nou
alocat.

 Este important să folosim termenii corect. De exemplu, nu putem folosi în loc de “alocarea
memoriei” termenul “crearea memoriei”, tot aşa cum nu este corect să folosim în loc de
“eliberarea memoriei” termenul “ştergere a memoriei”.

 Noţiunile care privesc alocarea şi eliberarea memoriei sunt prezentate în paragraful următor.

Liste liniare alocate simplu inlantuit


Definitia listelor
Def.:O lista liniara este o colectie de n>=0 noduri, X1,X2,…,Xn, aflate intr-o
relatie de ordine.Astfel, X1 este primul nod al listei, X2 este al doilea nod al
listei,…, Xn este ultimul nod.Operatiile permise sunt:
 Accesul la oricare nod al listei in scopul citirii sau modificarii informatiei
continute de acesta.
 Adaugarea unui nod, indiferent de pozitia pe care o ocupa in lista.
 Stergerea unui nod,indiferent de pozitia pe care o ocupa in lista.
 Schimbarea pozitiei unui nod in cadrul listei.

152
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Liste liniare alocate simplu inlantuit


Prezentare generala

O lista liniara simplu inlantuita este o structura de forma:


in1 adr1 in2 adr2 inn 0
adr1 adr2 adrn
Dupa cum se observa, fiecare nod, cu exceptia ultimului, retine adresa
nodului urmator.
1. Accesul la un nod al listei se face parcurgand nodurile care il preced.
2. Informatiile ocupa memorie, fiind prezente in cadrul fiecarui nod.
3. Avantajele alocarii inlantuite sunt date de rapiditatea operatiilor de adaugare si eliminare.
In cadrul unei astfel de liste, zona de memorie rezervata fiecarui elev se numeste
nod sau celula.
Definitie.Numim cod (celula) o unitate informationala de sine statatoare
(elementara) care contine informatii utile si date de legatura.Se numeste lista un
ansamblu de noduri (celule).
Exista mai multe tipuri de liste, dintre care:listele liniare simplu inlantuite, listeel
liniare dublu inlantuite, listele circulare, stivele si cozile.
Liste liniare simplu inlantuite cu numere intregi
Reprezentare
O astfel de lista va memora elementele unui sir de numere intregi si este alcatuita fireste
din noduri.Fiecare nod contine doua campuri: un numar al sirului(informatia utila) si adresa la
care se gaseste numarul urmator din sir(pointer catre nodul urmator).
Numerele memorate in noduri se mai numesc si cheile listei.
Pentru ultimul nod, pointerul catre nodul urmator marcheaza sfarsitul listei si are valoarea NIL.

LIMBAJUL PASCAL LIMBAJUL C/C++


CREAREA SI AFISAREA LISTELOR SIMPLU INLANTUITE
type ref=^inr; Crearea listelor
inr=record
nr:integer;
urm:ref; #include<iostream.h>
end; struct Nod
var qq,p,c,u:ref; a:array[1..15] of ref; {
nn,n,i:integer;
procedure init(var p:ref);
int info;
begin Nod* adr_urm;
writeln(' cite inregistrari vreti sa introduceti ');readln(n); };
new(c); writeln('introduceti inregistrarea prima ');
readln(c^.nr);
c^.urm:=nil;
Nod*v;
p:=c;u:=c; int nr;
for i:=2 to n do
begin void Adaug(Nod*& v, int nr)
writeln('introduceti inregistrarea ',i);
new(c);readln(c^.nr);c^.urm:=nil;u^.urm:=c;
{
u:=c; Nod* c=new Nod;
end; c->info=nr;
c->adr_urm=v;
end;
v=c;
procedure afisare(p:ref); }
var c:ref;
begin void Tip(Nod* v)
c:=p;
while (c <>nil) do {
begin Nod*c=v;

153
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

writeln(c^.nr:6); while(c)
c:=c^.urm;
{
end;
end; cout<<c->info<<endl;
begin c=c->adr_urm;
init(p); }
afisare(p);
readln;
}
end.
main( )
{
cout<<”numar=”; cin>>nr;
while(nr)
{
Adaug(v,nr);
cout<<”numar=”; cin>>nr;
};
Tip(v);
}

Operatii asupra unei liste liniare


LIMBAJUL PASCAL LIMBAJUL C/C++

{Sa se scrie toate operatiile cu o lista simplu inlantuita} #include<iostream.h>


type ref=^inr; struct Nod
inr=record {
nr:integer; int info;
urm:ref; Nod* adr_urm;
end; };
var p,c,u:ref;
n,i:integer; void Adaugare(Nod*& v, Nod*& sf, int
procedure init; val)
begin {
writeln(' cite inregistrari vreti sa introduceti ');readln(n); Nod* c;
new(c); writeln('introduceti inregistrarea pa '); if(v==0)
readln(c^.nr); {
c^.urm:=nil; v=new(Nod); v->info=val; v-
p:=c;u:=c; >adr_urm=0;
for i:=2 to n do sf=v;
begin }
writeln('introduceti inregistrarea ',i); else
new(c);readln(c^.nr);c^.urm:=nil;u^.urm:=c; {
u:=c; c=new(Nod); sf->adr_urm=c;
end; c->info=val; c->adr_urm=0;
end; sf=c;
procedure inserareinaintedepa; }
}
begin
new(c); void Inserare_dupa(Nod* v, Nod*& sf,
writeln('pe cine inserati inaite de pa inreg.(dati un numar int val, int val1)
');readln(c^.nr); {
c^.urm:=p; Nod* c=v, *d;
p:=c; while(c->info!=val) c=c->adr_urm;
end; d=new Nod; d->info=val1;
d->adr_urm=c->adr_urm; c-
procedure inserareinaintedepamaimulte; >adr_urm=d;
var multe:integer; if(d->adr_urm==0) sf=d;
begin }
writeln('cite inregisrari vreti sa inserati inainte de pa
');readln(multe); void Inserare_inainte(Nod*& v, int val,
for i:=1 to multe do

154
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

begin int val1)


new(c); {
writeln('pe cine inserati inaite de pa i(dati un numar Nod*c,*d;
',i);readln(c^.nr); if(v->info==val)
c^.urm:=p; {
p:=c; end; d=new Nod; d->info=val1; d-
end; >adr_urm=v; v=d;
procedure adaugunlasfirsit; }
begin else
new(c); {
writeln('dati numarul care-l puneti dupa ua inregistrare '); c=v;
readln(c^.nr); while(c->adr_urm->info!=val) c=c-
c^.urm:=nil; >adr_urm;
u^.urm:=c; d=new Nod; d->info=val1; d-
u:=c; >adr_urm=c->adr_urm; c->adr_urm=d;
end; }
procedure adaugunlasfirsitmaimulte; }
var multe:integer;
begin void Sterg(Nod*& v, Nod *& sf, int val)
writeln('cite inregistrari vreti sa mai puneti dupa ua {
');readln(multe); Nod* c,*man;
for i:=1 to multe do if(v->info==val)
begin {
new(c); man=v; v=v->adr_urm;
writeln('dati numarul care-l puneti dupa ua inregistrare ',i); }
readln(c^.nr); else
c^.urm:=nil; {
u^.urm:=c; c=v;
u:=c; while(c->adr_urm->info!=val) c=c-
end;end; >adr_urm;
man=c->adr_urm; c->adr_urm=man-
procedure pununadupacecaut; >adr_urm;
var cecaut:integer; pecinepun :ref; if(man==sf) sf=c;
begin }
writeln('introduceti valoarea inainte de care vreti sa faceti delete man;
adaugarea ');readln(cecaut); }
c:=p;
while(c<>nil) and (c^.nr<>cecaut) do void Listare(Nod* v)
c:=c^.urm; {
if (c=nil) then writeln(' nu este ce cauti in lista ') Nod* c=v;
else while(c)
begin {
new(pecinepun); cout<<c->info<<endl;
writeln(' pe cine vrei sa pui '); c=c->adr_urm;
readln(pecinepun^.nr); }
pecinepun^.urm:=c^.urm; cout<<endl;
c^.urm:=pecinepun ; }
end; main ( )
end; {

procedure punmaimulteinaintedececaut; Nod* v,*sf;


var cecaut:integer; pecinepun :ref; potadauga:boolean; int i;
begin for(i=1;i<=10;i++) Adaugare(v,sf,i);
potadauga :=true; Listare(v);
writeln('introduceti valoarea inainte de care vreti sa faceti Inserare_dupa(v,sf,7,11);
adaugarea ');readln(cecaut); Inserare_dupa(v,sf,10,12);
c:=p; Inserare_dupa(v,sf,1,13);
while potadauga do Listare(v);
begin Inserare_inainte(v,13,14);
while (c<>nil) and(c^.nr<>cecaut) do Inserare_inainte(v,1,15);

155
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

c:=c^.urm; Listare(v);
Sterg(v,sf,15);
if (c=nil) then potadauga:=false Sterg(v,sf,13);
else Sterg(v,sf,12);
begin Listare(v);
new(pecinepun); }
writeln(' pe cine vrei sa pui ');
readln(pecinepun^.nr);
pecinepun^.urm:=c^.urm;
c^.urm:=pecinepun ;
c:=c^.urm;
end;
end;end;
procedure pununadupamaimulte;
var cecaut:integer; pecinepun :ref;
begin

writeln('introduceti dupa a cit -a inregistrare vreti sa faceti


adaugarea ');readln(cecaut);
c:=p;
for i:=1 to cecaut-1 do
c:=c^.urm;
begin
new(pecinepun);
writeln(' pe cine vrei sa pui ');
readln(pecinepun^.nr);
pecinepun^.urm:=c^.urm;
c^.urm:=pecinepun ;
c:=c^.urm;
end;
end;
procedure pununainaintedemaimulte;
var cecaut:integer; pecinepun :ref;
begin

writeln('introduceti inainte de a cit -a inregistrare vreti sa faceti


inseararea ');readln(cecaut);
c:=p;
for i:=1 to cecaut-2 do
c:=c^.urm;
begin
new(pecinepun);
writeln(' pe cine vrei sa pui ');
readln(pecinepun^.nr);
pecinepun^.urm:=c^.urm;
c^.urm:=pecinepun ;
c:=c^.urm;
end;
end;
procedure stergpa;
var desters:ref;
begin
desters :=p;
p:=p^.urm;
dispose( desters);
end;
procedure stergua;
var oretinpepenua,desters:ref;
begin
c:=p;

156
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

while (c<>u) do

begin
oretinpepenua :=c;
c:=c^.urm;
end;
desters :=c;
oretinpepenua^.urm :=nil;
u:=oretinpepenua ;
dispose( desters);
end;

procedure stergdupaunacareocaut;
var oretinpepenua,desters:ref;cecaut:integer;
begin
writeln('dupa a cit-a intergistrare vreti sa stergeti
');readln(cecaut);
c:=p;
for i:=1 to cecaut do

begin
oretinpepenua :=c;
c:=c^.urm;
end;
desters :=c;
oretinpepenua^.urm :=c^.urm;

dispose( desters);
end;

procedure sterguele;
var oretinpepenua,desters:ref;multe:integer;
begin
writeln('cite vreti sa stergeti incepind de la sfirsit spre inceput
');readln(multe);
for i:=1 to multe do
begin
c:=p;
while (c<>u) do

begin
oretinpepenua :=c;
c:=c^.urm;
end;
desters :=c;
oretinpepenua^.urm :=nil;
u:=oretinpepenua ;
dispose( desters);
end;
end;

procedure stergdelapamaimulte;
var desters:ref;multe:integer;
begin
writeln('cite vreti sa stergeti incepind de la pa ');readln(multe);
for i:=1 to multe do
begin

157
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

desters :=p;
p:=p^.urm;
dispose( desters);
end;
end;

procedure stergdupacecaut;
var osterg:ref;cecaut:integer;
begin

c:=p;
writeln(' dupa ce valoare vrei sa stergi');
readln(cecaut);
while (c<>nil) and (c^.nr<>cecaut) do
c:=c^.urm;
if c=nil then writeln(' nu este in lista ')
else
begin
osterg:=c^.urm;
c^.urm:=c^.urm^.urm;
{dispose(osterg); }
end;
end;

procedure stergcecaut;
var oretin,osterg:ref;cecaut:integer;
begin

c:=p;
writeln(' ce valoare vrei sa stergi');
readln(cecaut);
while (c<>nil) and (c^.nr<>cecaut) do
begin
oretin:=c;
c:=c^.urm;end;
if c=nil then writeln(' nu este in lista ')
else
begin
osterg:=c;
oretin^.urm:=c^.urm;
dispose(osterg);
end;
end;

procedure stergcecautdeciteoriapare;
var oretin,osterg:ref;cecaut:integer;potsterge:boolean;
begin
writeln(' ce valoare vrei sa stergi');
readln(cecaut);
potsterge:=true;

while potsterge do
begin

c:=p;

while (c<>nil) and (c^.nr<>cecaut) do


begin
oretin:=c;
c:=c^.urm;end;

158
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

if c=nil then potsterge :=false


else
begin
osterg:=c;
oretin^.urm:=c^.urm;
dispose(osterg);
end;
end;end;
procedure afisare;
begin
c:=p;
while (c <>nil) do
begin
writeln(c^.nr:6);
c:=c^.urm;
end;
end;
procedure modificpa;
begin
c:=p;
writeln('cu cine modifici pe pa');readln(c^.nr);

end;
procedure modificua;
begin
c:=u;
writeln('cu cine modifici pe ua');readln(c^.nr);

end;
procedure modificcepozitiecaut;
var cecaut:integer;
begin
c:=p;
writeln(' a cit-a inregistrare vrei sa o modifici');
readln(cecaut);
for i:=1 to cecaut-1 do
c:=c^.urm;
writeln(' cu cine o modifici');
readln(c^.nr);
end;

begin
init;
afisare;
inserareinaintedepa;
afisare;
inserareinaintedepamaimulte;
afisare;
adaugunlasfirsit;
afisare;
adaugunlasfirsitmaimulte;
afisare;

pununadupamaimulte;
afisare;
pununainaintedemaimulte;
afisare; writeln('o sterg pe pa ');
stergpa ;afisare;
stergdelapamaimulte; afisare;

159
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

stergua;
writeln('o sterg pe ua ');
afisare;
sterguele;afisare;
stergdupaunacareocaut;
afisare;
pununadupacecaut;afisare;
stergdupacecaut;
afisare;
stergcecaut;
afisare;
stergcecautdeciteoriapare; afisare;
modificpa;
afisare;
modificua; afisare;
modificcepozitiecaut; afisare;
readln;
end.

Liste alocate dublu inlantuit

O lista alocata dublu inlantuit este o structura de date de


forma:

0 in1 adr2 adr1 in2 adr3 adrn-1 inn 0 0


0000adr3
adr1 adr2
adrn
Operatiile posibile asupra unei liste dublu inlantuite sunt:

1) creare;
2) adaugare la dreapta;
3) adaugare la stanga;
4) adaugare in interiorul listei;
5) stergere din interiorul listei;
6) stergere la stanga listei;
7) stergere la dreapta listei;
8) listare de la stanga la dreapta;
9) listare de la dreapta la stanga.

1) Creare

O lista dublu inlantuita se creeaza cu o singura inregistrare.Pentru a ajunge la numarul de inregistrari


dorit, utilizam functii de adaugare la stanga si la dreapta.Functia creare realizeaza citirea informatiei
numerice, alocarea de spatiu pentru inregistrare, completarea inregistrarii cu informatia si completarea
adreselor la dreapta si la stanga cu 0.

2) Adaugare la dreapta

Functia add citeste informatia numerica, aloca spatiu pentru inregistrare, completeaza adresele,
modifica adresa la dreapta a inregistrarii din s cu adresa noii inregistrari si ii atribuie
lui s valoarea noii inregistrari.

3) Adaugare la stanga

160
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

4) Adaugare in interiorul listei

Functia includ parcurge lista pentru a gasi inregistrarea cu informatia m, in dreapta careia urmeaza sa
introducem noua inregistrare, citeste informatia, aloca spatiu, completeaza informatia, completeaza
adresa stanga a noii inregistrari cu valoarea adresei inregistrarii de informatie m, si completeaza adresa
dreapta a noii inregistrari cu valoarea adresei dreapta a inregistrarii cu informatia utila m.

5) Stergere in interiorul listei

Functia Sterg parcurge lista pentru a gasi informatia care va fi stearsa, atribuie inregistrarii precedente
campul de adresa dreapta al inregistrarii care va fi stearsa, iar inregistrarii care urmeaza celei care va fi
stearsa i se atribuie campul de adresa stanga al inregistrarii pe care o stergem, dupa care se elibereaza
spatiul de memorie rezervat inregistrarii care se sterge.

6)-7) Stergere la stanga si la dreapta listei

8) Listare de la stanga la dreapta

Functia listare porneste din stanga listei si tipareste informatia


numerica a fiecarei inregistrari, atata timp cat nu s-a ajuns la capatul
listei.
LIMBAJUL PASCAL LIMBAJUL C/C++
OPERATII CULISTE DUBLU INLANTUITE
{Cu liste dublu inlantuite sa se simuleze crearea ,listarea in ambele sensuri si #include<iostream.h>
stergerea struct Nod
ultimului,primului element ,inserarea dupa un anumit numar de inregistrari { Nod *as,*ad;
sau stergerea elementui care are un anumit numar de inregistrare} int nr;
type ref=^inr; };
inr=record
as:ref; Nod *b,*s,*c;
nr:integer; int n,m,i;
ad:ref;
end; void Creare(Nod*& b, Nod*& s)
var p,c,u:ref; { cout<<”n=”; cin>>n;
n,i:integer; b=new Nod; b->nr=n;
procedure creare; b->as=b->ad=0;
begin s=b;
writeln('n=');readln(n); }
new(c); void Addr(Nod*& s)
writeln(' primul element ');readln(c^.nr); { cout<<”n=”; cin>>n;
c^.ad:=nil; Nod* d=new Nod;
c^.as:=nil; d->nr=n;
p:=c; d->as=s; d->ad=0;
u:=c; s->ad=d; s=d;
for i:=2 to n do }
begin
new(c); void Listare(Nod*& b)
writeln(' dati integistrarea ',i); { Nod* d=b;
readln(c^.nr); while(d)
c^.ad:=nil; { cout<<d->nr<<endl;
c^.as:=u; d=d->ad;
u^.ad:=c; }
u:=c; }
end;
end; void Includ(int m,Nod* b)
procedure adauginaintedeprima; {
begin Nod *d=b, *e;
new(c); while(d->nr!=m) d=d->ad;

161
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

writeln('pe cine adaug inainte de prima '); cout<<”n=”; cin>>n;


readln(c^.nr); e=new Nod;
c^.ad:=p; e->nr=n;
p^.as:=c; e->as=d;
c^.as:=nil; d->ad->as=e;
p:=c; e->ad=d->ad;
end; d->ad=e;
procedure adugadupaultima; }
begin
new(c); void Sterg(int m, Nod *b)
writeln(' pe cine adugi dupa ultima '); { Nod* d=b;
readln(c^.nr); writeln('------------------'); while(d->nr!=m) d=d->ad;
c^.ad:=nil; d->as->ad=d->ad;
c^.as:=u; d->ad->as=d->as;
u^.ad:=c; delete d;
u:=c; }
end;
procedure adaugadupaa_p1_acomponenta; main ( )
var p1:integer;q:ref; { cout<<”Creare lista cu o singura
begin inregistrare “<<endl;
c:=p; Creare(b,s);
writeln(' dupa a cita componenta adaugi(inserezi '); cout<<”Cate inregistrari se adauga ?”;
readln(p1); writeln('------------------'); cin>>m;
for i:=1 to p1-1 do for(i=1;i<=m;i++) Addr(s);
c:=c^.ad; cout<<”Acum listez de la stanga la
new(q); dreapta”<<endl;
writeln(' dati componenta care o inserati '); Listare(b);
readln(q^.nr); writeln('------------------'); cout<<”Includem la dreapta o
q^.ad:=c^.ad; inregistrare”<<endl;
c^.ad^.as:=q; cout<<”Dupa care inregistrare se face
q^.as:=c; includerea?”; cin>>m;
c^.ad:=q; Includ(m,b);
end; cout<<”Acum listez de la stanga la
procedure stegultima; dreapta”<<endl;
var q:ref; Listare(b);
begin cout<<”Acum stergem o inregistrare
q:=u; din interior”<<endl;
u:=u^.as; cout<<”Ce inregistrare se sterge?”;
u^.ad:=nil; cin>>m;
dispose(q); Sterg(m,b);
end; cout<<”Acum listez de la stanga la
dreapta”<<endl;
procedure stegprima; Listare(b);
var q:ref; }
begin
q:=p;
p:=p^.ad;
p^.as:=nil;
dispose(q);
end;
procedure stergA_p1_componenta;
var p1:integer;q:ref;
begin
c:=p;
writeln(' dati componenta care o stergeti din lista ');readln(p1);
writeln('------------------');
for i:=1 to p1-1 do
c:=c^.ad;
q:=c;
c^.as^.ad:=c^.ad;

162
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

c^.ad^.as:=c^.as;
dispose(q)
end;
procedure ins1;
var i:integer;d,q:ref;
begin
writeln(' in fata cui inserati ');readln(i); writeln('------------------');
d:=p;
while(i<>d^.nr) and (d<>nil) do
d:=d^.ad;
if d= nil then writeln(' nu ')
else
begin
new(q);
writeln('informatia care o inserati ');
readln(q^.nr);
q^.ad:=d;
q^.as:=d^.as;
d^.as^.ad:=q;
d^.as:=q;
end;
end;

procedure listare;
var c:ref;
begin
c:=p;
while(c<>nil) do
begin
writeln(c^.nr,' ');
c:=c^.ad;
end;
end;

procedure listare1;
var c:ref;
begin
c:=u;
while(c<>nil) do
begin
writeln(c^.nr,' ');
c:=c^.as;
end;
end;

begin
creare;
writeln('------------------');
listare; writeln('sterg pe ultima ------------------');
stegultima;
writeln('o listez de la sfirsit spre inceput------------------');
listare1;
adauginaintedeprima;
writeln('------------------');
listare; writeln('------------------');
adugadupaultima; listare; writeln('------------------');
adaugadupaa_p1_acomponenta; listare; writeln(' sterg prima
------------------');
stegprima;listare; writeln('------------------');
stergA_p1_componenta; listare; writeln('------------------');

163
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

ins1; listare;
readln;
end.

Elemente de teoria grafurilor

Grafuri orientate
Notiuni introductive
_
Definitie.Se numeste graf orientat perechea ordonata G=(x,l ).
-Daca in acest graf [x,y] apartin multimii г, vom spune ca x si y sunt adiacente, iar
varfurile x si y sunt incidente cu muchia [x,y].
-Daca г(g)=multimea vida, acest graf se numeste graf nul si reprezentarea lui in
plan se reduce la puncte izolate.
Definitie.Un graf partial al unui graf orientat dat este un graf G1=(x,g1) unde g1este
inclus sau = cu g.
Definitie. Un subgraf al unui graf orientat G=(x,g) este un graf H=(y1,g1),unde y1-
inclus sau = cu x, iar muchiile din g1 sunt toate muchiile din g care au ambele
extremitati in multimea y.
-Gradul unui nod x(d(x)) este de doua feluri:
*grad exterior
*grad interior
Definitie.Un drum al unui graf orientat L=[x0,x1,x2,…xp] este o succesiune de
varfuri cu proprietatea ca [x0,x1]aparrtine de g, [x1,x2] la fel, s.a.
-x0 si xp = extremitatile drumului;
-p=lungimea drumului;
-daca x0,x1,…,xp sunt distincte doua cate doua drumul=elementar;
-daca x0=xp,drumul=circuit
-daca toate varfurile circuitului, cu exceptia primului si ultimului sunt distincte,
circuitul=elementar;
-un circuit elementar care trece prin toate nodurile grafului se numeste circuit
hamiltonian.

Metode de reprezentare in memorie


a unui graf

Exista mai multe metode de reprezentare in memorie a unui graf orientat:


1-metoda matricei adiacente:
1, pentru[I,j] apartin de g
a[I,j]=
0, pentru[I,j]nu apartinde g

Parcurgerea grafurilor orientate

1.Parcurgerea in latime(BF-breadth first)


-parcurgerea in latime se face incepand de la un nod I, pe care il consideram parcurs;

164
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

-parcurgem apoi toti descendentii sai – multimea nodurilor j pentru care exista
[I,j]apartin de g;
-parcurgem apoi toti descendentii nodurilor parcurse la pasul anterior.
Parcurgerea BF se efectueaza prin utilizarea structurii numita coada, avand grija ca un nod sa fie vizitat
o singura data. Coada va fi alocata prin utilizarea unui vector.
LIMBAJUL PASCAL LIMBAJUL C/C++
PARCURGEREA GRAFURILOR

165
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

{Parcuregerea in latime nerecursiv si recursivla grafuri IN LATIME


ex:
n=6
8 muchii si anume (1,2),(1,3)(1,4),(2,4),(2,3),(3,4),(3,6), #include “grafuri.cpp”
(4,5) int coada[50],s[50],A[50]
=>1 2 3 4 6 5 } [50],I_c,sf_c,I,n;
uses crt;
var a:array[1..20,1..20] of integer; void bf_r1()
co,vi:array[1..20] of integer; { int k;
i,n,el,j,p,u,pl,m,x,y:integer; if (I_c<=sf_c)
procedure pp(i:integer);
{ for (k=1;k<=n;k++)
var j:integer; if ( (A[coada[I_c]][k]==1) &&
begin (s[k]==0) )
for j:=1 to n do { sf_c++;
if (a[co[i],j]=1) and( vi[j]=0) then begin
u:=u+1; coada[sf_c]=k;
co[u]:=j; s[k]=1;
vi[j]:=1; }
end; I_c++;
if i<=u then pp(i+1);
end; Bf_r1();
begin }
clrscr; }
writeln(' n=');readln(n);
writeln(' nuamrul de muchii ');readln(m);
main()
for i:=1 to m do [ Citire(“graf.txt”,A,n);
begin I_c=sf_c=1;
writeln('dati muchia ',i); Coada[I_c]=s[1]=1;
writeln( 'primul nod al muchiei ');readln(x);
writeln(' nodul de sfirsit al muchiei ');readln(y); Bf_r1();
a[x,y]:=1;a[y,x]:=1; For(I=1;I<=sf_c;I+
end; +)cout<<coada[I]<<” “;
for i:=1 to n do
vi[i]:=0;
}
writeln(' care este nodul de plecare ');readln(pl);
vi[pl]:=1;
co[1]:=pl;
p:=1;
u:=1;
while p<=u do
begin
el:=co[p];
for j:=1 to n do
if (a[el,j]=1) and (vi[j]=0) then begin
u:=u+1;
co[u]:=j;
vi[j]:=1;
end;
p:=p+1;
end;
for i:=1 to u do
write(co[i],' ');
pp(1);
writeln(' parcurgere recursiva in latime ');
for i:=1 to u do
write(co[i],' ');
readln;
end.

IN ADANCIME IN ADANCIME
{Parcuregerea in adincime la grafuri neorientate -se face incapand de la un nod I
ex:n=5 -dupa parcurgerea unui nod se parcurge
m=4 primul dintre descendntii sai neparcursii inca
si anume (1 2),(1 5), ( 2 3),(2 4) EX:
nodul de pelecare este 1 => #include “grafuri.cpp”
12345 int s[50],A[50][50],n;
} void df_r9int nod)
uses crt; {
var a:array[1..20,1..20] of integer; int k;
vi:array[1..20] of integer; cout<<nod<<” “;
i,n,el,j,p,u,pl,m,x,y:integer; s[nod]=1;
for (k=1;k<=n;k++)
procedure pp(pl:integer); if ((A[nod][k]==1) && (s[k]==0))

166
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Componente tare conexe


Graf conex

Un graf G este conex , daca oricare ar fi doua varfuri ale sale ,exista un lant care le
leaga.
Definitie:
Se numeste componenta conexa a grafului G=(X,U),un subgraf G1=(X1,U1) a lui
G ,conex , cu propietatea ca nu exista nici un lant care sa lege un nod din X1 cu un
nod din X-X1(pentru orice nod , nu exista un lant intre acel nod si nodurile care nu
fac parte din subgraf).
Graf tare conex .Componente tare conexe

Definitie:
Un graf orientat G=(X,U) este tare conex, daca pentru oricare doua noduri x si y
apartin de X, exista un drum de la x la y precum si un drum de la y la x.

Definitie
Fiind dat un graf orientat G=(X,U), se numeste componenta tare conexa a lui
G ,un subgraf G1=(X1,U1),tare conex, si maximal in raport cu aceasta propietate
(adica pentru orice nod x apartine de X-X1, subgraful indus de X1 U{x} nu mai este
tare conex).

LIMBAJUL PASCAL LIMBAJUL C/C++


COMPONENTE TARE CONEXE
EX: #include “grafuri.cpp”
{Se considera o multime formata din n persoane in care fiecare int suc[50],A[50][50],n,I,j;
persoana void df_r1(int nod)
se cunoaste pe sine si eventual alte persoane. Sa se formeze grupuri {
in int k;
care fiecare persoana sa suc[nod]=I;
for (k=1;k<=n;k++)
cunoasca toate celelalte persoane din grup( o persoana apartine unui if ( (A[nod] [k]==1)&&(suc[k]==0) )
singur grup). df_r1(k);
Relalia „ x cunoaste pe y" nu este in mod normal nici simetrica, nici }
tranzitiva. void df_r2(int nod)
{
Rezolvare int k;
Rezolvarea se bazeaza pe algoritmul de determinare a componentelor pred[nod]=I;
tare conexe intr-un for (k=1;k<=n;k++)
graf orientat.} if ( (A[k][nod]==1)&&(pred[k]—0) )
df_r2(k);
program tareconexe; }
type mat=array[1..50,1..50] of byte; main()
var f:text; {
n:byte; Citire(“Graf.txt”,A,n);
a:mat; Cout<<”Introduceti nodul de pornire
procedure citeste; “;cin>>I;
var i,x,y:byte; Suc[I]=pred[I]=I;
begin Df_r1(I);df_r2(I);
assign(f,'in7.pas'); For (j=1;j<=n;j++)
reset(f); If ( (suc[j]==pred[j])&& (suc[j]==I) )
readln(f,n); Cout<<j<<” “;
}
while not eof(f) do DESCOMPUNEREA IN
begin COMPONENTE TARI CONEXE

167
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

readln(f,x,y); #include “grafuri.cpp”


a[x,y]:=1; int suc[50],pred[50],A[50][50],n,nrc,I,j;
end; void df_r1(int nod)
close(f); {
end; int k;
suc[nod]=nrc;
procedure Roy_Warshall; for (k=1;k<=n;k++)
var i,j,k:byte; if ( (A[nod][k]==1)&&(suc[k]==0) )
begin df_r1(k);
for k:=1 to n do }
for i:=1 to n do void df_r2(int nod)
for j:=1 to n do {
if a[i,j]=0 then a[i,j]:=a[i,k]*a[k,j]; int k;
end; pred[nod]=nrc;
for (k=1;k<=n;k++)
procedure componente; if ( (A[k][nod]==1)&&(pred[k]==0)
var k,i,j:byte; df_r2(k);
viz:array[1..50] of boolean; }
begin main()
for i:=1 to n do viz[i]:=false; {
k:=1; Citire(“Graf.txt”,A,n);
for i:=1 to n do Nrc=1;
if not viz[i] then For (I=1;I,=n;I++)
begin If (suc[I]==0)
writeln('Componenta',k,':'); {
write(i,' '); suc[I]=nrc;
viz[i]:=true; df_r1(I);df_r2(I);
for j:=1 to n do for (j=1;j<=n;j++)
if(j<>i)and (a[i,j]<>0)and(a[j,i]<>0)then if (suc[j]!=pred[j]) suc[j]=pred[j]=0;
begin nrc++;
write(j,' '); }
viz[j]:=true; for (I=1;I<=n;I++)
end; {
k:=k+1; cout<<:”Componenta “<<I<<endl;
writeln for (j=1;j<=n;j++)
end; if (suc[j]==I) cout<<j<<” “;
end; cout<<endl;
}
begin }
citeste;
Roy_Warshall;
componente;
readln;
end.

Drumuri in grafuri Drumuri minime si maxime in


grafuri orientate

Consideram un graf orientat G=(X,U) cu n noduri, in care fiecarui arc ii este asociat un
numar intreg numit cost. Semnificatia
acestui cost poate fi foarte variata , in functie de domeniul pe care il descrie graful .

Matricea costurilor

168
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Pentru evidentierea costurilor tuturor arcelor unui graf cu n noduri se poate defini o
matrice a, cu n linii * n coloane.Exista doua forme ale acestei matrici:
Forma a): Fiecare element a[i,j] poate fi:
c , daca exista un arc de cost c>0 intre nodurile i si j;
0, daca i=j;
+∞ ,daca nu exista arc intre nodurile i si j .

Forma b): Este absolut similara,cu singura deosebire ca in loc de +∞ avem -∞.
Forma a) se foloseste pentru determinarea drumurilor de cost minim intre doua
noduri , iar forma b) este utilizata in aflarea drumurilor de cost maxim.
Daca dorim sa citim matrice costurilor ,evident ca nu putem introduce de la tastatura
“+”! In loc de + vom da un numar intreg foarte mare.
LIMBAJUL PASCAL LIMBAJUL C/C++
CAUTAREA UNUI SIR DE CARACTERE
{Fiind dat un graf neorientat G si doua varfuri x si y in acest graf, sa se Algoritmul lui ROY-FLOYD-vom aplica
determine un lant elementar de lungime minima, avand ca extremitati strategia generala Divide et
varfurile date. Datele de intrare se citesc din fisierul Graf.dat care are Impera(pentru lungimea minima):
urmatoarea componenta: #include “grafuri.cpp”
- pe prima linie se afla numarul de varfuri ale grafului(n); float A[50][50];
- pe a doua linie sunt inscrise cele doua extremitati ale lantului int n;
elementar separate prin spatii; void Drum(int I, int j)
- pe urmatoarele n linii se gasesc valorile matricei de adiacenta {
separate int k=1,gasit=0;
prin spatii. Datele de iesire se vor afrsa pe ecran si vor consta in: while ( (k<=n) && !gasit)
- mesajul "Nu exista lanl elementar Fntre cele doua varfuri" {
sau if ( (I!=) && (j!=k) && (A[I][j]==A[I]
- mesajul "Lantul minim are lungimea .... ", iar pe linia urmatoare [k]+A[k][I]) )
varfurile {
lantului Drum(I,k);Drum(k,j);
separate printr-un spatiu. Gasit=1;
K++;
Rezolvare }
Rezolvarea acestei probleme se bazeaza pe formarea matricei if (!gasit) cout<<j<<” “;
lanturilor. Un }
element al acestei matrici va contine Iungimea lantului minim dintre void Scriu_drum(int Nod_Initial, int
varfurile Nod_Final)
corespunzatoare liniei si coloanei.} {
program lant_elementar; if (A[Nod_Initial][Nod_Final]<Pinfinit)
const infinit=100; {
type matrice=array[1..20,1..20] of byte; cout<<”Drumul de la
var n,x,y:byte;a:matrice;f:text; “<<Nod_Initial<<” la “<<Nod_Final<<”
procedure citeste; are lungimea “<<A[Nod_Initial]
var i,j,p,q:byte; [Nod_Final]<<endl;
begin cout<<Nod_Initial<<” “;
assign(f,'in2.pas');reset(f); Drum(Nod_Initial,Nod_Final);
readln(f,n); }
else
for i:=1 to n do cout<<”Nu exista drum de la
for j:=1 to n do “<<Nod_Initial<<” la “<<Nod_Final;
if i=j then a[i,j]:=0 }
else a[i,j]:=infinit; void Lungime_Drumuri()
readln(f,x,y); {
while not eof(f) do int I,j,k;
begin for (k=1;k<=n;k++)
readln(f,p,q); for(I=1;I<=n;I++)
a[P,q]:=1; a[q,P]:=1; for (j=1;j<=n;j++)
end; if (A[I][j]>A[I][k]+A[k][j]
close(f) A[I][j]=A[I][k]+A[k][j];
}

169
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

end; main()
prOcedure mat_drumuri; {
var i,j,k:byte; Citire_cost(“Graf.txt”,A,n);
begin Lungime_Drumuri();
for k:=1 to n do Scriu_drum(4,2);
for i:=1 to n do }
for j:=1 to n do
if a[i,j]>a[i,k]+a[k,j] then *Algoritmul ROY-FLOYD pentru a gasi
begin drumuri de lungime maxima:
a[i,j]:=a[i,k]+a[k,j]; #include “grafuri.cpp”
a[j,i]:=a[i,j]; float A[50][50]
end; int n;
end; void Drum(int I,int j)
procedure drum(v1,v2:byte); {
var k:byte;gasit:boolean; int k=1,gasit=0;
begin while ( (k<=n) && !gasit)
k:=1;gasit:=false; {
while(k<=n)and not gasit do if ( (I!=k) && (j!=k) && (A[I][j]==A[I]
begin [k]+A[k][j]) )
if(v1<>k)and(v2<>k)and(a[v1,v2]=a[v1,k]+a[k,v2])then {
begin Drum(I,k0;Drum(k,j);
drum(v1,k);drum(k,v2); Gasit=1;}
gasit:=true; K++;
end; }
k:=k+1; if (!gasit) cout<<j<<” “;
end; }
if not gasit then write(v2,' '); void Scriu_drum(int
end; Nod_Initial,Nod_Final)
begin {
citeste; if (A[Nod_Initial][Nod_Final].Minfinit)
mat_drumuri; {
if a[x,y]=infinit then writeln('Nu exista lant elementar intre cele doua cout<<”Drumul de la “<<Nod_Initial<<”
varfuri') la “<<Nod_Final<<” are lungimea
else “<<A[Nod_Initial][Nod_Final]<<endl;
begin cout<<Nod_Initial<<” “;
writeln('Drumul minim are lungimea:',a[x,y]); Drum(Nod_Initial,Nod_Final);
write(x,' '); }
drum(x,y); else
end; cout<<”Nu exista drum de la
readln; “<<Nod_Initial<<” la “<<Nod_Final;
end. }
void Lungime_Drumuri()
{
int I,j,k;
for (k=1;k<=n;k++)
for (I=1;I<=n;I++)
for (j=1;j<=n;j++)
if (A[I][j]=A[I][k]+A[k][j];
}
main()
{
Citire_cost1(“Graf.txt”,A,n);
Lungime_Drumuri();
Scriu_drum(1,2);
}
ALGORITMUL
ALGORITMUL DIJKSTRA
{ Fie n localitati intre care exista o retea de drumuri. DIJKSTRA
Un turist care se gaseste in localitatea A doreste sa viziteze Fiind dat un graf memorat prin matricea
localitatea ponderilor, se cere sa se determine pentru

170
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

B cu cheltuieli minime. Cheltuielile turistului sunt direct proportionale orice x,y apartin de X lungimea minima a
cu distanta parcursa dintr-o localitate in alta. drumului de la nodul x la nodul y.Prin
Cunoscandu-se lungimea fiecarui drum dintre localitati, sa se lungimea unui drum intelegem suma
determine un ponderilor arcelor care-l alcatuiesc.
traseu pe care sa-l urmeze calatorul din localitatea A pana in Include “grafuri.cpp”
localitatea B Float A[50][50],D[50],min;
astfel incat costul calatoriei sa fie minim. Un drum intre doua localitali Int S[50],T[50],n,I,j,r,poz;
poate fi unidirectional sau bidirectional, pentru fiecare drum Void drum(int I)
cunosandu-se {
lungimea. if (T[I]) drum(T[I]);
cout<<I<<” “;
. Rezolvare }
Programul determina drumul minim intre doua varfuri ale unui graf main()
orientat {
folosind algoritmul Dijkstra. Citire+cost(“Graf.txt”,A,n);
n-numarul de localitati Cout<<”Introduceti nodul de pornire
a-matricea ponderilor asociata grafului; “<<endl;
d-vectorul care contine lungimea drumului minim dintre localitatea de Cout<<”r=”;cin>>r;S[r]=1;
plecare si o alta localitate; For (I=1;I<=n;I++)
{
p-vectorul care memoreaza varfurile prin care se trece pentru a D[I]=A[r][I];
obtine If (I!=r)
drumul minim.} If (D[I]<Pinfinit) T[I]=r;}
program drum_minim; For (I=1;I<=n;I++)
const infinit=1e38; {
type matrice=array[1..50,1..50] of real; min=Pinfinit;
multime=set of byte; for(j=1;j<=n;j++)
vect=array[1..50] of real; if (S[j]==0)
var n:byte;a:matrice;f:text;v1,v2:byte; if (D[j]<min)
d:vect;p:array[1..50] of byte; {
procedure citeste; min=D[j];
var i,x,y,j:byte;cost:real; poz=j;
begin }
assign(f,'in8.pas'); S[poz]=1;
reset(f); For (j=1;j<=n;j++)
readln(f,n); If (s[j]==0)
for i:=1 to n do If (D[j]>D[poz]+A[poz][j])
for j:=1 to n do {
if i=j then a[i,j]:=0 D[j]=D[poz]+A[poz][j];
else a[i,j]:=-1; T[j]=poz;
readln(f,v1,v2); }
while not eof(f) do for (I=1;I<=n;I++)
begin if (I!=r)
readln(f,x,y,cost); if(T[I])
a[x,y]:=cost; {
end; cout<<”distanta de la “<<r<<” la
close(f) “<<I<<” este “<<D[I]<<endl;
end; drum(I);
cout<<endl;
procedure Dijkstra; }
var varfuri:multime;i,j,k:byte;min:real; else
begin cout<<”nu exista drum de la “<<r<<” la
varfuri:=[1..n]-[v1]; “<<I<<endl;
for i:=1 to n do }
begin
d[i]:=a[v1,i];
P[i]:=v1
end;
for k:=1 to n-2 do
begin

171
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

min:=infinit;
for i:=1 to n do
if(i in varfuri) and (d[i]>0) and (d[i]<min) then
begin
min:=d[i];j:=i;
end;
varfuri:=varfuri-[j];
if j=v2 then break;
for i:=1 to n do
if(i in varfuri) and (d[j]<>-1) and (a[j,i]<>-1) then
if(d[i]=-1) or (d[i]>d[j]+a[j,i])then
begin
d[i]:=d[j]+a[j,i];
P[i]:=j;
end;
end;
end;
procedure scrie_drum(k:byte);
begin
if k<>v1 then scrie_drum(p[k]);
write(k,' ');
end;
begin
citeste;
Dijkstra;
if d[v2]=0 then write('Nu exista posibilitatea de deplasare de la ',v1,' la
',v2)
else
begin
writeln('Costul minim al deplasarii intre localitatile',v1,' si ',v2,' este
',d[v2]:7:2);
scrie_drum(v2)
end;
readln;
end.

Grafuri neorientate
Notiuni introductive

Definitie.Dca multimea g are proprietatea de simetrie, graful se numeste neorientat.


Definitie.Un graf partial al unui graf neorientat dat G=(X,g) este un graf G1=(X,g1
unde g1 inclus sau=cu g.
Definitie.Unsubgraf al unui graf neorientat G=(X,g) este un graf H=(Y<g1), unde
Yinclus in X, iar muchiile din g1 sunt toate muchiile din g care au ambele extremitati
in multimea Y.
Definitie.Lant.Pentru graful neorientat , un lant este o succesiune de varfuri cu
proprieatea ca oricare doua varfuri sunt adiacente.
Grafuri hamiltoniene
Definitie:
Se numeste ciclu hamiltonian intr-un graf, un ciclu elementar care contine toate varfurile
grafului .
Se numeste graf hamiltonian ,un graf care contine un ciclu hamiltonian.
Se numeste lant hamiltonian intr-un graf, un lant elementar care contine toate varfurile
grafului.

172
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Teorema:
Daca intr-un graf G=(X,U) cu n>=3 varfuri, gradul fiecarui varf x verifica conditia
d(x)>=n/2, atuncigraful este hamiltonian,

LIMBAJUL PASCAL LIMBAJUL C/C++

{ Se citeste matricea de adiacenta la un graf neorientat #include “grafuri.cpp”


Sa se genereze toate ciclurile hamiltoniene ale acestuia int st[50],a[50][50],n,k;
void Init()
ex:n=3 { st[k]=1; }
=>1 3 2 1 int AmSuccesor ()
1 2 3 1} { if (st[k]<n)
type sir =array[1..100] of integer; { st[k]++
return 1;
var x:sir; }
p,i,j,k,n,k1:integer; else return 0;
as,ev:boolean; }
a:array[1..50,1..50] of integer; int E_Valid()
{ if (!a[st[k-1]][st[k]]) return 0;
procedure succesor(var x:sir;k:integer;var as:boolean); else
begin for (int 1=1;I<=k-1;I++)
if (x[k]<n) then begin if (st[I]==st[k]) return 0;
as:=true; x[k]:=x[k]+1; if (k==n && !a[1][st[k]]) return 0;
return1;
end }
else int Solutie()
as:=false; { return k==n;}
end; void Tipar()
{ for (int I=1;I<=n;I++)
procedure valid(x:sir;k:integer;var ev:boolean); cout<<”Nodul “<<st[I]<<endl;
var i:integer; k=0;
begin }
ev:=true; void back()
if a[x[k-1],x[k]]=0 then ev:=false { int AS;
else k=2; Init();
begin while (k>1)
for i:=1 to k-1 do { do {} while ((AS=Am_Succesor())
if x[k]=x[i] then ev:=false; && !E_Valid());
if (k=n) and(a[x[n],x[1]]=0) then ev:=false; if (AS)
end; if (Solutie()) Tipar();
end; else {k++;Init();}
else k--;
procedure afis(x:sir;k:integer); }
var i:integer; }
begin main () { st[1]=1;k=2;st[k]=1;
for i:=1 to k do CitireN(“graf.txt”,a,n);
write( x[i] ,' '); Back();
write(x[1]:4); }
writeln;
end;

begin

write('dati numarul de noduri din graf');


readln(n);

for i:=1 to n-1 do


begin
for j:=i+1 to n do
begin

173
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

write('numarul ',i,',',j,' este ');


readln(a[i,j]);
a[j,i]:=a[i,j];
end;
end;x[1]:=1;
k:=2; j:=0;
x[k]:=1;
while(k>0) do
begin
repeat
succesor(x,k,as);
if as then valid(x,k,ev)
until (as and ev) or (not as);
if as then
if (k=n) then
afis(x,k)
else
begin
k:=k+1;
x[k]:=1;
end
else
k:=k-1 ;
end;
readln;
end.

Grafuri euleriene
Definitie:
Se numeste ciclu eulerian intr-un graf, un ciclu care contine toate muchiile grafului.
Se numeste graf eulerian, un graf care contine un ciclu eulerian.
Teorema:
Un graf fara varfuri izolate este eulerian, daca si numai daca este conex, si
gradele tuturor varfurilor sunt numere pare
LIMBAJUL PASCAL LIMBAJUL C/C++

174
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

{Stiind ca un graf conex(are o singura componenta #include “grafuri.cpp”


conexa) , int A[50][50],S[50],n;
fara virfuri izolate si care are gradele fiecarui virf Nod*Alista, *Indice;
un numar par Int A[50][50],S[50],n;
Sa se determine daca este ciclu eulerian sa nu Nod Alista,Indice;
ex:n=3 Void ciclu(Nod* v)
m=3 si anume (1,2),(1,3),(2,3) {int Nodul;
=>1 2 3 1 e ciclu eulerian} Nod Anod_baza,Anod_gasit,*Anod_urm;
var eulerian:boolean; Anod_urm=v->adr_urm;
e,grd,nd,c1:array[1..20] of integer; Anod_baza=v;
a:array[1..20,1..20] of integer; Do
n,m,i,j,k,k1,x,y,l:integer; { Nodul=1;
viz:array[1..20] of byte; while (A[Anod_baza->nd][Nodul]==0) Nodul+
function izolate:boolean; +;
var i,j,m,intr:byte; A[ANod_baza->nd][Nodul]=0;A[Nodul]
begin [ANod_baza->nd]=0;
izolate:=false; ANod_gasit=new Nod; ANod_gasit->nd=Nodul;
for i:=1 to n do ANod_gasit->adr_urm=0;
begin ANod_baza-
intr:=0; >adr_urm=ANod_gasit;ANod_baza=ANod_gasit;
for j:=1 to n do } while ((ANod_gasit->nd!=v->nd);
intr:=intr+a[i,j]; ANod_baza->adr_urm=ANod_urm;
grd[i]:=intr; Int adauga()
if intr=0 then begin {
izolate:=true; int I,gasit=0;
break; Indice=Alista;
end; While (Indice && !gasit)
end; {
end; for (I=1;I<=n;I++)
function gradepare:boolean; if (A[Indice->nd][I]==1) gasit=1;
var i:byte; if (!gasit) Indice=Indice->adr_urm;
begin }
gradepare:=true; if (Indice)
for i:=1 to n do {
if odd(grd[i]) then begin ciclu (Indice);
gradepare:=false; return 1;
break; }
end; else return 0;
end; }
function conex:boolean; int grade_pare()
var b,viz:array[1..20] of byte; {
i,j,p,u,v:byte; int I=1,j,s,gasit=0;
begin while ( (I<=n) && ! gasit)
for j:=1 to n do {
viz[j]:=0; s=0;
b[1]:=1; for (j=1;j<=n;j++) s+=A[I][j];
p:=1; if (s%2) gasit=1;
u:=1; I++;
viz[1]:=1; }
while p<=u do begin return !gasit;
v:=b[p]; }
for j:=1 to n do void df(int nod)
if (a[v,j]=1) and (viz[j]=0) then {
begin int k;
u:=u+1; S[nod]=1;
b[u]:=j; For (k=1;k<=n;k++)
viz[j]:=1; If ( (A[nod][k]==1) && (S[k]==0)) df(k);
end; }
p:=p+1; int conex()
end; {
conex:=true; int gasit=0,I;

175
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

Flux intr-o retea de transport

Defnitie.fluxul unei retele R este o functie definit pe X*X cu valori in N care


indeplineste anumite conditii.
Determinarea fluxului de valoare maxima
LIMBAJUL PASCAL LIMBAJUL C/C++

176
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

{Flux maxim intr-o retea de transport #include “grafuri.cpp”


O retea de transport este un graf orientat G=(V,E) #include <math.h>
care satisface urmatoarele int A[50][50]
conditii: [2],n,st,fin,gasit,coada[50],s[50],f[50],I_c,sf_c,I,j,min;
a) exista un unic varf s apartine V in care nu void refac(int Nod)
intra nici un {
arc(gradul interior 0) numit sursa; if (Nod!=st)
b) exista un unic varf d apartine V in care nu if (s[Nod}>0)
iese nici un {
arc(gradul exterior 0); if (min>A[s[Nod]][Nod][0]-A[s[Nod]][Nod][1])
c) pentru fiecare nod x apartine V-(s,d)exista min=A[s[Nod]][Nod][0]-A[s][Nod][Nod][1];
cel putin un drum de refac(s[Nod]);
la sursa la destinatie;cu alte cuvinte graful G A[s[Nod]][Nod][1]+=min;
este conex; }
d) pe multimea arcelor se defineste o functie else
c:E->R+,numita functie {
de capacitate; if (min>A[Nod][s[abs(Nod)]][1])
Algoritmul se executa intr-un nr finit de pasi.in cadrul min=A[Nod][abs(s[Nod])][1];
surselor prezentate refac(abs(s[Nod}));
in continuare determinare drumului de crestere din A[Nod][abs(s[Nod)][1]-=min;
graful rezidual asociat se }
realizeaza printr-o parcurgere BF a acestuia. }
ex:6 void drum_in_crestere()
125 {
137 gasit=0;
233 I_c=sf_c=1;coada[I_c]=st;
244 While( (I_c=sf_c) && (coada[sf_c]!=fin) )
342 {
356 I=1;
467 While ( (I<=n) && !gasit)
545 {
569 if ((A[coada[I_c]][I][0]-A[coada[I_c]][I][1]>0) && (s[I]==0))
=>fluxul maxim este 12} {
s[I]=coada[I_c];coada[++sf_c]=I;
}
else
const mare=30000; if ((A[I][coada[I_c]][1]>0) && (s[I]==0) && (I!=st) )
{
type ma=array[0..200,0..200] of boolean; s[I]=-coada[I_c];coada[++sf_c]=I;
sir=array[0..200 ] of byte; }
sirb=array[0..200] of boolean; I++;
interval=0..200; }
mc=array[0..100,0..100] of integer; I_c++;
var c,f,a:mc; }
co,t,d:sir; if (coada[sf_c]==fin gasit=1;
sel:sirb; }
i,j,k,m,n,min,flux:integer; void caut()
procedure init; {
begin do
for i:=1 to n do {
for j:=1 to n do for (I=1;I<=n;I++)s[I]=0;
if c[i,j]>f[i,j] then a[i,j]:=c[i,j]-f[i,j] drum_in_crestere();
else if (s[fin])
if f[j,i]>0 then {
a[i,j]:=f[j,i] min=32000;
else refac(fin);
a[i,j]:=mare; }
for i:=1 to n do a[i,i]:=0; } while (gasit);
fillchar(sel,sizeof(sel),false); }
sel[1]:=true;t[1]:=0; main()
end; {

177
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

CUPRINS

Prefata…………………………..……………………………………………………………..1
Exemple de roboti………….………………………………………………………………….2
Structura robotilor…………………………………………………………………………..…5
Sistemul mecanic al robotului…….……………………….………………………………..…
33
Sistemul de actionare si comanda la roboti……………………………………………………
39
Senzori…………………………………………………………………………………………
48
Aplicatii roboti ficşi si mobili in
industrie……………………………………………………..62
Constructia electronica a unui robot……….………………………………………………...…
93

Limbajele Pascal si C++ in paralel…………………………………….………………..…...…


101

Cuprins……………………………………………………………………………………...…
117

178
Rezolvarea temelor pentru concursurile de titularizare si grade didactice in informatica
Prof.Bogdan Constantin

179

You might also like