Sunteți pe pagina 1din 158

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 cunstruiasca numarul sau.


var m,n:word;
begin
write('n='); readln(n);
m:=0;
while (n<>0) do begin
m:=m*10+n mod 10;
n:=n div 10;
end;
write(m);
end.
2) Se citeste un numar natural n,sa se calculeze numarul cifrelor sale.
ex:123
=>3}

var n,nr:word;
begin
write('n='); readln(n);
nr:=0;
while (n<>0) do begin
nr:=nr+1;
n:=n div 10;
end;
write(nr);
end.
3) Pentru a, b numere naturale date, 0<=a<b, sa se afiseze toate numerele
deosebite din intervalul [a,b].Pentru fiecare numar deosebit se va afisa o
singura descompunere.Sa se precizeze numarul lor.Un numar natural m este
deosebit daca exista un numar natural n astfel incat m=n +s(n), unde s(n)
este suma cifrelor lui n.
Exemplu:
In intervalul [30,100] sunt 64 numere deosebite.}
var a,b,m,n,n1,s,nr:word;
begin
write('a='); readln(a);
write('b='); readln(b);
if b<=a then begin
writeln('Data incorecta!'); readln; exit; end;
nr:=0;
for m:=a to b do
for n:=0 to m do begin
n1:=n; s:=0;
while n1>0 do begin
inc(s,n1 mod 10);
n1:=n1 div 10; end;
if m=n+s then begin
inc(nr);
write(m,'este un numar deosebit.');
writeln(' ',m,'=',n,'+',s);
if (m-a+1) mod 20=0 then
readln;
break
end
end;
writeln('in intervalul[',a,',',B,'] SUNT',NR,'NUMERE DEOSEBITE');
readln;
end.
4) Se citeste un numar natural mai mare strict decat 9 avand numar impar de
cifre (validare).Sa se afiseze numarul obtinut prin eliminarea cifrei din

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

mijloc a numarului initial;.


Exemplu:
numarul initial:12345 numarul procesat:1245}
var n,n1:0..maxlongint;
cifre,i:byte;
begin
repeat
write('Numarul dat:'); readln(n);
n1:=n; cifre:=0;
repeat
inc(cifre);
n1:=n1 div 10
until n1=0
until (n>9) and odd(cifre);
i:=0;
repeat
inc(i);
if i<>cifre div 2+1 then
n1:=n1*10+n mod 10;
n:=n div 10
until n=0;
repeat
n:=n*10+n1 mod 10;
n1:=n1 div 10
until n1=0;
writeln('Numarul obtinut:',n);
end.
5) Pentru un numar intreg nr dat, cifra de control (cifra de baza) se obtine
astfel: se calculeaza suma cifrelor numarului dat, apoi suma cifrelor acestei
sume,etc.Operatiile inceteaza cand suma obtinuta este o cifra,numita cifra de
control (de baza) a numarului dat.Se citesc n>0 numere intregi.Sa se afiseze
numerele cu cifra de control para.
Exemplu:
n=8 (-35,567,-11,-56,23,0,65,635)
Se vor afisa urmatoarele numere:
-35 are cifra de baza 8;
-56 are cifra de baza 2;
65 are cifra de baza 2;
-11 are cifra de baza 2;
0 are cifra de baza 0;
535 are cifra de baza 4.}
var n,i,s:byte;
nr,nr1:integer;
begin
repeat
write('n='); readln(n);
until n>0;
i:=0;
repeat
inc(i); write ('Numarul',i,':');
readln(nr); nr1:=abs(nr);
repeat
s:=0;
repeat
inc(s,nr1 mod 10);
nr1:=nr1 div 10
until nr1=0;
nr1:=s
until nr1<10;
if not odd(nr1) then

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

writeln(nr,'are cifra de baza',nr1)


until i=n; writeln;
end.
6) Sa se calculeze ultima cifra a numarului a^n, unde a si n sunt numere
naturale mai mici ca 10000.
Exemplu:
2^1000 are ultima cifra 6.}
var a,n,i,p,r:word;
begin
write('a='); readln(a);
write('n='); readln(n);
r:=a mod 10; p:=1;
for i:=1 to n do
begin
p:=p*r; p:=p mod 10;
end;
writeln('ultima cifra:',p);
end.
7) Sa se genereze toate numerele naturale de patru cifre (abcd), ale caror
cifre sunt consecutive (cifra miilor este cea mai mica), iar a*d=(bc)/2.Sa se
precizeze numarul lor.
Observatie:
un singur numar indeplineste conditiile:4567}
var a,b,c,d,n:0..9;
nr:word;
begin
n:=0;
for a:=1 to 6 do
begin
b:=a+1; c:=b+1; d:=c+1;
if a*d=(10*b+c) div 2 then begin
nr:=1000*a+100*b+10*c+d;
write(nr:5); inc(n); end;
end;
writeln;
writeln(' numar de numere:',n);
end.
8) Se citesc de pe mediul standard de intrare doua numere naturale n si m. Sa
se afiseze cifra de pe pozitia m din numarul n.(cifrele vor fi numerotate de la
dreapta la stanga).Daca nu exista o cifra pe pozitia respectiva, se va afisa
0.
Exemplu:
Pentru n=4523, m=2 se va afisa 2, iar pt. n=123 si m=4 se va afisa 0.}
var n,m,cifra,k:word;
begin
write('n='); readln(n);
write('pozitia='); readln(m);
cifra:=0; k:=0;
while n<>0 do begin
k:=k+1;
if k=m then
cifra:=n mod 10;
n:=n div 10;
end;
writeln('cifra:',cifra);
end.
9) Sa se verifice daca numarul natural n este bine ordonat.(n are cifrele fie
in ordine crescatoare, fie in ordine descrescatoare).ex:123 este
Solutie;
Se pune problema in ce ordine are n cifrele: crescatoare sau descrescatoare?

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

Ne dam seama de acest lucru comparand ultimele doua cifre ale lui n.Dar daca
aceste sunt egale?Pentru a rezolva aceasta problema am facut un 'while' ce
elimina ultimele cifre din n. Apoi am facut o conventie: daca n are cifrele
in ordine descrescatoare , t=0, iar daca le are in ordine crescatoare t=1.}
var n,c,t,r:word;
ok:boolean;
begin
ok:=true;
write('n='); readln(n);
c:=n mod 10; n:=n div 10;
while c= n mod 10 do
n:=n div 10;
if c<n mod 10 then t:=0
else t:=1;
r:=n mod 10; n:=n div 10;
while n<>0 do begin
c:=r;
if (c> n mod 10) and (t=0) then ok:=false;
if (c< n mod 10) and (t=1) then ok:=false;
r:=n mod 10; n:=n div 10;
end;
if ok then writeln('bine ordonat')
else writeln('nu e bine ordonat');
end.
10) Se dau doua numar natural x si y cu cel mult zece cifre.Se cere sa se
afiseze suma dintre produsul cifrelor lui x si produsul cifrelor lui y.}
var
x, y, px, py:longint;
begin
write ('x='); readln(x);
write ('y='); readln(y);
px:=1;
while x<>0 do begin
px:=px*(x mod 10);
x:=x div 10;
end;
py:=1;
while y<>0 do begin
py:=py *(y mod 10);
y:=y div 10;
end;
writeln (px+py);
readln;
end.
11) Sa se determine cel mai mare numar care se poate forma cu
cifrele unui numar natural citit de la tastatura.}
var
x,i,c ,nr , ap:longint;
begin
writeln('dati numarul ');readln(nr);
for c:=9 downto 0 do begin
x:=nr;
ap:=0;
repeat
if x mod 10=c then inc(ap);
x:=x div 10;
until x=0;
for i:=1 to ap do write (c);
end;
readln;

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

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

3.5.2 Divizibilitate
1)Determinaţi toate numerele care sunt multipli de k, care depăşesc valoarea n.
program multipli2;
var k,i,n:longint;
begin
write('k=');readln(k);
write('n=');readln(n);
i:=k;
while i<=n do
begin
write(i,' ');
inc(i,k);
end;
end.
2) Se citesc n numere naturale.Sa se numere cate din ele sunt pare.

var n,i,x,nr_pare:integer;
begin
Write('n='); readln(n);
nr_pare:=0;
for i:=1 to n do begin
read(x);
if x mod 2 =0 then
nr_pare:=nr_pare+1;
end;
write(nr_pare);
end.

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

3) Se citeste un numar natural n Sa se numere divizorii sai (inclusiv 1 si


el insusi)}

var n,nr_div,i:integer;
begin
Write('n='); readln(n);
nr_div:=0;
for i:=1 to n do
if n mod i=0 then
nr_div:=nr_div+1;
write(nr_div);
end.
4) Sa se genereze toate numerele naturale de patru cifre de forma 1bcd care
indeplinesc simultan conditiile:d<c, b-c=1, iar b si d sunt divizibile cu 3 .
Sa se precizeze numarul lor.
Exemplu:
Sunt 6 numere:1320, 1650, 1653, 1980, 1983, 1986}
var b,c,d,n:0..9;
nr:word;
begin
n:=0;
for b:=3 to 9 do
for d:=0 to 6 do begin
c:=b-1;
if (d<c) and (b mod 3=0) and (d mod 3=0) then begin
nr:=1000+100*b+10*c+d;
write(nr:5); inc(n);
end;
end;
writeln;
writeln('sunt',n,'numere');
end.
5) Sa se verifice daca numarul natural n este perfect sau nu.( n este perfect
daca este egal cu suma divizorilor sai mai mici ca el).
Exemplu:
n=6 este perfect deoarece 6=1+2+3.}
var n,i,s:word;
begin
write('n='); readln(n);
s:=0;
for i:=1 to n div 2 do
if n mod i=0 then s:=s+i;
if n=s then
writeln('numar perfect')
else
writeln('numarul nu este perfect');
end.

6) Sa se determine cel mai mic numar natural nenul care are exact n divizori
(inclusiv divizorii banali), d>=2 dat.Sa se afiseze acest numar impreuna cu
divizorii sai.
Exemplu:
d=10 : n=48
Divizori: 1,2,3,4,6,8,12,16,24,48}
var d,nr:byte;
n,i:word;
begin
repeat
write('d='); readln(d)
until d>=2;

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

n:=2;
repeat
nr:=0;
for i:=1 to n do
if n mod i=0 then inc(nr);
if nr=d then begin
writeln('Cel mai mic numar natural cu exact',d,'divizori este',n);
write('Divizorii lui', n,' sunt:');
for i:=1 to n do
if n mod i=0 then write(i:5);
writeln;
break end
else inc(n)
until false;
readln
end.
7) SA se determine descompunerea in factori primi a unui numar natural n,
citit de pe mediul standard de intrare.Afisarea se va efectua ca in exemplul
urmator.
Exemplu:
pentru n=12 avem:
12|2
6|2
3|3
1|-}
var n,p:word;
begin
write('n='); read(n); p:=2;
while n>1 do
begin
while n mod p=0 do
begin
writeln(n,'|',p);
n:=n div p;
end;
p:=p+1;
end;
writeln(1,'|-');
end.
8) SA se determine suma numerelor naturale mai mici ca n, divizibile cu 5.}
var i,n,s:word;
begin
write('n='); readln(n);
s:=0;
for i:=5 to n do
if i mod 5=0 then s:=s+i;
writeln('s=',s);
end.
9) Sa se determine cifrele x si y astfel incat numarul 1x2y sa fie divizibil
cu 3.
Solutie:
Daca x si y sunt cifre atunci x,y apartin multimii{0,1,..,9) cu x<>0.Vom
verifica daca suma 1+x+2+y=3+x+y este divizibila cu 3}
var x,y:byte;
begin
for x:=1 to 9 do
for y:=0 to 9 do
if (x+y+3) mod 3=0 then
writeln(1,x,2,y);
end.

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

9) Se citesc pe rand un numar prim x si n numere naturale.Fara a inmulti cele


n numere, sa se determine k maxim, pentru care x^k divide produsul celor n
numere.
Exemplu:
pentru n=4 si x=3 si numerele 23, 36, 4, 6 se va afisa k=3, deoarece 3^3 divide
23*36*4*6}
var n,x,k,i,nr:word;
begin
write('n='); readln(n);
write('nr. prim:'); readln(x);
k:=0;
for i:=1 to n do begin
write('nr='); readln(nr);
while nr mod x=0 do begin
k:=k+1; nr:=nr div x;
end;
end;
writeln('k maxim:',k);
end.
10) Se dau doua n numere naturale nenule (n<20) .Se cere sa se afiseze
media aritmetica a numerelor pare. Daca nu exista numere pare se va afisa
mesajul "Nu exista numere pare ".}
var n,k,s,i,x: longint;
begin
write ('n='); readln (n);
s:=0; k:=0;
for i:=1 to n do begin write ('dati numarul ',i);
readln (x);
if x mod 2 =0 then
begin
s:=s +x;
k:=k+1;
end;
end;
if k>0 then
write (s/k:0:2)
else
write (' nu exista numere pare');
readln;
end.
11) Se dau doua n numere naturale nenule (n<40) .Se cere sa se afiseze
cel mai mare divizor comun.}
var n,a,b,d,i,x: longint;
begin
write ('n='); readln (n);
writeln(' dati primul numar ');
readln(x);
d:=x;
for i:=2 to n do begin writeln(' dati numarul al ',i,' lea ');
read(x);
a:=d; b:=x;
while a<>b do
if a >b then
a:=a-b
else
b:=b-a;
d:=a;
end;
writeln ;
write (' c.m.m.d.c=',d);

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

readln;
end.
3.5.2 Numere prime

1) Se citeste un numar natural n.Sa se verifice daca el este prim.}

var n,i:integer;
prim:boolean;
begin
write('n='); readln(n);
prim:=true;
for i:=2 to trunc(sqrt(n)) do
if n mod i =0 then
prim:=false;
if prim then
write('Numarul este prim')
else
write('Numarul nu este prim');
end.
2) Se citeste un numar natural n.Sa se afiseze divizorii sai primi.
ex:n=9
=>3}

var n,i,j:integer;
prim:boolean;
begin
write('n='); read(n);
for i:=2 to n-1 do
if n mod i=0 then begin
prim:=true;
for j:=2 to trunc(sqrt(i)) do
if i mod j =0 then
prim:=false;
if prim then write(i);
end;
end.
3) Sa se afiseze toate numerele prime mai mici sau egale decat n, n>1 dat.
ex:n=10
=>2 3 5 7}
var n,i,j:byte;
prim:boolean;
begin
write('n='); readln(n);
for i:=2 to n do begin
prim:=true;
for j:=2 to trunc(sqrt(i)) do
if i mod j=0 then begin
prim:=false; break; end;
if prim then write(i:5);
end;
writeln;
end.
4) Sa se afiseze toate numerele naturale x mai mici decat n,natural, cu
proprietatea ca x-1 si x+1 sunt numere prime.
Exemplu:
pentru n=15 se vor afisa: 4,6,12.}
var x,y,n,i,k:integer;
t:boolean;
begin

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

write('n='); readln(n);
for x:=2 to n-2 do
begin
k:=0;
t:=true;
for i:=2 to trunc(sqrt(x)) do
if x mod i=0 then t:=false;
if t then k:=k+1;
y:=x+2; t:=true;
for i:=2 to trunc(sqrt(y)) do
if y mod i=0 then t:=false;
if t then k:=k+1;
if k=2 then write (x+1,' ');
end;
end.
5) Se citeste un numar natural de cel mult 8 cifre. Sa se afiseze cel
mai apropiat numar prim fata de acesta.}
VAR x,i,k,n1,n2: longint;
ok: boolean;
begin
writeln('dati numarul ');
readln (x); n1:=x;
repeat
inc(n1);
ok:=true;
for i:=2 to trunc(sqrt(n1)) do
if n1 mod i =0 then ok:=false;
until ok;
n2:=x+1;
repeat
dec(n2); ok:=true;
for i:=2 to trunc (sqrt(n2)) do
if n2 mod i=0 then ok:=false;
until ok;
if k-n2<n1-x then writeln (n2)
else writeln(n1);
readln;
end.
6) Se da un numar natural n (0<n<1000000).Se cere sa se afiseze toate
perechile de numere gemene (a,b), a,b<=n. Perechea (a,b) este o
pereche de numere gemene daca a si b sunt prime si valoarea absoluta a
diferenteia-b este 2.}
var
i,j,n,l:integer;
bec: boolean;
begin
write ('n='); readln(n);
for i:=2 to n-2 do begin bec:=true;
for j:=2 to trunc(sqrt(i)) do
if i mod j=0 then bec:= false;
if bec then begin
l:=trunc (sqrt(i+2));
for j:=2 to l do
if (i+2) mod j=0 then
bec:=false;
if bec then write ('(',i,',',i+2,') ');end;
end;
readln;
end.

36
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:

37
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

38
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

39
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:

40
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 sirul Fibonacci, n>0 dat.Sirul lui
Fibonacci este definit astfel: f(1)=0, f(2)=1, f(n)=f(n-1)+f(n-2).
Exemplu:
n=7 : 1, 1, 2, 3, 5, 8,13.}
var n,a,b,c,i,fibo:word;
begin
write('n='); readln(n);
if n=0 then fibo:=0
else if n=1 then fibo:=1
else begin
a:=0; b:=1;
for i:=2 to n do begin
c:=a+b; a:=b; b:=c; end;
fibo:=b; end;
writeln('Termenul de rangul',n,'din sirul lui Fibonacci:',fibo);
end.
3) Se citeste de la tastatura o valoare n intreaga,
pozitiva. Sa se verifice
daca acest numar este un termen in sirul lui Fibonacci. In caz contrar, sa
se descompuna intr-o suma de termeni Fibonacci.

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

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

3.5.5 Calculul unor sume cu termen general


1)Determinarea sumei 1+2+...+n .
program suma1;
uses crt;
var n,i,s:integer;
begin

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

clrscr;
writeln('Introduceti n:');readln(n);
s:=0;
for i:=1 to n do
begin
s:=s+i;
writeln('Suma primelor',i,'numere este',s);
end;
writeln('Suma totala este:',s);
readln;
end.
Varianta 2: Determinarea sumei a n numere folosind clauza downto .
program suma2;
var n,i,s:integer;
begin
writeln('Introduceti n:');readln(n);
s:=0;
for i:=n downto 1 do
begin
s:=s+i;
writeln('Suma ultimelor ',n-i+1,' numere este ',s);
end;
writeln(' Suma totala: ',s);
readln;
end.
2) Sa se calculeze suma S=1+1*2+1*2*3+...+1*2*....*n, unde n este un numar
natural citit.
ex:n=2
=>3
}

var p,n,s,i:integer;
begin
Write('n='); readln(n);
p:=1; s:=0;
for i:=1 to n do begin
p:=p*i;
s:=s+p;
end;
write(s);
end.
3) Pentru n>0 dat, sa se evalueze expresia:
E=1+1*3+1*3*5+...+1*3*..*(2*n+1)
Exemple:
a)n=2 : E=19
b)n=3 : E=124
c)n=4 : E=1069
d)n=5 : E=11464}
var n,i:byte;
e,p:word;
begin
write('n='); readln(n);
e:=1; p:=1;
for i:=1 to n do begin
p:=p*(2*i+1);
inc(e,p);
end;
write('E=',e);
end.

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

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
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:

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

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  N  R
definim

O( f ) = {t : N  N  R | (c  R+) (m0, n0  N) (m  m0) (n  n0)


     t(m, n)  cf (m, n)]}

Similar, se obtin si celelalte generalizari.

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)}

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

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)

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

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

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.

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.

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

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

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)

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

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,

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.

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

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.

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

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

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)

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.

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

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

Impunand conditiile initiale, obtinem

c1  c2      = 0         n = 0


r1c1  r2c2 = 1         n = 1

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

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

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

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

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

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

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

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

Indiferent de conditia initiala, c1 este deci 1.

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

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

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

c fiind o constanta. Obtinem succesiv

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

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

56
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

57
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.

58
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.

59
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:

60
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)!

61
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

62
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!).

63
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:

64
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ă.

65
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.

66
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

67
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;

68
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.

69
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ă

70
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.

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

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

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

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;

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];

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

unde id1,id2,…,idn sunt identificatori de unde id_v1,id_v2,..,id_vn sunt identificatori de


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

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

trunc:R→Z int(x)-partea intreaga din x ceil:R→Z Euler)


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

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

genereaza valoarea logica true). genereaza o valoare nenula).


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;

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

for i:=1 to n do cout<<’’n= ’’;cin>>n;


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++)

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

writeln (’media este’,max); if(medii[i]>max)


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.

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

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

□ 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.

78
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

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

La declarare, variabilele globale sunt iniţializate cu 0.

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.

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

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

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

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

Var s,i,n:integer; #Include<iostream.h>


Function ss(n:integer):integer; int i,n;
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.

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

Mecanismul recursivitatii

▫ 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.

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

n→2
n→3 Functia se autoapeleaza. De aceasta data parametrul n ia valoarea 2
.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 ;

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

end. }

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 3 3 Referinta catre p
val n prod 2 3 Referinta catre p
1 3 Referinta catre p

Pentru ca val este 2 –mai mic ca 3 - se efectueaza prod :=prod*val ; dupa 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.

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

▫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
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.

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

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


nivel, se intampla la orice nivel.

→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;

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

end. cin>>n;
citire(a,1);
tipar (a,1);
maxi=max(a,n);
cout<<a[maxi];
}
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)

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

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);
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

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

b[k]:=a[i]; b[k]=a[j];
i:=i+1; j=j+1;
k:=k+1; k=k+1;
end }
else if (i<=m)
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;
divimp(xxx1,m,a); cout<<”n=”;cin>>n;
divimp(m+1,xxx2,a); for (i=1;i<=n;i++)
interclasare(xxx1,xxx2,m,a); {
end;end; cout<<”a[“<<i<<”]=”;cin>>a[i];}
begin divimp(1,n,a);
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

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

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:
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; }

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

var st,dr:indice;x:tipelement; }
begin
st:=p;dr:=q;x:=a[p]; main( )
while st<dr do { int I;
begin cout<<”n=”;cin>>n;
while (st<dr) and (a[dr]>=x) do dec(dr); for (i=1;i<=n;i++)
a[st]:=a[dr];
while (st<dr) and (a[dr]>=x) do dec(dr); { cout<<”a[“<<i<<”]=”;cin>>a[i];}
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);

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

readln(a[i]); }
end;end;
procedure afisare;
var i:indice;
begin
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;

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

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;
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;

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

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++
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.

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

 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
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

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

Cum procedam?Observam, ca o dama trebuie sa fie plasata singura pe linie.Plasam prima dama pe
linia 1 coloana 1.

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

97
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-4-a.

D
D

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

3 sau situatia:
1
4 D st(1) = 3 i = 1
2 st(3) = 1 j=3
D | st(i) – st(j) l|= | 3-1 | = 2
| i-j | = |1-3 | = 2

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

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 problema
( ca doua dame sa nu fie plasate in aceeasi diagonala).A proceda astfel, inseamna ca nu lucram
conform strategiei backtracking.

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( )
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( ))
begin && !E_Valid( ));
READLN(N); if (AS)
write('dati vectorul '); if (Solutie( ))
readln(v); Tipar( );
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)

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

else
begin
k:=k+1;
x[k]:=0;
end
else
k:=k-1 ;
end;
readln;
end.

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); }

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

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
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.

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

LIMBAJUL PASCAL LIMBAJUL C/C++


Tipul multime
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

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

LIMBAJUL PASCAL LIMBAJUL C/C++


SPECTACOLE
{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.

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

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
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]; }

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

greutateaobiectului[i+1]:=auxiliara; else
auxiliara:=c[i]; {cout<<''Obiectul ''<<ordine[i]<<' ' <<gv /g[i]<<en
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.

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

=>Daca primcipiul de optimalitate se verifica in forma 3, spunem ca se aplica programarea


dinamica metoda mixta.
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.

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

Aceasta este si cea mai mare suma care se poate forma.


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.

107
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.
}

108
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.

109
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;

110
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
Var x:integer; Void main void()
A:^integer; { int x,*a=&x;
Begin x=10;

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

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>
union test
{ int a;
char b[10];

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

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;
Var s1,S2,S3: string; }
Begin
Readln(s2);

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

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 “
}

LIMBAJUL PASCAL LIMBAJUL C/C++


STREGEREA DINTR-UN SIR
Sintaxa:

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

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>
main()
{
int s;

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

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.

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.

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

Î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:

□ 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

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

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; }
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);
while not vida(a,dim) do void Pop (Nod*& v)
begin { Nod* c;
y:=elimin(a,dim); if (!v) cout<< ”stiva este vida”;
for i:=1 to dim do else
writeln(a[i]);writeln; { c=v;
if y>=12 then {writeln('valoarea functiei cout<<” am scos”<<c-
se poate calcula direct') } >info<<end1;
if not vida(a,dim) then a[dim]:=y-1 v=v->adr_inap;
else delete c;
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;

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

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;
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;

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

pop(v);
tipar(v);
readln;

if v<>nil then v^.info:=man-1;


end;
writeln('f=',man-1) ;
readln;
end.

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);

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

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).

| 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

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

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;
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)

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

{
Nod* c;
If (!v) cout<<”stiva este vida”;
Else
{
c=v;
cout<<”am scos”<< c-
>info<<end1;
v=v->adr_inap;
delete c;
}
}

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

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

7
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 {
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; }

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

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);
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;

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

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);
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ă.

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

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
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:

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

■ 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.

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:

7 adr₃
9 nil

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

3 adr₂
adr₁ adr₂ adrn

adrt

□ 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

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

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:

□ 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

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

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.

 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.

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.

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

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;
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);
}

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

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 int val1)
begin {
new(c); Nod*c,*d;
writeln('pe cine inserati inaite de pa i(dati un numar if(v->info==val)
',i);readln(c^.nr); {
c^.urm:=p; d=new Nod; d->info=val1; d-
p:=c; end; >adr_urm=v; v=d;
end; }
procedure adaugunlasfirsit; else
begin {
new(c); c=v;
writeln('dati numarul care-l puneti dupa ua inregistrare '); while(c->adr_urm->info!=val) c=c-
readln(c^.nr); >adr_urm;
c^.urm:=nil; d=new Nod; d->info=val1; d-
u^.urm:=c; >adr_urm=c->adr_urm; c->adr_urm=d;
u:=c; }
end; }
procedure adaugunlasfirsitmaimulte;
var multe:integer; void Sterg(Nod*& v, Nod *& sf, int val)
begin

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

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);
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);

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

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;
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

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

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
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;

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

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;
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

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

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;
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.

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

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

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

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

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;
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

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

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;
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;

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

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('------------------');
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 gama, vom spune ca x si y sunt
adiacente, iar varfurile x si y sunt incidente cu muchia [x,y].
-Daca gama(g)=multimea vida, acest graf se numeste graf nul si reprezentarea
lui in plan se reduce la puncte izolate.

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

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;
-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
{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

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

u:=u+1; coada[sf_c]=k;
co[u]:=j;
vi[j]:=1; s[k]=1;
end; }
if i<=u then pp(i+1); I_c++;
end; Bf_r1();
begin
clrscr; }
writeln(' n=');readln(n); }
writeln(' nuamrul de muchii ');readln(m); main()
for i:=1 to m do
begin
[ Citire(“graf.txt”,A,n);
writeln('dati muchia ',i); I_c=sf_c=1;
writeln( 'primul nod al muchiei ');readln(x); Coada[I_c]=s[1]=1;
writeln(' nodul de sfirsit al muchiei ');readln(y); Bf_r1();
a[x,y]:=1;a[y,x]:=1;
end; For(I=1;I<=sf_c;I+
for i:=1 to n do +)cout<<coada[I]<<” “;
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;
procedure pp(pl:integer); for (k=1;k<=n;k++)
var j:integer; if ((A[nod][k]==1) && (s[k]==0))
begin df_r(k);
write(pl,' ');vi[pl]:=1; }
for j:=1 to n do main()
if (a[pl,j]=1) and (vi[j]=0) then pp(j); {
end; Citire(‘Graf.txt”,A,n);
Df_r(1);
}
begin
clrscr;
writeln(' n=');readln(n);
writeln(' numarul de muchii ');readln(m);

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

for i:=1 to m do
begin
writeln('dati muchia ',i);
writeln( 'primul nod al muchiei ');readln(x);
writeln(' nodul de sfirsit al muchiei ');readln(y);
a[x,y]:=1;a[y,x]:=1;
end;
for i:=1 to n do
vi[i]:=0;
writeln(' care este nodul de plecare ');readln(pl);
pp(pl);
readln;
end.

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) )

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

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
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.

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

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

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<<” “;

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

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];
}
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++)

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

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 DIJKSTRA
{ Fie n localitati intre care exista o retea de drumuri.
Fiind dat un graf memorat prin matricea
Un turist care se gaseste in localitatea A doreste sa viziteze
ponderilor, se cere sa se determine pentru
localitatea
orice x,y apartin de X lungimea minima a
B cu cheltuieli minime. Cheltuielile turistului sunt direct proportionale
drumului de la nodul x la nodul y.Prin
cu distanta parcursa dintr-o localitate in alta.
lungimea unui drum intelegem suma
Cunoscandu-se lungimea fiecarui drum dintre localitati, sa se
ponderilor arcelor care-l alcatuiesc.
determine un
Include “grafuri.cpp”
traseu pe care sa-l urmeze calatorul din localitatea A pana in
Float A[50][50],D[50],min;
localitatea B
Int S[50],T[50],n,I,j,r,poz;
astfel incat costul calatoriei sa fie minim. Un drum intre doua localitali
Void drum(int I)
poate fi unidirectional sau bidirectional, pentru fiecare drum
{
cunosandu-se
if (T[I]) drum(T[I]);
lungimea.
cout<<I<<” “;
}
. Rezolvare
main()
Programul determina drumul minim intre doua varfuri ale unui graf
{
orientat
Citire+cost(“Graf.txt”,A,n);
folosind algoritmul Dijkstra.
Cout<<”Introduceti nodul de pornire
n-numarul de localitati
“<<endl;
a-matricea ponderilor asociata grafului;
Cout<<”r=”;cin>>r;S[r]=1;
d-vectorul care contine lungimea drumului minim dintre localitatea de
For (I=1;I<=n;I++)
plecare si o alta localitate;
{
D[I]=A[r][I];
p-vectorul care memoreaza varfurile prin care se trece pentru a
If (I!=r)
obtine
If (D[I]<Pinfinit) T[I]=r;}
drumul minim.}
For (I=1;I<=n;I++)
program drum_minim;
{
const infinit=1e38;
min=Pinfinit;
type matrice=array[1..50,1..50] of real;
for(j=1;j<=n;j++)
multime=set of byte;
if (S[j]==0)
vect=array[1..50] of real;
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; {

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

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
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.

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

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.
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); }

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

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
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++

{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)

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

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;
for i:=1 to n do df(1);
if viz[i]=0 then begin for (I=1;I<=n;I++)
conex:=false; if (S[I]==0) gasit=1;
break; return !gasit;
end; }

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

end; main()
begin { CitireN(“Graf.txt”,A,n);
write(' cite noduri are graful n='); if (conex())
readln(n); if (grade_pare())
write(' cite muchii are graful m='); {
readln(m); Alista=new Nod;
for I:=1 to n do Alista->nd=1;Alista->adr_urm=0;
for j:=1 to n do While (adauga());
a[i,j]:=0; Indice=Alista;
writeln('dati muchiile '); While (Indice)
for i:=1 to m do { cout<<Indice->nd<<” “;
begin Indice=Indice->adr_urm;
writeln('primul nod al muchiei ',i,' este ');readln(x); }
writeln('urmatorul nod al muchiei ',i,' este }
');readln(y); else cout <<”Graful nu indeplineste conditiile de
a[x,y]:=1; paritate”;
a[y,x]:=1; else cout<<”Graful nu este conex”;
end; }
eulerian:=not izolate and gradepare and conex;
if not eulerian then writeln ('graful nu este eulerian
')
else
begin
writeln('este eulerian ');
nd[1]:=1;
k:=1;
repeat
for j:=1 to n do
if a[nd[k],j]=1 then begin
k:=k+1;
nd[k]:=j;
a[nd[k-1],j]:=0;
a[j,nd[k-1]]:=0;
grd[j]:=grd[j]-1;
grd[nd[k-1]]:=grd[nd[k-1]]-1;
break;
end;
until nd[k]=1;
while k-1 <m do begin
for i:=1 to k-1 do
if grd[nd[i]]>0 then begin
c1[1]:=nd[i];
L:=i;
break;
end;
k1:=1;
repeat
for j:=1 to n do
if a[c1[k1],j]=1 then begin
k1:=K1+1;
c1[k1]:=j;
a[c1[k1-1],j]:=0;
a[j,c1[k1-1]]:=0;
grd[j]:=grd[j]-1;
grd[c1[k1-1]]:=grd[c1[k1-1]]-1;
break;
end;
until c1[k1]=c1[1];
for j:=k downto L do
nd[j+k1-1]:=nd[j];

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

for j:=1 to k1-1 do


nd[j+1]:=c1[j+1];
k:=K+k1-1;
end;
writeln('un ciclu care trece prin toate muchiile este
');
for i:=1 to m+1 do
write(' ',nd[i]);
end;
readln;
end.

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++

{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;

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

sir=array[0..200 ] of byte; s[I]=-coada[I_c];coada[++sf_c]=I;


sirb=array[0..200] of boolean; }
interval=0..200; I++;
mc=array[0..100,0..100] of integer; }
var c,f,a:mc; I_c++;
co,t,d:sir; }
sel:sirb; if (coada[sf_c]==fin gasit=1;
i,j,k,m,n,min,flux:integer; }
procedure init; void caut()
begin {
for i:=1 to n do do
for j:=1 to n do {
if c[i,j]>f[i,j] then a[i,j]:=c[i,j]-f[i,j] for (I=1;I<=n;I++)s[I]=0;
else drum_in_crestere();
if f[j,i]>0 then if (s[fin])
a[i,j]:=f[j,i] {
else min=32000;
a[i,j]:=mare; refac(fin);
for i:=1 to n do a[i,i]:=0; }
fillchar(sel,sizeof(sel),false); } while (gasit);
sel[1]:=true;t[1]:=0; }
end; main()
procedure bf; {
var nod,i,p,u:integer; Citire_Cap(“Graf.txt”,A,n,st,fin);
ok:boolean; Caut();
begin For (I=1;I<=n;I++)
co[1]:=1; p:=1; u:=1; ok:=false; {
while(p<=u)and not ok do begin for (j=1;j<=n;j++) cout <<A[I][j][1]<<” “;
nod:=co[p]; cout<<endl;
for i:=1 to n do }
if (a[nod,i]>0) and (a[nod,i]<mare) and not sel[i] then }
begin
t[i]:=nod; sel[i]:=true;
inc(u); co[u]:=i;
if i=n then ok:=true;
end;
inc(p);
end; end;
procedure drum(x:integer);
begin
if x<>1 then begin
if min>a[t[x],x] then
min:=a[t[x],x];
drum(t[x]);
end;
end;
procedure adauga(x:integer);
begin
if x>1 then begin
f[t[x],x]:=f[t[x],x]+min;
adauga(t[x]);
end;
end;
procedure solve;
begin
fillchar(f,sizeof(f),0);
flux:=0;
repeat
init; min:=mare;
bf;

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

if sel[n] then begin


drum(n);
adauga(n);
flux:=flux+min;
end;
until not sel[n];
end;
procedure scrie;
begin
writeln(' fluxul maxim de la primul nod la ultimul ');
writeln(flux);
writeln('dela la este ');
for i:=1 to n do
for j:=1 to n do
if f[i,j]>0 then
writeln(' ',i,' ',j,' ',f[i,j]);
end;
procedure load_graf_cost(var a:mc;var
n,m:integer;s:string;digraf:boolean;v:integer);
var i,j,co:integer;f:text;
begin
assign(f,s);
reset(f);
readln(f,n);
m:=0;
for i:=1 to n do
for j:=1 to n do
a[i,j]:=v;
while not seekeof(f) do begin
readln(f,i,j,co);a[i,j]:=co;
inc(m);
end;
close(f);
end;
begin
load_graf_cost(c,n,m,'in16.pas',TRUE,0);
flux:=0;
solve;
scrie;
readln;
end.

157
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

158

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