Sunteți pe pagina 1din 224

SPIRU HARET

(coordonator)


EDITURA FUNDAIEI ROMNIA DE MINE,
BUCURETI, 2003

Grigore Albeanu, Luminia Rpeanu,


Luminia Radu, Alexandru Averian. - Bucureti: Editura Fundaiei
Romnia de Mine, 2003
224 p., 20,5 cm
Bibliogr.
ISBN 973-582-665-8

I. Albeanu, Grigore
II. Rpeanu, Luminia
III. Radu, Luminia
IV. Averian, Alexandru

004.42
Editura Fundaiei Romnia de Mine, 2003
ISBN 973-582-665-8

Coperta: Marilena BLAN

Bun de tipar: 24.01.2003; Coli tipar: 14
Format: 16/61 x 86

Editura i Tipografia Fundaiei Romnia de Mine
Splaiul Independenei, nr. 313, Bucureti, S. 6, O. P. 83
Tel.: 410 43 80; Fax. 410 51 62; www.spiruharet.ro

3









Prefa ... 5
1. 7
1.1. Fiiere n limbajul Pascal ... 7
1.2. Fiiere n limbajul C ...... 17
2. .. 31
2.1. Liste simplu nlnuite ... 32
2.2. Liste dublu nlnuite . 46
2.3. Liste circulare .... 50
2.4. Stive ... 53
2.5. Cozi .... 55
2.6. Grafuri .... 62
2.7. Arbori ..... 87
3. .... 101
3.1. Metoda Divide et Impera 101
3.2. Metoda programrii dinamice 107
3.3. Metoda Greedy 116
3.4. Metoda backtracking 125
3.5. Metoda Branch and Bound 135
4. ... 145
5.


173
6. ... 201
6.1. Teoria i practica programrii .... 201
6.2. Probleme pentru concursuri ... 222
... 224


4

Capitolele lucrrii au fost elaborate dup cum urmeaz:

Prefaa, Cap. IV, Cap. V 2, Cap VI 2, Bibliografia

Cap. II, Cap. III, 2, Cap. VI 1.

Cap. I
Cap III 1, 3, 4, 5, Cap. V 1.

Lectura textului integral al lucrrii, structurarea materialului, verificarea
programelor (Pascal, C, C++) i procesarea final a materialului au fost
efectuate de Prof. univ. dr. Grigore Albeanu.
5
Prefa







Realizarea unui software complex presupune att organizarea
intrrilor i ieirilor, ct i o foarte bun gestiune a datelor i prilor
componente.
Aceast lucrare continu demersul iniiat n cadrul volumului
Algoritmic i programare n limbajul Pascal, Editura Fundaiei
Romnia de Mine, 2001, oferind cadrul teoretic i practic n nv-
area tehnicilor de programare fundamentale. Sunt tratate modaliti
de lucru cu fiiere, structuri de date complexe, metode de elaborarea
algoritmilor, organizarea subprogramelor n uniti de translatare
precum i conceptele de baz ale metodei de proiectare bazat pe
lucrul cu obiecte.
Conceptele, tehnicile i strategiile sunt ilustrate prin exemple,
att n limbajul Pascal, ct i n limbajul C. Ultima parte ilustreaz
metodologia OOP (engl. Object Orieted Programming) cu ajutorul
limbajului C++.
Materialul este util att elevilor i studenilor ce urmeaz specia-
lizrile informatic i matematic-informatic, absolvenilor n vederea
examenelor de titularizare, definitivat, ct i pregtirii complementare
n cadrul nvmntului postuniversitar de informatic.
Prin colecia de exemple, probleme propuse (la nivelul fiecrui
capitol) i teste de evaluare general (capitolul 5) lucrarea este util
pregtirii individuale sau n cadrul cercurilor de elevi sau seminariilor
studeneti, pentru participarea la concursurile de programare i la
diferite examene: bacalaureat, licen, titularizare etc.
Studenii de la cursurile cu frecven redus i nvmnt la
distan vor gsi exemple utile aprofundrii noiunilor transmise n
cadrul cursurilor: Algoritmic i programare, Tehnici de programare,
Informatic i Bazele informaticii.

Grigore ALBEANU

6
7


Se numete fiier, o structur de date ale crei compo-
nente, numite nregistrri, de dimensiune fix sau variabil, sunt stoca-
te (depuse), de obicei, pe un suport magnetic (band sau disc) de pe
care pot fi citite/scrise direct din program.
Dac nregistrrile din fiier au o dimensiune
variabil, se impune existena unor marcaje speciale numite separatori
de nregistrare.
Organizarea datelor n fiiere este necesar, dac:
volumul datelor prelucrate este foarte mare i depete capa-
citatea memoriei interne disponibile.
datele trebuie stocate n vederea unei prelucrri ulterioare, n
cadrul aceluiai program sau al altora.
n Turbo Pascal se poate lucra cu trei tipuri de
fiiere:
1) fiiere cu tip componentele au acelai tip i sunt stocate pe disc.
2) fiiere fr tip componentele sunt blocuri de informaii de
lungime fix i sunt stocate pe disc.
3) fiiere text componentele sunt caractere structurate pe linii de
lungimi variabile putnd fi stocate pe suport magnetic sau, fac
obiectul operaiilor de intrare-ieire cu consola (tastatura, ecran).
Tipul fiier se aseamn cu tipul tablou prin faptul
c toate componentele au acelai tip, dar se deosebete de acesta prin
modul de acces la componente i prin accea c numrul componen-
telor unui tip fiier nu este limitat.
Accesul la componentele unui fiier poate fi:
1) secvenial - pentru a accesa o anumit component trebuie
parcurse toate componentele care o preced.
2) direct orice component se poate accesa imediat dac se
precizeaz numrul ei de ordine in fiier, fr s fie necesar
parcurgerea elementelor precedente.
Accesul direct este permis numai pentru fiierele cu sau fr tip
stocate pe disc. Discul este singurul suport adresabil, care permite
calculul adresei unei componente, dac i se cunoate lungimea i
numrul de ordine n fiier.
8
Fiecrui fiier cu sau fr tip stocat pe disc i se asociaz de ctre
compilator o variabil numit indicator de fiier care cuprinde, n tot
timpul prelucrrii fiierului, numrul de ordine al componentei
curente.
ntr-un program Turbo Pascal un fiier se identific
printr-o variabil de tip fiier. Aceast variabil de tip fiier nu are
voie s apar n atribuiri sau expresii.
Prelucrarea fiecrui fiier trebuie precedat de apelul unei proceduri
standard ASSIGN, prin care variabilei de tip fiier i se asociaz
numele unui anumit fiier fizic. Toate operaiile n care se va specifica
variabila respectiv se vor face asupra fiierului fizic asociat prin
procedura assign.

Procedure assign
Forma general Procedure assign (var fiier;nume:string);
i e r u 4 3 0 T d ( T f 0 . 0 0 0 4 T c 0 5 1 4 2 T w - 1 8. 0 0 6 - 4 3 p 6 n u p o r t e x t e r n . 9 5 1 0 T d ( ) T j E MC 2 5 . 6 5 . 6 4 3 6 1 . 1 7 2 3 1 2 . 0 0 p j E MC 2 6 7 . 6 3 . 6 4 3 6 1 5 0 . 2 1 1 2 . 0 0 p j E MC 2 6 7 . 6 3 . 6 85 1 4 6 1 . 1 7 2 0 . 4 81 3 8. 3 . 6 2 6 7 . 6 3 . 6 4 3 6 1 5 0 . 2 1 1 2 . 0 0 p 1 3 9 . . 6 2 6 7 . 6 3 . 6 2 2 6 . 3 . 6 4 3 6 1 0 . 4 80 6 5 . 5 2 2 6 7 . 6 3 . 6 4 3 6 1 5 0 . 2 1 1 2 . 0 0 p 0 6 5 . 5 2 2 6 7 . 6 3 . 6 4 3 6 1 4 3 6 1 0 . 4 8B T ( ) T j E MC / ( ) < < / MC I D 6 2 > B DC / T T 2 1 T f - 0 T c 1 0 . 9 0 5 T 0 1 0 . 9 0 5 5 3 T 6 1 2 5 3 4 1 0 2 T m ( Ob s e r v T o a t e o p e 2 g n ) T j / T T 0 1 T 1 2 0 T w 8. 4 0 4 0 T d < 0 2 F A > T j / T T 1 2 2 ) T j 0 . 1 7 9 5 T c ( i a T 5 . 6 . T d ( A S S I GN ) T j - / T T 1 4 ) T j 0 . 1 82 1 T f 3 T c 1 3 T w 2 . 8A i e r e r e ( v r a r e a f i e c ) T j / C 2 _ 0 1 T f 5 . 1 9 1 8T w 0 . 87 6 0 T d < 0 1 0 3 > T j / T d e l c a r ( a g e n e r a l ) ] T J/ C 2 _ 0 1 T f 0 3 1 7 8T w 0 . 87 6 0 T d < 0 1 0 3 > T j / T d e p n r a r e a f i e c
9
Executarea procedurii reset (fiier) realizeaz:
Iniializarea indicatorului de fiier cu valoarea 0 (pentru fiiere cu
sau fr tip);
Iniializarea variabilei Filemode din unit-ul System astfel nct
s permit, n continuare, executarea de operaii de citire pentru
fiiere de tip text sau operaii de citire/scriere pentru fiiere cu
tip sau fr tip.
Apelul se termin cu eroare, dac fiierul fizic nu
exist. Dac fiierul este deschis n momentul apelului, acesta se
nchide, apoi se redeschide.
Apelul procedurii rewrite are forma: Rewrite(fiier) i executarea
procedurii const n:
Iniializarea indicatorului de fiier cu valoarea 0 (pentru fiier cu
sau fr tip).
Iniializarea variabilei filemode pentru a permite n continuare:
operaii de scriere pentru fiier de tip text, respectiv operaii de
scriere/citire pentru fiiere cu sau fr tip.
Apelul se termin cu eroare, dac nu este loc
suficient pe disc pentru noul fiier. Dac fiierul fizic asociat exist pe
suportul extern coninutul su este ters. Dac fiierul s-a deschis prin
executarea acestei proceduri, operaiile de citire sunt permise numai
dup ce s-au fcut scrieri.
Apelul procedurii close are forma: close(fiier) i are ca efect nchide-
rea fiierului prin care operaiile de citire/scriere a componentelor lui
sunt interzise pn la o nou deschidere.
Poziia curent dintr-un fiier (zona n care se
efectueaz operaiile de intrare/ieire) se numete indicator de fiier.

Fiiere text. Creare i exploatare
Un fiier text este format din caractere structurate pe linii. Fiecare
linie este terminat cu un marcaj sfrit de linie (eng. eol - end of line),
format din caracterele CR i LF (tastei ENTER i corespunde secvena
de caractere CR (eng. carriage return) i LF (eng. line feed) cu
codurile ASCII 13, respectiv 10, secven care reprezint marcajul de
sfrit de linie).
Fiierele text se stocheaz pe disc sau sunt
asociate unui dispozitiv logic (i se termin cu caracterul ^Z)
Tipul fiier t ext se declar conform diagramei:

Tip fiier text


Dimensiunea zonei tampon asociat unui fiV@@(p@b
11
Funcia EOF (End Of File) este de tip boolean, deci ntoarce dou
valori: true, dac poziia curent n fiier este dup ultimul caracter al
fiierului, sau fiierul este vid, respectiv false, n celelalte cazuri.
: eof [(var fiier)]
Funcia seekoln este de tip boolean, deci ntoarce dou valori: true,
dac avem sfrit de linie, respectiv false, n caz contrar
: seekeol n[(fiier)];
: atunci cnd caracterul curent ce urmeaz a fi citit din zona
tampon asociat fiierului este un caracter egal cu SPAIU sau TAB,
se crete adresa caracterului curent din zona tampon astfel nct s fie
un caracter diferit de spaiu sau tab. Returneaz true, cnd caracterul
curent care urmeaz s fie citit din zona tampon reprezint un marcaj
de sfrit de linie sau de sfrit de fiier; false altfel.
Funcia EOLN returneaz un rezultat de tip boolean, true dac
indicatorul este la sfrit de linie, iar false, n caz contrar.
: eol n[(fiier)];
Funcia seekeol n difer de funcia eol n prin
faptul c face salt peste caracterul SPAIU (blanc) sau TAB, nainte
de a testa sfritul de linie.
Funcia SEEKEOF este de tip boolean
Apel Seekeof [(fiier)];
Efect a) se modific adresa caracterului curent din zona
tampon astfel nct acesta s fie un caracter diferit de
spaiu, tab sau sfrit de linie (face salt peste ele)
b) returneaz: true, cnd poziia curent n fiier este
dup ultimul caracter al acestuia i false, n caz contrar.
Funcia seekeof difer de eof prin faptul c face un
salt peste caracterele: tab, blanc, sfrit de linie, nainte de a testa
sfritul de fiier.
Procedura APPEND(nume fiier) deschide fiierul n vederea adug-
rii la sfarit n fiier.
Procedura ERASE
Apelul: Erase(fiier);
Efect: Realizeaz tergerea fiierului fizic asociat variabilei
fiier. n momentul apelului fiierul trebuie s fie nchis.
Procedura RENAME schimb n program numele fiierului de pe
suport extern. Apelul rename (fiier,nume) realizeaz redenumirea
12
fiierului fizic asociat variabilei fiier cu numele dat prin irul de
caractere nume. n momentul apelului fiierul asociat variabilei fiier
trebuie s existe, s fie nchis i nu trebuie s existe un alt fiier cu
numele nume.
rename(f,'document.dat') schimb numele
fizic asociat lui f cu numele fizic document.
S se afieze numrul cuvintelor citite dintr-un fiier
text, introdus de la tastatur (cuvintele sunt separate prin unul sau mai
multe spaii).
Soluie:
nr_cuv_din_fis_INPUT;
c:char; n:longint;

n:=0; write('linia:');
eof

seekeoln

read(c);
(c<>' ') eoln read(c);
n:=n+1
;
readln;
write('Introducei linia:')
;
writeln('Fiierul cuprinde:',n,'cuvinte')
. {n reine numarul de cuvinte din text}
Exemplu de executare:
Intrare: Ana are main Ieire: Fiierul are 6 cuvinte.
Crina are calculator

S se afieze numrul numerelor din fiecare linie a
fiierului standard de intrare INPUT.
Soluie:
afis_nr_de_numere_din_liniile_fisierului_input;
n,nr,i:byte;
i:=1; write('linia', i,':');
eof

n:=0;
seekeoln
read(nr); inc(n) ;
readln;
writeln('din linia', i, 's-au citit' ,n, 'numere');
inc(i);
write('linia',i,':')

.
Exemplu de executare:
Intrare: Ieire:
linia 1: 10 20 30 din linia 1 s-au citit 3 numere
linia 2: 40 50 din linia 2 s-au citit 2 numere.

Fiiere cu tip
Fiierele cu tip sunt construite din articole cu lungime
fix, de acelai tip (pot fi: array, string, set, record sau tipuri simple de
date-intregi, char, etc); se mai numesc i fiiere cu prelucrare la nivel
de articol.
Declararea unui fiier cu tip se realizeaz astfel:


13

. S declarm un fiier ale crui articole sunt numere
ntregi.
IDENTIFICATOR DE TIP
OF
FILE
Soluie:
fisint = integer;
a:fisint;
sau a: integer;
. S se declare un fiier cu articole de tip .
Soluie:
inreg =
nume:string[30];
varsta:byte;
;
fisier = inreg;
f:fisier;{f-reprezint fiierul cu tip ce poate conine articole }
14
Accesul la datele fiierului cu tip este secvenial
sau direct.
Citirea i scrierea din/in fiier
1) read(fiier, v
1
, v
2
, , v
n
); - prelucreaz n componente succesive
din fiier, ncepand cu componenta situat la poziia indicatorului
de articol i se memoreaz n variabilele v
1
, v
2
, , v
n
(valoarea
indicatorului de articol crete cu 1, dup citirea unei componente).
2) write(fisier, v
1
, v
2
, , v
n
); - se scrie coninutul variabilelor
v1,v2,,vn n componentele succesive ale fiierului fiier
(indicatorul creste cu 1 dup scrierea fiecrei variabile), evident
tot ncepand de la poziia iniial a indicatorului.
Funcii i proceduri utile n prelucrarea fiierelor cu tip
1) EOF(fiier) ntoarce true, dac pointerul este la sfaesit de fiier,
sau false, altfe;
2) Filesize(fiier) ntoarce numrul de componente al fiierului
asociat variabilei fiier;
3) Filepos(fiier) ntoarce poziia pointerului(numrul de ordine al
componentei curente);
4) Seek(fisier,n) - pointerul se poziioneaz la valoarea n. Exemplu:
seek(fisier,7)-pointerul de fiier puncteaz a aptea valoare.
5) Truncate(fiier) terge toate componentele fiierului ncepand cu
componenta indicat de pointerul de fiier pan la ultima
component din fiier.
6) Erase(fiier)- terge fiierul;
7) Rename(fiier,noul-nume) schimb din program numele
fiierului de pe suport extern.
Se consider fiierul cu nregistrri DATE , care are
urmtoarea structur:
cod_mat:string[5]; den_m:string[20]; cod_mag:integer;
cant:real; um :string[4]; pu:real;
S se scrie un program care sorteaz fiierul descris anterior dup
valorile campului cod material.
Soluie:
inr = cod_mat:integer; den_mat:string[20]; cod_mag:integer;
cant:real; um:string[4]; pu:real; ;
fisier = inr;
inr1, inr2:inr; f:fisier;ok:boolean; i, j, t, mag:integer;
m1,m2:integer; c_er:integer;

15
sort1(i,j:integer);
k:integer;
ok:= ;
k:=i j-1
seek(f,k); read(f,inr1,inr2);
inr1.cod_mat>inr2.cod_mat
seek(f,k); write(f,inr2,inr1); ok:=
;
ok;
;
{program principal}

assign(f,'date');reset(f);
ok:= ;
i:=0 filesize(f)-2

seek(f,i); read(f,inr1,inr2);
inr1,cod_mag>inr2.cod_mag
seek(f,i); write(f,inr2,inr1);ok:=false ;

ok;
close(f);
reset(f);read(f,inr1); mag:=inr1.cod_mag; i:=0;
writeln('Magazia:',inr1.cod_mag);
eof(f)

read(f,inr1);
inr1
mag=cod_mag j:=filepos(f)-1; sort1(i,j)

i:=filepos(f)-1; mag:=inr1.cod_mag;
writeln(Magazia:, cod_mag);
;
;
.
Fiiere fr tip
Fiierele fr tip sunt constituite din blocuri de
lungime fix i aceeai pentru fiecare bloc.
Un bloc cuprinde o succesiune de octei.
Citirea/scrierea dintr-un fiier fr tip presupune transferul unuia sau
mai multor blocuri.
Declararea fiierelor fr tip se realizeaz astfel:


FILE


Deschiderea fiierelor fr tip se realizeaz astfel:
Rewrite(fiier,[dimensiune_bloc])
Reset(fiier,[dimensiune_bloc]);
unde dimensiune_bloc este de tip ntreg i reprezint numrul de octei
pe care a fost scris blocul(implicit este 65536 octei)
Citirea i scrierea:
Blockread(fiier, variabil, nr_blocuri_care_se_vor_citi)-citete
din fiier n variabila un numr de blocuri specificate.
Blockwrite(fiier, variabil, nr_blocuri_care_se_vor_scrie)-
scrie blocurile specificate.
Indicatorul de fiier reine numrul blocului
curent. Accesul poate fi secvenial sau direct.
Asemnator cu fiierele cu tip se pot folosi
urmtoarele funcii/proceduri: seek, eof, filesize, filepos, erase, rename.
S se creeze un fiier fr tip cu n inregistrri avand
cmpurile: nume:string[16]; varsta:integer;

inregistrare= nume:string[20]; varsta:integer; end;
f:file;inr:inregistrare;
n,i:integer;
assign(f,'date');write('n=');readln(n); rewrite(f);
i:=1 n
write('Nume=');readln(inr.nume);
write('Varsta=');readln(inr.varsta);
blockwrite(f,inr,1);
;
close(f);
.
16
17

Fiierul este un grup de octei stocai pe un suport de memorie extern


care este tratat n mod unitar de ctre sistemul de operare.
Lucrul cu fiiere n C presupune cunoscut modul de lucru cu
date de tip struct i cu pointeri. Se utilizeaz conceptul de flux
(stream).
Un flux se reprezint, n C, printr-un pointer la o entitate de tip
FILE care conine informaii despre poziia curent n flux, indicatori
de eroare i de sfrit de fiier, zone tampon (eng. buffers) asociate.
Limbajul C permite folosirea a dou tipuri de flux: text i binare.
Un flux text presupune transferul de caractere organizate n linii
de caractere. Fluxul binar reprezint o succesiune de octei care nu
suport nici o modificare n timpul transferului.
Deschiderea i nchiderea unui fiier
Orice fiier nainte de a fi prelucrat trebuie deschis. Dup terminarea
prelucrrii unui fiier acesta trebuie nchis. Forma general a funciei
pentru deschidere:
FILE *fopen(const char *numele_fis, const char *mod);
- "deschide un fiier" i-i asociaz numele respectiv;
- returneaz un pointer spre tipul FILE (vezi fiierul STDIO.H) sau
Null, n caz de eroare
unde: numele_fis = pointer ctre numele fiierului ce urmeaz a fi
deschis; mod = pointer spre un ir de caractere care definete modul de
prelucrare al fiierului, dup deschidere. Se definete astfel:
r = deschiderea unui fiier text pentru citire
w = deschiderea unui fiier text pentru scriere
a = deschiderea unui fiier text pentru adugare
r+ = deschiderea unui fiier text pentru modificare
r+b = citire/scriere binar
rb = citire binar
wb = scriere binar
Cu funcia fopen, un fiier inexistent se poate
"deschide" n modul r, w sau a, iar n acest caz este i creat.
Dac se deschide un fiier existent n modul w
atunci se va crea unul nou cu acelai nume, vechiul coninut se pierde.
Apelul: fp = fopen("INPUT.TXT") - la apel se deschide fiierul cu
numele INPUT.TXT i se stabilete o legtur logic ntre pointerul fp
i fiierul INPUT.TXT.
18
Deschiderea unui fiier n modul a pentru
adugarea de nregistrri dup ultima nregistrare existent n fiier.
Fiierele corespunztoare dispozitivelor standard nu
se deschid de ctre utilizator, ntruct ele sunt deschise automat la
lansarea programului.
Fiierele disc i dispozitivele periferice sunt gestio-
nate de variabila pointer.
Prelucrarea pe caractere a unui fisier
Fiierele standard pot fi scrise i citite caracter cu caracter, folosind
dou funcii simple: putc i getc Forma general:
putc( c, *pf);
returneaz valoarea lui , reprezentand codul ASCII al caracterului
scris n fiier sau , dac este eroare; pf reprezint pointer spre tipul
a crui valoare a fost returnat de funcia fopen la deschiderea
fiierului n care se scrie.
n particular pf poate fi unul din pointerii: stdout -
ieire standard; stderr ieire pe terminal n caz de eroare; stdaux -
ieire serial; stdprn - ieire paralel la imprimant. Forma general:
getc( *pf);
returneaz codul ASCII al caracterului citit sau la sfrit de
fiier; pf - pointer spre tipul a crui valoare a fost returnat de
funcia fopen la deschiderea fiierului. n particular pf poate fi
pointerul stdin (citire (intrare) de la tastatur).
nchiderea unui fiier (eliberarea spaiului de memorie alocat folosind
fopen i ntreruperea legturii logice) se realizeaz cu funcia fclose
care are prototipul
fclose ( *pf);
i returneaz valoarea: 0, la nchidere normal sau -1, n caz de eroare.
S se elaboreze un program pentru a copia intrarea
standard la ieirea standard folosind funciile putc i getc.
Soluie:
# <stdio.h>
main(void) {
c;
c= getc (stdin);
(c != EOF) {putc(c, stdout); c=getc(stdin);}
}
19
Cum se copiaz intrarea standard la imprimant?
Soluie:
# include <stdio.h>
main(void){
c;
c= getc (stdin);
while (c != EOF){putc(c, stdprn); c=getc(stdin);}
}
Operaii de intrare/ieire cu iruri de caractere
Biblioteca standard a limbajului C conine funciile: i care
permit citire dintr-un, repectiv scrierea ntr-un fiier ale crui nregis-
trri sunt iruri de caractere. Prototipul: *fgets ( *s, n,
*pf); returneaz valoarea pointerului s sau NULL la ntlnirea
sfritului de fiier; s pointerul spre zona n care se pstreaz
caracterele citite (numele unui tablou de tip char de dimensiune cel
puin n); n dimensiunea n octei a zonei n care se citesc caracterele
din fiier; pf pointerul spre tipul FILE a crui valoare s-a definit la
deschiderea fiierului.
Citirea se oprete la ntlnirea caracterului '\n' sau
dup citirea a cel mult n-1 caractere. n acest caz, n zona receptoare
se transfer caracterul '\n' i apoi caracterul '\0' (NULL
Funcia fputs scrie ntr-un fiier un ir de caractere care se termin prin
'\0' i are prototipul fputs( *s, *pf);
Returneaz codul ASCII al ultimului caracter scris n fiier sau -
1 la eroare; pf pointer spre tipul FILE care definete fiierul n care
se scrie; s pointerul spre zona care conine irul de caractere, care se
scrie.
Pentru a citi de la intrarea standard stdin, se poate
folosi funcia gets, care nu mai are parametrii pf i n Parametrul pf
este implicit stdin.
La fiierele text, cnd este ntalnit caracaterul
acesta este transformat ntr-o secven "newline". Fiierele binare nu
produc transformri.
Operaii de intrare-ieire cu format
Acest lucru se realizeaz folosind funciile: fscanf citire cu format
dintr-un fiier; fprintf scriere cu format n fiier. Opereaz la fel ca
printf i scanf cu excepia faptului c lucreaz cu fiiere, nu cu consola.
20
Apelul lui fscanf: fscanf( *pf, *format, par
1
, par
2
, ,par
n
) -
citete date, conform formatului, din stream; returneaz valoare EOF,
la ntalnirea sfaritului de fiier; pf - pointer spre tipul FILE, a crui
valoare a fost definit prin apelul funciei fopen; format - conine texte
i/sau specificatori de format (_). Parametrii par
1
, par
2
, ,par
n

definesc zonele receptoare ale datelor citite prin intermediul funciei
fscanf.
: Apelul fscanf(pf, "%d %c %f", &i, &n, &c);
Apelul fprintf( *pf, *format, par
1
, par
n
) - scrie date, n
stream, conform formatului.
Poziionarea ntr-un fiier
Pan acum am citit/scris datele unui fiier n mod secvenial de la
nceput pn la sfarit. Utiliznd funcia fseek se poate accesa orice
articol al unui fiier (acces aleator). Cu ajutorul ei se poate deplasa
capul de citire/scriere al discului n vederea prelucrrii ntregistrrilor
fiierului ntr-o ordine oarecare, diferit de cea secvenial.
Prototipul fseek( *pf, deplasament, origine);
Returneaz 0, la poziia corect sau o valoare diferit de 0, n caz
de eroare;
unde: deplasament reprezint numrul de octei peste care se va
deplasa capul de citire/scriere al discului, iar origine ia una din
valorile:
0 Deplasamentul se consider de la nceputul fiierului;
1 Deplasamentul se consider din poziia curent a
capului de citire/scriere;
2 Deplasamentul se consider de la sfaritul fiierului.
O alt funcie util n cazul accesului aleator este funcia ftell, care
indic poziia capului de citire/scriere din fiier.
Prototip ftell( *pf);
Returneaz O valoare de tip care definete poziia curent a
capului de citire/scriere, i anume reprezint deplasa-
mentul n octei a poziiei capului fa de nceputul
fiierului .
Folosind funcia cutai i citii orice byte
dintr-un fiier specificat

21
Soluie:
#include <stdio.h>
#include<stdlib.h>
main( ) {
*pf;
loc;
((pf= fopen("g1.cpp", "r"))==NULL) {
printf ("Nu pot deschide fisierul! ");
(1);
}
printf(Introducei locaia , n octeti, din fiier, ce se va vizualiza! );
scanf(%d, &loc);
(fseek(fp, loc, 0)){
printf("Eroare de cautare! ");
(1);
}
printf("Valoarea de la locatia %ld este %c", loc, getc(pf));
fclose(pf);
}
Alte funcii pentru prelucrarea fiierelor
1 nchiderea unui fiier se realizeaz cu ajutorul funciei fclose
care are prototipul: fclose ( *f); Funcia returneaz
valoarea 0 la nchidere normal, respectiv -1 n caz de eroare.
2 Testarea atingerii sfritului de fiier se poate realiza cu ajutorul
funciei feof, care are prototipul: feof ( *f); Funcia feof
returneaz valoare 0, dac indicatorul de fiier nu este la sfritul
fiierului, respectiv o valoare diferit de 0, dac indicatorul de
fiier este la sfrit.
3 rename( *nume_vechi, *nume_nou);-
redenumete un fiier;
4 remove( *filename); - terge un fiier de pe
suportul de informaie pe care este memorat;
5 fread( *ptr, size, n, *stream);-
citete date dintr-un fiier; mai precis, citete n elemente, fiecare
cu lungimea size din stream, ntr-un bloc specificat de ptr;
6 fwrite( *ptr, size, n, *
stream) - adaug fiierului stream n elemente, fiecare avand
dimensiunea size din blocul specificat de ptr.


Se consider un fiier text IN.txt ce conine numere
ntregi dispuse pe mai multe linii i separate prin spaii. Scriei
un program care creeaz un fiier OUT.txt ce conine pe fiecare
linie media aritmetic a numerelor situate pe aceeai linie n
fiierul IN.txt. Media aritmetic va fi scris cu doua zecimale

#include <stdio.h>
#include <string.h>
main ( ){ *fin, *fout;
sir[256],sn[256];
n,i,j1,j2,suma; media;
(!(fin=fopen("IN.txt","r"))){
printf("\n Nu pot deschide sursa!");
(1);}
(!(fout=fopen("OUT.TXT","w"))){
printf("\n Nu pot crea fisierul destinatie!");
(1);}
(!feof(fin)){
fgets(sir,256,fin);
n=0;i=0;j1=0;j2=0;suma=0;
(sir[i]){
(sir[i]=' ') {sn=substr(sir,j1,j2);
suma=suma+atoi(sn);
j1=j2=i+1;sn=' ';i++; }
{i++; j2++;}}
media=suma/n;
fprintf(fout, "%10.2f\n",media);
}
fclose(fin);fclose(fout);
}
substr( sir[256]; int j1,j2){
ss[]="'; i;
((j1>strlen(sir)||(j2>strlen(sir))
return 1;
for(i=j1;i<j2;i++) ss[i-j1]=sir[i];
return ss;
}
medie;
x,s,i:integer; f,g:text;
assign(f,'IN.TXT');
RESET(f);
assign(g,'out.TXT');
REWRITE(g);
eof(f) do

s:=0;
i:=0;

read(f,x);
i:=i+1;
s:=s+x;
eoln(f);
writeln(g,s/i:4:2);
writeln(s/i:4:2);
readln(f);
;
close(f);
close(g);
.









22
Scriei un program care verific dac dou fiiere Input1.txt i
Input2.txt au coninut identic.
Soluie:
23
i: ;
f,g: ;
s,s1: ;
identic: ;
assign(f.Input1.txt);
reset(f);
assign(g.Input2.txt);
reset(g);
Identic:=true;

( eof(f))

( eof(g))
(identic)


readln(f,s);
readln(g,s1);
s<>s1 identic:= ;
;
eof(f) eof(g)
Identic:= ;
eof(g) eof(f)
Identic:= ;
identic
write(Fiierele sunt identice)
write(Fisierele nu sunt identice);
#include <stdio.h>
#include <string.h>
main ( ){
sir1[256],sir2[256];
*f1, *f2;
ind;
((f1=fopen("Input1.txt","r"))
==NULL)
{
printf("\n Nu pot deschide fis1!");
exit(1);
}
((f2=fopen("Input2.txt","r"))
==NULL)
{
printf("\n Nu pot deschide fis2!");
exit(1);
}
ind=0;
((!feof(f1))&&(!feof(f2))){
fgets(sir1,f1);
fgets(sir2,f2);
(strcmp(sir1,sir2)!=0)
ind=1
}
clrscr();
(ind=0)
printf("\n Fisierele sunt identice!");

printf("\n Fisierele nu sunt
identice!")
fclose(f1);
fclose(f2);
}
close(f);
close(g);
.


24
Creai un program care transform toate literele mici din
fiierul INPUT.txt n majuscule.
Soluie:

pr;
crt;
f,f1: ;i: ;
s,s1: ;
clrscr;
assign(f,'in.txt');
reset(f);
assign(f1,'in1.txt');
rewrite(f1);
eof(f)

readln(f,s);
s1:='';
i:=1 to length(s) do
s1:=s1+upcase(s[i]);
writeln(f1,s1);
;
close(f);close(f1);
.
S se traduc programul de mai sus n limbajul C.
Se consider o matrice a cu n linii i n coloane stocat n
fiierul Matrice.txt (pe prima linie este scris valoarea n, iar pe
urmtoarele n linii matricea a, linie cu linie). Se cere s se afieze n
fiierul SUMA.TXT, suma elementelor de pe diagonala principal.

matrice;
crt; mat =
[1..10,1..10] ;
a:mat;
i,j,s,n: ; f,g: ;
assign(f,'Matrice.txt');
reset(f);
assign(g,'Suma.txt');
rewrite(f);
readln(f,m);
readln(f,n);
i:=1 m

j:=1 n read(f,a[i,j]);
readln(f)
;
s:=0;
i:=1 n s:=s+a[i,i];
writeln(g,s);
close(f);
close(g);
readln;
26
fiecrei linii. S se scrie n fiierul IESIRE.TXT pe prima linie
numrul de numere distincte, iar pe urmtoarele linii, desprite prin
spaii, aceste numere ordonate cresctor.
Dac fiierul INTRARE.TXT conine
2 3.7 2 5 8 5
Atunci fiierul IEIRE.TXT conine
4
2 3.7 5 8

Se cere s se scrie n fiierul OUT.TXT numrul de numere
prime de pe fiecare linie din fiierul IN.TXT i pe urmtoarea linii
numerele prime din fiierul de intrare.
Se dau dou fiiere MULT1.TXT i MULT2.TXT care conin,
desprite prin cate un spaiu mai multe numere reale reprezentand
cate o mulime fiecare. Se cere s se scrie n fiierul INT_REUN.TXT
pe prima linie, intersecia celor 2 mulimi, iar urmtoarea linie
reuniunea lor.
Dac fiierul MULT1.TXT conine
5.5 6 8 7.6
i fiierul MULT2.TXT conine
5.5 8 7
atunci fiierul INT_REUN.TXT
5.5 8
5.5. 6 7 7.6 8
Fiierul text FIS.DAT conine numere i cuvinte pe mai multe
linii, fiecare avand maximum 255 de caractere. S se realizeze un
program care inventariaz coninutul fiierului, afisand pentru fiecare
linie i pentru ntregul fisier numrul de caractere, numrul de cuvinte
i numrul de valori numerice.
S se ordoneze descresctor dup medii, nregistrrile unui fiier
care conine datele i rezultatele candidaiilor la un examen de
admitere n clasa a IX-a (sau la facultate). Fiecare nregistrare este
compus din cinci cmpuri: un nume (variabil de tip string cu 20 de
caractere), trei note reale reprezentand notele la cele dou probe,
media obinut la examen i un cmp logic ce memoreaz rezultatul
final (ADMIS sau RESPINS). Programul va afia rezultatul
examenului de admitere n funcie de un numr citit de la tastatur
reprezentnd numrul de locuri posibile.
27
Fiierul PRODUSE.DAT conine informaii despre produsele
dintr-un magazin alimentar: numele produsului (maxim 20 de
caractere), preul unitar (numr ntreg, maxim 100.000), cantitatea
(numar real) i termenul de garanie (sub forma zi-luna-an cnd expir
termenul de folosin al produsului). S se afieze n funcie de data (i
s se elimine din fiier) produsele expirate i costul lor.
S se determina frecvena apariiei caracterelor (date de codul
lor ASCII) dintr-un fiier precizat.
S se afieze pe ecran toate caracterele unui fiier text existent,
caracterele netiparibile (cu cod ASCII mai mic dect 32) fiind
nlocuite la scriere cu codul lor ASCII, precedat de caracterul '#'.
S se creeze un fiier text avand ca surs dou fiiere text, al
doilea fiind adugat n continuarea primului.
[Numere mari] Se consider dou numere naturale n i m care
au cel puin 200 de cifre. S se determine produsul celor dou numere.
Pe prima linie a fiierului de intrare INPUT.TXT este scris numrul n,
avand cifrele desprite prin cate un spaiu; pe a doua linie este scris
numarul m, n mod similar. n fiierul OUTPUT.TXT se va scrie pe
fiecare linie cate o cifra din rezultat.
[Goldbach] Se consider un numr n>6 par. S se determine
toate reprezentrile lui n ca sum de numere prime (sum cu numr
minim de termeni). Rezultatele vor fi scrise n fiierul OUTPUT.TXT,
fiecare linie coninand toi termenii dintr-o reprezentare.
: Pentru n = 8, atunci OUTPUT.TXT conine
3 5
5 3
Nu se consider perechile (1, 7) i (7, 1) din cauza numrului 1.
[Factor prim] Se consider un ir de n numere ntregi. S se
determine factorul prim care apare la puterea cea mai mare n des-
compunerea produsului celor n numere. Pe prima linie a fiierului
INPUT.TXT este scris numrul n, reprezentand numrul de elemente
din ir; pe urmtoarea linie sunt scrise cele n numere. Rspunsul se va
afia pe ecran sub forma: i^j cu semnificaia: factorul i la puterea j
INPUT.TXT pe ecran se va afia :
4 3^4
24 9 17 21
28
[Cel mai mare divizor comun] Se consider n numere scrise n
baza 16. S se determine cel mai mare divizor comun al celor n
numere. Pe prima linie a fiierului INPUT.TXT este scris numrul de
numere n; pe urmtoarele n linii se gsesc numerele scrise n
hexazecimal. Numrul care reprezint c.m.m.d.c. al celor n numere, se
va afia pe ecran.
INPUT.TXT se va afisa :
4\n 1A \n 8 \n 10 \n 2 2
[Cifre romane] S se scrie un program care transform un
numr scris cu cifre romane n scrierea cu cifre arabe. n fiierul
INPUT.TXT sunt scrise mai multe numere n scriere romana (corecte),
fiecare pe cte o linie. Este posibil ca unele din cifrele romane sa fie
scrise cu litere mici. Rspunsurile se vor afia pe ecran, fiecare numr
pe cte o noua linie.
INPUT.TXT pe ecran se va afia:
CDLIV 454
MMMMDLXXIII 4573
MCLXVI 1166
CMXLLVIII 948
[Propoziii] Se consider un text scris pe n linii (n fiierul de
intrare INPUT.TXT). Fiecare linie constituie o propoziie. Cuvintele
sunt formate doar din litere mari i litere mici i sunt desprite prin:
spaiu, virgul i punct. Nici o propozitie nu are mai mult de 250 de
caractere. Textul nu conine cuvinte n care s apar liniua de
desprire (exemplu: "ntr-un").
S se determine propoziia cu cele mai multe cuvinte i s se
afieze pe ecran scriind fiecare cuvnt pe linie nou avnd prima liter
majuscul; separatorii nu se vor afia.
INPUT.TXT se va afisa
Ce faci Alo
Unde esti Este
O sa reusim Ora
buna dimineata Sapte
Alo, este ora sapte si treizeci de minute, fix. Si
Treizeci
De
29
Minute
Fix
[Matrice] Se d matricea A cu m linii i n coloane. S se scrie
un program care prin intermediul unui meniu realizeaz urmtoarele
operaii:
Elimin din matrice linia L i coloana k fr a folosi o nou
matrice;
Ordoneaz cresctor elementele de pe o coloan oarecare j prin
interschimbri de linii.
Datele de intrare se vor citi dintr-un fiier text.
[Ordonare] Se consider un tablou bidimensional ptratic de
dimensiune n*n de numere ntregi. Se cere s se inverseze liniile i
coloanele acestuia astfel nct tabloul obinut s conin elemente de
pe diagonala principal n ordine cresctoare. Datele de intrare se
citesc din fiierul de intrare INPUT.TXT sub forma urmtoare: pe
prima linie este scris numrul n, reprezentnd numrul de linii i
coloane, iar pe urmtoarele n linii, se gsesc elementele tabloului linie
dup linie.
Rezultatul va fi scris n fiierul OUTPUT.TXT. Pe fiecare linie a
fiierului se va scrie o linie a tabloului obinut.
INPUT.TXT OUTPUT.TXT
3 -1 8 7
2 4 3 2 3 4
1 5 6 1 6 5
-1 7 8

[Frecvene] Se consider un fiier INPUT.TXT care conine un
text. Se cere determinarea listei cu frecvena de apariie maxim. In
cazul cand exist mai multe soluii se vor afia toate. Fiierul de
intrare conine pe fiecare linie cel mult 250 de caractere. Nu se va face
distincie ntre litera mic i litera mare. Rezultatul se va afia pe
ecran.
INPUT.TXT pe ecran se va afisa:
Mama si cu tata merg la piata A apare de 7 ori
Memoriu, memoriu! M apare de 7 ori

30
[Ordonare n matrice] Se consider o matrice de dimensiune
n*m. S se reaeze elementele n matrice astfel nct ele s apar n
ordine cresctoare att pe linii ct i pe coloane. Matricea A se gsete
n fiierul de intrare INPUT.TXT, fiecare linie a matricei pe cte o
linie din fiier.
Nu sunt specificate valoarile pentru n i m. Matricea obinut se
va scrie, n mod similar, n fiierul OUTPUT.TXT. n cazul n care
exist mai multe soluii se va scrie n fiier numai una.
INPUT.TXT OUTPUT.TXT
3 2 5 44 3 1 1 2 2 2 2 2
6 7 55 4 3 2 3 3 3 3 3 4
4 10 4 2 4 5 4 4 4 4 4 5
34 5 6 8 2 4 5 5 5 6 6 7
5 3 2 4 41 3 8 10 34 41 44 55
O matrice cu elemente ntregi este memorat n fiierul text
in.txt sub urmtorul format: pe prima linie numrul n de linii i
numrul m de coloane. Pe urmtoarele n linii, elementele de pe fiecare
linie a matricii. Citii matricea i tiprii-o pe coloane n fiierul
out.txt.

Citii un text scris pe mai multe linii n fiierul text.txt.
Calculai, pentru fiecare liter a alfabetului, procentul de cuvinte care
ncep cu acea liter. Separatori ntre cuvinte vor fi considerai:
blancul, punctul, virgula i sfritul de linie.

Creai cu editorul Pascal un fiier text pe mai multe linii.
Scriei un program care calculeaz:
a) Numrul de cuvinte din fiier. Ca separatori ntre cuvinte se
vor considera blancurile i sfritul de linie.
b) Tiprii liniile care conin cel puin o vocal.
c) Cte linii conin mai mult de n cuvinte, n citit de la tastatur?

31

O structur de date este o mulime de date organizate ntr-un anumit
mod mpreun cu relaiile dintre acestea.
n funcie de modul de alocare, structurile de date se clasific n:
structuri de date statice : tabloul, nregistrarea, mulimea, fiierul.
Structurile de date statice ocup o zon de memorie constant pe
toat durata de executare a blocului n care apare declaraia i
elementele ocup poziii fixe. Fiierele sunt structuri de date
externe (vezi capitolul 1).
structuri de date semistatice: stiva alocat static, coada alocat
static. Structurile de date semistatice ocup o zon de memorie de
dimensiune constat, alocat pe toat durata executrii blocului n
care apare declaraia de structur, iar elementele ocup poziii
variabile pe parcursul executrii programului.
structuri de date dinamice: lista nlnuit, structuri arborescente.
Structurile de date dinamice ocup o zon de memorie de
dimensiune variabil, alocat dinamic. Alocarea dinamic permite
gestionarea memoriei n timpul executrii programului. Ele sunt
mult mai flexibile dect cele statice i din aceast cauz sunt
extrem de avantajoase.
O list este o colecie de elemente de informaie (noduri)
aranjate ntr-o anumit ordine. Lungimea unei liste este numrul de
noduri din list. Structura corespunztoare de date trebuie s ne
permit s determinm eficient care este primul/ultimul nod n
structur i care este predecesorul/succesorul (dac exist) unui nod
dat. Limbajele Pascal sau C(++) ofer posibiliti de implementare a
acestor structuri att static ct i dinamic. Operaiile curente care se
fac n liste sunt: inserarea unui nod, tergerea (extragerea) unui nod,
concatenarea unor liste, numrarea elementelor unei liste etc.
Implementarea unei liste se poate face n principal n dou moduri:
Implementarea secvenial, n locaii succesive de memorie,
conform ordinii nodurilor n list. Avantajele acestei tehnici
sunt accesul rapid la predecesorul/succesorul unui nod i
gsirea rapid a primului/ultimului nod. Dezavantajele sunt
inserarea/tergerea relativ complicat a unui nod i faptul c
nu se folosete ntreaga memorie alocat listei.
Implementarea nlnuit. Fiecare nod conine dou pri:
informaia propriu-zis i adresa nodului succesor. Alocarea
memoriei fiecrui nod se poate face n mod dinamic, n timpul
rulrii programului. Accesul la un nod necesit parcurgerea
tuturor predecesorilor si, ceea ce poate lua ceva mai mult
timp. Inserarea/tergerea unui nod este, n schimb, foarte
rapid.
Listele se pot clasifica dup numrul de legturi n:
liste simple
liste duble
liste circulare
O list simpl are o singur legtur, legtura ultimului element este
adresa NIL/NULL. Pentru a accesa lista avem nevoie de o variabil
care s pstreze adresa primului element (cap sau pr i m). O list
dubl are dou legturi: legtura de tip urmtor i legtura de tip
precedent sau anterior. O lista circular este o lista n care, dup
ultimul nod, urmeaz primul, deci fiecare nod are succesor i
predecesor.
Listele se pot clasifica dup locul n care se fac operaiile de
adugare/eliminare astfel:
stive
cozi



ntre nodurile unei liste simplu nlnuite este definit o singur relaie
de ordonare. Fiecare nod conine un pointer a crui valoare reprezint
adresa nodului urmtor din list.

Limbajul Pascal
type lista = ^nod
nod=record
inf:tip ;
urm: lista;
end;

Limbajul C(++)
typedef struct nod {
tip inf;
struct nod *urm;
}lista;
unde ur meste adresa urmtorului nod (pointer ctre urmtorul nod),
iar i nf este un cmp de informaie util.
Operaii asupra listei simplu nlnuite
:
1. Se iniializeaz pointerul pr i mcu Ni l / NULL, deoarece lista la
nceput este goal;
2. Se rezerv zon de memorie n memoria heap pentru nodul curent;
32
3. Se ncarc nodul curent cu date;
4. Se determin adresa ultimului nod i se realizeaz legtura cu
nodul creat;
5. Se reia cu pasul 2 dac se introduce un nod nou.
x al crui cmp cheie a fost iniializat n
faa unei liste nlnuite
LISTA-INSEREAZA(p,x)
1: urm(x) p
2: dac p<>NIL atunci px
p a elementului x se realizeaz
prin subprogramul LISTA-CAUTA i returneaz pointerul la acest
obiect.
LISTA-CAUTA(p,x)
1. qp
2. ct timp q<>NIL i cheie(q)<>x execut qurm(q)
3. returneaz q

Probleme rezolvate
1. Fiind dat o list simplu nlnuit cu elemente numere ntregi s se
realizeze un program care s execute urmtoarele operaii: crearea,
parcurgerea, adugarea unui nod la nceputul listei, adugarea unui nod
la sfritul listei, tergerea unui nod de pe o poziie dat.


Limbajul C(++)
Funcia MALLOC se folosete
pentru a rezerva octei din
memoria heap. Trebuie inclus
fiierul antet: stdlib.h sau
alloc.h
Limbajul Pascal:
Procedura NEW(pointer)- alocarea
dinamic a memoriei pentru
variabila dinamic pointer.
Procedura DISPOSE(pointer)-
eliberarea memoriei ocupate de
ctre variabila dinamic pointer.









Parcurgerea unei liste liniare simplu nlnuite se realizeaz cu un
pointer care pleac de la capul listei i va referi pe rnd fiecare nod,
prelucrnd informaiile din nod apoi se trece la urmtorul nod, prelu-
crm informaiile din nod etc.
33
34
tergerea unui nod de pe o poziie dat p din interiorul listei se
realizeaz astfel: se parcurge lista pn la pozitia p-1, se pstreaz
nodul de pe poziia p, se realizeaz legtura ntre nodul p-1 i p+1 i,
apoi se elibereaz memoria ocupat de nodul p.
:
lista=^nod;
nod= inf:integer; urm:lista ;
p,x:integer;cap:lista;{adresa primului nod al listei}
adaug( cap:lista;x:integer); {adaugarea la sfarsitul listei}
nou,q:lista;
new(nou);nou^.inf:=x;nou^.urm:=nil;
cap=nil cap:=nou
q:=cap;
q^.urm<> q:=q^.urm;
q^.urm:=nou;
;
;
adaug_inc( cap:lista;x:integer); {adaugarea la inceput}
nou:lista;
new(nou);nou^.inf:=x;nou^.urm:=nil; {crearea nodului nou}
cap= cap:=nou
nou^.urm:=cap;cap:=nou;
{realizarea legaturii si primul nod devine nodul creat}
;
;
listare(cap:lista);{listarea listei}
t:lista;
t:=cap;
t<>nil
write(t^.inf,' '); {prelucrarea informatiei}
t:=t^.urm; {trecerea la urmatorul nod}
;
;
sterge( cap:lista; p:integer);
35
{stergerea nodului de pe pozitia p}
q,w,t:lista;i:integer;
cap= writeln('Lista vida !!! ')
p=1
{stergere la inceputul listei}
q:=cap; cap:=cap^.urm; dispose(q);

(cap<> nil)
t:=cap; i:=1;
(t^.urm<> nil) (i+1<p)
inc(i) ;t:=t^.urm ;
t^.urm= write('nu exista suficiente pozitii')
w:=t^.urm; t^.urm:=t^.urm^.urm;
dispose(w)


;
read(x);
x<>0 adaug_inc(cap,x); read(x); ;
listare(cap);
write('pozitia');read(p);sterge(cap,p);
listare(cap);
write('informatia adaugata la sfarsit');read(x);adaug(cap,x);
listare(cap)
.

#include <stdio.h>
#include<stdlib.h>
#include<alloc.h>
typedef struct nod {
int inf;
struct nod*urm;
}lista;
lista *prim;
lista *creare(void);
void parcurgere(lista *p);
36
lista* sterg_inc(lista *prim){
lista *p;
p=prim;
prim=prim->urm;
free(p);
return prim;
}
void adauga(lista*prim) {
/*adauga un nod la o lista simplu inlantuita
si returneaza pointerul spre nodul adaugat sau zero daca nu s-a realizat
adaugarea*/
lista *p,*q;
for (p=prim;p->urm!=NULL;p=p->urm)
q=(lista*) malloc(sizeof(q));
scanf("%d",&q->inf);
q->urm=NULL;
p->urm=q;
}
void main(){
lista *prim;
prim=creare(); parcurgere(prim); prim=sterg_inc(prim);
printf("\n");
parcurgere(prim); adauga(prim); parcurgere(prim);
}
lista *creare(){
int n,i,inf; lista *prim,*p,*q;
printf("nr. de elemente");scanf("%d",&n);
printf("informatia primului nod"); scanf("%d",&inf);
prim=(lista*)malloc(sizeof(prim)); prim->inf=inf;prim->urm=NULL;
for(q=prim,i=2;i<=n;i++){
printf("inf . %d:",i);scanf("%d",&inf);
p=(lista*)malloc(sizeof(p));
p->inf=inf;p->urm=NULL; q->urm=p; q=p;
}
return(prim);
}
void parcurgere(lista *p){
lista *q;
for (q=p;q;q=q->urm) printf("%d ",q->inf);
}
2. Inversarea legturilor ntr-o list simplu nlnuit.
Se parcurge lista iniial folosind trei variabile dinamice p1, p2, p3
care vor face referire la elementele consecutive din list. p1 va fi
capul listei modificate.

:
invers;
lista=^nod;
nod= inf:integer; urm:lista ;
i,n,x:integer; p:lista;
creare( p:lista; x:integer);
q:lista;
p=nil new(p); p^.inf:=x; p^.urm:=nil
q:=p; q^.urm<>nil q:=q^.urm;
new(q^.urm); q^.urm^.inf:=x; q^.urm^.urm:=nil;
;
;
listare(p:lista);
q:lista;
q:=p; q<>nil write(q^.inf,' '); q:=q^.urm ;
;
Subprogramul de inversare n C:
l i st a* i nver s( l i st a*p) {
l i st a *p1, *p2, *p3;
p1=p;
p2=p- >ur m;
p- >ur m=NULL;
whi l e ( p2) {
p3=p2- >ur m;
p2- >ur m=p1;
p1=p2;
p2=p3;
}
r et ur n p1;
}
inversare(p:lista):lista;
p1,p2,p3:lista;
p1:=p;
p2:=p^.urm;
p^.urm:=nil;
p2<>nil
p3:=p2^.urm;
p2^.urm:=p1;
p1:=p2;
p2:=p3;
end;
inversare:=p1;
;
37
38
read(n);
i:=1 n read(x); creare(p,x) ;
listare(p);writeln;
p:=inversare(p);
listare(p)
.

3. S se efectueze suma a dou polinoame rare (polinom cu foarte
muli coeficieni egali cu zero) folosind liste simplu nlnuite.
Lista are ca informaie gradul i coeficientul fiecrui termen de
coeficient nenul. Pentru a calcula suma este necesar s parcurgem
listele celor dou polinoame i s adugm corespunztor n cea de-a
treia list.
lista=^nod;
nod= grad:1..5000; coef:integer; urm:lista ;
a,b,p,q,r:lista;
i,n,m:integer;
creare( p:lista);
write('cati coeficienti nenuli are polinomul');readln(n);
new(p);readln(p^.coef,p^.grad);
p^.urm:=nil;b:=p; {b este adresa ultimului nod}
i:=2 n
new(a);
write('coef ',i,':');readln(a^.coef); write('grad ',i,':');readln(a^.grad);
b^.urm:=a; b:=a; b^.urm:=nil

;
listare(p:lista);
a:lista;
a:=p;
a<>nil write(a^.coef,'x^', a^.grad,' +'); a:=a^.urm ;
writeln(#8,' ');
;
39
aduna(p,q:lista;var r:lista);
a,b,c,d:lista;
a:=p;b:=q; {c este adresa ultimului nod pentru lista suma}
(a<>nil) (b<>nil)
a^.grad=b^.grad
r=nil
new(c);c^.grad:=a^.grad;
c^.coef:=a^.coef +b^.coef;
r:=c; r^.urm:=nil;
new(d); d^.grad:=a^.grad;
d^.coef:=a^.coef+b^.coef;
c^.urm:=d;c:=d;c^.urm:=nil
;
a:=a^.urm;b:=b^.urm;
a^.grad<b^.grad
r=nil
new(c); c^.grad:=a^.grad;
c^.coef:=a^.coef ; r:=c; r^.urm:=nil;
new(d); d^.grad:=a^.grad; d^.coef:=a^.coef;
c^.urm:=d;c:=d;c^.urm:=nil;
;
a:=a^.urm;
r=nil
new(c);c^.grad:=b^.grad;
c^.coef:=b^.coef;r:=c;r^.urm:=nil;
new(d); d^.grad:=b^.grad; d^.coef:=b^.coef;
c^.urm:=d;c:=d;c^.urm:=nil;
;
b:=b^.urm;
;
40
a<>nil c^.urm:=a;
b<>nil c^.urm:=b;
;
creare(p);creare(q);listare(p);listare(q);
r:=nil;
aduna(p,q,r);
listare(r);
readln;
.
Exerciii:
1. S se implementeze n C aplicaia de mai sus.
2. S se scrie un subprogram pentru calcularea produsului a dou
polinoame rare.
3. S se calculeze valoarea unui polinom ntr-un punct dat.

Calcularea produsului se va face prin parcurgerea tuturor perechilor de


termeni astfel:
-fiecare pereche genereaz un nod n polinomul produs
-gradul noului nod va fi suma gradelor nodurilor din pereche
-coeficientul noului nod va fi produsul coeficienilor termenilor din
pereche
-se elimin nodurile din lista de termeni prin pstrarea fiecrui grad o
singur dat astfel: dac exist dou noduri cu acelai grad unul din
ele va fi eliminat, iar coeficientul celuilalt va avea valoarea sumei
coeficienilor celor doi termeni.
Valoarea unui polinom se va calcula prin parcurgerea listei i
adugnd la valoare produsul dintre coeficient i valoarea dat la
puterea gradului din nod.

4.Dndu-se dou liste simplu nlnuite cu elemente numere intregi
distincte, s se afiseze diferena celor dou liste i elementele comune
celor dou liste.
Diferena celor dou liste conine elementele primeia care nu
sunt n cea de-a doua. Se parcurge prima list i pentru fiecare nod se
verific dac este n cea de-a doua list, dac nu se afl atunci se
adaug listei trei. Intersecia celor dou liste se determin parcurgnd
41
prima list i pentru fiecare nod se verific dac elementul se afl i n
cea de-a doua list, dac da atunci se adaug n cea de-a treia list.

lista=^nod;
nod = inf:integer; urm:lista ;
q,cap1,cap2,cap3:lista;
gasit:boolean;
creare(var cap:lista);
n,i:integer;
nou,q:lista;
write('nr elem'); read(n); new(cap); read(cap^.inf);
cap^.urm:=nil;
i:=2 to n
new(nou); read(nou^.inf); nou^.urm:=nil; q:=cap;
q^.urm<>nil q:=q^.urm;
q^.urm:=nou

;
diferenta(cap1,cap2:lista);
x:integer;
q2:lista;
q:=cap1;
q<>nil
x:=q^.inf; gasit:=false; q2:=cap2;
q2<>nil
q2^.inf=x gasit:=true; q2:=q2^.urm
;
gasit write(x, ' '); q:=q^.urm

;
afisare(cap:lista);
q:lista;
q:=cap;
q<>nil write(q^.inf,' '); q:=q^.urm ;
writeln;
;
42
intersectie(cap1,cap2:lista; cap3:lista);
q,q2,nou,q3:lista;
x:integer;
q:=cap1;
q<>nil
x:=q^.inf; gasit:=false; q2:=cap2;
q2<>nil
if q2^.inf=x gasit:=true;
q2:=q2^.urm;
;
gasit cap3=nil
new(cap3); cap3^.inf:=x; cap3^.urm:=nil

new(nou); nou^.inf:=x ; nou^.urm:=nil; q3:=cap3;
q3^.urm<> nil q3:=q3^.urm;
q3^.urm:=nou
;
q:=q^.urm

;
creare(cap1); creare(cap2); afisare(cap1); afisare(cap2);
diferenta(cap1,cap2);
writeln; diferenta(cap2, cap1);
writeln('intersectie'); intersectie(cap1,cap2,cap3); afisare(cap3);
.

Exerciiu: S se implementeze aplicaia de mai sus in C.

5. S se creeze o list simplu nlnuit, cu informaie numeric astfel
nct la orice moment al inserrii lista s fie ordonat cresctor dup
informaie.
Paii: -crearea unui nod nou
-dac informaia care se adaug este mai mic dect informaia
din capul listei atunci se insereaz n faa primului nod
-altfel se parcurge lista pn la primul nod a crei informaie este
mai mare dect informaia noului nod i se insereaz.
43

#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
struct nod { int inf; struct nod*urm;} lista;
lista *prim;
lista *creare(void);
void parcurgere(lista *p);
main(){
lista *prim;
prim=creare();
parcurgere(prim);
}
lista *creare(){
int n,inf; lista *prim,*p,*q,*nou;
printf("nr. de elemente");scanf("%d",&n);
prim=NULL;
(int i=1;i<=n;i++){
printf("informatia nod");scanf("%d",&inf);
nou=(lista *)malloc(sizeof(lista));
nou->inf=inf;
(prim==NULL){
prim=nou;prim->urm=NULL;
}
(prim->inf>inf){
nou->urm=prim;prim=nou;
}
{
p=q=prim;
(p&&p->inf<inf){q=p; p=p->urm;}
(p) {q->urm=nou; nou->urm=p;}
{q->urm=nou; nou->urm=NULL;}
}
}
prim;
}
parcurgere(lista *p){ lista *q;
(q=p;q;q=q->urm) printf("%d ",q->inf);
}
44
Exerciiu: S se implementeze aplicaia de mai sus n Pascal.

6. S se scrie un program pentru interclasarea a dou liste ordonate
simplu nlnuite.
Se va parcurge simultan cele dou liste urmnd ca introducerea unui
nod n lista final s fie fcut din lista care are valoarea informaiei
din nod mai mic.
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
struct nod {int inf; struct nod*urm;}lista;
lista *inter(lista *prim1, lista*prim2){
lista *prim,*ultim;
(prim1->inf>prim2->inf){
prim=prim2;prim2=prim2->urm;
}
{
prim=prim1;
prim1=prim1->urm;
}
ultim=prim;
(prim1&&prim2)
(prim1->inf>prim2->inf){
ultim->urm=prim2;
ultim=prim2;
prim2=prim2->urm;
}
{ultim->urm=prim1;
ultim=prim1;
prim1=prim1->urm;
}
(prim1) ultim->urm=prim1; ultim->urm=prim2;
prim;
}
lista *creare(void);
void parcurgere(lista *p);
45
main(){
lista *prim1,*prim2,*prim;
prim1=creare();
prim2=creare();
/* parcurgere(prim1) */;
prim=inter(prim1,prim2);
parcurgere(prim1);
}
lista *creare(){
int n,inf; lista *prim,*p,*q,*nou;
printf("nr. de elemente");scanf("%d",&n);
prim=NULL;
for(int i=1;i<=n;i++){
printf("informatia nod");scanf("%d",&inf);;
nou=(lista *)malloc(sizeof(lista));
nou->inf=inf;
(prim==NULL){
prim=nou;
prim->urm=NULL;
}
(prim->inf>inf){
nou->urm=prim;prim=nou;
}
{
p=q=prim;
(p&&p->inf<inf){q=p;p=p->urm;}
(p) {q->urm=nou;nou->urm=p;}
{
q->urm=nou;nou->urm=NULL;
}
}
}
prim;
}
parcurgere(lista *p){ lista *q;
for (q=p;q;q=q->urm) printf("%d ",q->inf);
}

Exerciiu: S se implementeze aplicaia de mai sus n limbajul Pascal.



Pentru liste duble create dinamic modul de definire a unui nod este:









Limbajul Pascal
type lista=^nod;
nod=record
inf:tip;
urm, ant:lista;
end;
typedef struct nod{
inf tip;
struct nod *urm;
struct nod *ant;
}lista;
Operaiile care se pot defini asupra listelor dublu nlnuite sunt
aceleai ca i n cazul listelor simplu nlnuite:
- crearea unei liste dublu nlnuite;
- accesul la un element al unei liste dublu nlnuite;
- inserarea unui nod ntr-o list dublu nlnuit;
- tergerea unui nod dintr-o list dublu nlnuit;
- tergerea unei liste dublu nlnuite.

1. S se scrie un program care va conine un meniu cu principale
operaii asupra listei dublu nlnuite.

lista=^nod;
nod= inf:integer; urm,ant:lista ;
cap:lista;
x:integer;
creare( cap:lista);
new(cap); write('inf=');readln(cap^.inf); cap^.urm:=nil;cap^.ant:=nil;
;
adaugare( cap:lista);
q,nou:lista;
new(nou);readln(nou^.inf);nou^.urm:=nil;
q:=cap; q^.urm <> nil q:=q^.urm; q^.urm:=nou;nou^.ant:=q;
;
46
47
inserare(var cap:lista);
nou,q:lista;
k,i:integer;
writeln('unde inserezi? ');
read(k);new(nou);
write('ce? ');readln(nou^.inf);
k=1
cap^.ant:=nou; nou^.urm:=cap; nou^.ant:=nil; cap:=nou;
q:=cap;
i:=1;
(q^.urm<>nil) (i<k)
q:=q^.urm; inc(i)
;
i=k
nou^.ant:=q^.ant; q^.ant^.urm:=nou;
nou^.urm:=q; q^.ant:=nou;
write('nu exista');
readln


;
stergere( cap:lista);
q,p:lista;
k,i:integer;
write('unde stergi? '); readln(k);
cap<>nil
k=1 q:=cap; cap:=cap^.urm;
dispose(q);
cap^.ant:=nil;

p:=cap;i:=1;
(p^.urm<>nil) (i<k)
p:=p^.urm; inc(i);
;
48
i=k
q:=p; p^.ant^.urm:=p^.urm;
p^.urm^.ant:=p^.ant; dispose(q);
write('nu exista'); readln end

;
parcurgere( cap:lista);
q:lista;
q:=cap;
q<>nil write(q^.inf, ' '); q:=q^.urm end;
readln
;
parcurgere_inv( cap:lista);
q:lista;
q:=cap;
q^.urm<>nil q:=q^.urm;
q<>nil write(q^.inf, ' '); q:=q^.ant ;
readln;
;
x<> 7
writeln('1.creare'); writeln('2.adaugare');
writeln('3.inserare'); writeln('4.stergere');
writeln('5.parcurgere'); writeln('6.parcurgere_inv');
writeln('7.iesire');
readln(x);
x of
1:creare(cap);
2:adaugare(cap);
3:inserare(cap);
4:stergere(cap);
5:parcurgere(cap);
6:parcurgere_inv(cap);


.

49
2. Crearea i parcurgerea listei dublu nlnuite n limbajul C:

#include<stdio.h>
#include<stdlib.h>
nod{int inf; struct nod*urm,*ant; } lista;
lista*prim ,*ultim;
creare(int n);
parcurg(lista*prim);
parcurg1(lista*ultim);
main(){
int n;
printf("numarul de elemente:");scanf("%d",&n);
creare(n);
puts("\n Parcurgere directa");parcurg(prim);
puts("\n Parcurgere indirecta");parcurg1(ultim);
}
creare(int n){
int i;
lista *p;
prim=(lista*)malloc(sizeof(lista));
printf("informatia primului nod"); scanf("%d",&prim->inf);
prim->urm=prim->ant=NULL;
ultim=prim;
(i=2;i<=n;i++){
p=(lista*)malloc(sizeof(lista));
printf("inf=");scanf("%d",&p->inf);
p->ant=ultim;ultim->urm=p;
p->urm=NULL;
ultim=p;
}
}
parcurg(lista*p){
(p){
printf("%d ",p->inf); parcurg(p->urm);
}
}
parcurg1(lista *p){
lista *q;
(q=p;q;q=q->ant) printf("%d ",q->inf);
}
50
Dup numrul de legturi, listele circulare se mpart n: liste simple i
liste duble. Listele circulare simple sunt liste simple care au n plus
propietatea c valoarea cmpului urmtor a ultimului nod este adresa
capului listei. Listele circulare duble sunt liste duble care au
propietatea c legtura urmtor a celui de-al doilea cap este primul
cap i legtura anterior a primului cap este al doilea cap.

Crearea i parcurgerea listei circulare simplu nlnuite n limbajul
C:

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
nod{ int inf; nod *urm;}lista;
main(){
lista *prim,*p,*q;
int i,n;
/*crearea listei circulare*/
printf("inf primului nod");
prim=(lista*)malloc(sizeof(lista));
scanf("%d",&prim->inf);prim->urm=NULL;
p=prim;
printf("nr de elemente");scanf("%d",&n);
(i=2;i<=n;i++){
q=(lista*)malloc(sizeof(lista));
printf("inf=");scanf("%d",&q->inf);
p->urm=q;p=q;
}
p->urm=prim;
/*parcurgerea listei*/
printf("%d ",prim->inf);
(q=prim->urm;q!=prim;q=q->urm)
printf("%d ",q->inf);
}

Se d un grup de n copii aezai n cerc, care
sunt numrai din m n m. Copilul care a fost numrat cu valoarea m
este eliminat. Dndu-se pasul de eliminare m se cere s se precizeze
ordinea ieirii din cerc.
51
Simularea eliminrii copiilor se realizeaz cu o list
circular la care se realizeaz eliminarea nodului care are ca
informaie numrul copilului scos din joc. Numrarea se va face
parcurgnd m elemente de la poziia de unde s-a efectuat ultima
tergere.


lista=^nod;
nod= inf:integer; urm:lista ;
i,n,m,j:integer;
prim,q,p:lista;
creare( prim:lista;x:integer);
new(prim); prim^.inf:=x; prim^.urm:=prim ;
adaugare(var prim:lista;x:integer);
q,p:lista;
new(q);
q:=prim;
q^.urm<>prim q:=q^.urm;
new(p); p^.inf:=x;
q^.urm:=p;p^.urm:=prim;
;
listare(prim:lista);
q:lista;
new(q);q:=prim;
write(q^.inf,' ');
q^.urm<>prim q:=q^.urm; write(q^.inf,' ') ;
;
{program principal}
read(n); creare(prim,1);
i:=2 n adaugare(prim,i); listare(prim);
read(m); p:=prim;
i:=1 n-1
i=1 j:=1 m-2 p:=p^.urm
j:=1 m-1 p:=p^.urm;
q:=p^.urm; write(q^.inf,' '); p^.urm:=q^.urm; dispose(q);
;
writeln('castigator=',p^.inf);
.
52

#include <stdio.h>
#include<stdlib.h>
nod{int inf; nod *urm,*ant; }lista;
lista *prim,*p,*q;
creare(void);
parcurgere(void);
int n,m,i,k;
main(){
creare();
printf("pasul de numarare");scanf("%d",&m);
parcurgere();
(p!=p->ant){
( i=1;i<m;i++)p=p->urm;
printf("%d ",p->inf);
p->ant->urm=p->urm;
p->urm->ant=p->ant;
q=p;p=p->urm;free(q);
}
printf("%d",p->inf);
}
parcurgere(){
(p=prim,i=1;i<=n;i++,p=p->urm) printf("%d",p->inf);
/* p=p->urm;*/
}
creare(){
printf("nr. de copii");scanf("%d",&n);
prim=(lista*)malloc(sizeof(lista));prim->inf=1;
prim->urm=prim->ant=NULL; p=prim;
(i=2; i<=n; i++){
q=(lista*)malloc(sizeof(lista));
q->inf=i;
p->urm=q;
q->ant=p;
p=q;
}
q->urm=prim;prim->ant=q;
}

stiv stack este o list liniar cu proprietatea c operaiile de
inserare/extragere a nodurilor se fac n/din vrful listei. Ultimul nod
inserat va fi i primul ters, stivele se mai numesc i liste LIFO (eng.
Last In First Out) sau liste pushdown

53










Cel mai natural mod de reprezentare pentru o stiv este implementarea
secvenial ntr-un tablou S[1 .. n], unde n este numrul maxim de
noduri. Primul nod va fi memorat n S[1], al doilea n S[2], iar ultimul
n S[top], unde top este o variabil care conine adresa (indicele)
ultimului nod inserat. Algoritmii de inserare i de tergere (extragere)
a unui nod:
pop
push
push(x, S[1 .. n])
{adauga nodul x in stiva}
top = n stiva plina
top top+1
S[top] x
succes

pop(S[1 .. n])
{sterge ultimul nod inserat din stiva si il returneaza}
top =0 stiva vida
x S[top]
top top-1
x

Cei doi algoritmi necesit timp constant, deci nu depind de mrimea
stivei.
54
Realizai un meniu n limbajul Pascal care s
conin operaii asupra stivei.
stiva=^nod;
nod= inf:integer; urm:stiva ;
cap:stiva;
x:integer;
adauga( cap:stiva);
nou:stiva;
new(nou);
writeln('Ce sa adaug? ');
readln(nou^.inf);
nou^.urm:=nil;
cap=nil cap:=nou
nou^.urm:=cap;
cap:=nou;
;
;
sterge( cap:stiva);
q:stiva;
cap=nil writeln('Stiva vida')
q:=cap;
cap:=cap^.urm;
dispose(q)
;
;
parcurgere(cap:stiva);
q:stiva;
q:=cap;
q<> nil
writeln('|',q^.inf,'|'); q:=q^.urm end;
writeln('___')
;
55
x<> 4
writeln('1.Adaugare');
writeln('2.Stergere');
writeln('3.Listare');
writeln('4.Iesire');
writeln('Dati optiunea');
readln(x);
x
1:adauga(cap);
2:sterge(cap);
3:parcurgere(cap)

.

Exerciiu: S se implementeze n limbajul C aplicaia de mai sus.
1. S se scrie un program care citind numere ntregi din fiierul in.txt
creeaz o stiv i o afieaz. S se transforme un numr din baza
10 n baza b folosind o stiv.
2. Pe o linie de cale ferat se gsesc, ntr-o ordine oarecare, n
vagoane numerotate de al 1 la n. Linia continu cu alte k linii de
manevr. Cunoscnd ordinea iniial a vagoanelor, s se obin la
ieire vagoanele n ordine: 1,2 ,n; liniile de manevr sunt destul
de lungi nct s ncap pe o singur linie toate cele n vagoane.
Indicaie: Se dorete partiionarea vagoanelor n k submulimi care au
vagoanele ordonate cresctor
O coad (eng. queue) este o list liniar n care inserrile se fac doar
n capul listei, iar extragerile doar din coada listei. Cozile se numesc i
liste FIFO (eng. irst n irst ut). O reprezentare secvenial pentru
o coad se obine prin utilizarea unui tablou C[0 .. n-1], pe care l
tratm ca i cum ar fi circular: dup locaia C[n-1] urmeaz locaia
C[0]. Fie p variabila care conine indicele locaiei predecesoare primei
locaii ocupate i fie u variabila care conine indicele locaiei ocupate
ultima oar. Variabilele p i u au aceeai valoare atunci i numai
56
atunci cnd coada este vid. Iniial, avem p= u= 0. Inserarea i
tergerea (extragerea) unui nod necesit timp constant.

Operaii asupra cozii:
insert-queue(x, C[0 .. n-1])
{adauga nodul x in capul cozii}
p (p+1) n
p=u coada plina
C[p] x
succes
delete-queue(C[0 .. n-1])
{sterge nodul din coada listei si il returneaza}
p=u coada vida
u (u+1) n
x C[u]
x
Testul de coad vid este acelai cu testul de coad plin. Dac s-ar
folosi toate cele n locaii, atunci nu am putea distinge situaia de
coad plina i cea de coad vid, deoarece n ambele situaii am
avea p = u. Se folosesc efectiv numai n-1 locaii din cele n ale
tabloului C, deci se pot implementa astfel cozi cu cel mult n-1 noduri.

Relizarea unui meniu pentru implementarea
static a cozii.

: Cea mai simpl implementare a cozii static este folosirea
unui tablou. Pentru gestionarea cozii este nevoie de dou elemente: p
poziia primului element i u poziia de dup ultimul element din
coad. Se va face o utilizare circular a spaiului alocat astfel:
urmtoarea poziie este p mod n +1.

coada=array[1..50] of integer;
c:coada; p,n,u,o,x:integer;
adaugare( c:coada; p,u:integer;x:integer);
p<>(u mod n)+1
c[u]:=x; u:=u mod n +1
writeln('coada plina');
;
57
stergere( c:coada; p,u,x:integer);
p<>u x:=c[p]; p:=p mod n+1
writeln('coada goala');
;
listare(c:coada;p,u:integer);
i:integer;
p=u writeln('coada goala')

i:=p;
i<>u write(c[i],' '); i:=i mod n+1 ;
;
;
writeln('nr max de elem');
read(n);n:=n+1;
p:=1;u:=1;
repeat
writeln('1..adaugare');
writeln('2..stergere');
writeln('3..listare');
write('citeste optiunea');readln(o);
o
1:
write('introduceti numarul adaugat');readln(x);
adaugare(c,p,u,x);
;
2:
stergere(c,p,u,x);
p<>u writeln(x);
;
3: listare(c,p,u);
;
writeln;
o=4;
.

Exerciiu: S se implementeze aplicaia de mai sus n limbajul C++.

58
S se creeze un program care s conin un
meniu cu operaii asupra unei cozi alocate dinamic.
#include <conio.h>
#include<stdlib.h>
#include<iostream.h> // intrri-ieiri n C++
nod {int inf; nod *urm; }lista;
adaug(lista* &prim, int x){
lista *nou, *p;
nou= lista; // crearea unui nod n C++
nou->inf=x;nou->urm=NULL;
if (prim==NULL) prim=nou;
else {
nou->urm=prim; prim=nou;
}
}
lista * creare(){
int n,x;
lista*prim;
prim=NULL;
clrscr();
cout<<"\n nr. de noduri=";cin>>n;
(int i=0;i<n;i++){
cout<<"inf "<<(i+1)<<":";
cin>>x;
adaug(prim,x);
}
prim;
}
parcurgere(lista *prim){
lista *p;
clrscr();
p=prim;
(p!=NULL){
cout<<p->inf<<' '; p=p->urm;}
cout<<'\n';
getch();
}
59
sterg(lista *&prim){
lista *p;
(prim==NULL) cout<<"coada este vida";
{
p=prim;
while (p->urm->urm!=NULL){p=p->urm;}
delete p->urm; p->urm=NULL;
}
}
void main(){
lista *prim=NULL;
int opt,x;
do{
clrscr();
cout<<"Coada\n";
cout<<"1.Creare coada\n";
cout<<"2.Adaugare\n";
cout<<"3.Stergere\n";
cout<<"4.Parcurgere\n";
cout <<"5.Iesire\n";
do{
cout<<"optiunea";cin >>opt;
}while (opt<1&&opt>5);
switch(opt){
case 1:{prim=creare();break;}
case 2:{
clrscr();cout<<"inf. noua:";cin>>x;
adaug(prim,x);break;
}
case 3:{
clrscr();
cout<<"inf stearsa="<<(prim->inf);
sterg(prim);break;
}
case 4:{
parcurgere(prim); getch();break;
}
}
}while (opt!=5);
}
60
Exerciiu: S se realizeze programul n Pascal corespunztor
aplicaiei de mai sus.

1. Fiind dat o list simplu nlnuit avnd informaii numere ntregi
s se elimine numerele negative.
2. S se realizeze interclasarea a n liste simplu nlnuite ordonate
cresctor.
3. Fiind date dou liste simple cu informaii de tip ntreg, s se
realizeze subprograme pentru urmtoarele operaii: intersecia,
reuniunea, diferena i diferena simetric a elementelor celor
dou liste.
4. S se scrie un program care citete cuvintele dintr-un fiier text
in.txt, cuvintele sunt separate prin spaii i afieaz numrul de
apariii al fiecrui cuvnt din fiier. Se vor folosi liste simplu
nlnuite.
5. S se elimine dintr-o list simplu nlnuit toate nodurile care au
o informaie dat.
6. S se realizeze operaii cu matrici rare folosind alocarea dinamica.
7. Fiind dat o list dubl, s se separe n dou liste elementele de pe
poziii pare de elementele de pe poziii impare.
8. Fiind dat o list dubl cu informaii de tip ir de caractere, s se
fac ordonarea elementelor listei.
9. Fiind dat o list dubl cu informaii de tip ntreg s se
construiasc o list dubl numai cu elemente prime.
10. Pe o tij sunt n bile colorate cu cel mult k culori, fiecare bil
avnd o etichet cu un numr de la 1 la n. S se mute bilele pe alte
k tije, pe fiecare punnd numai bile din aceeai culoare. S se
afieze bilele de pe fiecare din cele k tije, folosind structuri
dinamice.
Indicaie: Tija iniial reprezint o stiv, informaia dintr-un nod va fi
compus din numrul bilei i numrul culorii. Se va parcurge stiva i
se adaug n stiva corespunztoare culorii, apoi se terge din stiva
iniial. Se va lucra cu un vector de stive pentru cele k tije.

11. S se implementeze subprograme pentru operaiile de baz cu liste
circulare duble.
12. Fie un traseu circular ce cuprinde n orae. O main trebuie s
parcurg toate oraele i s se ntoarc de unde a plecat.
Parcurgerea se poate face n ambele sensuri. Se cere s se
61
determine un traseu posibil de parcurgere astfel nct s nu rmn
n pan tiind c n fiecare ora exist o staie de benzin cu o
cantitate de benzin suficient, iar maina consuma c litri la 100
de kilometri.
13. Fiind dat o list circular dubl, s se fac un subprogram de
inserare a unui element pe o poziie dat.
14. S se realizeze un subprogram care terge elementele egale cu
zero dintr-o list circular.
15. S se creeze o list de liste, s se parcurg i s se tearg.
16. S se scrie un program care citete cuvintele dintr-un text i
afieaz numrul de apariii al fiecrui cuvnt din textul respectiv.
17. S se scrie un program care citete cuvintele dintr-un text i scrie
numrul de apariie al fiecrui cuvnt, n ordinea alfabetic a
cuvintelor respective.
18. ntr-o gar se consider un tren de marf ale crui vagoane sunt
inventariate ntr-o list. Lista conine, pentru fiecare vagon,
urmtoarele date: codul vagonului, codul coninutului vagonului,
adresa expeditorului, adresa destinatarului. Deoarece n gar se
inverseaz poziia vagoanelor, se cere listarea datelor despre
vagoanele respective n noua lor ordine.
Indicaie: se creeaz o stiv n care se pstreaz datele fiecrui vagon.
Datele corespunztoare unui vagon constituie un element al stivei,
adic un nod al listei simplu nlnuite. Dup ce datele au fost puse n
stiv, ele se scot de acolo i se listeaz.

19. La o agenie CEC exist un singur ghieu care se deschide la ora 8
i se nchide la ora 16, dar publicul aflat la coad este deservit n
continuare. Deoarece la ora nchiderii coada este destul de mare se
ridic problema oportunitii deschiderii a nc unui ghieu la
agenia respectiv. Se cunosc operaiile efectuate la agenie i
timpul lor de execuie. n acest scop se realizeaz o simulare pe
calculator a situaiei existente care s stabileasc o medie a orelor
suplimentare efectuate zilnic pe o perioad de un an.
Indicaie: Programul de simulare a problemei indicate construiete o
coad de ateptare cu persoanele care sosesc la agenie n intervalul de
timp indicat. Se va folosi funcia random pentru a determina operaia
solicitat i apoi pentru a determina intervalul de timp ntre dou
persoane care vin la agenie.

62
20. S se realizeze un program care implementeaz subprograme
pentru crearea i exploatarea unei cozi duble.
21. Se d o matrice rar memorat ntr-o list. Se cere:
a) s se afieze toate elementele diferite de zero de pe diagonala
principal, secundar;
b) s se afieze pe ecran matricea sub forma obinuit, fr
reconstituirea ei n memorie.

Noiuni introductive
Un graf este o pereche G = <V, M>, unde V este o mulime de vrfuri,
iar M = VxV este o mulime de muchii. O muchie de la vrful a la
vrful b este notat cu perechea ordonat (a, b), dac graful este
orientat, i cu mulimea {a, b}, dac graful este neorientat. Dou
vrfuri unite printr-o muchie se numesc adiacente. Un drum este o
succesiune de muchii de forma (a
1
, a
2
), (a
2
, a
3
), ..., (a
n-1
, a
n
) sau de
forma {a
1
, a
2
}, {a
2
, a
3
}, ..., {a
n-1
, a
n
} dup cum graful este orientat sau
neorientat. Lungimea drumului este egal cu numrul muchiilor care l
constituie. Un drum simplu este un drum n care nici un vrf nu se
repet. Un ciclu este un drum care este simplu, cu excepia primului i
ultimului vrf, care coincid. Un graf aciclic este un graf fr cicluri.
Un subgraf al lui G este un graf <V', M'>, unde V' V, iar M' este
format din muchiile din M care unesc vrfuri din V'. Un graf parial
este un graf <V, M">, unde M" M.
Un graf neorientat este conex, dac ntre oricare dou vrfuri
exist un drum. Pentru grafuri orientate, aceast noiune este ntrit:
un graf orientat este tare conex, dac ntre oricare dou vrfuri i si j
exist un drum de la i la j i un drum de la j la i.
n cazul unui graf neconex, se pune problema determinarii
componentelor sale conexe. O componenta conex este un subgraf
conex maximal, adic un subgraf conex n care nici un vrf din
subgraf nu este unit cu unul din afar printr-o muchie a grafului iniial.
mprirea unui graf G = <V, M> n componentele sale conexe
determina o partiie a lui V i una a lui M.
Un arbore este un graf neorientat aciclic conex. Sau, echivalent,
un arbore este un graf neorientat n care exist exact un drum ntre
oricare dou vrfuri. Un graf parial care este arbore se numete
arbore partial. Vrfurilor unui graf li se pot ataa informaii numite
uneori valori, iar muchiilor li se pot ataa informaii numite uneori
lungimi sau costuri.

Metode de reprezentare a grafurilor
a) Matricea de adiacen
Cea mai cunoscut metod de memorare a grafurilor neorientate este
matricea de adiacen, definit n felul urmtor: 1, dac exist muchie
(arc) de la vrful i la vrful j i 0, n caz contrar. n cazul grafurilor
neorientate, aceast matrice este simetric, folosindu-se efectiv numai
jumtate din spaiul matricei. n unele probleme este eficient ca
cealalt jumtate a matricei s fie folosit pentru reinerea altor
informaii. Matricea de adiacen este folosit n general pentru grafuri
cu un numr mic de noduri, deoarece dimensiunea ei este limitat de
dimensiunea stivei.

Exemplu de graf orientat:
















0 0 1 0 0 1 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 1
0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7
0
1
2
3
4
7
5
6
0
0
0
0
0
1
0
0
8
0 0 0 0 0 0 0 0 8 0
1
4
5
6
3
2
8
7
0
b) Listele de muchii
Aceast metod de memorare presupune reinerea unei matrice cu 2
linii i m coloane, pe fiecare coloan fiind reinute dou extremiti ale
unei muchii. Aceasta reprezentare este eficient atunci cnd avem de
examinat toate muchiile grafului.
63
64
Listele de muchii sunt folosite n cazul algoritmilor care prelucreaz
secvenial muchiile, cum ar fi de exemplu algoritmul Kruskal de aflare
a arborelui parial de cost minim n cazul grafurilor rare (cu numr
mic de muchii).

c) Listele de vecini.
Prin liste de vecini (adiacen) se realizeaz ataarea la fiecare vrf i a
listei de vrfuri adiacente lui (pentru grafuri orientate, este necesar ca
muchia s plece din i). ntr-un graf cu m muchii, suma lungimilor
listelor de adiacen este 2m, dac graful este neorientat, respectiv m,
dac graful este orientat. Dac numrul muchiilor n graf este mic,
aceast reprezentare este preferabil din punct de vedere al memoriei
necesare. Este posibil s examinm toi vecinii unui vrf dat, n medie,
n mai puin de n operaii. Pe de alt parte, pentru a determina dac
dou vrfuri i i j sunt adiacente, trebuie s analizm lista de adiacen
a lui i (i, posibil, lista de adiacen a lui j), ceea ce este mai puin
eficient dect consultarea unei valori logice n matricea de adiacen.
Listele de vecini sunt cele mai recomandate n tratarea algoritmilor din
teoria grafurilor din dou motive principale:
1. spatiul folosit este gestionat dinamic, putndu-se memora astfel
grafuri de dimensiuni mari;
2. complexitatea optim pentru majoritatea algoritmilor fundamen-
tali din teoria grafurilor (parcurgeri, conexitate, muchii i puncte
critice, algoritmi de drum minim etc.) este obinut numai folosind
liste de vecini.
Exist dou modaliti de implementare a listelor de vecini.
a) Prima dintre ele folosete o matrice T cu 2 linii i 2m coloane i
un vector C cu n elemente care reine pentru fiecare nod indicele
coloanei din T pe care este memorat primul element al listei
nodului respectiv (sau 0 dac vrful respectiv nu are vecini). Apoi,
pentru o anumit coloan i din T, T(i,1) reine un element din lista
curent, iar T(i,2) reine coloana pe care se gsete urmtorul
element din lista respectiv sau 0 dac lista s-a terminat.
b) Cea de-a doua implementare folosete pentru fiecare nod o list
simplu nlnuit memorat n heap. Pentru fiecare list este
suficient s pstrm o singur santinel (cea de nceput a listei),
introducerea vrfurilor fcndu-se mereu la nceputul listei
(deoarece ordinea vrfurilor n list nu conteaz).

Exemplu:


65















1
4
5
6
3
2
8
7
0
0
1
2
3
4
7
5
6
8
2 5
6
6
4
5
3 7
2 8
Parcurgerea grafurilor
Parcurgerea unui graf presupune examinarea n vederea prelucrrii
tuturor vrfurilor acelui graf ntr-o anumit ordine, ordine care s
permit prelucrarea optim a informaiilor ataate grafului.
a) Parcurgerea DF (parcurgerea n adncime)
Parcurgerea DF (Depth First) presupune ca dintr-un anumit nod v,
parcurgerea s fie continuat cu primul vecin al nodului v nevizitat
nc. Parcurgerea n adncime a fost formulat cu mult timp n urm
ca o tehnic de explorare a unui labirint. O persoan care caut ceva
ntr-un labirint i aplic aceast tehnic are avantajul ca urmtorul loc
n care caut este mereu foarte aproape.
Parcurgerea vrfurilor n adncime se
face n ordinea: 1 3 4 5 2 6
1
4
5
6
3
2
Cel mai cunoscut mod de imple-
mentare a parcurgerii DF se realizeaz
cu ajutorul unei funcii recursive, dar
exist i cazuri n care este recomandat
o implementare nerecursiv.
Implementarea acestei metode se
face folosind o stiv. Aceasta este iniia-
66
lizat cu un nod oarecare al grafului. La fiecare pas, se ia primul vecin
nevizitat al nodului din vrful stivei i se adaug n stiv dac nu mai
exist se coboar n stiv.
Algoritmul recursiv:
DF(G)
fiecare v V marca[v] nevizitat
fiecare v V
marca[v] = nevizitat ad(v)

ad(v)
{varful v nu a fost vizitat}
marca[v] vizitat
fiecare virf w adiacent lui v
marca[w] = nevizitat ad(w)
Algoritmul iterativ:
iterad(v)
S stiva vida
marca[v] vizitat
push(v, S)
S nu este vida
exista un varf w adiacent lui ftop(S)
astfel incat marca[w] = nevizitat
marca[w] vizitat
push(w, S)
pop(S)

unde funcia ftop returneaz ultimul vrf inserat n stiv.
Parcurgerea n adncime a unui graf nu este unic; ea depinde
att de alegerea vrfului iniial, ct i de ordinea de vizitare a
vrfurilor adiacente.
Problem: Ct timp este necesar pentru a parcurge un graf cu n
vrfuri i m muchii?
Rezolvare:
Deoarece fiecare vrf este vizitat exact o dat, avem n apeluri ale
procedurii ad. n procedura ad, cnd vizitm un vrf, testm marcajul
fiecrui vecin al su. Dac reprezentm graful prin liste de adiacen,
adic prin ataarea la fiecare vrf a listei de vrfuri adiacente lui,
atunci numrul total al acestor testri este m, dac graful este orientat,
67
i 2m, dac graful este neorientat. Algoritmul necesit un timp O(n)
pentru apelurile procedurii ad i un timp O(m) pentru inspectarea
mrcilor. Timpul de executare este O(max(m, n)) = O(m+n).
Dac reprezentm graful printr-o matrice de adiacen, se obine
un timp de executare de O(n
2
).

b) Parcurgerea BF (parcurgerea n lime)
Parcurgerea BF (Breath First) presupune faptul c dup vizitarea unui
anumit nod v, sunt parcuri toi vecinii nevizitai ai acestuia, apoi toi
vecinii nevizitai ai acestora din urm, pn la vizitarea tuturor nodu-
rilor grafului.
Parcurgerea n lime este folosit de obicei atunci cnd se
exploreaz parial anumite grafuri infinite, sau cnd se caut cel mai
scurt drum dintre dou vrfuri.
Implementarea acestei metode se face folosind o coad. Aceasta
este iniializat cu un nod oarecare al grafului. La fiecare pas, se
viziteaz nodul aflat n vrful cozii i se adaug n coad toi vecinii
nevizitai ai nodului respectiv.

Parcurgere_BF(nod start)
Coada start
Vizitat(start) adevrat
coada nu este vid
ic nodul de la nceputul cozii
adaug toti vecinii nevizitati ai lui ic n coad
Vizitat(i) adevrat, unde i este un vecin nevizitat al
nodului ic

Pentru a efectua o parcurgere n laime a unui graf (orientat sau
neorientat), aplicm urmtorul principiu: atunci cnd ajungem ntr-un
vrf oarecare v nevizitat, l marcm i vizitm apoi toate vrfurile
nevizitate adiacente lui v, apoi toate vrfurile nevizitate adiacente
vrfurilor adiacente lui v etc. Spre deosebire de parcurgerea n
adncime, parcurgerea n lime nu este n mod natural recursiv.
lat(v)
C coada vida
marca[v] vizitat
insert-queue(v, C)

68
C nu este vida
u delete-queue(C)
fiecare virf w adiacent lui u
marca[w] = nevizitat marca[w] vizitat
insert-queue(w, C)
Pentru compararea celor dou metode apelm procedurile iterad i lat
din procedura parcurgere(G)
parcurge(G)
fiecare v V marca[v] nevizitat
fiecare v V
marca[v] = nevizitat {iterad sau lat} (v)

Algoritmul lui Dijkstra
Fie G = (X,U) un graf orientat, unde X este mulimea vrfurilor i U
este mulimea muchiilor. Fiecare muchie are o lungime nenegativ.
Unul din vrfuri este desemnat ca vrf surs. Problema este s
determinm lungimea celui mai scurt drum de la surs ctre fiecare
vrf din graf. Vom folosi un algoritm greedy, datorat lui E.W. Dijkstra
(1959). Notm cu C mulimea vrfurilor disponibile (candidaii) i cu
S mulimea vrfurilor deja selectate. n fiecare moment, S conine
acele vrfuri a cror distan minim de la surs este deja cunoscut,
n timp ce mulimea C conine toate celelalte vrfuri. La nceput, S
conine doar vrful surs, iar n final S conine toate vrfurile grafului.
La fiecare pas, adugam n S acel vrf din C a crui distan de la
surs este cea mai mic.
La fiecare pas al algoritmului, un tablou D conine lungimea
celui mai scurt drum special ctre fiecare vrf al grafului. Dup ce
adugm un nou vrf v la S, cel mai scurt drum special ctre v va fi,
de asemenea, cel mai scurt dintre toate drumurile ctre v. Cnd
algoritmul se termin, toate vrfurile din graf sunt n S, deci toate
drumurile de la surs ctre celelalte vrfuri sunt speciale i valorile din
D reprezint soluia problemei.
Matricea M d lungimea fiecarei muchii, cu M[i, j] = +, dac
muchia (i, j) nu exist. Soluia se va construi n tabloul D[2 .. n].
Algoritmul este:

S = {0}
for i = 1 to n D[i] = M[1][i]
69
for i = 1 to n-2
caut cel mai mic D[v] pentru fiecare v S
S = S {v}
toate vrfurile u S
(D[u] > D[v] + M[v][u]) D[u] = D[v] + M[v][u]

Implementare n C:

# <stdio.h>
# <string.h>
# FALSE 0
# TRUE 1
# MAXN 20
setupDijkstra
( nod_p, a[MAXN][MAXN], startnod_p);
doDijkstra
( nod, a[MAXN][MAXN], startnod);
traceinfo
( S[MAXN], D[MAXN], nod);
main(){
nod, startnod;
a[MAXN][MAXN];
printf("Algoritmul lui Dijkstra\n");
(setupDijkstra(&nod, a, &startnod)) 1;
doDijkstra(nod, a, startnod);
0;
}
setupDijkstra
( nod_p, a[MAXN][MAXN], startnod_p){
i, j;
{
printf("Introduceti 0 pentru a specifica graful,sau 1 pentru exemple ");
scanf("%d", &i);
} ((i < 0) || (i > 1));
(i == 1){
*nod_p = 5;
(i=0; i<*nod_p; i++)
(j=0; j<*nod_p; j++) a[i][j]=99;
a[0][1]=a[1][0]=1; a[1][2]=a[2][1]=3; a[0][3]=a[3][0]=2;
a[3][4]=a[4][3]=4; a[1][4]=a[4][1]=2; a[2][4]=a[4][2]=1;
70
printf("A Matrix: a b c d e\n");
for (i=0; i<*nod_p; i++){
printf(" %c", 'a'+i);
for (j=0; j<*nod_p; j++)
printf("%3d", a[i][j]);
printf("\n");
}
*startnod_p = 0;
}
71
(urmnod >= nod) ;
// printf(" D[%c]=%2d, ", 'a'+urmnod, mic);
printf("adauga nodul %c to S\n", 'a'+urmnod);
S[urmnod] = TRUE;
(j=0; j<nod; j++){
(!S[j]){
/* printf("Compara D[%c]=%2d si D[%c]+M[%c][%c]=%2d, ", \
'a'+j, D[j], 'a'+urmnod, 'a'+urmnod, 'a'+j, \
D[urmnod]+a[urmnod][j]);
*/
(D[j] > D[urmnod] + a[urmnod][j]){
D[j] = D[urmnod] + a[urmnod][j];
/*printf("D[%c] schimba %2d\n", 'a'+j, D[j]); */
}

/* printf("nu schimba\n"); */
}
}
traceinfo(S, D, nod);
}
}
traceinfo( S[MAXN], D[MAXN], nod){
i;
printf(" S = {");
(i=0; i<nod; i++) (S[i]) printf("%c", 'a' + i);
printf("}\n");
printf(" D = ");
for (i=0; i<nod; i++) printf("%3d", D[i]);
printf("\n");
}

Algoritmul lui Bellman-Ford (determinarea drumu-
rilor minime dintre un nod i celelalte noduri ntr-un graf care poate
s aib cicluri negative).
Dac graful conine muchii de cost negativ, algoritmul Dijkstra nu mai
funcioneaz corect, deoarece nu putem gsi - acum - nodurile cele
mai apropiate de surs, n ordine cresctoare a distanei fa de
aceasta. Aceast problem este rezolvat de algoritmul Bellman-Ford,
care n plus determin i existena ciclurilor de cost negativ care pot fi
atinse pornind din nodul surs. Ca i n cazul algoritmului Dijkstra,
72
vom folosi vectorul D care reine distana minim gsit la un moment
dat de la s la celelalte noduri. Algoritmul foloseste o coad Q, care
este iniializat cu nodul s. La fiecare pas, algoritmul scoate un nod v
din coad i gsete toate nodurile w a cror distan de la surs la
acestea poate fi optimizat prin folosirea nodului v. Dac nodul w nu
se afl deja n coad, el este adugat acesteia. Aceti pai se repet
pn cnd coada devine vid.
Algoritmul utilizeaz tehnica de relaxare, procednd la
descreterea estimrii d[v] a drumului minim de la sursa s la fiecare
vrf v V pn cnd este obinut costul adevrat (u,v) corespunztor
unui drum minim. Algoritmul returneaz adevarat dac i numai dac
nu conine cicluri de cost negativ accesibile din surs.
Algoritmul este:
BELLMAN-FORD(G,c,s)
1.INIT(G,s)
2. pentru i1,|X[G]|-1 executa
3. pentru fiecare muchie (u,v) U
4. RELAXEAZA(u,v,c)
5. pentru fiecare muchie (u,v) U executa
6. daca d[v]>d[u]+c(u,v)
7. returneaza FALS
8. returneaza ADEVARAT

Implementare n C:
# <stdio.h>
# <string.h>
# FALSE 0
# TRUE 1
# MAXN 26
# INFINIT 999
setupBellman( *nod_p, a[MAXN][MAXN], start_p);
doBellman( nod, a[MAXN][MAXN], start);
traceinfo( D[MAXN], nod);
main(){
nod, start; a[MAXN][MAXN];
printf("Algoritmul lui Bellman-Ford\n");
(setupBellman(&nod, a, &start)) 1;
(doBellman(nod, a, start)){
printf(" Ciclu negativ\n"); 2;}
0;}
73
setupBellman
( nod_p, a[MAXN][MAXN], start_p){
i, j;
{
printf("Introduceti 0 pentru graf, or 1 pentru exemple ");
scanf("%d", &i);
} ((i < 0) || (i > 1));
(i == 1){
*nod_p = 5;
(i=0; i<*nod_p; i++) (j=0; j<*nod_p; j++) a[i][j]=99;
a[0][1]=a[1][0]=1; a[1][2]=a[2][1]=3; a[0][3]=a[3][0]=2;
a[3][4]=a[4][3]=4; a[1][4]=a[4][1]=2; a[2][4]=a[4][2]=1;
printf("A Matrix: a b c d e\n");
(i=0; i<*nod_p; i++){
printf(" %c", 'a'+i);
(j=0; j<*nod_p; j++) printf("%3d", a[i][j]);
printf("\n");
}
*start_p = 0;
}
{
printf("Introduceti nr. noduri (1-%d) ", MAXN);
(scanf("%d", nod_p) != 1) 1;
( (*nod_p < 1) || (*nod_p > MAXN) ) 2;
for (i=0; i<*nod_p; i++){
printf("Introduceti randul %d al matricii: ", i+1);
for (j=0; j<*nod_p; j++)
if (scanf("%d", &a[i][j]) != 1) return 3;
}
printf("Introduceti nodul de start (1-%d) ", *nod_p);
(scanf("%d", &i) != 1) 4;
( (i < 1) || (i > *nod_p) ) 5;
*start_p = i-1;
}
0;
}

doBellman( nod, a[MAXN][MAXN], start){
D[MAXN]; int i, u, v;
/* initializare */
74
(i=0; i<nod; i++){
(i == start) D[i] = 0; D[i] = INFINIT;
}
printf("Initializared\n"); traceinfo(D, nod);
for (i=1; i<nod; i++){
for (u=0; u<nod; u++){
for (v=0; v<nod; v++){
if (a[u][v] < 99){
/*
printf("Compara D[%c]=%3d si D[%c]+M[%c][%c]=%3d, ",\
'a'+v, D[v], 'a'+u, 'a'+u, 'a'+v, D[u]+a[u][v]);
*/
if (D[v] > D[u] + a[u][v]){
D[v] = D[u] + a[u][v];
printf("D[%c] schimba to %2d\n", 'a'+v, D[v]);
}
printf("nu schimba\n");
}
}
}
traceinfo(D, nod);
}
(u=0; u<nod; u++){
(v=0; v<nod; v++){
(a[u][v] < 99){
/*printf("Compara D[%c]=%3d and D[%c]+M[%c][%c]=%3d, ",\
'a'+v, D[v], 'a'+u, 'a'+u, 'a'+v, D[u]+a[u][v]);
*/
(D[v] > D[u] + a[u][v]) 1;
printf("nu exista ciclu negativ\n");
}
}
}
0;
}
traceinfo( D[MAXN], nod){
i;
printf(" D = ");
(i=0; i<nod; i++) printf("%4d", D[i]);
printf("\n");}
75
Probleme rezolvate

. S se afieze componentele conexe folosind parcurgerea DF a
grafului. Graful este reprezentat prin matricea de adiacen citit din
fiier TEXT.

Rezolvare: Implementarea Pascal folosind parcurgerea DF recursiv:
a: [1..100,1..100] of integer;
viz: [1..100] of integer;
f:text;n,i,j:integer;
df(X:integer);
i:byte;
write(x, ' ');
viz[x]:=1;
i:=1 n (a[x,i]=1) (viz[i]=0) df(i);
;
citire;
assign(f,'matrice.txt');
reset(f);
readln(f,n);
i:=1 n
j:=1 n read(f,a[i,j]);
readln(f);
;
;
citire;
i:=1 n viz[i]:=0;
i:=1 n viz[i]=0 df(i);writeln ;
.

Exerciiu:
Implementai n lumbajul C aplicaia de mai sus folosind funcia Df
(iterativ) de mai jos.

df(int x){
i,k,y,s[10],gasit;
k=1;
76
s[1]=x;viz[x]=1;printf("%d ",x);
(k>=1) /*cat timp stiva este nevida */ {
y=s[k];gasit=0;
(i=1;i<=n;i++)
(viz[i]==0&&a[y][i]==1) {
printf("%d ",i); //vecin nevizitat
viz[i]=1;
s[++k]=i;
gasit=1;
break;
}
(!gasit) k--;
}
}

S se parcurg un graf reprezentat prin matricea sa de
adiacen folosind parcurgerea BF.
Rezolvare:
a: [1..100,1..100] of integer;
viz,c:array[-2..100] of integer;
f:text; n,i,j,v,p,u,x:integer;
citire;
assign(f,'matrice.txt');
reset(f);
readln(f,n);
i:=1 n
j:=1 n read(f,a[i,j]);
readln(f);
;
write('Dati nodul de plecare ');
readln(v);
;
bf(v:integer);
viz[v]:=1;write(v,' ');
c[1]:=v;
p:=1;
u:=1;
77
p<=u
x:=c[p]; p:=p+1;
i:=1 n (viz[i]=0) (a[i,x]=1)
write(i,' '); viz[i]:=1; u:=u+1; c[u]:=i;
;
;
;
citire; i:=1 n viz[i]:=0; bf(v) .
Exerciiu: S se implementeze aplicaia de mai sus n limbajul C.

S se determine componentele tari conexe ale unui graf
orientat.
Rezolvare:
Componenta tare conex care va conine vrful i va fi dat de sub-
graful indus de multimea nodurilor j pentru care a[i,j]=a[j,i]=1, unde a
este matricea drumurilor .
tare_conexe;
nmax=100;
graf = [1..nmax,1..nmax] of byte;
marcaj = [1..nmax] of boolean;
a:graf;
i,j,k,n:integer;
m:marcaj;
modificare:boolean;
write('Dati nr de noduri: '); readln(n);
writeln('dati arcele grafului (i,j) :');
writeln('0 0 pentru sfarsit ');
readln(i,j);
i*j<>0
a[i,j]:=1; readln(i,j);
;
k:=1 n i:=1 n j:=1 n
a[i,j]=0 a[i,j]:=a[i,k]*a[k,j];
k:=1;
i:=1 to n
m[i]
78
write('componenta tare conexa ',k,':',i,' ');
j:=1 n
(j<>i) (a[i,j]<>0) (a[j,i]<>0)

write(j,' ');
m[j]:=true;
;
inc(k);
writeln;
;
.
# <stdio.h>
n, a[10][10],viz[10];
citire(){
m,i,j,x,y;
printf("n=");scanf("%d",&n); printf("m=");scanf("%d",&m);
(i=1;i<=n;i++) (j=1;j<=n;j++)a[i][j]=0;
/*citirea arcelor si construirea matricei de adiacenta */
(i=1;i<=m;i++) { scanf("%d %d",&x,&y);a[x][y]=1;}
}
main(){
int k,i,j,m[10];
citire();
//se construieste matricea drumurilor
(k=1;k<=n;k++) (i=1;i<=n;i++) (j=1;j<=n;j++)
(a[i][j]==0) a[i][j]=a[i][k]&&a[k][j];
k=1; (i=1;i<=n;i++)m[i]=0;
(i=1;i<=n;i++)
(!m[i]) {
/* daca varful i nu a fost introdus intr- componenta tare conexa */
printf("componenta tare conexa %d: %d ",k,i);
(j=1;j<=n;j++)
(j!=i&&a[i][j]==1&&a[j][i]==1){
printf("%d ",j); m[j]=1;
}
k++;
printf("\n");
}
}
79
Dndu-se dou grafuri reprezentate prin matricea de adia-
cen s se precizeze dac cel de-al doilea graf este graf parial sau
subgraf al primului graf.
Rezolvare:
crt;
mat= [1..100,1..100] integer;
a,b:mat;
n,m,n1,m1,i,j:integer;
creare;
x,y,i,j:integer;
writeln(' MARTICEA 1');
write('Dati numarul de varfuri');
readln(n);
write('Dati numarul de muchii');
readln(m);
i:=1 n j:=1 n a[i,j]:=0;
i:=1 m
write('Dati primul capat al muchiei ',i,' : ');
readln(x);
write('Dati al doilea capat al muchiei ',i,' : ');
readln(y);
a[x,y]:=1; a[y,x]:=1

;
creare1;
x,y,i,j:integer;
WRITELN(' MATRICEA 2');
write('Dati numarul de varfuri');readln(n1);
write('Dati numarul de muchii');readln(m1);
i:=1 n1 j:=1 n1 b[i,j]:=0;
i:=1 m1
write('Dati primul capat al muchiei ',i,' : '); readln(x);
write('Dati al doilea capat al muchiei ',i,' : '); readln(y);
b[x,y]:=1;
b[y,x]:=1;
;
;
80
subgraf;
s:boolean;
s:=true; n1>n s:=false;
i:=1 n1 j:=1 n1
(a[i,j]=1) (b[i,j]=0) s:=false;
s=false writeln(' B nu e subgraf al lui A.')
writeln(' B e subgraf al lui A.');
;
graf_p;
g:boolean;
g:=true; n<> n1 g:=false;
i:=1 n j:=1 n
(a[i,j]=0) (b[i,j]=1) g:=false;
g=false writeln(' B nu e graf partial al lui A.')
writeln(' B e graf partial al lui A.');
;
clrscr;
creare;creare1;
graf_p;subgraf;
.
Exerciiu: S se implementeze aplicaia de mai sus n limbajul C.

Determinarea drumurilor minime ntre oricare dou noduri.
Rezolvare: Se folosete algoritmul lui ROY-FLOYD. Se pornete de
la matricea costurilor C.
k=1,n
i=1,n
j=1,n
c[i,j]=min(c[i,j],c[i,k]+c[k,j])
Simultan cu determinarea lungimilor minime ale drumurilor pot fi
reinute drumurile folosind un tablou d, unde d[i,j] reprezint muli-
mea predesesorilor lui j pentru drumul minim de la i la j.
c: [1..100,1..100] of longint; v: [1..100]of integer;
d: [1..100,1..100] of set of 1..10;
n,m,i,j,k,nr:integer; x,y:integer;
81
citire;
cost,x,y:integer;
write('nr. de noduri');readln(n);
write('nr. de muchii');readln(m);
i:=1 n
j:=1 n i<>j c[i,j]:=maxint c[i,j]:=0;
i:=1 m
write('Dati capetele arcului si costul ');
readln(x,y,cost); c[x,y]:=cost;
;
;
initializare;
{determina multimea predecesorilor, initializeaza multimea D}
i:=1 n
j:=1 n
(i<>j) (c[i,j]<maxint) d[i,j]:=[i] d[i,j]:=[];
;
drum(i,j:integer); {reconstituirea drumului}
k:integer;
i<>j
k:=1 n k d[i,j]
inc(nr);
v[nr]:=k;
drum(i,k);
dec(nr);


k:=nr 1 write(v[k], ' ');
writeln;
;
;
citire;initializare;
k:=1 n i:=1 n j:=1 n
c[i,j]>c[i,k]+c[k,j]
c[i,j]:=c[i,k]+c[k,j]; d[i,j]:=d[k,j]
c[i,j]=c[i,k]+c[k,j] d[i,j]:=d[i,j]+d[k,j];
82
i:= 1 n
j:=1 n write(c[i,j]:4);
writeln
;
write('Dati doua noduri'); readln(x,y);
writeln('costul minim= ', c[x,y], ' drumurile minime=' );
x:=1 n y:=1 n
writeln('drum de la ',x,'la ',y);
c[x,y]=maxint write('nu exista')
nr:=1;v[1]:=y;
drum(x,y)


.
Exerciiu: S se implementeze algoritmul Roy-Floyd n limbajul C.

S se verifice dac un graf reprezentat dinamic este conex sau
complet.
Rezolvare:
Se folosete un tablou de liste unde bl[i] reprezint lista vecinilor lui i.
lista=^nod;
nod= inf:integer; urm:lista ;
bl: [1..100] lista;
f:text;
i,n,x:integer;
complet:boolean;
adaugare ( p:lista;x:integer);
t,q:lista;
new(q);q^.inf:=x;q^.urm:=nil;
p=nil p:=q
t:=p; t^.urm<>nil t:=t^.urm;
t^.urm:=q;
;
;
83
listare(p:lista);
t:lista;
t:=p;
t<> nil
write(t^.inf,' ');
t:=t^.urm
end;
writeln;
;
df(i:integer);
q,t,st:lista;
viz: [1..100] integer;
conex,gasit:boolean;
j:integer;
j:=1 n viz[j]:=0;viz[i]:=1;write(i,' ');new(q);q^.inf:=i;
q^.urm:=nil;st:=q;
st<>nil
x:=st^.inf; t:=bl[x]; gasit:=false;
t<> nil
viz[t^.inf]=0
new(q); q^.inf:=t^.inf; q^.urm:=nil; viz[t^.inf]:=1;
write(t^.inf,' '); q^.urm:=st; gasit:=true; st:=q; break;
;
t:=t^.urm;
;
gasit t:=st; st:=st^.urm; dispose(t) ;
;
conex:=true;
j:=1 n viz[j]=0 conex:=false;
conex write('conex') write('nu este conex');
;
numarare( p:lista):integer;
nr:integer; t:lista;
nr:=0;t:=p;
t<>nil nr:=nr+1; t:=t^.urm ;
numarare:=nr
;
84
assign(f,'in.txt');reset(f);
readln(f,n);
i:=1 n
eoln(f)
read(f,x);
adaugare(bl[i],x)
;
readln(f);
;
writeln;
df(1);
complet:=true;
i:=1 n numarare(bl[i])<>n-1 complet:=false;
complet write('complet') write ('incomplet');
.
Exerciiu: S se implementeze aplicaia de mai sus n limbajul c.
Fiind dat un graf, s se verifice dac este aciclic.
Rezolvare:
Un graf este aciclic dac este fr cicluri. Presupunem c fiecare nod
face parte dintr-o component conex. Se ia fiecare muchie i dac
extremitile sunt n aceeai component conex atunci adugnd
aceea muchie se formeaz ciclu; dac nu sunt n aceeai component
conex toate nodurile care sunt n aceeai component cu extremitatea
a doua trec n componenta conex a extremitii 1.
f:text;
a: [1..1000] integer; n:integer; nume:string;
ciclic;
i,j,k:integer;
('Care este numele fisierului de intrare ?');
readln(nume);
assign(f,nume); reset(f);
readln(f,n);
i:=1 n a[i]:=i;
seekeoln(f)
readln(f,i,j);
85
a[i]=a[j]
writeln('Graful din fisierul ',nume,' contine cel putin un ciclu');
close(f); halt;
;
k:=1 n a[k]=a[j] a[k]:=a[i];
;
writeln('Graful din fisierul ',nume,' nu contine cicluri');
close(f);
;
ciclic
.
# <stdlib.h>
# <iostream.h>
# <stdio.h>
# <conio.h>
*f;
n,a[10];
ciclic(){
i,j,k;
fscanf(f,"%d",&n);
(i=1;i<=n;i++)a[i]=i;
fscanf(f,"%d %d",&i,&j);
(a[i]==a[j]) {
cout<<"contine ciclu";
fclose(f);
exit(1);
}
for (k=1; k<=n; k++){
if (a[k]==a[j]) a[k]=a[i];
}
cout<<"nu contine cicluri";
}
main(void){
f=fopen("in.txt","r");clrscr();
ciclic();
}
86
Se d un graf i un nod - considerat ca nodul nr. 1; se
cere s se determine toate nodurile accesibile din acest nod.
Rezolvare:

a: [1..20,1..20] integer; {matricea de adiacenta}
c: [1..20] integer;
{vectorul unde pastram nodurile accesibile}
n,i,j,k,p:integer; gasit:boolean;
write('dati numarul de noduri; n=');readln(n);
writeln('dati matricea de adiacenta:');
i:=1 n j:=1 n read(a[i,j]);
c[1]:=1; k:=1; gasit:=true; i:=1;
i<=k
j:=1 n
a[i,j]=1
p:=1 k
c[p]=j gasit:=false;
gasit k:=k+1; c[k]:=j
;
i:=i+1
;
k=n writeln('Toate nodurile sunt accesibile.')
i:=1 k write(c[i],',');
.
Exerciiu:S se implementeze aplicaia de mai sus n limbajul C.

Determinarea ciclului de lungime 3 dintr-un graf.
Rezolvare:
i,j,n,k:integer;
a: [1..50,1..50] integer;
f:text;
assign(f,'c:\lucru\graf.txt');
reset(f);
read(f,n);
87
i:=1 n j:=1 n a[i,j]:=0;
eof(f)
readln(f,i,j);
a[i,j]:=1; a[j,i]:=1
;
i:=1 n-2 j:=i+1 n-1
k:=j+1 n
(a[i,j]=1) (a[j,k]=1) (a[k,i]=1) writeln(i,' ',j,' ',k);
.
Fie G un graf orientat. G este un arbore cu radacina r, dac exist n
G un vrf r din care oricare alt vrf poate fi ajuns printr-un drum unic.
Adncimea unui vrf este lungimea drumului dintre rdcina i
acest vrf; nlimea unui vrf este lungimea celui mai lung drum
dintre acest vrf i un vrf terminal. nlimea arborelui este nalimea
rdcinii; nivelul unui vrf este nlimea arborelui minus adncimea
acestui vrf.
Reprezentarea unui arbore cu rdcin se poate face prin adrese,
ca i n cazul listelor nlnuite. Fiecare vrf va fi memorat n trei
locaii diferite, reprezentnd informaia propriu-zis a vrfului (valoa-
rea vrfului), adresa celui mai vrstnic fiu i adresa urmtorului frate.
Pstrnd analogia cu listele nlnuite, dac se cunoate de la nceput
numrul maxim de vrfuri, atunci implementarea arborilor cu rdcina
se poate face prin tablouri paralele.
Dac fiecare vrf al unui arbore cu rdacin are pn la n fii,
arborele respectiv este n-ar.
ntr-un arbore binar, numrul maxim de vrfuri de adncime k
este 2
k
. Un arbore binar de nlime i are cel mult 2
i+1
-1 vrfuri, iar
dac are exact 2
i+1
-1 varfuri, se numeste arbore plin. Vrfurile unui
arbore plin se numeroteaz n ordinea adncimii.
Un arbore binar cu n vrfuri i de nlime i este complet, dac
se obine din arborele binar plin de nlime i, prin eliminarea, dac
este cazul, a vrfurilor numerotate cu n+1, n+2, , 2
i+1
-1. Acest tip de
arbore se poate reprezenta secvenial folosind un tablou T, punnd
vrfurile de adncime k, de la stnga la dreapta, n poziiile T[2
k
],
T[2
k+1
], , T[2
k+1
-1] (cu posibila excepie a nivelului 0, care poate fi
incomplet). Un arbore binar este un arbore n care fiecare vrf are cel
mult doi descendeni, fcndu-se distincie ntre descendentul stng i
descendentul drept al fiecrui vrf.











Reprezentarea arborilor binari
Reprezentarea prin paranteze: se ncepe cu rdcina arborelui, iar
fiecare vrf care are descendeni este urmat de expresiile ataate
subarborilor care au ca rdcin descendenii vrfului, desprite prin
virgul i cuprinse ntre paranteze. Dac lipsete un descendent sub-
expresia corespunztoare este cuvntul vid. Pentru arborele de mai
sus, reprezentarea este: 6(2(1,(4(3,5)), 8(7, 9(,10)))
Reprezentarea standard: n care pentru fiecare vrf i este precizat des-
cendentul su stng ST(i) descendentul su drept DR(i) = i informaia
asociat v`rfului INF(i):
static:ST i DR sunt dou tablouri ST=(0, 1, 0, 3, 0, 2, 0,7, 0, 0)
DR=(0, 4, 0, 5, 0, 8, 0, 9,10,0) rad=6
dinamic:


type arbore=^nod;
nod=record
inf:integer;
st,dr:arbore;
end;
typedef struct nod{
int inf;
struct nod *st;
struct nod *dr;
}arbore;
si se declara arbore *rad;







Reprezentarea cu doi vectori DESC i TATA: n vectorul DESC,
avnd valori 1, 1,0 se precizeaz pentru fiecare nod ce fel de
descendent este el pentru printele su iar n vectorul TATA se indic
pentru fiecare vrf, nodul printe. Pentru exemplul de mai sus:
TATA=(2,6,4,2,4,0,8,6,8,9) DESC=(-1,-1,-1,1,1,0,-1,1,1,1)

88
89
Parcurgerea arborilor binari
:se viziteaz rdcina, se traverseaz subarborele stng
n preordine, se traverseaz subarborele drept n preordine;
: se traverseaz subarborele stng n inordine, se
viziteaz rdcina, se traverseaz subarborele drept n inordine;
: se traverseaz subarborele stng n postordine, se
traverseaz subarborele drept n postordine, se traverseaz
rdcina.

S se creeze un arbore binar i apoi s se parcurg n
preordine, s se caute un nod n arbore, s se afieze cheile de pe un
anumit nivel dat, s se afieze drumurile de la rdcin la frunze i s
se calculeze adncimea arborelui creat.
Rezolvare:
arb_binar;
arbore=^nod;
nod = st,dr:arbore; inf:integer ;
p:arbore;k,x,y,max,z:integer;a: [1..100] integer;
{Procedura creare arbore binar}
creare( p:arbore);
x:integer;
read(x);
x=0 p:=nil
new(p); p^.inf:=x;
write('Dati stanga lui ',x); creare(p^.st);
write('Dati dreapta lui ',x); creare(p^.dr);
;
;
{Procedura parcurgere arbore binar - prin preordine}
preordine(p:arbore);
p<>nil
write(p^.inf,' ');
preordine(p^.st); preordine(p^.dr);
;
;
90
{Cautarea unui nod din arbore}
cautare(p:arbore; x:integer):boolean;
p=nil cautare:=false
x=p^.inf cautare:=true
cautare:= cautare(p^.st,x) cautare(p^.dr,x);
;
{Afisarea tuturor cheilor de pe nivelul dat}
nivel(p:arbore;k,x:integer);
p<>nil
k=x write(p^.inf,' ');
nivel(p^.st,k+1,x);
nivel(p^.dr,k+1,x);
;
;
{Drumurile de la radacina la frunze}
drum_frunze(p:arbore;k:integer);
i:integer;
(p^.st=nil) (p^.dr=nil)
a[k]:=p^.inf;
i:=1 k write(a[i],' ');
writeln

p<>nil
a[k]:=p^.inf;
drum_frunze(p^.st,k+1);
drum_frunze(p^.dr,k+1);
;
;
{Afisarea numarului maxim de nivele}
adancime(p:arbore;k:integer; max:integer);
p<>nil
k>max max:=k;
adancime(p^.st,k+1,max);
adancime(p^.dr,k+1,max);

;
91
creare(p);
preordine(p);
{Pentru procedura cautare}
read(x);
writeln(cautare(p,x));
{Pentru procedura nivel}
write('Nivelul= ');read(y);nivel(p,0,y);
{Pentru procedura drum_frunze}
drum_frunze(p,1);
{Pentru procedura adancime}
adancime(p,0,max);
writeln('Numarul de nivele este: ',max);
.
# <stdio.h>
# <alloc.h>
# <iostream.h>
# <conio.h>
nod{
inf;
nod *st, *dr;
}arbore;
arbore *rad;
a[10], max=0;
arbore *creare(){
x;arbore *p;
cout<<"inf"; cin>>x;
(x==0) NULL;
{ (p)=(arbore*) malloc(sizeof(arbore)); (p)->inf=x;
cout<<"inf st. a lui"<<x; p->st=creare();
cout<<"inf dreapta a lui"<<x; p->dr=creare();
}
p;
}
preordine(arbore *p){
(p){
printf("%d ",p->inf); preordine(p->st); preordine(p->dr);
}
}
92
inordine(arbore *p){
(p){
inordine(p->st); printf("%d",p->inf); inordine(p->dr);
}
}
postordine(arbore *p){
if (p){
postordine(p->st); postordine(p->dr); printf("%d",p->inf);
}
}
cautare(arbore *p, x){
(p){
(p->inf==x) 1;
cautare(p->st,x)||cautare(p->dr,x);
}
0;
}
nivel(arbore*p, int k,int x){
(p){
if (k==x) printf("%d ",p->inf);
nivel(p->st,k+1,x); nivel(p->dr,k+1,x);
}
}
drum_frunze(arbore*p,int k){
i;
((p->st)&&(p->dr)) {
a[k]=p->inf;
(i=1;i<=k;i++) printf("%d ",a[i]);printf("\n");
}
{
(p) {
a[k]=p->inf;
drum_frunze(p->st,k+1); drum_frunze(p->dr,k+1);
}
}
}
adancime(arbore *p, k){
if (p) {
(k>max) max=k; adancime(p->dr,k+1) ;adancime(p->st,k+1);
}}
93
main(){
x;
rad=creare();
preordine(rad);
printf("inf cautata:");scanf("%d", &x);
(cautare(rad,x)) printf("exista"); printf("nu exista");
cout<<"nivelul";cin>>x;
cout<<"nodurile de pe nivelul "<<x<<":";nivel(rad,0,x);
cout<<"drumuri:";drum_frunze(rad,1);
adancime(rad,0);
printf("adancimea=%d",max);
}
Arbori binari de cutare
Arborele binar de cutare este un arbore binar n care pentru orice nod,
cheia din succesorul su stng este mai mic dect cheia din nod, iar
cheia din succesorul su drept este mai mare dect cheia din nod. n
arborele binar de cutare informaia din noduri este unic. Prin
parcurgerea n inordine a arborelui de cutare se obine n ordine
cresctoare valorile din cmpurile cheie.
Crearea se realizeaz adugnd n arbore rnd pe rnd cte un
nod corespunztor fiecrei informaii.
Adugarea unu nod:
dac arborele nu are nici un nod se creaz rdcina;
dac arborele exist se compar informaia nodului nou cu cea din
nodul curent. Dac este mai mare, se reia procesul pentru
subarborele din dreapta; dac este mai mic, se reia pentru
subarborele din stnga, iar n caz de egalitate se afieaz eroare.
Cutarea se realizeaz astfel: se caut n nodul curent; dac
informaia s-a gsit, algoritmul se ncheie, astfel dac informaia este
mai mare dect informaia din nodul curent, se caut n subarborele
drept al acestuia, altfel n subarborele stng.
Program pentru crearea i exploatarea unui arbore
binar de cutare.
Rezolvare:
arbore=^nod;
nod = inf:integer; st,dr:arbore ;
p:arbore;x:integer;
94
inserare( p:arbore;x:integer);
q:arbore;
new(q);
q^.inf:=x;
q^.st:=nil;
q^.dr:=nil;
p=nil p:=q
p^.inf=x write('Exista')
p^.inf<x inserare(p^.dr,x)
inserare(p^.st,x)
;
srd(p:arbore);
p<>nil srd(p^.st); write(p^.inf,' '); srd(p^.dr)
;
stergere( p:arbore;x:integer);
t:arbore;
p=nil write('nu exista')
p^.inf<x stergere(p^.dr,x)
p^.inf>x stergere(p^.st,x)
p^.st=nil
t:=p; p:=p^.dr; dispose(t)
p^.dr=nil
t:=p;p:=p^.st;dispose(t);


t:=p^.st;
t^.dr^.dr<>nil t:=t^.dr;
p^.inf:=t^.dr^.inf; dispose(t^.dr);
t^.dr:=nil

;
read(x);
x<>0 inserare(p,x); read(x) ;
srd(p);read(x);stergere(p,x);srd(p);
.
95
# <iostream.h>
# <conio.h>
# <stdio.h>
nod { inf; nod *st,*dr;}arbore;
arbore *rad;
arbore *q;
adaug(arbore* &p,int x){
(p==NULL){
p= nod;
p->inf=x;
p->st=p->dr=NULL;
}
(p->inf>x) adaug(p->st,x);
(p->inf<x) adaug(p->dr,x);
cout <<"informatia exista";
}
creare(arbore* &p){
x,n,i;
cout <<"n=";cin>>n;
(i=1;i<=n;i++){
cout<<"inf";cin>>x;
adaug(p,x);
}
}
inordine(arbore *p){
(p){
inordine(p->st); printf("%d",p->inf); inordine(p->dr);
}
}
arbore *cauta(arbore*p, int x){
(p==NULL) NULL;
(p->inf<x) {
q=p;p=p->st;cauta(p,x);
}
(p->inf>x){
q=p;p=p->st; cauta(p,x);
}
p;
}
96
sterge(arbore *&r, x){
arbore *t,*q1,*p;
int a;
t=cauta(r,x);
(t==NULL){
cout<<"informatia nu se gaseste";
getch();
}
(t->dr==t->st){
(t->inf<q->inf) q->st=NULL;
delete t;
}
(t->st==NULL&&t->st){
(q->inf<t->inf) q->dr=t->st; q->st=t->st;
delete t;
}
(t->st==NULL&&t->dr){
(q->inf>t->inf) q->st=t->dr; q->dr=t->dr;
delete t;
}
{
p=t;
while (p->st!=NULL){q=p;p=p->st;}
}
q1=t;
t->inf=p->inf;
(p->dr==p->st){
q->st=NULL;
delete p;
}
{
q->st=p->dr;
delete p;
}
(q1->st&&q1->inf<q1->st->inf){
a=q1->inf;
q1->inf=q1->st->inf; q1->st->inf=a;
q1=q1->st;
}
}
97
void main(){
int x;
arbore *rad=0;
creare(rad);
inordine(rad);
sterge(rad,2);
}


Probleme rezolvate n limbajul Pascal
S se scrie un subprogram pentru afiarea numrului cheilor
negative i pozitive dintr-un arbore binar.
p3(p:arbore);
p<>nil
p3(p^.st);
p^.inf<0 nr1:=nr1+1;
p^.inf>=0 nr2:=nr2+1;
p3(p^.dr);
;
;
S se scrie un subprogram pentru afiarea cheilor impare
dintr-un arborele binar.
p2(p:arbore);
p<>nil
p^.inf 2 =1 write(p^.inf,' ');
p2(p^.st); p2(p^.dr)

;
S se scrie un subprogram pentru aflarea produsului cheilor
pozitive dintr-un arborele binar.
p4(p:arbore):longint;
p<>nil p^.inf >0 p4:=p^.inf*p4(p^.st)*p4(p^.dr)
p4:=p4(p^.st)*p4(p^.dr)
p4:=1
;
98
S se scrie un subprogram pentru aflarea numrului de
frunze dintr-un arborele binar .
p5(p:arbore):integer;
p=nil p5:=0 (p^.st=nil) (p^.dr=nil) p5:=1
p5:=p5(p^.st)+p5(p^.dr)
;
. S se scrie un subprogram pentru afiarea nodurilor care au
un succesor dintr-un arbore binar.
p6(p:arbore);
p<>nil
((p^.st=nil) (p^.dr<>nil)) ((p^.st<>nil) (p^.dr=nil))
write(p^.inf,' ');
p6(p^.st); p6(p^.dr)

end;
S se scrie un subprogram pentru aflarea numrului de
noduri de pe un nivel dat dintr-un arbore binar.
p7(p:arbore;k:integer):integer;
p<>nil k=l p7:=1+p7(p^.st,k+1)+p7(p^.dr,k+1)
p7:=p7(p^.st,k+1)+p7(p^.dr,k+1)
p7:=0
;

Probleme propuse:

1. Se d un graf orientat cu n noduri. S se verifice dac exist un
nod avnd gradul interior n-1 i gradul exterior 0.
2. Fie G = (X,U) un graf orientat i far circuite. S se determine o
renumerotare a vrfurilor sale astfel ncat dac (u,v)U, atunci
numrul de ordine al lui u este mai mic dect numrul de ordine al
lui v (sortare topologic).
3. Fie G = (X,U) un graf orientat cu n vrfuri. S se determine un alt
graf avnd aceleai vrfuri, aceeai matrice a drumurilor i avnd
un numr minim de arce (se pot scoate, introduce noi arce).
99
4. La un turneu particip n juctori, fiecare juctor jucnd pe rnd
mpotriva celorlali juctori. tiind c nu exist jocuri egale, s se
construiasc o list care s cuprind toi juctorii astfel ncat doi
juctori i, j sunt alturi dac juctorul i la nvins pe juctorul j.
5. La curtea regelui Artur s-au adunat 2n cavaleri i fiecare din ei are
printre cei prezeni cel mult n-1 dumani. S se arate c Merlin,
consilierul lui Artur, poate s-i aeze n aa fel pe cavaleri la o
masa rotund nct nici unul dintre ei s nu stea alturi de vreun
duman.
6. Fie G=(X,U) un graf conex cu n noduri. S se determine eficient
cel mai mic k astfel nct tergnd nodurile etichetate cu 1,2...k, n
aceast ordine s rezulte un graf ale crui componente conexe au
toate cel mult n/2 noduri.
7. S se determine, ntr-un graf conex, un ciclu care conine dou
noduri date, dar nu conine un al treilea nod.
8. Numim transpusul unui graf G = (X,U), graful care are aceeai
mulime de noduri, arcele sale fiind arcele grafului G, dar avnd
sens opus. Dndu-se G prin matricea de adiacen sau prin liste de
vecini, s se determine n fiecare caz transpusul grafului dat.
9. Find date n persoane n care fiecare persoan se cunoate pe sine
i eventual alte persoane. S se formeze grupuri n care fiecare
persoan s cunoasc toate celelalte persoane din grup (o persoan
aparine unui singur grup). Relaia x cunoate pe y nu este n
mod normal nici simetric, nici tranzitiv.
Indicaie: Se asociaz problemei date un graf orientat cu n noduri i se
construiete matricea de adiacen (a[i,j]=1 daca i cunoaste pe j =i 0
dac i nu cunoate pe j). Pentru fiecare persoan neataat la un
moment dat unui grup se va construi grupul din care face parte
aceasta. Soluia nu este unic.
10. S se determine, ntr-un graf turneu, un drum elementar care trece
prin toate vrfurile. Un graf turneu este un graf orientat cu
proprietatea c ntre oricare dou vrfuri distincte exist un arc i
numai unul.
Indicaie: Se adaug arcul format din nodurile 1 i 2 ntr-o list liniar.
Fiecare din vrfurile urmtoare se adaug la drumul creat anterior fie
n fa, fie la sfrit, fie intercalat n list.
11. Fie G=(X,U) un graf ponderat. S se calculeze diametrul grafului.
Se numete diametrul unui graf, notat d(G), d(G)=max{l[i]/ iX},
unde l[i] este lungimea drumului maxim care are ca extremitate
iniial vrful i.
100
12. Fie G un graf orientat n care fiecare arc are asociat un cost pozi-
tiv. S se determine un circuit elementar care s treac prin toate
vrfurile grafului care s aib cost minim.
13. Se consider un grup de n persoane. Fiecare persoana are cel puin
n/2 prieteni i cel mult k dumani n grup. Una din persoane are o
carte pe care fiecare dorete s o citeasc. S se determine o mo-
dalitate prin care cartea s circule pe la fiecare persoan o singur
dat, transmiterea ei facndu-se numai ntre doi prieteni, iar n
final cartea s ajung din nou la proprietarul crii.
14. Pentru un graf dat n numerotare aciclic (orice arc u = (x,y) din U
satisface condiia x<y), determinai distana minim de la vrful 1 la
toate celelate vrfuri z pentru care exist drumuri de la 1 la z, precum i
cte un drum de lungime minim. Sunt date arcele i lungimile lor.
15. Ptratul unui graf orientat G se determin astfel: exist arc de la x
la y n ptratul unui graf dac exist n G un drum de lungime 2 de
la x la y. S se determine ptratul unui graf cnd graful este repre-
zentat fie prin liste de adiacen, fie prin matricea de adiacen.
16. Se d un graf orientat aciclic i se cere aranjarea vrfurilor sale
astfel nct orice arc are prima extremitate naintea celei de-a doua
extremiti n aranjare.
17. Se d un graf orientat aciclic, n care numrul maxim de arce n
orice drum este k. S se determine o partiie a mulimii vrfurilor
grafului n cel mult k submulimi, astfel nct pentru orice dou
noduri x,y din aceeai submulime s nu existe drum de la x la y i
nici de la y la x.
Indicaie: Graful este aciclic, deci exist noduri cu gradul 0 i se
formeaz prima submulime cu aceste noduri i apoi se vor elimina
aceste noduri din graf mpreuna cu arcele ce pleac din ele obinndu-
se un graf orientat aciclic pentru care se reia procedeul.
18. Un graf orientat se numete semi-conex dac pentru pentru orice
pereche de vrfuri diferite x i y exist drum de la x la y sau drum
de la y la x. S se verifice dac G este semi-conex.
19. S se realizeze un program care s deseneze un graf (planar)i apoi s
se marcheze succesiv pe desen drumul de lungime minim ntre dou
noduri date.
20. Se consider o clas de n ( n <= 40 ) cursani ntre care exist relaii de
simpatie, nu neaparat reciproce. S se formeze grupuri de cursani ntre
care exist relaii de prietenie reciproc. Un cursant nu poate s
aparin mai multor grupuri.

101
Divide et Impera
3.1.1. Prezentarea metodei
Metoda general de programare cunoscut sub numele de divide et
impera (dezbin i stapnete) const n mprirea repetat a unei
probleme n subprobleme de acelai tip, dar de dimensiune mai mic,
urmat de combinarea soluiilor subproblemelor rezolvate pentru a
obine soluia problemei iniiale. Fiecare subproblem se rezolv
direct dac dimensiunea ei este suficient de mic nct s poat fi
rezolvat imediat cu un procedeu specific, altfel este mprit n
subprobleme mai mici folosind acelai procedeu prin care a fost
descompus problema iniial. Procedeul se reia pn cnd, n urma
descompunerilor repetate, se ajunge la probleme care admit rezolvare
imediat.
Algoritmul fiind de natur repetitiv i deoarece subproblemele
au aceeai form cu cea a problemei iniiale, metoda Divide et
impera poate fi implementat elegant folosind o funcie recursiv.
n continuare este dat funcia general care implementeaz
algoritmul.

divimp(X: problema)
(X este suficient de mica) then y rezolv(X)
{
descompune problema x n subproblemele X
1
, X
2
,, X
k

i 1 k
y
i
divimp(X
i
)
/* combin y
1
, y
2
, , y
k
pentru a obine y soluia problemei X */
y combin(y
1
, y
2
, , y
k
)
y
Uneori recursivitatea se poate nlocui cu un ciclu iterativ. Versiunea
iterativ poate fi mai rapid i folosete mai puin memorie
comparativ cu varianta recursiv care utilizeaz o stiv pentru
memorarea apelurilor.
3.1.2. Probleme rezolvate
[Cel mai mare divizor comun] Fie n numere naturale nenule
x
1
, x
2
,,x
n
. S se calculeze cmmdc pentru numere date.

102
Rezolvare:
divizor_comun;
x: [1..25] of integer; n, i:integer;
Divizor(a,b:integer):integer;
a<>b a>b a:=a-b b:=b-a;
Divizor := a
;
cmmdc(lo,hi:integer):integer;
m:integer;
(hi-lo<=1) cmmdc := Divizor(x[lo],x[hi])
m:=(lo+hi) div 2;
cmmdc:= Divizor(cmmdc(lo,m), cmmdc(m+1,hi));
;
;
write('n = '); readln(n); writeln('Introduceti numerele');
i:=1 n write('x[',i,'] = '); readln(x[i]) ;
writeln('cmmdc:= ', cmmdc(1,n));
.
[Cutare binar] Fie x
1
, x
2
,,x
n
un ir de numere ntregi
ordonate cresctor i x un numr ntreg. S se verifice dac x se afl
printre elementele irului i dac da, s se afieze poziia acestuia.
Rezolvare:
cautare;
crt;
x: [1..100] integer; nr:integer;
cauta(lo,hi:integer):integer;
m:integer;
(lo<=hi) m:=(lo+hi) div 2;
nr=x[m] cauta:=m
nr<x[m] cauta:=cauta(lo,m-1)
cauta:=cauta(m+1,hi)
cauta:=0
end;
103
n,i,pos:integer;
ch:char;
write('n = ');readln(n);
writeln('Introduceti numerele');
i:=1 n write('x[',i,'] = '); readln(x[i]) ;
writeln;
write('Numarul cautat = ');
readln(nr);
pos := cauta(1,n);
pos <> 0
writeln(nr,' se afla in sir la pozitia ', pos)
writeln(nr,' nu se afla in sir!');
write('Continuati (y/n) ?[y] ');
ch:=UpCase(readkey);
ch = 'N';
.
. [Sortare rapid] Fie n N* i numerele x
1
, x
2
,,x
n
. S se scrie
o procedur recursiv de sortare (quicksort) n ordine cresctoare a
numerelor date.
Rezolvare:
# <stdio.h>
QSort (int *table, int left,int right){
leftp,rightp,aux;
type = 1;
leftp =left;
rightp=right;
{
( table[leftp]>table[rightp] ){
type ^= 1;
aux = table[leftp];
table[leftp] = table[rightp];
table[rightp] = aux;
}
type ? rightp--: leftp++;
} (leftp < rightp);
( leftp-left > 1) QSort(table,left,leftp-1);
( right-rightp >1) QSort(table,rightp+1,right);
}
104
main(){
n,i;
x[100];
printf(n = ); scanf(%d,&d);
(i=0;i<n;i++) scanf(%d,&x[i]);
Qsort(x,0,n-1);
(i=0;i<n;i++) printf(%8d,x[i]);
}
[Problema turnurilor din Hanoi] Se dau 3 tije numerotate cu 1,
2, 3 i n discuri perforate, cu diametre diferite. Iniial toate discurile
se afl pe tija 1 n ordinea descrescatoare a diametrelor lor, n sensul
de la baz la vrful tijei. Se pune problema de a muta toate cele n
discuri pe tija 2 (utiliznd i tija 3) i respectnd urmatoarele reguli:
a fiecare pas se mut un singur disc;
pe fiecare tij deasupra unui disc pot apare numai discuri
cu diametru mai mic.
Rezolvare:
# <stdio.h>
Hanoi( n, a, b){
(n==1) printf("\%d - %d\n",a,b);
{
Hanoi(n-1, a, 6-a-b);
printf("\%d - %d\n",a,b);
Hanoi(n-1, 6-a-b,b);
}
}
main(){
n;
printf("Numarul de discuri = "); scanf("%d",&n);
Hanoi(n,1,2);
}
[Sortare prin interclasare] Se consider un vector ne numere
intregi de lungime n. Descriei un algoritm de ordonare a numerelor
prin metoda de sortare prin interclasare.
Rezolvare:
# <stdio.h>
# MAX 100

105
MSort( tabel[], temp[], lo, hi){
mid, k, t_lo, t_hi;
(lo >= hi) ;
mid = (lo+hi) / 2;
MSort(tabel,temp, lo, mid);
MSort(tabel,temp, mid+1, hi);
t_lo = lo;
t_hi = mid+1;
(k = lo; k <= hi; k++)
( (t_hi > hi || tabel[t_lo] < tabel[t_hi]) && (t_lo <= mid) )
temp[k] = tabel[t_lo++];
temp[k] = tabel[t_hi++];
(k = lo; k <= hi; k++)
tabel[k] = temp[k];
}
main(){
n, i;
tabel[MAX];
temp[MAX];
printf("n = ");
scanf("%d",&n);
printf("Introduceti numerele:\n");
(i=0;i<n;i++){
printf("tabel[%d] = ",i);
scanf("%d",&tabel[i]);
}
MSort(tabel, temp, 0, n-1);
(i=0;i<n;i++) printf("%d ",tabel[i]);
}
3.1.3. Probleme propuse
1. Fie x
1
, x
2
,,x
n
un ir de numere reale. S se determine max{x
1
,
x
2
,,x
n
}.
2. Se d x
1
, x
2
,,x
n
(cu nN) un ir de numere, descriei un program
Divide et Impera care s determine al k-lea cel mai mic element
din ir (k N, k<n).
3. Se consider un vector de x cu n componente numere intregi. S
se sorteze componentele vectorului folosind metoda de sortare
prin interclasare.
106
4. Se d o plac de tabl cu lungimea x i limea y avnd n guri
date prin coordonatele lor ntregi. Se cere s se decupeze o bucat
dreptunghiular de arie maxim i fr guri tiind c sunt permise
numai tieturi orizontale i verticale.
5. Se consider un vector de lungime n. Se numete plierea
vectorului operaia de suprapunere a unei jumti (donatoare)
peste cealalt jumtate (receptoare). Dac n este impar elementul
din mijloc se elimin. Elementele rezultate dup pliere vor avea
numeroatarea jumtii receptoare. Plierea se poate repeta pn
cnd se obine un singur element (final). Scriei un program care
s determine toate elementele finale posibile i s afieze
succesiunile de plieri corespunztoare. Rezolvai aceiai problem
innd cont c la pliere fiecare element receptor se dubleaz i din
acesta se scade elementul donator corespunztor.
6. Rezolvai problema turnurilor din Hanoi folosint dou tije de
manevr. Comparai numrul de mutri efectuate.
7. Fie P(x) un polinom de grag n cu coficien. Compara @" P 0`#0$lPj` tor.2 T3Tw 0.443 0 TdDrTdungh1 Tw0>Tjtrebui>Tjsc>Tj/Tusfd356innd cont c i n u m ` p h Y 0 ` = 5 ` 0
107

3.2.1. Principii fundamentale ale programrii dinamice


Programarea dinamic, ca i metoda divide et impera, rezolv
problemele "combinnd" soluiile subproblemelor. Un algoritm bazat
pe programare dinamic rezolv fiecare subproblem o singur dat i,
apoi, memoreaz soluia ntr-un tablou, prin aceasta evitnd
recalcularea soluiei dac subproblema mai apare din nou i
subprobemele care apar n descompunere nu sunt independente.
Metoda programrii dinamice se aplic problemelor de
optimizare. n problemele de optim metoda const n determinarea
soluiei pe baza unui ir de decizii d
1
, d
2
, d
3
....d
n
, unde d
i
transform
problema din starea s
i-1
n starea s
i
.
Paii pentru rezolvarea unei probleme folosind programarea
dinamic:
1. Caracterizarea structurii unei soluii optime;
2. Definirea recursiv a valorii unei soluii optime;
3. Calculul valorii unei soluii optime
4. Construirea unei soluii optime din informaia calculat.
Principii fundamentale ale programrii dinamice:
1. Dac d
1
, d
2
, ... d
n
este un ir optim de decizii care duc un
sistem din starea iniial n starea final, atunci pentru orice i
(1in) d
1
, d
2
, ... d
i
este un ir optim de decizii.
2. Dac d
1
, d
2
, ... d
n
este un ir optim de decizii care duc un
sistem din starea iniial n starea final, atunci pentru orice i
(1in) d
i
, d
i+1
, ... d
n
este un ir optim de decizii.
3. Dac d
1
, d
2
, ... , d
i
, d
i+1
... d
n
este un ir optim de decizii care
duc un sistem din starea iniial n starea final, atunci pentru
orice i (1in) d
1
, d
2
,... , d
i
i d
i
, d
i+1
, ... d
n
sunt dou iruri
optime de decizii.

3.2.2. Probleme rezolvate
[Subir cresctor maximal] Se consider un ir de n numere
ntregi. S se determine cel mai lung subir cresctor din acesta.
Exemplu: n=8
7 1 8 2 11 4 12 3
Subirul cresctor maximal: 7 8 11 12 cu lungimea 4
Rezolvare: Se construiete tabloul L reprezentnd lungimea maxim a
unui subir maximal care l conine ca prim element pe a[i] astfel
108
L[n]=1 i L[i]=1+max{L[j]/ j>i i a[j]>a[i]} pentru i de la n-1 la 1
(metoda nainte - deoarece soluia unei subprobleme se afl pe baza
subproblemelor din urm).
i,j,n,poz,max:integer;
l,a:array[1..30] of integer;
write('n=');read(n);
i:=1 n write('a[',i,']='); read(a[i]) ;
i:=1 n l[i]:=0;
l[n]:=1;
i:=n-1 1
max:=0;
j:=1+i n
(a[j]>a[i]) (max<l[j]) max:=l[j];
l[i]:=1+max
;
max:=0;
i:=1 n max<l[i]
max:=l[i];
poz:=i
;
write(a[poz],' '); i:=poz;
max>1
(a[i]>a[poz]) (l[i]=max-1)
poz:=i;
write(a[poz],' ');
max:=max-1
;
i:=i+1

.
# <stdio.h>
main(){
n,i,j,poz,max,a[100],l[100];
printf("n=");scanf("%d",&n);
(i=1;i<=n;i++) scanf("%d",&a[i]);
109
(i=1;i<=n;i++) l[i]=0;
l[n]=1;
(i=n-1;i>0;i--){
max=0;
(j=i+1;j<=n;j++)
((max<l[j])&&(a[j]>a[i])) max=l[j];
max=max++;
l[i]=max;
}
max=0;
(i=1;i<=n;i++) if (l[i]>max) {max=l[i];poz=i;}
printf(" %d ",a[poz]); i=poz;
(max>1){
((a[i]>a[poz]) &&(l[i]==max-1)) {
poz=i;
printf("%d ",a[poz]);
max=max-1;
}
i++;
}
}
Exerciiu: S se rezolve aceast problem folosind varianta napoi
de programare dinamic (soluia unei subprobleme se afl pe baza
subproblemelor dinainte).
Indicaie: Tabloul L se construiete astfe L[1]=1 i L[i]=1+max{L[j] /
j<i i a[j]<a[i]} pentru i de la 2 la n.
[Datorii] Domnul Tudor s-a mprumutat de n ori de la o banc
cu diferite sume de bani. El trebuie s restituie banii bncii, dar dup
prima restituire tie c nu mai poate restitui toate sumele mprumutate
la rnd ci doar acelea care nu au fost mprumutate n etape succesive.
S se determine suma maxim pe care o poate recupera banca i care
sunt mprumuturile restituite.
Rezolvare: Elementele tabloului L se calculeaz dup formula
L[i]=a[i]+max{L[j] / j>i+1]}
a,l:array[1..100]of integer;
max,n,i,j,poz:integer;

read(n);
110
i:=1 n read(a[i]);
i:=n 1
max:=0;
j:=i+2 n (max<l[j]) max:=l[j];
max:=max+a[i];
l[i]:=max
;
max:=l[1];poz:=1;
i:=1 n l[i]>max
max:=l[i];
poz:=i
;
writeln('suma maxima este: ',l[1]);
max:=l[1];poz:=1;write('sirul: ');
write(a[poz],' '); i:=poz+2;
(i<n ) (l[i]<>max-a[poz]) i:=i+1;
max:=max-a[poz];
poz:=i;
max=0
.
# <stdio.h>
main(){
n,i,j,poz,max,a[100],l[100];
printf("n=");scanf("%d",&n);
(i=1;i<=n;i++) scanf("%d",&a[i]);
(i=n;i>0;i--){
max=0;
(j=i+2;j<=n;j++) (max<l[j]) max=l[j];
max=max+a[i];
l[i]=max;
}
max=l[1];poz=1;
(i=1;i<=n;i++) (l[i]>max) {max=l[i];poz=i;}
printf("suma maxima %d\n",l[1]);
max=l[1];poz=1;
(max>0){
printf("%d ",a[poz]);
i=poz+2;
111
((i<n) && (l[i]!=max-a[poz])) i++ ;
max=max-a[poz];
poz=i;
}
}
[Subiruri comune] Dndu-se dou iruri comune s se deter-
mine cel mai lung subir comun.
Rezolvare:
(varianta mersului napoi): Se construiete
tabloul c care reine lungimea maxim a celui mai lung subir comun a
celor dou iruri pn la i respectiv j.
a,b,d:string;
i,j,n,m,max,t,v:integer;
c: [1..50,1..50] integer;
write('primul sir:');readln(a);write('sirul doi:');readln(b);
n:=length(a);m:=length(b);
i:=1 m a[1]=b[i] c[1,i]:=1 c[1,i]:=0;
i:=1 n a[i]=b[1] c[i,1]:=1 c[i,1]:=0;
i:=2 n j:=2 m
a[i]=b[j] c[i,j]:=c[i-1,j-1]+1 c[i,j]:=0;
max:=0;
i:=1 n j:=1 m
max<c[i,j] max:=c[i,j]; t:=i; v:=j ;
writeln('secventa maxima are lungimea :',max);
d:=a[t];
max>1
dec(max); dec(t);
d:=a[t]+d
;
writeln(d);
.
Exerciiu: S se implementeze n C aplicaia de mai sus.
[Partiii] S se determine numrul de moduri n care se poate
descompune un numr natural n suma de numere.
Exemplu: n=4, numrul de moduri = 5
Rezolvare: Se construiete tabloul a unde a[n][0] reprezint numrul
de moduri n care se poate descompune:

112
a[n,n]=1;
a[n,k]=a[n-k,0] pentru n2k;
a[n,k]=a[n-k,i] pentru i de la 1 la k.
# <stdio.h>
main(){
n,i,k,j,p,a[100][100];
printf("n=");scanf("%d",&n);
a[1][0]=1;a[1][1]=1;
( i=2;i<=n;i++){
a[i][0]=0;
(k=1;k<=i;k++){
(k==i) a[i][k]=1;
(i<2*k) a[i][k]=a[i-k][0];
{
a[i][k]=a[i-k][k];
( l=1;l<=k-1;l++)
a[i][k]=a[i][k]+a[i-k][l];
}
a[i][0]=a[i][0]+a[i][k];
}
}
printf("nr de moduri=%d",a[n][0]);
}
Exerciiu: S se implementeze n Pascal aplicaia de mai sus.
[Drum] Dndu-se un tablou bidimensional cu elemente
numere naturale. S se determine un traseu de la poziia 1,1 la poziia
n,m, deplasarea fcndu-se numai n direciile S i E, astfel nct
suma elementelor de pe traseu s fie maxim.
Rezolvare: este:
i,j,n,m,max,p,q:integer;
a,l: [1..10,1..10] integer;

read(m,n);
i:=1 n j:=1 m read(a[i,j]);
l[1,1]:=a[1,1];
i:=2 m l[1,i]:=l[1,i-1]+a[1,i];
i:=2 n l[i,1]:=l[i-1,1]+a[i,1];
i:=2 n j:=2 m
113
l[i-1,j]>l[i,j-1] l[i,j]:=l[i-1,j]+a[i,j]
l[i,j]:=l[i,j-1]+a[i,j];
writeln(l[n,m]); max:=l[n,m];p:=n;q:=m; write(a[n,m],' ');
(p<>1) (q<>1)
l[p-1,q] = l[p,q]-a[p,q] p:=p-1 q:=q-1;
write(a[p,q],' ');
;
write(a[1,1]);
.
Exerciiu: S se implementeze aplicaia de mai sus n C.
3.2.3. Probleme propuse
1. [Triunghi] Se consider un triunghi de numere. S se calculeze cea
mai mare dintre sumele numerelor ce apar pe drumurile ce pleac din
vrf i ajung la baz i s se reconstituie drumul de sum maxim. n
punctul (i,j) se poate ajunge numai din (i-1,j) sau (i-1,j-1).
Exemplu:
N = 3
6
3 8
8 4 1
suma maxim este 18 i drumul 6 8 4
Indicaie: Se construiete tabloul c astfel c[i,j]=max{a[i,j]+ c[i+1,j],
a[i,j]+ c[i+1,j+1]} (varianta mersului nainte). c[1,1] este suma
maxim cerut.
2. [nmulirea optim a unui ir de matrice] Se dau n matrice.
Asociativitatea nmulirii a dou matrice ne ofer mai multe
posibiliti de a calcula produsul i care au un numr diferit de
operaii. S se determine o posibilitate de asociere a nmulirii
matricelor astfel nct numrul de operaii s fie minim.
Indicaie: Se construiete tabloul bidimensional L, unde l[i,j] repre-
zint numrul minim de nmuliri pentru a efectua produsul A
i
A
i+1
.....A
j
.
3. [Triangularizarea optim a poligoanelor] Se d un poligon convex i
o funcie de pondere p definit pe triunghiurile formate de laturile i
diagonalele poligonului. S se gseasc o triangulare care minimizea-
z suma ponderilor triunghiurilor din triangularizare.
Indicaie Exist o coresponden ntre triangularizarea unui poligon i
parantezarea unei expresii cum ar fi produsul unui ir de matrici.
4.[ Tiprirea uniform] Textul de intrare este o succesiune de n cuvin-
te de lungimi l
1
, l
2
,...l
n
, lungimea fiind msurat n caractere. Se dore-
114
te tiprirea uniform a paragrafului pe un anumit numr de linii, fieca-
re linie avnd cel mult m caractere astfel: dac o linie conine cuvinte-
le de la cuvntul i la cuvntul j, cu i j iar ntre cuvinte se las exact
un spaiu. S se minimizeze suma cuburilor numrului de spaii supli-
mentare de la sfritul liniilor, n raport cu toate liniile, mai puin ultima.
5. [Problema patronului] Un patron a cumprat un calculator i dorete
s nvee s lucreze cu el. Pentru aceasta va umple un raft de cri din
colecia Informatica n lecii de 9 minute i 60 secunde. Raftul are
lungimea L cm (L numr natural). Seria dispune de n titluri 1, 2, ,n
avnd grosimile g
1
, g
2
, ..., g
n
cm (numere naturale). S se selecteze
titlurile pe care le poate cumpra patronul, astfel nct raftul s fie
umplut complet (suma grosimilor crilor cumprate s fie egal cu
lungimea raftului) i numrul crilor achiziionate s fie maxim.
Olimpiada Naional de Informatic 1996
Indicaie: Se construiete tabloul bidimensional a unde a[i,j] reprezin-
t numrul maxim de cri dintre primele i (n ordinea dat la intrare)
cu lungimea total j sau, 0 dac nu exist nici o submulime a mulimii
primelor i cri cu lungimea total j.
6. [Planificarea unei recepii] Corporaia AMC are o structur ierarhi-
c, relaiile de subordonare formeaz un arbore n care rdcina este
preedintele. Fiecare angajat are un coeficient de convieuire (numr
real). Preedintele dorete s organizeze o petrecere astfel nct nici un
angajat s nu se ntlneasc cu seful su direct. Informaticianul Tom
trebuie s alctuiasc lista invitailor astfel nct suma coeficienilor de
convieuire a invitailor s se maximizeze i preedintele s participe
la propia petrecere.
7. [Mouse] Un experiment urmrete comportarea unui oricel pus
ntr-o cutie dreptunghiular, mprit n mxn cmrue egale de form
ptrat. Fiecare cmru conine o anumit cantitate de hran. orice-
lul trebuie s porneasc din colul (1,1) al cutiei i s ajung n colul
opus, mncnd ct mai mult hran. El poate trece dintr-o camer n
una alturat (dou camere sunt alturate dac au un perete comun),
mnnc toat hrana din cmru atunci cnd intr i nu intr
niciodat ntr-o camer fr hran. Stabilii care este cantitatea maxi-
m de hran pe care o poate mnca i traseul pe care l poate urma
pentru a culege aceast cantitate maxim. Se d n, m i cantitatea de
hran existent n fiecare cmeru (numere ntre 1 i 100).
Olimpiada judeean de informatic, 2002

115
Exemplu:
2 4
1 2 6 3
3 4 1 2
:
7 21
1 1 --> 2 1 --> 2 2 --> 1 2 --> 1 3 --> 1 4 -->2 4
8. [Semne] Pentru n numr natural, s se gseasc o combinaie de semne
+ i - (adic un vector x = (x(1), x(2), ..., x(k)), x(i) se afl n <-1, 1>) i
un numr k natural nenul astfel nct:
n = x(1)*1
2
+x(2)*2
2
+...+x(k)*k
2
.
Datele se citesc dintr-un fiier text ce conine pe fiecare linie cte un
numr ce reprezint valorile lui n pentru care se doresc reprezentri ca
mai sus. Datele de ieire vor fi introduse ntr-un fiier text pe cte o
linie combinaia de semne corespunztoare.
Exemplu:
:
2
4
8
5
:
- - - +
- - +
- - + + - - +
+ + - - +
Indicaie: Pentru k ncepnd de la 1, se gsesc ntr-o list numerele care
se pot obine cu k semne; lista pentru k se obine din cea pentru k-1.
Pentru unele numere k este foarte mare i programul nu ar intra n
timp. O alt soluie ar fi folosirea observaiei:
(n+3)
2
-(n+2)
2
-(n+1)
2
+n
2
=(n+3+n+2)*1-(n+1+n)*1=2n+5-2n-1=4
Prin adugarea secvenei + - - + se ajunge de la un numar n la n+4.
Dac am obine secvenele pentru n = 0, 1, 2 i 3, am rezolva
problema. Acestea sunt:
0 secvena vid
1 +
2 - - - + (dat n exemplu)
3 - (pentru -1), apoi + - - +
116
9. [ah] a) Dndu-se dou poziii pe o tabl de ah de dimensiune
ptratic nxn, s se determine cel mai scurt drum dintre acestea
utiliznd mutrile calului.
b) Determinai numrul minim de cai care pot fi amplasai pe o tabl
de ah de dimensiune nxm astfel nct s nu se atace.
10. [Linii navale] Pe malul de nord i cel de sud al unui fluviu exist n
orae. Fiecare ora are un unic ora prieten pe cellalt mal; nu exist
dou orae pe un mal avnd acelai priten pe cellalt mal. Intenia este
ca oraele prietene s se lege printr-o linie naval. Se impune ns
restricia ca s nu existe linii navale care s se intersecteze. S se
determine numrul maxim de linii navale care pot fi nfiinate, cu
respectarea condiiei de mai sus. Pe prima linie a fiierului de intrare
apare numrul n de perechi de orae prietene, iar pe urmtoarele n linii
apar perechile de orae prietene (primul pe malul de nord, iar al doilea
pe malul de sud), fiecare ora fiind specificat prin distana sa (cel mult
egal cu 6000) fa de kilometrul 0 al fluviului.
Indicaie: Se ordoneaz posibilele linii navale dup primul argument
i se determin cel mai lung subir cresctor format din coordonatele
celui de-al doilea argument. (vezi problema rezolvat 1).
11. [Drumuri minime] Se consider un graf orientat, fiecare arc avnd
un cost ataat. Se cere s se determine pentru fiecare pereche de
vrfuri ( i, j) i s se tipreasc lungimea drumului minim de la i la j.
12. [Submulimi de sum dat] S se determine pentru un vector dat
dac un numr k se poate scrie ca sum de numere din vector, un
element din vector se poate folosi o dat.
Indicaie: Se construiete un tablou a cu valori logice, unde a[i] este
dac i se poate scrie ca sum de elemente din vectorul dat i
n caz contrar.
3.3.1. Prezentarea metodei
Algoritmii de tip Greedy sunt folosii la probleme de optimizare i
sunt n general simpli i eficieni. Un astfel de algoritm determin
soluia optim n urma unei succesiuni de alegeri. La fiecare moment
decizional, din algoritm se va alege opiunea care pare a fi cea mai
potrivit pe baza unui criteriu de optim local, n ideea c la final se va
obine o soluie optim global.
117
n general, datele de intrare pentru un algoritm Greedy se prezint sub
forma unei mulimi finite, iar soluia este o submulime sau o
permutare a datelor de intrare n aa fel nct s fie ndeplinite anumite
condiii de optim. Condiiile de optim cer determinarea unei soluii
care maximizeaz sau minimizeaz o funcie dat, numit funcie
obiectiv.
Dac un element este inclus n soluie el va rmne n aceast
mulime, nu se face nici o revenire asupra unei decizii luate.
Selectarea unui element la un moment dat poate depinde de
elementele alese pn la acel moment dar nu depinde de cele care
urmeaz s fie alese ulterior.
Dac un element a fost selectat, dar nu poate face parte din
soluie atunci acest element nu va mai fi luat n calcul la alegerile
urmtoare. n acest fel se poate ajunge rapid la o soluie, dar nu se
asigur (pentru toate problemele) optimalitatea global. Exist i
probleme pentru care o astfel de metod nu conduce la soluie, dei
aceasta exist. Problemele care se pot rezolva folosind algoritmi de tip
Greedy trebuie s verifice dou proprieti: proprietatea alegerii
Greedy i substructura optimal.
Proprietatea alegerii Greedy spune c se poate ajunge la o
soluie de optim global dac la fiecare pas de decizie se selecteaz un
element care ndeplinete criteriul de optim local. Proprietatea de
structur optimal spune c soluia optimal a problemei conine
soluiile optimale ale subproblemelor.
O problem care se va rezolva folosind o strategie Greedy este
dat de:
O mulime finit de candidai care reprezint datele de
intrare;
O funcie care verific dac o anumit mulime de elemente
constituie o soluie posibil, nu neaparat optim, a
problemei;
O funcie care verific dac o submulime a datelor de
intrare este o soluie parial a problemei;
O funcie de selecie care alege la orice moment cel mai
potrivit candidat dintre elementele nefolosite nc;
O funcie obiectiv care trebuie minimizat sau maximizat.

Un algoritm Greedy nu furnizeaz dect o singur soluie. n
contiunare este prezentat forma general a metodei.

118
greedy(C) {C este mulimea datelor de intrare }
S {S este multimea care va conine soluia}
Soluie(S) C do
x select(C)
C C \ {x}
Posibil(S {x}) S S {x}
Solutie(S) S
write(nu exista soluie)
Aceast metod i gsete multe aplicaii n teoria grafurilor la
determinarea unui arbore parial de cost minim (Kruskal, Prim), la
determinarea drumurilor de cost minim de la un vrf la celelalte
vrfuri ale unui graf (Dijkstra), compresia datelor (arbori Huffman)
.a.
3.3.2. Probleme rezolvate
[Problema continu a rucsacului] Avem la dispoziie un
rucsac cu care se poate transporta o greutate maxim G. Trebuie s
alegem din n obiecte pentru care se cunoate greutatea g
i
i profitul p
i

care se obine prin transportul obiectului i cu rucsacul. S se
determine obiectele care trebuiesc alese pentru transport astfel nct
profitul obinut s fie maxim, iar greutatea total a acestora s nu
depeasc G tiind c putem lua orice parte dintr-un obiect.
Rezolvare: Programul n C este:
# <stdio.h>
# MAX 25
main(){
p[MAX]; g[MAX];
n,i,j,aux,nr[MAX];
G, gr,profit,sol[MAX];
printf("Greutatea maxima G = ");scanf("%f",&G);
printf("Numarul de obiecte: ");
scanf("%d", &n);
(i=0; i<n; i++){
printf("Obiectul nr. %d:\n",i+1);
printf("Greutatea = "); scanf("%d",&g[i]);
printf("Profitul = "); scanf("%d",&p[i]);
sol[i] = 0.0; nr[i] = i;
}
119
/*
ordonare descrescatoare dupa raportul p/g
*/
(i=0;i<n-1;i++) (j=i+1;j<n;j++)
(p[i]/g[i] < p[j]/g[j]){
aux=p[i]; p[i]=p[j]; p[j]=aux;
aux=g[i]; g[i]=g[j]; g[j]=aux;
aux=nr[i]; nr[i]=nr[j]; nr[j]=aux;
}
/*alegere */
gr = G;
(i=0; i<n && g[i]<gr; i++){
sol[i] = 1.0; //100%
gr -= g[i];
}
if (i < n) sol[i] = gr/g[i];
/*afisare zezultate */
profit = 0.0;
(i=0;i<n;i++)
(sol[i] > 0){
printf("Obiect %d - %5.2f%%\n", nr[i]+1, sol[i] *100);
profit += sol[i] * p[i];
}
printf("Profit = %5.2f", profit);
}
.[Planificarea activitilor] ntr-o sal, ntr-o zi trebuie plani-
ficate n activiti, pentru fiecare activitate se cunoate intervalul n
care se desfoar [s, f). Se cere s se planifice un numr maxim de
activiti astfel nct s nu se suprapun.
Rezolvare:Programul Pascal este:
Activitati;
crt;
max=100;
n,i,j,aux:integer;
s,f: [1..max] of integer;
sol: [1..max] of 0..1;
nsol, finish:integer;
{ citire date }

120
write('Nr de activitati = '); readln(n);
i:=1 n
writeln('Activitatea nr. ',i,':');
write('Start = '); readln(s[i]);
write('Finish = '); readln(f[i]);
sol[i]:=0;
;
{ordonare dup termenul final}
i := 1 n-1
j := i + 1 n
( f[i] > f[j])
aux:=s[i]; s[i]:=s[j]; s[j]:=aux;
aux:=f[i]; f[i]:=f[j]; f[j]:=aux;
;
{calcul}
finish := 0;
i := 1 n
(s[i] >= finish )
sol[i]:=1;
121
# <stdio.h>
# <conio.h>
main(){
i,j,k,c,S; sol[100]; x,xmax;
/*citire date */
printf("k = "); scanf("%d",&k); printf("c = "); scanf("%d",&c);
printf("S = "); scanf("%d",&S);
/*calcul */
xmax=1; (i=1; i<k; i++) xmax*=c;
x = xmax;
(i=0; S>0; i++){ sol[i] = S / x; S %= x; x /= c; }
/*afisare */
x = xmax;
(j=0; j<i; j++,x/=c)
if(sol[j]>0) printf("%d monede cu valoarea %d\n", sol[j], x);
getch();
}
[Numere frumoase] Numerele frumoase sunt acele numere
care au n descompunerea lor numai factori primi de 2, 3 i 5. Fiind
dat un numr natural n<1000, s se afieze pe ecran primele n
numere frumoase.
Rezolvare: Programul Pascal este:
nrFrumoase;
max = 1000;
min(a,b:integer):integer;
a <= b min:=a min:=b ;
t,n2,n3,n5:integer;
f: [1..max] of longint;
i,j,k,l,n:integer;
write('n = '); readln(n);
n2:=2; i:=1; n3:=3; j:=1; n5:=5; k:=1; t:=1; l:=1; f[1]:=1;
(l<=n)
t:=min(n2,min(n3,n5));
l:=l+1; f[l]:=t;
t = n2 inc(i); n2 := 2*f[i] ;
t = n3 inc(j); n3 := 3*f[j] ;
122
t = n5 inc(k); n5 := 5*f[k]
;
i:=1 n write(f[i],' ');
readln;
.
[Copaci i ciori] Pe n copaci aezai n cerc se afl n-1 ciori,
maxim una pe fiecare copac. Dndu-se o configuraie iniial i una
final a ciorilor i tiind c la un moment dat o singur cioar poate
zbura de pe copacul ei pe cel liber, s se scrie un program care s de-
termine o secven de zboruri pentru a ajunge la configuraia final.
Rezolvare: Programul C este:
# <stdio.h>
# MAX 10
initial[MAX]; final[MAX]; n;
CopacLiber(){
i=0; (initial[i]!=0) i++; i; }
Copac( c){
i=0; (initial[i] != c) i++; i; }
Zboara( s, d){
printf("Cioara %d zboara de pe copacul %d pe %d !\n", \
initial[s], s+1,d+1);
initial[d] = initial[s]; initial[s] = 0;
}
main(){ i, k;
printf("n = "); scanf("%d",&n);
printf("Introduceti configuratia initiala (0 pt. liber):\n");
(i=0;i<n;i++)
{printf("initial[%d] = ",i+1); scanf("%d",&initial[i]);}
printf("Introduceti configuratia finala (0 pt. liber):\n");
(i=0;i<n;i++)
{printf("final[%d] = ",i+1);scanf("%d",&final[i]);}
(i=0;i<n;i++)
(final[i] && initial[i] != final[i]){
(initial[i]) {
k = CopacLiber(); Zboara(i,k);
}
k = Copac(final[i]); Zboara(k,i);
}
}
123
[Problema comis-voiajorului] Un comis-voiajor trebuie s
viziteze un numr de n orae i s revin n oraul de plecare.
Cunoscnd legturile dintre oricare dou orae se cere s se afieze
cel mai scurt traseu posibil pe care poate s-l parcurg comis-
voiajorul tiind c nu trebuie s treac de dou ori prin acelai ora.
Rezolvare: Programul Pascal este:
comis;
max = 25;
harta: [1..max,1..max] of integer;
traseu: [1..max] of integer;
v: [1..max] of 0..1;
i,j,k,min,n,lungime,pos:integer;
write('n = '); readln(n);
i:=1 n-1 j:=i+1 n
write('distanta[',i,', ', j,'] = '); readln(harta[i,j]);
harta[j,i]:=harta[i,j];
;
write('Orasul de pornire = '); readln(k);
lungime:=0; traseu[1]:=k; v[k]:=1;
i:=2 n
min:=maxint;
j:=1 n
v[j] = 0
harta[k, j] < min
min := harta[k, j];
pos := j
;
inc(lungime,min); traseu[i]:=pos; v[pos]:=1; k:=pos
;
inc(lungime,harta[k,1]);
i:=1 n write(traseu[i]:3);
writeln(traseu[1]:3);
writeln('lungimea = ', lungime);
readln;
.

124
3.3.3. Probleme propuse
1. [Problema planificrii optime a lucrrilor] Se presupune c avem de
executat un numr de n lucrri, cunoscndu-se pentru fiecare lucrare i
termenul de finalizare t
i
i penalizarea p
i
pltit n cazul n care
lucrarea nu este predat la termen. tiind c fiecare lucrare este
executat ntr-o unitate de timp i c nu se pot executa mai multe
lucrri simultan, s se planifice ordinea de execuie a lucrrilor astfel
nct penalizarea total s fie minim.
2. [Amplasarea canalelor] n jurul unui ora avem N bazine cu ap ce
trebuiesc unite ntre ele prin canale. Fiecare bazin poate fi unit prin
cte un canal cu mai multe bazine. Perechile de bazine ce vor fi unite
sunt date ntr-o list. Un canal poate trece doar prin interiorul sau
exteriorul cercului format de bazine. Se cere modul de amplasare al
fiecrui canal.
3. Se dau numerele ntregi nenule a
1
, a
2
, , a
n
i b
1
, b
2
, , b
m
cu n
m. S se determine o submulime {x
1
, x
2
, , x
m
} a mulimii {a
1
, a
2
,
, a
n
} care s maximizeze expresia E = b
1
x
1
+ b
2
x
2
+ + b
m
x
m
.
4. ntr-un depozit al monetriei statului sosesc n saci cu monezi. Se
cunoate numrul de monezi din fiecare sac i se dorete mutarea
monezilor dintr-un sac n altul n aa fel nct n fiecare sac s apar
acelai numr de monezi. Scriei un program care rezolv problema
efectund un numr minim de mutri.
5. Fie n iruri ordonate cresctor S
1
, S
2
, , S
n
cu lungimile L
1
, L
2
, ,
L
n
. S se interclaseze cele n iruri obinndu-se un singur ir cresctor
de lungime L
1
+ L
2
+ + L
n
cu un numr minim de comparaii ntre
elementele irurilor.
6. Fie X = {x
1
, x
2
, ,x
n
} o mulime de numere reale. S se detmine o
mulime de cardinal minim de intervale de lungime 1 a cror reuniune
s includ mulimea X.
7. Se cunosc poziiile oraelor unei ri date prin coordonatele lor. S
se determine configuraia unei reele telefonice astfel nct toate
oraele s fie conectate la reea i costul reelei s fie minim.
8. Se dau n i k, naturale, kn. S se construiasc un tablou nn care
ndeplinete simultan condiiile:
conine toate numerele de la 1 la n
2
o singur dat;
pe fiecare linie numerele sunt aezate n ordine cresctoare, de la
stnga la dreapta;
suma elementelor de pe coloana k s fie minim.
9. Un instructor de schi trebuie s distribuie n perechi de schiuri la n
elevi nceptori. Descriei un algoritm care s fac distribuirea n aa
125
fel nct suma diferenelor absolute dintre nlimea elevului i
lungimea schiurilor s fie minim.
10. Se d un polinom P(X) cu coeficieni ntregi. S se afle toate
rdcinile raionale ale polinomului.
11. Se dau n puncte n plan prin coordonatele lor numere ntregi. S se
construiasc, dac este posibil, un poligon convex care s aib ca
vrfuri aceste puncte.
12. Fiind dat o hart cu n ri, descriei un algoritm euristic care s
determine o modalitate de colorare a hrii astfel nct dou ri care
se nvecineaz s fie colorate diferit.
13. Descriei un algoritm euristic care s determine o modalitate prin
care un cal aflat n colul stnga-sus s strbat ntreaga tabl de ah
fr a trece de dou ori prin aceeai poziie.
14. Descriei un algoritm euristic care s schimbe o sum S dat
folosind un numr minim de monete avnd valorile v
1
, v
2
, , v
n
.
3.4.1.Prezentarea metodei
Aceast tehnic se folosete la rezolvarea problemelor a cror soluie
se poate reprezenta sub forma unui vector S = x
1
x
2
...x
n
cu x
1
S
1
, x
2

S
2
, , x
n
S
n
, iar mulimile S
1
, S
2
, , S
n
, care pot coincide, sunt
mulimi finite ordonate liniar (pentru orice element, cu exceptia
ultimului este cunoscut succesorul). Pentru fiecare problem concret
sunt precizate relaiile dintre componentele vectorului care memoreaz
soluia, numite condiii interne. Mulimea S = S
1
S
1
se numete
spaiul soluiilor, iar elementele produsului cartezian care satisfac i
condiiile interne se numesc soluii rezultat. Metoda evit generarea
tuturor combinaiilor completnd pe rnd componentele vectorului
soluie cu valori ce ndeplinesc condiiile de continuare, scurtndu-se
astfel timpul de calcul.
Vectorul x este privit ca o stiv, lui x
k
nu i se atribuie o valoare
dect dup ce x
1
, , x
k-1
au primit valori. La nceput x
k
este iniializat
la o valoare (cu ajutorul unei funcii init) al crei succesor este primul
element din S
k
. Cu ajutorul unei funcii succesor x
k
ia valoarea
primului element din S
k
. Dup ce x
k
a primit o valoare, nu se trece
direct la atribuirea unei valori lui x
k+1
126
Nendeplinirea condiiilor de continuare exprim faptul c oricum am
alege x
k+1
, , x
n
, nu vom ajunge la o soluie. n acest caz se face o
nou alegere pentru x
k
sau, dac S
k
a fost epuizat, se micoreaz k cu o
unitate i se ncearca o nou alegere pentru x
k
(k >0) din restul
elementelor lui S
k
nc nealese folosind funcia succesor. Ca urmare se
trece la atribuirea unei valori lui x
k+1
doar dac sunt ndeplinite
condiiile de continuare.
Algoritmul se termin n momentul n care au fost luate n calcul
toate elementele mulimii S
1
.
Metoda backtracking poate fi descris prin urmtoarea proce-
dur (n varianta iterativ):
k := 1; init(k, st);
k > 0
succesor(as, st, k);
as valid(ev, st, k);
(not as) or (as ev);
as solutie(k) tipar
k := k + 1; init(k, st)
k := k 1;
;
Rezolvarea problemelor prin aceast metod necesit un timp mare de
execuie, motiv pentru care metoda este recomandat numai n
cazurile n care spaiul soluiilor este destul de redus, sau dac nu se
cunoate un alt algoritm mai rapid.
Metoda admite i o variant recursiv n care stiva nu este
gestionat explicit de programator. n continuare este dat forma
general a procedurii backtracking n variant recursiv (care se va
apela cu Back(1)):
Back(k);
i:integer;
solutie(k) then tipar(x)
init(k,x);
succesor(x,k)
x[k]:=i; valid(x,k) Back(k+1) ;
;
127
3.4.2. Probleme rezolvate
[Permutri] Se d un numr n N, se cere s se genereze
toate permutrile mulimii {1, 2, ,n}.
Rezolvare:
permutari;
crt;
stack = [1..25] integer;
st: stack;
n:integer; k:integer;
as, ev: boolean;
init(k:integer; st: stack);
st[k]:=0 ;
succesor( as:boolean; st: stack; k:integer);
st[k] < n st[k] := st[k] + 1; as := true
as:=false;
;
valid( ev:boolean; st: stack; k:integer);
i:integer;
ev:=true; i:=1 k-1 st[k] = st[i] ev:=false ;
solutie(k:integer) :boolean;
solutie:=(k=n) ;
tipar;
i:integer;
i:=1 n write(st[i],' '); writeln ;
write ( ' n = ' ); readln(n) ;
k:=1; init(k,st);
(k>0)
succesor (as, st, k) ;
as valid(ev,st,k);
( as) (as ev) ;
as solutie(k) tipar
k:=k+1; init(k,st)
k:=k-1
;
.
128
[Descompunere ca sum de numere prime] S se descompun
un numr natural n n toate modurile posibile ca sum de numere
prime.
Rezolvare:
desc_prime;
Prime, x : [1..100] of integer;
n,k,i,p,S:integer;
Prim(nr:integer):boolean;
i:integer;
Prim:=true; i:=2;
i*i <= nr
nr i = 0
Prim:=false; break;
inc(i);
;
Tipar;
i:integer;
i:=1 k write(Prime[x[i]],' '); writeln ;
write('n = '); readln(n);
p:=0;
i:=2 n Prim(i)
inc(p); Prime[p]:=i ;
S:=0;
k:=1; x[k]:=0;
k>0
inc(x[k]);
(x[k] <= p) (S + Prime[x[k]] <= n)
S + Prime[x[k]] = n Tipar

inc(S,Prime[x[k]]); inc(k); x[k] := x[k-1]-1
dec(k); Dec(S,Prime[x[k]]);
.

129
[Problema damelor] Pe o tabl de ah trebuie aezate opt
dame astfel nct s nu existe dou dame pe aceeai linie, coloan sau
diagonal. Problema se generalizeaz imediat pentru n dame pe o
tabl cu n linii i n coloane. S se determine toate soluiile.
Rezolvare :
# <stdio.h>
# <conio.h>
# <math.h>
stack[25];
stack st;
n;
tipar(){
j;
(j = 0; j < n; j++) printf("%d ", st[j]);
printf("\n");
}
dame( k){
i,j, valid;
(k==n) tipar();
(i = st[k]+1; i <= n; i++) {
st[k] = i; valid = 1;
(j = 0; j < k; j++)
((st[j]==st[k])||(abs(st[k]-st[j])==k-j)) valid = 0;
(valid ==1) dame(k+1);
}
st[k] = 0;
}
main(){
i;
printf("n = "); scanf("%d",&n);
(i = 0; i < n; i++) st[i]=0;
dame(0);
getch();
}
[Problema colorrii hrilor] Fiind dat o hart cu n ri, se
cer toate soluiile de colorare a hrii utiliznd un numr minim de
culori, astfel nct dou tri cu frontier comun s fie colorate
diferit. Menionm c este demonstrat faptul c sunt suficiente 4
culori pentru a colora orice hart.

130
Rezolvare:
Culori;
crt;
stack = [1..25] integer;
st: stack;
i,j,k,n:integer;
as, ev: boolean;
a: [1..25,1..25] integer;
init(k:integer; st: stack);
st[k]:=0 ;
succesor( as:boolean; st: stack; k:integer);
st[k] < 4 st[k] := st[k] + 1; as := true
as:=false;
;
valid( ev:boolean; st: stack; k:integer);
i:integer;
ev:=true;
i:=1 k-1 (st[k]=st[i]) (a[i,k]=1) ev:= false;
;
solutie(k:integer) :boolean;
solutie:=(k=n) ;
tipar;
i:integer;
i:=1 n write(st[i],' '); writeln end;
write (' n = '); readln(n);
i:=1 n j:=1 i-1
write('a[',i,',',j,']= '); readln(a[i,j]); a[j,i]:=a[i,j] end;
k:=1; init(k,st);
(k>0)
succesor (as, st, k) ; as valid(ev,st,k);
( as) (as ev) ;
as solutie(k) tipar
k:=k+1; init(k,st)
k:=k-1;
;
.
131
[Sritura calului] Se consider o tabl de ah n x n i un cal
plasat n colul din stnga sus. Se cere s se afieze toate posibilitile
de mutare a calului astfel nct s treac o singur dat prin fiecare
ptrat al tablei.
Rezolvare:
# <stdio.h>
# <conio.h>
tabla[25][25];
linT[8] = {-1,+1,+2,+2,+1,-1,-2,-2};
colT[8] = {+2,+2,+1,-1,-2,-2,-1,+1};
tabla tab;
n;
tipar(){
i,j;
(i = 0; i < n; i++){ printf("\n");
(j = 0; j < n; j++) printf("%3d", tab[i][j]);
}
printf("\n"); getch();
}
cal( lin, col, k){
i,lin2,col2;
(tab[lin][col]) ;
k++;
tab[lin][col]=k;
(k==n*n) tipar();
( i = 0; i < 8; i++){
lin2 = lin + linT[i];
col2 = col + colT[i];
(lin2>=0 && lin2<n && col2>=0 && col2<n)
cal(lin2,col2,k);
}
tab[lin][col] = 0;
}
main(){
i,j;
printf("n = "); scanf("%d",&n);
(i = 0; i < n; i++) (j = 0; j < n; j++) tab[i][j]=0;
cal(0,0,0);
printf("\n%d solutii",t);
}
132
3.4.3. Probleme propuse
1. Se dau numerele naturale n i k, s se genereze toate
aranjamentele (funciile injective) de elemente din mulimea {1, 2,
, n} luate cte k.
2. Fie dou numere naturale n i k cu n k, se cere s se genereze
toate submulimile (combinrile) de k elemente din mulimea {1,
2, ,n}.
3. Se dau mulimile A
1
= {1, 2, , p
1
}, A
2
= {1, 2, , p
2
}, , A
n
=
{1, 2, , p
n
} se cere s se genereze produsul cartezian al
mulimilor A
1
, A
2
, , A
n
.
4. S se descompun un numr natural n n toate modurile posibile
ca sum de numere naturale.
5. Se consider mulimea {1, 2, , n}. Se cer toate partiiile acestei
mulimi.
6. Se d o sum S i n tipuri de monede avnd valorile v
1
, v
2
, , v
n

lei. Se cer toate modalitile de plat a sumei S utiliznd aceste
monede.
7. Considerndu-se o tabl de ah de dimensiuni n n, s se
determine toate modalitile de amplasare a n ture pe aceast tabl
n aa fel nct s nu se atace ntre ele.
8. Un ntreprinztor ce dispune de un capital C trebuie s leag
dintre n oferte la care trebuie avansate fonfurile f
i
i care aduc
profiturile p
i
pe acelea pe care le poate onora cu capitalul de care
dispune i care i aduc profitul total maxim.
9. S se determine toate delegaiile de n persoane din care p femei
care se pot forma din t persoane din care v femei.
10. Avem la dispoziie 6 culori: alb, negru, rou, albastru, verde,
galben. S se genereze toate steagurile ce se pot forma cu trei
culori diferite avnd la mijloc alb sau negru.
11. Un comis-voiajor trebuie s viziteze un numr de n orae i s
revin n oraul de plecare. Cunoscnd legturile dintre orae se
cere s se afieze toate drumurile posibile pe care poate s le
parcurg comis-voiajorul tiind c nu trebuie s treac de dou ori
prin acelai ora.
12. ntr-un grup de persoane fiecare persoan se cunoate pe sine i
cunoate eventual i alte persoane din grup. S se determine toate
modurile n care cele N persoane se pot repartiza n echipe astfel
nct orice persoan din grup sc Tf0.001 Tc 0.0332 Tw 0.4433 0 Td[( )-5(din grup s)]TJ/C2_0 1
133
13. Cei doi fii ai unei familii motenesc prin testament, n mod egal, o
avere format din monede avnd ca valori numere ntregi pozitive.
O condiie din testament cere ca fraii s mpart monezile n
dou pri avnd valori egale pentru a intra n posesia lor, altfel
suma va fi donat unei biserici. Scriei un program care s i ajute
pe cei doi frai s intre n posesia motenirii.
14. Pe malul unui ru se gsesc c canibali i m misionari. Ei urmeaz
s treac rul cu o barc cu dou locuri. Dac pe unul dintre
maluri se vor afla mai muli canibali dect misionari acetia din
urm vor fi mncai de canibali. Se cere un program care s
afieze toate modalitile de trecere a rului n care misionarii s
nu fie mncai.
15. Pentru elaborarea unui test de aptitudini avem un set de n
ntrebri, fiecare fiind cotat cu un numr de puncte. S se
elaboreze toate chestionarele avnd ntre a i b ntrebri distincte,
fiecare chestionar totaliznd ntre p i q puncte. ntrebrile sunt
date prin numr i punctaj.
16. 2n + 1 persoane particip la discuii (mas rotund) care dureaz n
zile. S se gseasc variantele de aezare la mas astfel ca o
persoan s nu aib n dou zile diferite acelai vecin.
17. S se determine 5 numere de cte n cifre fiecare cifr putnd fi 1
sau 2, astfel nct oricare dintre cele 5 numere s coincid n m
poziii i s nu existe nici o pozitie care s conin aceeai cifr n
toate cele 5 numere.
18. S se genereze o secven binar de lungime 2
n
+n+1 astfel nct
orice dou secvente consecutive de n biti s fie diferite.
19. Se dau x
1
, x
2
, , x
n
numere naturale cu cel mult 9 cifre i n 100.
Fiecare numr x
i
este reprezentat n baza b
i
(2 b
i
10) care nu
este cunoscut. S se gaseasc baza b
i
pentru fiecare numr x
i

astfel nct intervalul [a, b] n care sunt cuprinse cele n numere
(dup transformarea n baza 10) s fie de lungime minim.
20. Numrul 123456789 nmulit cu 2, 4, 7 sau 8 d ca rezultat tot un
numr de nou cifre distincte (fr 0). Aceast proprietate nu
funcioneaz pentru numerele 3, 6 sau 9. Exist totui multe
numere de nou cifre distincte (fr 0) care nmulite cu 3 au
aceeai proprietate. S se listeze toate aceste numere n care
ultima cifr este 9.
21. S se dispun pe cele 12 muchii ale unui cub toate numerele de la
1 la 12, astfel nct suma numerelor aflate pe muchiile unei fee s
fie aceeai pentru toate feele.
134
22. Toate oraele unei ri sunt legate la o reea de linii feroviare.
Dou orae i i j pot fi legate prin cel mult o legtur direct prin
care circul un singur tren pe zi ntre orele p(i, j) i s(i, j). Dac se
dau dou orae A i B, s se afieze traseul, staiile de schimbare a
trenurilor i timpii de ateptare n aceste staii astfel nct durata
total a cltoriei s fie minim.
23. Configuraia unui teren este specificat printr-o gril gen tabl de
ah de dimensiune nn, fiecare careu avnd o anumit nlime.
ntr-un careu precizat al grilei se plaseaz o minge. tiind c
mingea se poate deplasa ntr-unul din cele maxim 8 careuri vecine
doar dac acesta are o cot strict mai mic, s se genereze toate
trasele pe care le poate urma mingea pentru a prsi terenul.
24. Un cal i un rege se afl pe o tabl de ah. Unele cmpuri ale
tablei sunt "arse", poziiile lor fiind cunoscute. Calul nu poate
clca pe cmpuri "arse", iar orice micare a calului face ca
respectivul cmp s devin "ars". S se afle dac exist o
succesiune de mutri permise (cu restriciile de mai sus), prin care
calul s poat ajunge la rege i s revin la poziia iniial. Poziia
iniial a calului, precum i poziia regelui sunt considerate
"nearse".
25. Fie o matrice n x m cu valori de 0 i 1. Dndu-se o poziie iniial
(i,j) s se gseasc toate ieirile din matrice mergnd doar pe
elemente cu valoarea 1.
26. O fotografie alb-negru este dat printr-o matrice cu valori 0 i 1.
Fotografia prezint unul sau mai multe obiecte. Punctele fiecrui
obiect sunt marcate cu 1. Se cere un program care s calculeze
numrul de obiecte din fotografie.
27. Se d o matrice binar n care elementele cu valoarea 1
delimiteaz o suprafa marcat cu elemente de zero. Dndu-se
coordonatele unui punct n cadrul matricei s se coloreze
suprafaa n interiorul creia cade punctul.
28. Se dau n puncte albe i n puncte negre n plan prin perechi (i,j) de
numere ntregi. Fiecare punct alb se va uni cu un singur punct
negru asttfel nct segmentele formate s nu se intersecteze. S se
gseasc o soluie tiind ca oricare 3 puncte sunt necoliniare.
29. Se dau n puncte n plan prin perechi (i,j) de numere ntregi. S se
selecteze 4 puncte ce reprezint colurile ptratului care cuprinde
numrul maxim de puncte din cele n puncte date.
135
30. Se d un cuvnt si o matrice de caractere de dimensiune m x n. S
se gseasc n matrice prefixul de lunginme maxim al cuvntului
dat.
31. Se d un numr natural par n. S se afieze toate irurile de n
paranteze care se nchid corect.
32. Se consider o bar de lungime n i k repere de lungimi l
1
, l
2
,,
l
k
. Din bar trebuiesc tiate buci de lungimea reperelor date,
astfel nct s avem cel puin cte o bucat de lungime l
i
cu i =
1..k i pierderile s fie nule.
33. Se consider un numr nelimitat de piese dreptunghiulare de
dimensiuni a 2a. Piesele se vor folosi la pavarea fr fisuri a
unei zone rectangulare de dimensiuni ka pa. Se cer toate
soluiile (reprezentare grafic).

Branch and Bound
3.5.1. Prezentarea metodei
Metoda branch and bound foloseste la rezolvarea problemelor la care
domeniul n care se caut soluia este foarte mare i nu se cunoate un
alt algoritm care s conduc mai rapid la rezultat. Problemele care pot
fi abordate prin aceast metod pot fi modelate ntr-un mod asem-
ntor celui folosit la metoda backtracking. Se pleac de la o configu-
raie iniial i se reine irul de operaii prin care aceasta este transfor-
mat ntr-o configuraie final dac aceasta este dat, n alte cazuri se
cere configuraia final tiind c trebuie s verifice anumite condiii de
optim.
Diferena dintre cele dou metode const n faptul c metoda
backtracking la fiecare etap selecteaz un singur succesor dup care
se face verificarea condiiilor de continuare, iar metoda branch and
bound genereaz la fiecare pas toate configuraiile posibile (toi succe-
sorii) care rezult din cea curent i le stocheaz ntr-o list. Se alege
apoi un element din list dup un criteriu ce depinde de problem i
se reia procesul de expandare.
Alegerea optim a unui element din aceast list pentru
expandare se face cu ajutorul unei funcii f = g + h n care g este o
funcie care msoar lungimea drumului parcurs de la configuraia
iniial pn la nodul curent, iar h este o funcie (euristic) care
estimeaz efortul necesar pan se ajunge la soluie i este specific
fiecrei probleme. Alegerea funciei h este foarte important din punct
de vedere a vitezei de execuie a programului.
136
Se lucreaz cu dou liste: lista open n care se rein configuraiile
neexpandate nc i lista close care le memoreaz pe cele expandate.
Soluia se construiete folosind un arbore care se parcurge pe baza
legturii tat.
Nodurile sunt nregistrri care cuprind urmtoarele informaii:
1. configuraia la care s-a ajuns, t;
2. valorile funciilor g si h,
3. adresa nodului 'tat';
4. adresa nregistrrii urmtoare n lista open sau close;
5. adresa nregistrrii urmtoare n lista succesorilor.
Algoritmul este urmtorul:
A. nregistrarea corespunztoare configuraiei iniiale este ncrcat
n open cu g=0 i f=h;
B. att timp ct nu s-a selectat spre expandare nodul corespunztor
configuraiei finale i lista open este nevid, se execut
urmtoarele:
1. se selecteaz din lista open nodul t cu f minim;
2. se expandeaz acest nod obinnd o list liniar simplu
nlnuit cu succesorii si;
3. pentru fiecare succesor din aceast list se execut:
3.1. se ataeaz noul g, obinut ca sum ntre valoarea lui g
a configuraiei t i costul expandrii (de obicei 1);
3.2. se testeaz dac acest succesor aparine listei open sau
close i n caz afirmativ, se verific dac valoarea lui g
este mai mic dect cea a configuraiei gsite n list:
3.2.1. n caz afirmativ, nodul gsit este direcionat
ctre actualul printe (prin fixarea legturii tat)
i se ataeaz noul g, iar dac acest nod se gsete
n close, este trecut n open;
3.2.2. n caz c acest nod nu se gsete n open sau
close, este introdus n lista open;
C. dac s-a selectat pentru expandare nodul corespunztor configu-
raiei finale atunci se traseaz folosind o procedur recursiv
drumul de la configuraia iniial la cea final utiliznd legtura
'tat';
D. dac ciclul se ncheie deoarece lista open este vid nseamn c
problema nu are soluie.
Algoritmul se poate implementa folosind o singur list,
iar diferenierea dintre nodurile expandate i cele neexpandate se va
face dup un cmp special. Apare ns dezavantajul c operaiile de
137
cutare se fac ntr-o list mai lung. Acest dezavantaj se poate elimina
folosind o structur special numit tabel hash. n unele cazuri se
poate folosi un arbore binar.
3.5.2. Probleme rezolvate
[Problema discret a rucsacului] Se d un rucsac de capacita-
te M i un numr de n obiecte, specificndu-se masele obiectelor i
profiturile ce se obin prin transportul lor cu rucsacul. Se cere un pro-
gram care s determine obiectele alese astfel nct s se obin un
profit maxim. Soluia se va da sub forma unui vector definit astfel:
x
k
=0 dac obiectul k nu este luat n rucsac, x
p
= 1 dac obiectul p este
luat n rucsac.
Rezolvare:
n rezolvarea acestei probleme nu vom folosi dou liste ci un arbore
binar. Algoritmul face, n prealabil, o ordonare descresctoare a
obiectelor dup raportul profit/mas. Se pornete de la configuraia
iniial n care nici obiect nu a fost nc ales. Se parcurge iterativ lista
de obiecte. La fiecare iteraie se decide includerea sau nu a obiectului
curent n rucsac i se expandeaz configuraia curent n dou
configuraii corespunztoare celor doi subarbori. Nodul corespunztor
fiului drept se obine din nodul tat la care se adaug obiectul curent,
iar cel corespunztor fiului stng se obine din nodul tat ns fr
adugarea obiectului analizat. Analiza continu numai pe una din cele
dou ramuri ale arborelui binar, iar opiunea pentru una din cele dou
ramuri se face pe baza unei funcii H care estimeaz profitul.

RucsacBB;
crt;
max = 25;
TObiect = masa, profit:integer; nr:integer ;
PNod= ^Nod;
Nod =
nivel,luat:integer;
p_estimat,profit,masa:integer;
tata,drept,stang:PNod;
;
n: integer;
obiect: [1..max] TObiect;
G, profitmax,masatotala:integer;
solutie: [1..max] 0..1;
138
Sort;
i,j:integer; aux:TObiect;
i:=1 n-1 j:=i+1 n

(obiect[i].profit/obiect[i].masa < obiect[j].profit/obiect[j].masa)
aux:= obiect[i]; obiect[i]:=obiect[j]; obiect[j]:=aux;
;
;
H(pn:PNod):integer;
i,k:integer; p,m:integer;
p := pn^.profit; m := pn^.masa; k := pn^.nivel;
m <= G
i:= k + 1 n m + obiect[i].masa <= G

p := p + obiect[i].profit; m := m + obiect[i].masa
;
H := p
H:=-1;
;
Branch;
k:integer; nodc,stang,drept:PNod;
k:=0; new(nodc); nodc^.tata:= nil; nodc^.nivel:=k;
nodc^.luat:=0; nodc^.masa:=0; nodc^.profit:=0;
inc(k); new(stang); new(drept);
nodc^.stang:=stang; nodc^.drept:=drept;
stang^.tata:=nodc; stang^.nivel:=k; stang^.luat:=0;
stang^.masa:=nodc^.masa; stang^.profit:=nodc^.profit;
stang^.p_estimat:= H(stang); drept^.tata:=nodc;
drept^.nivel:=k; drept^.luat:=1;
drept^.masa:=nodc^.masa + obiect[k].masa;
drept^.profit:=nodc^.profit + obiect[k].profit;
drept^.p_estimat:=H(drept);
stang^.p_estimat > drept^.p_estimat
nodc:=stang nodc:=drept;
k=n;
139
profitmax := nodc^.profit; masatotala := nodc^.masa;
nodc^.tata<>nil
solutie[nodc^.nivel]:=nodc^.luat; nodc:=nodc^.tata;

;
i:integer;
write('Capacitatea rucsacului = '); readln(G);
write('Numarul obiectelor = '); readln(n);
i:= 1 n
write('Masa[',i ,'] = '); readln(obiect[i].masa);
write('Profitul[',i ,'] = '); readln(obiect[i].profit);
obiect[i].nr := i;
;
Sort;
Branch;
writeln('Solutie:');
i:= 1 n solutie[i]=1 write(obiect[i].nr,' ');
writeln;
writeln('Profitul obtinut = ', profitmax);
writeln('Masa totala = ', masatotala);
readln;
.
[Jocul Perspico] Se consider o tabl cu 4 x 4 csue, fiecare
csu conine un numr ntre 1 si 15 si o csut conine zero (este
liber). tiind c 0 i poate schimba poziia cu orice numr natural
aflat deasupra, la dreapta, la stnga sau jos, n raport cu pozii n
care se afl numrul 0, se cere s se precizeze irul de mutri prin
care se poate ajunge de la o configuraie iniial dat la o confi-
guraie final. Se cere de asemenea ca acest sir s fie optim, n sensul
c trebuie s se ajung la configuraia final ntr-un numr minim de
mutri.
Rezolvare:
# <stdio.h>
# <stdlib.h>
# <conio.h>
# MAX 4
# maxop 4
140
Nod{
conf[MAX][MAX];
h, g;
Nod *down, * up;
}Nod, *PNod;
PNod New(PNod p){
PNod pnod = (PNod) malloc( sizeof(Nod) );
(pnod==NULL){
printf("\nNot enough memory !\n");
exit(0);
}
*pnod = *p;
return pnod;
}
Insert(PNod * list, PNod pnod){
pnod->down = *list; *list = pnod;
}
RemoveAll(PNod *list){
PNod p;
(*list){
p = *list; *list = (*list)->down;free(p);
}
}
PNod Expand(PNod pnod){
i, j, k, ii, jj;
lin[maxop] = {-1, 0, 1, 0};
col[maxop] = { 0, 1, 0,-1};
PNod list = NULL; PNod newNod = NULL;
(i=0; i < MAX; i++) (j=0; j < MAX; j++)
(pnod->conf[i][j]==0) ii=i,jj=j;
(k = 0; k < maxop; k++){
i = ii + lin[k]; j = jj + col[k];
if(i >= 0 && i < MAX && j >= 0 && j < MAX){
newNod = New(pnod);
newNod->conf[ii][jj] = newNod->conf[i][j];
newNod->conf[i][j] = 0; Insert(&list,newNod);
}
}
list;
}
141
Equals(PNod n1, PNod n2){
i, j;
(n1->h != n2->h) 0;
(i = 0; i < MAX; i++) (j = 0; j < MAX; j++)
(n1->conf[i][j] != n2->conf[i][j]) return 0;
1;
}
PNod Extract(PNod * list, PNod p){
PNod temp = *list, spy = *list;
(p==NULL || p == *list){ *list = (*list)->down; temp;}
(temp != p){ spy = temp; temp = temp->down;}
spy->down = temp->down;
temp;
}
PrintNod(PNod pnod){
i,j;
(i = 0; i < MAX; i++){ printf("\n|");
(j = 0; j < MAX; j++) printf("%3d", pnod->conf[i][j]);
printf(" |");
}
printf("\nApasati orice tasta ...); getch();
}
Print(PNod pnod){
(pnod->up) Print(pnod->up); PrintNod(pnod);}
PNod Choice(PNod list){
f, min = 32000; PNod pmin = NULL;
(list){
f = list->h + list->g; ( f < min ){pmin = list; min = f;}
list=list->down;}
pmin;
}
ComputeH(PNod t, PNod fin){
i, j, k, r, s; t->h = 0;
(i = 0; i < MAX; i++) (j = 0; j < MAX; j++)
(r = 0; r < MAX; r++) (s = 0; s < MAX; s++)
if (t->conf[i][j] == fin->conf[r][s]) t->h += abs(r-i) + abs(s-j);
}
PNod Search(PNod list, PNod pnod){
(list && !Equals(list,pnod)) list = list->down;
list;}
142
Branch(Nod *in, Nod *fin){
PNod Open = NULL; PNod Close = NULL;
PNod TempList = NULL; PNod theOne, temp, found;
PNod initial = New(in); Pnod final = New(fin);
ok = 0; initial->g = 0;
ComputeH(initial,final); final->h = 0; Insert(&Open,initial);
(Open){ theOne = Choice(Open); Extract(&Open,theOne);
Insert(&Close,theOne);
(Equals(theOne, final)){ok = 1; break;}
TempList = Expand(theOne);
(TempList){
temp = Extract(&TempList,NULL);
temp -> g = theOne->g + 1;
( found = Search(Open, temp) ){
(temp->g < found->g){
found->g = temp->g; found->up = theOne;}
free(temp);
}
( found = Search(Close, temp) ){
(temp->g < found->g){
found-> g = temp->g; found->up = theOne;
Extract(&Close, found);
Insert(&Open, found);}
free(temp);
}
{ temp->up = theOne; ComputeH(temp,final);
Insert(&Open,temp);}
}
}
(ok){ printf("\nSolutie:\n"); Print(theOne);}
printf("Nu am avem solutii !");
RemoveAll(Open); RemoveAll(Close);
}
main(){
Nod in = {{ 5, 1, 3, 4, 9, 7, 8, 0, 6, 2, 10, 11,
13, 14, 15, 12}, 0, 0, NULL,NULL};
Nod fin ={{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,
13,14,15, 0},0,0, NULL,NULL};
clrscr(); Branch(&in,&fin); getch();
}
3.5.3. Probleme propuse
1. [Generalizare] S se rezolve problema pentru o tabl de
dimensiuni n x n cu numere de la 1 la n
2
-2 i cu dou zerouri (locuri
libere).
2. [Diamante] Se d o tabl sub form de cruce pe care sunt aejate 32
de piese de diamant () aa cum se poate observa n figura de mai jos.
Poziia din centru este liber. O pies se poate muta doar srind
peste o alt pies ntr-un loc liber, numai pe orizontal sau pe vertical
iar piesa peste care se sare trebuie luat. Se cere s se gaseasc un ir
de mutri astfel nct (s lum ct mai multe piese de diamant)
pornind de la configuraia iniial s se ajung la o configuraie final
care s conin numai o singur pies i aceasta s se afle n centru.

143















3. [Operaii] Se d un tablou mn (1 m+n 15) cu elemente numere
ntregi. Se numete "operaie" n acest tablou nmulirea unei linii sau
coloane cu -1. S se determine cea mai mic secven de operaii care
aduce tabloul la o form n care toate sumele de linii sau coloane dau
numere nenegative.
4. [Buldozerul] Un teren de form dreptunghiular de dimensiuni mn
este mprit n ptrate de dimensiuni egale (ca la ah). Unele ptrate
conin grmezi de pamnt iar altele sunt netede. Un buldozer plasat
ntr-un ptrat neted trebuie s niveleze tot terenul. S se gseasc un
loc de unde poate porni buldozerul i ordinea de nivelare a ptratelor
(n cazul n care exist o soluie) tiind c acesta:
se deplaseaz doar pe direciile N, S, E, V;
nu se poate deplasa peste un loc neted;








Configuraia iniial

7 8 r e B * B T / 0 1 8 < < / M 1 9 8 1 > T j / T T 1 1 T f 6 3 > > B D C r e 9 7 0 6 s 2 1 1 5 2 n 6 0 1 0 > > B D C 5 2 f 1 2 3 1 2 . 7 2 r e f 9 7 0 T 7 7 . 4 8 5 2 f 1 2 3 1 2 . 7 2 r e f 9 7 0 T 2 . 3 4 8 5 2 f 1 2 3 1 2 . 7 2 r e f 9 7 0 3 > . c 1 0 5 2 f 1 2 3 1 2 . 7 2 r e f 9 7 0 - 1 4 5 . 3 2 - 1 5 3 . 9 9 r e f B T / P < < / M C I D > > B D C 0 g / T T 1 1 T f 1 . 5 4 6 2 8 T c 1 0 4 2 2 0 0 0 1 0 . 0 2 8 7 . 6 3 0 3 . 2 1 2 2 T m 7 0
trece dintr-un loc neted peste ptratul cu pmnt de lng
el n alt ptrat neted netezind astfel ptratul peste care a
trecut.
5. [Obstacole i cai] Pe o tabl de ah n n se gsesc p cai i k
obstacole amplasate ntr-o configuraie iniial dat. Mutarea calului
este cea cunoscut de la ah. Calul poate sri peste un obstacol sau
peste un alt cal, dar nu poate staiona pe o poziie ocupat de un cal
sau de un obstacol. S se determine, dac exist, un ir de mutri ale
cailor astfel nct s se ajung la o configuraie final dat.
6. [Inele] Fie dou inele n care sunt aezate echidistant 13 bile.
Inelele au dou bile n comun. Deci n
total vor fi 24 de bile din care 11 negre,
11 roii i dou gri (ca n figura de mai
jos). Fiecare inel se poate roti n sensul
acelor de ceasornic cel puin o poziie i
cel mult 12, antrennd cu el cele 13 bile
din interiorul su. Problema const n a
aduce o configuraie iniial dat, la
configuraia (final) din figura urmtoare printr-un numr minim de
rotiri.
7. [Joc] Se d o tabl de joc cu 31 de ptrate care conine opt piese de
O i opt piese de X ca n figura de mai jos.
O pies poate fi mutat numai pe orizontal i pe vertical ntr-
un loc liber nvecinat, sau prin sritur peste o alt pies alturat dac
se ajunge ntr-un loc liber. Jocul const n a schimba ntre ele locurile
ocupate de piesele 'O i 'X' ntr-un numr minim de mutri.

A B C D E F G
1
2 O O O
3 O O O

4 O O X X
5 X X X
6 X X X
7




144
145

Pentru un program realizat conform principiului modularizrii, trebuie


avute n vedere att consistena, ct i cuplajul modulelor. Consistena
unui modul este o mrime ce caracterizeaz relaiile dintre elementele
unui modul, iar cuplajul exprim interconexiunile dintre module.
Orice modul are trei atribute fundamentale: funcia, interfaa i
logica intern. Funcia modulului descrie transformarea care are loc la
apelarea modulului, interfaa indic modul de apelare a elementelor
modulului, iar logica intern indic fluxul n cadrul modulului.
Conform principiului consistenei, elementele unui program care
sunt strns legate ntre ele trebuie s fac parte din acelai modul, iar
elementele nelegate trebuie s fie introduse n module diferite (a se
vedea uniturile Turbo Pascal i fiierele antet utilizate de mediile de
programare C sau C++).
Cuplajul modulelor caracterizeaz mecanismul de transmitere a
datelor i a atributelor acestora ntre module. Dac se urmrete
maximizarea independenei modulelor atunci va crete i consistena
modulelor. Totui, de multe ori, programul este organizat n module,
nu neaprat independente, unele dintre acestea fiind legate ntre ele
printr-un graf de cuplare. Dintre dou module cuplate, la un moment
dat, unul este modul apelant (client), iar cellalt este modul apelat
(furnizor de serviciu).
Exist mai multe modaliti de cuplare: cuplare prin coninut,
cuplare prin date comune, cuplare prin fiiere de date, cuplare prin
indicatori de control i cuplare prin structuri de date.
Cuplajul bazat pe coninut apare cnd modulul apelant folosete
elemente ale modulului apelat: date declarate n modulul apelat care
nu au fost declarate globale sau externe, coninutul unui modul este
fizic inclus n alt modul (ncuibarea subprogramelor n Pascal) etc.
Cuplajul prin date comune este caracteristic acelor module care folo-
sesc o structur de date declarat global. Cuplarea prin fiiere de date
asigur independena modulelor de numrul i ordinea fizic a datelor.
Indicatorii de control sunt date care transmise unui modul determin
modul de executare a acestuia: variabile logice, identificatori de
funcii etc. Cuplarea prin structuri de date apare atunci cnd modulul
apelant transmite modulului apelat, ca parametru, o ntreag structur
de date.
146
Modulele Turbo Pascal se mai numesc i uniti de translatare (pot fi
compilate separat; vezi i metodele de proiectare C, C++ i Java) sau
unituri. Un modul Turbo Pascal este o colecie de constante, tipuri
definite, variabile, proceduri i funcii care sunt compilate separat i
pot fi folosite de alte module sau de programul principal. Modulele
Turbo Pascal, cele mai importante, sunt: SYSTEM - implementeaz
operaiile de nivel cobort; DOS - implementeaz funciile sistemului
de operare MS-DOS; CRT - permite controlul tastaturii i al moni-
torului; GRAPH - implementeaz funciile grafice uzuale; PRINTER -
permite controlul imprimantei; OVERLAY - permite segmentarea
programelor.
Un avantaj major al introducerii unitilor de translatare const
n facilitarea lucrului n echip.
O unitate de translatare Turbo Pascal are structura:
<id_unit>;

<lista_unitilor_de_translatare_apelate>;
declaraii globale
lista_funciilor_i_procedurilor_publice;
declaraii_locale
proceduri_i_funcii (definiii ale subprogramelor publice i locale)

secven_de_iniializare
i are patru seciuni: antet, interfa, implementare i iniializare.
Antetul specific numele modulului <id_unit> care trebuie s
coincid cu numele fiierului surs.
Partea de interfa conine declararea funciilor i procedurilor
care sunt definite n modul i pot fi folosite (apelate) de alte module.
Descrierea algoritmului fiecrui subprogram declarat n interfa este
realizat n seciunea .
Constantele, tipurile, variabilele, procedurile i funciile decla-
rate n partea de implementare sunt obiecte interne modului, fiind
ascunse altor module.
Deoarece dimensiunea unui modul este n general limitat (iar
pentru Turbo Pascal, limita maxim este de 64KB), un proiect este
compus din mai multe module, produsul final putnd avea o
dimensiune mult mai mare de 64KB.

[LU] Se consider sistemul de ecuaii liniare Ax=b, unde A este
o matrice ptratic de dimensiune n, iar b este un vector coloan n -
dimensional. S se determine soluia x = A
-1
b (n ipoteza existenei i
unicitii soluiei), prin metoda descompunerii matricei A n produsul
a dou matrice triunghiulare.
Rezolvare:
Un sistem de ecuaii liniare, Ax=b, poate fi rezolvat astfel: Se descom-
pune matricea coeficienilor n produsul a dou matrice triunghiulare
i apoi se rezolv dou sisteme triunghiulare.
Cutm matricele L i U astfel nct:
L = , U = i A =LU.

1
0 1
0 0 1
0 0 0 1
1 , 2 , 1 ,
1 , 2
n n n n
l l l
l
L
O L L
M
M

n n
n
n
u
u u
u u u
,
, 2 2 , 2
, 1 2 , 1 1 , 1
0 0 0
0
L O L L
L
L
La pasul 1, calculm u
1,j
i l
i,1
cu ajutorul relaiilor: u
1,j
= a
1, j
, 1j n;
l
i,1
= a
i,1
/u
1,1
, 1 i n. La paii urmtori se determin u
i,j
i l
i,j
astfel:
Dac i j atunci relaia:
a
i,j
= l
i,1
u
1,j
+ l
i,2
u
2,j
+ + l
i,i-1
u
i-1,j
+ u
i,j

conduce la:
u
i,j
= a
i,j
- , 2 i j.

=
1
1
, ,
i
k
j k k i
u l
Dac i>j atunci relaia:
a
i,j
= l
i,1
u
1,j
+ l
i,2
u
2,j
+ +l
i,j-1
u
j-1,j
+ l
i,j
u
j,j

conduce la:
l
i,j
=
j j
j
k
j k k i j i
u u l a
,
1
1
, , ,
) (

=
, i > j 2.
Soluia sistemului considerat se obine prin rezolvarea sistemelor
Ly=b (inferior triunghiular) i Ux=y (superior riunghiular).
Observm c, dac exist 1 j n astfel nct u
j,j
=0 atunci
procedeul nu mai poate continua. De asemenea, cnd u
j,j
este mic,
acurateea rezultatelor scade deoarece erorile de rotunjire se nmulesc
cu 1/u
j,j
. Este necesar astfel, interschimbarea ecuaiilor sistemului
astfel nct la pasul j, valoarea u
j,j
s fie, n valoare absolut (modul),
cea mai mare. Se va obine, astfel, descompunerea PA=LU unde P
este o matrice obinut din matricea I
n
=
i,j
=( i = j 1 0), prin
147
148
interschimbarea liniilor conform interschimbrii intervenite pentru
matricea A. Urmtorul pas const n rezolvarea sistemelor Ly=Pb i
Ux=y. Implementarea variantei stabile este realizat de procedurile
LUSTAB i LUSISTAB din unitatea de translatare MATH i vor fi
utilizate n cadrul aplicaiei R4.4. Programul prezentat mai jos,
utilizeaz descompunerea LU fr interschimbare, implementat de
procedura LUDESC pentru rezolvarea sistemului de ecuaii dat. n
plus se calculeaz determinantul matricei sistemului i inversa acesteia
(cnd exist din punct de vedere al reprezentrii numerelor n virgul
mobil). Se folosesc procedurile suplimentare LUSISTEM i LUDET.
Aceast metod este util atunci cnd avem de rezolvat mai multe
sisteme cu aceeai matrice sau cnd dorim o soluie cu precizie ridica-
t. Textul surs al unitii MATH este descris n finalul seciunii.
Programul Pascal este urmtorul:

R4_1;
math;
a:matrice; {tip de date definit in math}
b,x,y,c,e:vector; {tip de date definit in math}
i,j,k,n:integer;
det:real;
writeln;
write('Dimensiunea sistemului');readln(n);
writeln('Matricea sistemului este :');
i:=1 n
write('Linia',i:2,' '); j:=1 n read(a[i,j]);
writeln
;
writeln;
writeln('Termenul liber este :');
i:=1 n read(b[i]); writeln;
ludesc(n,a);
succes {variabil definit n math}
writeln(' Sistemul este LUDESC incompatibil')

lusistem(n,a,b,x);
writeln;
writeln(' Solutia sistemului este :');writeln;
i:=1 n writeln(x[i]:10:6); writeln;
ludet(n,a,det);
writeln('LU-Determinantul matricei sistemului este: ',det);
writeln;
writeln('Matricea inversa - pe coloane este:');
j:=1 n
write(' Coloana ',j,' ');
i:=1 n e[i]:=0; e[j]:=1;
lusistem(n,a,e,y);
i:=1 n
write(y[i]:10:4,' ');
i 6 = 0 writeln
;
writeln
.

[LLT] O matrice cu numere reale, simetric este pozitiv defini-
t, dac se poate scrie ca produsul dintre matricea inferior triunghiu-
lar L i transpusa acesteia. S se scrie o procedur care s testeze
dac o matrice este pozitiv definit i n caz afirmativ, s obin
descompunerea LL
T
, unde prin L
T
notm transpusa matricei L. S se
utilizeze aceast procedur pentru a rezolva un sistem de ecuaii, cu
matrice pozitiv definit.
Rezolvare:
Dac A este o matrice simetric i pozitiv definit, atunci exist o ma-
trice inferior triunghiular L, astfel nct A=LL
T
.
Elementele matricei L se obin prin scrierea egalitii :

n n n n
n
n
a a a
a a a
a a a
, 2 , 1 ,
, 2 2 , 2 1 , 2
, 1 2 , 1 1 , 1
L
M O M M
L
L
= ,

n n n n
l l l
l l
l
, 2 , 1 ,
2 , 2 1 , 2
1 , 1
0
0 0
L
M O M M
L
L

n n
n
n
l
l l
l l l
,
2 , 2 , 2
1 , 1 , 2 1 , 1
0 0
0
L
M O M M
L
L
prin urmtoarele relaii:
1 , 1 1 , 1
a l = ;
1 , 1 1 , 1 ,
l a l
i i
= ; i>1;
149
2 1
1
2
, , ,

=
n
k
k j j j j j
l a l , j>1;
j j
j
k
k j k i j i j i
l l l a l
,
1
1
, , , ,

=
, i>j>1.
Procedeul se blocheaz cnd exist 1 j n astfel nct rezulta-
tul expresiei de sub radical este negativ sau zero. n aceast situaie
matricea nu este pozitiv definit.
Dac matricea este simetric i pozitiv definit atunci pentru a
rezolva sistemul Ax = b se consider cele doua sisteme Ly = b i
L
T
x=y care se rezolva prin substitutie (eliminare) nainte, respectiv
napoi.
Procedura LLTD verific dac matricea, primit ca argument,
este pozitiv definit i obine descompunerea LL
T
, n caz afirmativ.
Procedura LLSISTEM rezolv cele dou sisteme triunghiulare.
Procedurile sunt incluse n unitatea de translatare MATH. Ele
sunt folosite n programul de mai jos.

r4_2;
math;
a:matrice;n,i,j:integer;
b,x,y:vector;
writeln;
write('Dimensiunea sistemului:');read(n);
i:=1 n
write('Linia ',i); j:=1 n read(a[i,j]); writeln
;
writeln('Termenul liber :'); i:=1 n read(b[i]); writeln;
lltd(n,a);
nenul write('Eps este prea mare ')
pozdef write('Matricea nu este pozitiv definita')

writeln('Matricea sistemului este pozitiv definita');
llsistem(n,a,b,x); writeln('Solutia sistemului este :');
i:=1 n writeln (x[i]:8:4);
.
150
[Iterativitate]. S se utilizeze metodele iterative Iacobi i Gauss-
Seidel pentru a rezolva un sistem de ecuaii liniare (numrul ecuaii-
lor fiind egal cu numrul necunoscutelor).
Rezolvare:
Considerm sistemul Ax=b, unde A este o matrice ptratic, de di-
mensiune n, cu elemente reale. Presupunem c a
i,i
0 pentru oricare
1 i n . Atunci sistemul
a
i,1
x
1
+ a
i,2
x
2
+ + a
i,n
x
n
= b
i
, i=1,2, ... ,n;
se mai poate scrie astfel :
i i
i j
j j i i i
a x a b x
, ,

, i = 1, 2, , n.
Dac presupunem c x
(0)
este o aproximare iniial a soluiei sistemu-
lui, atunci formula de mai sus sugereaz urmtoarea metod iterativ
pentru determinarea soluiei sistemului Ax=b:
i i
i j
m
j j i i
m
i
a x a b x
,
) (
,
) 1 (

+
, i = 1, 2, , n; m 0.
Aceasta este metoda aproximrii simultane (metoda lui Iacobi). Dac
n membrul drept al relaiei anterioare, utilizm componentele recent
calculate, obinem metoda aproximrii succesive (metoda Gauss-Seidel).
Iteraia Gauss-Seidel este definit prin formula:
i i
n
i j
m
j j i
i
j
m
j j i i
m
i
a x a x a b x
,
1
) (
,
1
1
) 1 (
,
) 1 (

=

+ =

=
+ +
, i=1, 2, .., n; m 0.
Cele dou metode converg n cazul unui sistem liniar cu matrice dia-
gonal dominant:

>
i j
j i i i
a a
, ,
, i =1, 2, , n.
Funcia Pascal diag_dom verific dac o matrice ptratic de
dimensiune n este diagonal dominant.
Procedurile Iacobi i Seidel implementeaz cele dou formule
iterative. Acestea sunt folosite n programul urmtor, care determin
soluia unui sistem de ecuaii liniare cu matrice diagonal dominant.
Algoritmul se oprete dup un numr de iteraii specificat sau
cnd precizia eps a fost atins.

151
r4_3;
math;
a:matrice;
b,x:vector;
i,j,n,niter:integer;
writeln;
write('Dimensiunea sistemului>');read(n);
writeln('Coloanele matricei --- b ');
i:=1 n
j:=1 n read(a[i,j]);
read (b[i]); writeln
;
write('Numar-iteratii >');read(niter);
diag_dom(n,a)
i:=1 n x[i]:=0; iacobi(n,a,b,niter,x);
writeln;
writeln('Solutia obtinuta prin metoda Iacobi :');
i:=1 n writeln (x[i] );
i:=1 n x[i]:=0; Seidel(n,a,b,niter,x);
writeln;
writeln('Solutia obtinuta prin metoda Gauss-Seidel:');
i:=1 n writeln(x[i])
end
write(' Algoritmii Iacobi i Gauss-Seidel nu converg.')
.
[Prelucrarea datelor prin metoda celor mai mici ptrate] Fie
ARxR, A = {(x
1
,y
1
), (x
2
,y
2
), ..., (x
n
,y
n
)}. Presupunem c y
i
sunt
valorile n x
i
ale unei funcii reale a crei expresie analitic nu este
cunoscut. Se cere identificarea unui model f, care s minimizeze su-
ma ptratelor erorilor:
( )

=
=
n
i
i i
x f y S
1
2
) ( .
Rezolvare:
Pentru a determina un astfel de model, se folosete metoda celor mai
mici ptrate. Aceasta este aplicat frecvent pentru urmtoarele modele
(dintre care se va face alegerea ): y = a + b x (liniar); y = a x
b
(putere);
y = a b
x
(exponential); y = c
1
+c
2
x+...+ c
k+1
x
k
(polinomial); y = a + b/x
152
(hiperbolic) etc. i implic rezolvarea unor sisteme de ecuatii,
necunoscutele fiind coeficienii curbei.
Pentru modelul liniar sistemul (cu necunoscutele a i b) ce tre-
buie rezolvat este urmtorul:

= +
= +


= = =
= =
n
i
n
i
n
i
i i i i
n
i
i
n
i
i
y x x b x a
y x b na
1 1 1
2
1 1
.
;

Determinarea parametrilor modelului putere se bazeaz pe rezol-
varea urmtorului sistem:

= +
= +


= = =
= =
n
i
n
i
n
i
i i i i
n
i
n
i
i i
y x x b x a
y x b a n
1 1 1
2
1 1
ln ln ln ln ln
; ln ln ln

cu necunoscutele ln a i b.
Modelul exponenial necesit rezolvarea urmtorului sistem:

= +
= +


= = =
= =
n
i
n
i
n
i
i i i i
n
i
n
i
i i
y x x b x a
y x b a n
1 1 1
2
1 1
ln ln ln
; ln ln ln

cu necunoscutele ln a i ln b.
n cazul modelului polinomial, trebuie rezolvat urmtorul sistem
cu k+1 ecuaii i k+1 necunoscute {c
0
,c
1
,...,c
k
}:

= + + +
= + +
= + + +



= = = =
+
= = =
+
=
= = =
n
i
n
i
n
i
n
i
i
k
i
k
i k
k
i
k
i
n
i
n
i
n
i
i i
k
i k i
n
i
i
n
i
n
i
n
i
i
k
i k i
y x x c x c x c
y x x c x c x c
y x c x c c
1 1 1 1
2 1
1 0
1 1 1
1 2
1
1
0
1 1 1
1 0
.
;
;
L
L
L
L

Pentru determinarea parametrilor modelului hiperbolic, trebuie
rezolvat urmtorul sistem cu dou ecuaii i necunoscutele a i b:
153

= +
= +


= = =
= =
n
i
n
i
n
i
i
i
i i
n
i
n
i
i
i
x
y
x
b
x
a
y
x
b an
1 1 1
2
1 1
.
1 1
;
1

Pentru rezolvarea acestor sisteme, programul r4_4, utilizeaz
procedurile LUSTAB i LUSISTAB din unitatea MATH, anunate la
problema R4.1. Datele de intrare sunt nregistrate n fiierul text 'reg.dat',
creat cu ajutorul unui editor de texte, sau este ieirea unui alt program
de prelucrare. Valorile sunt nregistrate cte o pereche pe rnd.
Programul cere numrul de perechi i tipul modelului matematic al
datelor.
Pentru fiecare model se afieaz suma ptratelor erorilor sau
mesaje adecvate privind inaplicabilitatea metodei pentru datele consi-
derate. Dac datele sunt corecte din punctul de vedere al modelului
atunci se afieaz i parametrii acestuia.
Programul Pascal este urmtorul:
r4_4;
math;
a:matrice;
b,coef:vector;
sx,sy,sxy,slogx,slogy,s2x,s2logx,slogxy:real;
suma,ss,sxlogy,s1px,s1px2,sypx,x,y:real;
xnegativ:boolean;
ynegativ:boolean;
xzero:boolean;
c:char;
putere,s:vector;
i,j,k,l,n:integer;
sx:=0; { suma valorilor x }
sy:=0; { suma valorilor y }
sxy:=0; { suma valorilor x*y }
slogx:=0; { suma valorilor log x }
slogy:=0; { suma valorilor log y }
s2x:=0; { suma patratelor valorilor x }
s2logx:=0; { suma patratelor valorilor log x }
slogxy:=0; { suma produselor valorilor logx,logy }
sxlogy:=0; { suma produselor x, logy }
154
155
s1px:=0; { suma inverselor }
s1px2:=0; { suma patratelor inverselor }
sypx:=0; { suma rapoartelor y/x }
k:=1;
writeln;
writeln('Prelucrarea datelor din fsierul reg.dat');
writeln;
write('Numr observatii :'); read(n);
assign(input,'reg.dat');
reset(input);
i:=1 n
readln(x,y);
xnegativ:=x <= 0;
ynegativ:=y <= 0;
xzero:= abs(x) < eps;
xnegativ
slogx:=slogx+ln(x);
s2logx:=s2logx+ln(x)*ln(x)
;
ynegativ
slogy:=slogy+ln(y);
sxlogy:=sxlogy+x*ln(y)
;
xzero
s1px:=s1px+1/x;
s1px2:=s1px2+1/(x*x);
sypx:=sypx+y/x
;
sx:=sx+x;
sy:=sy+y;
sxy:=sxy+x*y;
s2x:=s2x+x*x;
(x>0) (y>0) slogxy:=slogxy+ln(x)*ln(y);
;
close(input);
writeln('---------------------------------------------');
writeln;
writeln(' L - liniar H - hiperbolic');
writeln(' P - putere E - exponential');
writeln(' A - polinomial');
156
writeln;
assign(input,'con');
reset(input);
eoln readln;
read(c);
writeln('S-a selectat ',c);
c ['l','L','H','h','p','P','e','E','a','A'];
close(input);
k:=1; suma:=0;
c ['l','L']
a[1,1]:=n; a[1,2]:=sx;
a[2,1]:=sx; { incarca matricea sistemului }
a[2,2]:=s2x;
b[1]:=sy;
b[2]:=sxy; { incarca termenul liber }
lustab(2,a,b); { descompunere lu }
succes
lusistab(2,a,b,coef) ; { rezolva sistem }
assign(input,'reg.dat');
reset(input);
i:=1 n
readln(x,y);
suma:=suma+sqr(y-coef[1]-coef[2]*x)
;
close(input)
writeln('Erori mari in date.',
'Sistem ru condiionat');
;
c ['h','H']
xzero writeln ('Modelul nu se aplica')
a[1,1]:=n; a[1,2]:=s1px;
a[2,1]:=s1px; a[2,2]:=s1px2 ;
b[1]:=sy; b[2]:=sypx;
lustab(2,a,b);
succes
lusistab(2,a,b,coef) ;
157
assign(input,'reg.dat'); reset(input);
i:=1 n
readln(x,y);
suma:=suma+sqr(y-coef[1]-coef[2]/x)
;
close(input);
suma:=-1;
writeln('Erori mari in date.',
'Sistem ru conditionat');
;
;
c ['p','P']
xnegativ ynegativ writeln('Modelul nu se aplica')
a[1,1]:=n; a[1,2]:=slogx;
a[2,1]:=slogx; a[2,2]:=s2logx ;
b[1]:=slogy; b[2]:=slogxy;
lustab(2,a,b);
succes
lusistab(2,a,b,coef) ;
coef[1]:=exp(coef[1]);
assign(input,'reg.dat');
reset(input);
i:=1 n
readln(x,y);
suma:=suma+sqr(y-coef[1]*exp(coef[2]*ln(x)))
;
close(input);
suma:=-1;
writeln('Erori mari n date.',
'Sistem ru condiionat');
;
;
c ['e','E']
ynegativ writeln('Modelul nu se aplica')
158
a[1,1]:=n; a[1,2]:=sx;
a[2,1]:=sx; a[2,2]:=s2x ;
b[1]:=slogy; b[2]:=sxlogy;
lustab(2,a,b);
succes
lusistab(2,a,b,coef) ;
coef[1]:=exp(coef[1]);
coef[2]:=exp(coef[2]);
coef[2]<=0
suma:=-1;
writeln(' Erori n date ')
assign(input,'reg.dat');
reset(input);
i:=1 n
readln(x,y);
suma:=suma+sqr(y-coef[1]*exp(x*ln(coef[2])))
;
close(input)
suma:=-1 ;
writeln('Erori mari n date.',
'Sistem ru condiionat');
;
;
c ['a','A']
write('Gradul polinomului:');
assign(input,'con');
reset(input);
read(k);
close(input);
writeln(' ... ',k);
i:=1 2*k s[i]:=0;
i:=1 k+1 b[i]:=0;
assign(input,'reg.dat');
reset(input);
159
i:=1 n
readln(x,y); putere[1]:=1;
l:=2 2*k+1 putere[l]:=putere[l-1]*x;
l:=1 2*k s[l]:=s[l]+putere[l+1];
l:=1 k+1 b[l]:=b[l]+putere[l]*y
;
a[1,1]:=n;
i:=2 k+1
a[1,i]:=s[i-1]; {ncarc matricea sistemului}
j:=2 k+1 a[j,1]:=s[j-1];
i:=2 k+1
j:=2 k+1 a[i,j]:= s[i+j-2];
lustab(k+1,a,b);
succes
lusistab(k+1,a,b,coef);
assign(input,'reg.dat');
reset(input);
i:=1 n
readln(x,y);
putere[1]:=1;
l:=2 k+1 putere[l]:=x*putere[l-1];
ss:=coef[1];
l:=2 k+1 ss:=ss+coef[l]*putere[l];
suma:=suma+sqr(y-ss)
;
close(input)
suma:=-1;
writeln('Erori mari in date. Sistem ru conditionat');
;
;
writeln;
writeln('Suma patratelor erorilor',suma);
writeln;
if suma <> -1 then begin
writeln('Parametrii modelului :');
i:=1 k+1 write(coef[i]);
;
writeln;
160
writeln(' L - liniar H - hiperbolic');
writeln(' P - putere E - exponential');
writeln(' A - polinomial O - Oprire');
writeln;
assign(input,'con');
reset(input);
eoln readln;
read(c) ;
writeln;
writeln('S-a selectat ',c);
close(input)
c ['o','O']
.

[Unitatea Math.tpu] Descriei un text surs pentru unitatea
Math aetfel nct s ofere serviciile descrise n aplicaiile anterioare.
Rezolvare:
math;{
1. Se salveaz cu numele "math.pas";
2. Constante globale:
maxlin; numarul maxim de linii.
Maxcol; numarul maxim de coloane.
eps; precizia (cel mai mic numar pozitiv).
3. Tipuri globale:
matrice;
vector.
4. Variabile globale:
succes ;
pozdef ;
nenul.
5. Proceduri globale (publice):
vdif; prodmv; vadd;
ludesc; lusistem; ludet; lustab; lusistab ;
lltd; llsistem;
Iacobi; Seidel.
6. Funcii globale:
diag_dom;
norma .
}

161
maxlin=30;
maxcol=30;
Eps=1E-10;
matrice = array[1..maxlin,1..maxcol] of real;
vector = array[1..maxcol] of real;
succes,pozdef,nenul:boolean;
vdif(n:integer; x,y:vector; z:vector );
prodmv(n:integer; a:matrice; x:vector; y:vector);
vadd(n:integer; x:vector; y:vector);
ludesc(n:integer; a:matrice);
lusistem(n:integer; a:matrice; b:vector; x:vector);
ludet(n:integer; a:matrice; det:real);
lustab(n:integer; a:matrice; b:vector);
lusistab(n:integer; a:matrice; b,x:vector );
lltd(n:integer; a:matrice);
llsistem(n:integer; a:matrice; b:vector; x:vector);
diag_dom(n:integer;a:matrice):boolean;
norma(n:integer; x:vector):real;
Iacobi(n:integer;a:matrice; b:vector;
niter:integer; x:vector);
Seidel(n:integer;a:matrice;b:vector;
niter:integer; x:vector);
{--------------------------------------------------------}
vdif(n:integer; x,y:vector; z:vector);
i:integer;
i:=1 n z[i]:=x[i]-y[i]
;
{--------------------------------------------------------}
prodmv(n:integer;a:matrice;x:vector; y:vector);
i,j:integer;
writeln('Prodmv');
i:=1 n
y[i]:=a[i,1]*x[1];
j:=2 n y[i]:=y[i]+a[i,j]*x[j];
;
162
{--------------------------------------------------------}
vadd(n:integer; x:vector;y:vector);
i:integer;
i:=1 n x[i]:=x[i]+y[i]
;
{--------------------------------------------------------}
ludesc(n:integer; a:matrice);
{
Apel: LUdesc(n,a);
Descriere parametri:
n - dimensiunea matricei;
a - matricea de descompus.
Funcie:
Descompune matricea a in produsul a doua matrice
triunghiulare . Matricea a se distruge.
Metoda:
Algoritmul este prezentat la problema R4.1.
}
i,k,j:integer;s:real;
succes:=true; i:=1 n a[i,1]:=a[i,1]/a[1,1];
i:=2;
(i <= n) succes
s:=0; k:=1 i-1 s:=s+a[i,k]*a[k,i];
a[i,i]:=a[i,i]-s; succes:=abs(a[i,i]) > eps;
succes
j:=i+1 n
s:=0; k:=1 i-1 s:=s+a[i,k]*a[k,j];
a[i,j]:=a[i,j]-s
;
j:=i+1 n
s:=0; k:=1 i-1 s:=s+a[j,k]*a[k,i];
a[j,i]:=(a[j,i]-s)/a[i,i]
;
i:=i+1

;
{-----------------------------------------------------}
163
lusistem(n:integer; a:matrice; b:vector;
x:vector);
{
Apel: LUsistem(n,a,b,x);
Descriere parametri:
n - dimensiunea sistemului;
a - matricea sistemului;
b - termenul liber;
x - soluia sistemului.
Funcia:
Rezolv sistemul LUx=b;
Metoda:
Se rezolv dou sisteme triunghiulare.
}
i,j:integer;
b1,y:vector;
s:real;
{
Rezolvare sistem inferior triunghiular;
}
y[1]:=b[1];
i:=2 n
s:=0;
j:=1 i-1 s:=s+a[i,j]*y[j];
y[i]:=b[i]-s
;
writeln;
{
Rezolvare sistem superior triunghiular;
}
x[n]:=y[n]/a[n,n];
i:=n-1 1
s:=0;
j:=i+1 n s:=s+a[i,j]*x[j];
x[i]:=(y[i]-s)/a[i,i]
;
;
{-----------------------------------------------------}

164
ludet(n:integer;a:matrice; det:real);
{
Apel: ludet(n,a,det);
Descriere parametri:
n - dimensiunea matricei;
a - descompunerea lu a matricei initiale;
det - valoarea determinantului.
Funcia:
Calculeaza determinantul unei matrice.
}
i:integer;
p:real;
p:=1;
i:=1 n p:=p*a[i,i];
det:=p
;
{-----------------------------------------------------}
lustab(n:integer; a:matrice; b:vector);
{
Apel: lustab(n,a,b);
Descriere parametri:
n - dimensiunea matricei;
a - matricea ce se va descompune;
p - termenul liber .
Funcia:
Descompunerea LU a matricei a;
Metoda:
Algoritmul este prezentat la problema R4.1.
Proceduri locale:
max(i,k) :- k este indicele liniei pe care se afl
elementul de modul maxim din coloana i;
perlin(i,k) :- permuta liniile i i k.
}
i,j,k:integer; s:real;
procedure max(i:integer; var k:integer);
j:integer;
valmax:real;
valmax:=abs(a[i,i]); k:=i;
165
j:=i+1 n
valmax < abs(a[j,i])
valmax:=abs(a[j,i]); k:=j

end; {MAX}
procedure perlin(i,k:integer);
s:real;
j:integer;
j:=1 n s:=a[i,j]; a[i,j]:=a[k,j]; a[k,j]:=s ;
s:=b[i]; b[i]:=b[k]; b[k]:=s
end;{PERLIN}
max(1,j);
j <> 1 perlin(1,j);
i:=2;
succes:=abs(a[1,1])>eps;
(i <= n) succes
max(i,j);
j <> i perlin(i,j);
a[i,1]:=a[i,1]/a[1,1];
j:=2 i-1
s:=0;
k:=1 j-1 s:=s+a[i,k]*a[k,j];
a[i,j]:=(a[i,j]-s)/a[j,j]
;
j:=i n
s:=0;
k:=1 i-1 s:=s+a[i,k]*a[k,j];
a[i,j]:=a[i,j]-s
;
succes:=abs(a[i,i]) > eps ;
i:=i+1
;
;
{----------------------------------------------------}
lusistab(n:integer; a:matrice; b,x:vector);
{
Apel: LUsistab(n,a,b,x,p);
Descriere parametri:
166
n - dimensiunea sistemului;
a - matricea sistemului;
b - termenul liber;
x - soluia sistemului;
p - permutarea rezultat prin interschimbri.
Funcia:
Rezolv sistemul LUx=b;
Metoda:
Se rezolv dou sisteme triunghiulare.
}
i,j:integer;
y:vector;
s:real;
{
Rezolvare sistem inferior triunghiular;
}
y[1]:=b[1];
i:=2 n
s:=0; j:=1 i-1 s:=s+a[i,j]*y[j];
y[i]:=b[i]-s
;
writeln;
{
Rezolvare sistem superior triunghiular;
}
x[n]:=y[n]/a[n,n];
i:=n-1 1
s:=0; j:=i+1 n s:=s+a[i,j]*x[j];
x[i]:=(y[i]-s)/a[i,i]

;
{-----------------------------------------------------}
lltd(n:integer; a:matrice);
{
Apel: LLtd(n,a);
Descrierea parametrilor:
n - dimensiunea matricei;
a - matrice patratica cu elemente reale.
Funcia:
167
Obine n matricea A o descompunerea n produsul unei matrice
inferior triunghiulare cu transpusa acesteia, dac matricea A este
pozitiv definit.
Metoda:
Conform algoritmului prezentat la problema R4.2.
}
i,j,k:integer; sim:boolean;
pozdef:= true; i:=1;
(i <= n) pozdef
j:=i+1;
(j <= n) pozdef
pozdef :=a[i,j]=a[j,i]; j:=j+1
;
i:=i+1;
;
pozdef:= (a[1,1] > 0) pozdef;
pozdef
a[1,1] :=sqrt(a[1,1]); nenul:= a[1,1] >= eps;
nenul
j:=2 n
a[j,1]:=a[j,1]/a[1,1]; a[1,j]:= a[j,1]
;
i:=2;
(i <= n) pozdef nenul
k:=1 i-1 a[i,i]:=a[i,i]-sqr(a[i,k]);
pozdef:=a[i,i] > 0;
pozdef
a[i,i]:=sqrt(a[i,i]); nenul := a[i,i] >= eps;
nenul
j:=i+1 n
k:=1 i-1 a[j,i]:=a[j,i]-a[j,k]*a[i,k];
a[j,i]:=a[j,i]/a[i,i]; a[i,j]:=a[j,i]

;
i:=i+1

;
168
{-----------------------------------------------------}
llsistem(n:integer;a:matrice; b:vector; x:vector);
{
Apel: LLsistem(n,a,b,x);
Descrierea parametrilor:
n - dimensiunea sistemului;
a - matricea ce conine descompunerea LL
T
b - termenul liber;
x - soluia sistemului.
Funcia:
Rezolv dou sisteme triunghiulare conform celor prezentate la
problema R4.2.
}
i,j,k:integer; y:vector;
y[1]:=b[1]/a[1,1];
i:=2 n
y[i]:=b[i];
k:=1 i-1 y[i]:=y[i]-a[i,k]*y[k];
y[i]:=y[i]/a[i,i]
;
x[n]:=y[n]/a[n,n];
i:=n-1 1
x[i]:=y[i];
j:=i+1 n x[i]:=x[i]-a[i,j]*x[j];
x[i]:=x[i]/a[i,i]
;
;
{-----------------------------------------------------}
diag_dom(n:integer; a:matrice):boolean;
{
Apel : diag_dom(n,a);
Descrierea parametrilor:
n - dimensiunea matricei;
a - matrice patratic cu elemente reale.
Funcia: Verific dac o matrice este diagonal dominant
}
i,j:integer;
v:boolean;
s:real;
169
v:=true; i:=1;
(i <= n) v
s:=0;
j:=1 n j <> i s:=s + abs(a[i,j]);
s >= abs (a[i,i]) v:=false i:=i+1;
;
diag_dom:=v
;
{-----------------------------------------------------}
norma(n:integer; x:vector):real;
{
Apel : norma(n,x)
Descrierea parametrilor:
n - dimensiunea vectorului;
x - vector cu n componente.
Functia: Calculeaza norma uniform.
}
v, p:real; i:integer;
v:=abs(x[1]);
i:=2 n p:=abs(x[i]); v < p v:=p ;
norma:=v
;
{-----------------------------------------------------}
Iacobi(n:integer; a:matrice; b:vector;
niter:integer; x:vector);
{
Apel: Iacobi(n,a,b,niter,x)
Descrierea parametrilor:
n - dimensiunea sistemului;
a - matricea sistemului;
b - termenul liber;
niter - numrul de iteraii;
x - soluia sistemului.
Functia: Rezolv un sistem cu n ecuaii liniare i n necunoscute
prin metoda Iacobi.
Metoda: Algoritmul prezentat la problema R4.3.
}
i,j,k:integer; y,e:vector; s:real;
170
i:=1 n y[i]:=x[i]; k:=1;
( k<= niter) (norma(n,e) > eps)
i:=1 n
s:=0; j:=1 n j <> i s :=s+a[i,j]*y[j];
x[i]:=(b[i]-s)/a[i,i]
;
vdif(n,x,y,e); i:=1 n y[i]:=x[i]; k:=k+1
;
{-----------------------------------------------------}
Seidel(n:integer; a:matrice; b:vector;
niter:integer; x:vector);
{
Apel : Seidel(n,a,b,niter,x)
Descrierea parametrilor:
n - dimensiunea sistemului liniar;
a - matricea sistemului de ecuaii;
b - termenul liber al sistemului;
niter - numarul de iteraii ;
x - soluia sistemului.
Funcia: Rezolv un sistem liniar cu n ecuaii i n necunoscute
prin metoda Gauss-Seidel.
Metoda: Algoritmul prezentat la problema R4.3.
}
y,e:vector;i,j,k:integer;
i:=1 n y[i]:=x[i]; k:=1;
(k <= niter) (norma(n,e) > eps)
i:=1 n
x[i]:=b[i]; j:=1 n i <> j x[i]:=x[i]-a[i,j]*x[j];
x[i]:=x[i]/a[i,i];
;
vdif(n,x,y,e); i:=1 n y[i]:=x[i]; k:=k+1
;
Writeln; Writeln('Unitul Math - GA2003'); Writeln
.

171

1. O bibliotec de grafic bidimensional, trebuie s ofere programa-
torului posibilitatea lucrului n coordonate utilizator (numere reale).
Aceasta trebuie s conin subprograme pentru:
realizarea transformrilor geometrice (translaie absolut i
relativ, rotaie absolut i relativ, simetrie etc.);
desenarea primitivelor grafice (linie, cerc, dreptunghi, elipsa etc.);
realizarea transformrii imaginii din spaiul de coordonate
utilizator n spaiul de coordonate ecran.
operaia de decupare (clipping).
S se realizeze o unitate numit care s utilizeze unita-
tea i care s ofere ct mai multe din facilitile anunate mai
sus.
2. Se consider declaraiile:
MatProg10;
max_lin=10;
max_col=10;
matrice= [1..max_lin,1..max_col] real;
vector_linie= [1..max_col] real;
vector_coloana= [1..max_lin] real;
copy_lin_vector (a:matrice; i:integer; x:vector_linie);
copy_col_vector
(a:matrice; i:integer; x:vector_coloana);
copy_diag_vector(a:matrice; x:vector_coloana);
add_number( a:matrice; x:real);
subtract_number( a:matrice; x:real);
divide_by_number( a:matrice; x:real);
replace_diag_vector( a:matrice; x:vector_coloana);
mul_linie_add( a:matrice; i:integer; x:real; j:integer);
mul_col_add( a:matrice; i:integer; x:real; j:integer);
interschimba_lin( a:matrice; i,j:integer);
interschimba_col( a:matrice; i,j:integer);
sum_lin_vector(a:matrice; x:vector_coloana);
sum_col_vector(a:matrice; x:vector_linie);
generare( a:matrice);
tiparire(a:matrice);
a) S se implementeze unitatea conform urmtoarelor specificaii:
172
Procedura copy_lin_vector copiaz linia i a matricei a ntr-un
vector linie.
Procedura copy_col_vector copiaz coloana i a matricei a ntr-un
vector coloan.
Procedura copy_diag scoate ntr-un vector elementele de pe
diagonala matricei a.
Procedura add_number adun un scalar la toate elementele
matricei a.
Procedura subtract_number scade un scalar din toate elementele
matricei a.
Procedura divide_by_number mparte toate elementele matricei a
la un numr real nenul.
Procedura replace_diag_vector nlocuiete elementele de pe
diagonala matricei a cu cele specificate ntr-un vector coloan.
Procedura mul_linie_add adun la linia j, linia i, ale crei
elemente se nmulesc cu un numr real.
Procedura mul_col_add adun la coloana j, coloana i, ale crie
elemente se nmulesc cu un numr real.
Procedura interschimba_lin realizeaz interschimbarea liniilor i i
j.
Procedura interschimba_col realizeaz interschimbarea coloanelor
i i j.
Procedura sum_lin_vector calculeaz ntr-un vector coloan suma
elementelor de pe liniile matricei a.
Procedura sum_col_vector calculeaz ntr-un vector linie suma
elementelor de pe coloanele matricei a.
Procedura generare realizeaz ncrcarea unei matrice a cu valori
numerice.
Procedura tiparire afieaz la mediul standard de ieire, valorile
elementelor matricei a.
b) S se utilizeze unitatea pentru implementarea unor algoritmi pentru
calculul rangului unei matrice;
3. Elaborai o unitate de translatare Pascal pentru definirea tipului
complex i a operaiilor cu numere complexe. Se cer utilizarea formei
algebrice i a formei trigonometrice.
4. Elaborai o unitate pentru lucrul cu numere mari. Trebuie imple-
mentate operaii precum: adunare, scdere, mprire ntreag, deter-
minarea restului mpririi a dou numere ntregi, calculul rdcinii
ptrate.
173


La prima vedere orice program poate fi perceput ca o colecie de date
i de operaii care se execut asupra datelor. n programarea procedu-
ral aceste dou elemente sunt tratate separat, reprezentarea datelor se
realizeaz cu ajutorul tipurilor de date, iar reprezentarea operaiilor se
face prin funcii i proceduri.
Folosirea funciilor nu este suficient dac se dorete o descriere
i implementare eficient a unor algoritmi ce necesit structuri de date
complexe n rezolvarea problemelor. n plus, dac se dorete reutili-
zarea unor programe scrise anterior n rezolvarea unor noi probleme
va fi necesar un efort considerabil din partrea programatorului s
adapteze codul surs reutilizat la noile nevoi, iar aceasta va duce la
apariia a numeroase erori. Din acest motiv este mult ngreunat i
lucrul n echip, dac un programator trebuie s implementeze o
funcie, acesta va trebui s studieze i celelalte module ale progra-
mului.
Un limbaj de programare potrivit acestor sarcini ar trebui s
permit att ncapsularea structurilor de date ct i a funciilor care
opereaz cu aceste structuri ca o singur entitate, s permit
ascunderea detaliilor de implementare a operaiilor i s permit
reutilizarea i extinderea unor module existente (chiar i a celor
compilate fr recompilare).
S-a impus astfel, nevoia unui model de programare capabil s
depeasc limitrile programrii structurate i care s permit
realizarea unei abstractizri adecvate a datelor i a operaiilor n aa fel
nct s permit o tratare unitar a acestora. Aa s-a nscut clasa
limbajelor de programare orientate pe obiecte din care face parte i
limbajul C++.
Modelul de programare orientat pe obiecte rezolv aceste
probleme prin urmtoarele principii importante: abstractizare,
ncapsulare, modularizare, motenire i polimorfism.
Abstractizarea este un model n care un obiect este privit prin prisma
metodelor (operaiilor) sale, ignorndu-se pentru moment detaliile de
implementare a acestora. O bun abstractizare va defini n mod clar
graniele conceptuale ale obiectului, va scoate n eviden doar
174
aspectele semnificative ale obiectului, acelea care fac ca acesta s se
diferenieze de alte obiecte i va estompa celelalte caracteristici.
Aadar, n procesul de abstractizare atenia este ndreptat spre
aspectul exterior al unui obiect, spre modul su de comportare i nu
spre felul n care aceast comportare este implementat. Comportarea
unui obiect se caracterizeaz printr-un numr de servicii sau resurse pe
care acesta le pune la dispoziia altor obiecte. Mulimea operaiilor
unui obiect mpreun cu regulile lor de apelare constituie interfaa
obiectului.
Programatorii utilizeaz abstractizarea pentru a simplifica ana-
liza, proiectarea i implementarea programelor complexe. n C++
instrumentul de baz pentru abstractizare este clasa.
ncapsularea este conceptul complementar abstractizrii. Dac
rezultatul operaiei de abstractizare pentru un anumit obiect este
identificarea interfeei, atunci ncapsularea trebuie s defineasc repre-
zentarea (structura) intern a obiectului i s selecteze o implementare
a interfeei acestuia. Prin urmare, ncapsularea este procesul n care
are loc separarea interfeei de implementare i ascunderea implemen-
trii fa de exterior.
Separarea interfeei de reprezentarea unui obiect i de imple-
mentarea metodelor sale permite modificarea structurii obiectului i a
metodelor fr a afecta n nici un fel programul care folosete obiec-
tul, ntruct acesta depinde doar de interfa. ncapsularea permite
modificarea programelor ntr-o manier eficient, cu un efort limitat i
bine localizat.
Clasele obinute n urma abstractizrii i ncapsulrii trebuie grupate i
apoi stocate ntr-o form fizic, denumit modul. Modulele pot fi
privite ca fiind containerele fizice n care declarm clasele i obiectele
rezultate n urma proiectrii la nivel logic. Modulele formeaz aadar
arhitectura fizic a programului. Modularizarea const n divizarea
programului ntr-un numr de module care vor fi compilate separat,
dar care sunt conectate ntre ele. Scopul descompunerii n module este
reducerea costurilor prin posibilitatea de a proiecta i revizui pri ale
programului ntr-un mod independent.
Concret, n C++ modulele nu sunt altceva dect fiierele ce pot
fi compilate separat. n practic se obinuiete ca interfaa unui modul
175
s fie plasat ntr-un fiier header (cu extensia ".h"), n timp ce
implementarea acestuia se va regsi ntr-un fiier surs (cu extensia
".cpp"). Dependenele dintre module vor fi exprimate utliznd directi-
vele "#include".
Referitor la modularizare, cititorul poate observa asemnri i
deosebiri ale modularizrii la nivelul C, C++, n raport cu modula-
rizarea permis de implementarea Borland a limbajului Pascal.

Nu de puine ori, scriind programe n maniera clasic, eram pui n


situaia de a adapta sau rescrie funcii scrise anterior. Aceast etap de
implementare consuma mai mult timp dect era necesar i, n plus,
exista riscul apariiei a numeroase erori. O variant mult mbuntit
de reutilizare a codului este motenirea. Motenirea este unul dintre
cele mai importante concepte ale limbajelor de programare pe obiecte.
Aceasta permite extinderea obiectelor existente i construirea de noi
obiecte ntr-un mod simplu. Astfel, o clas poate moteni toate carac-
teristicile uneia sau a mai multor clase create anterior la care poate
aduga trsturi noi i, n anumite condiii, poate redefini unele din
metodele motenite.
Polimorfismul este o facilitate a programrii orientate obiect care
ofer instanelor unor clase posibilitatea de a reaciona ntr-un mod
specific la un mesaj (la un apel de funcie). Spre exemplu, ntr-o
ierarhie de clase obinut prin motenire, care reprezint forme
geometrice (puncte, linii, dreptunghiuri, cercuri) fiecare obiect are o
funcie Draw(). Apelul acestei funcii avnd o referin la un obiect
grafic generic trebuie s se comporte corespunztor obiectului referit.
Conceptul fundamental din programarea orientat pe obiecte l
reprezint noiunea de clas ca tip de date definit de utilizator.
Cuvntul cheie class ne permite s intrm n universul programrii
orientate pe obiecte, cu ajutorul lui putem defini tipuri abstracte de
date. Variabilele declarate pe baza unui tip abstract se numesc obiecte.
Putem spune c:
Clasa = Date + Operaii.
Spre deosebire de structurile cunoscute din limbajul C, clasele
conin nu numai date membre ci i funcii membre, constructori i cel
mult un destructor. n general o clas se definete astfel:
176
nume{
:
<date membre private>
<constructori privati>
<metode private>
:
<date membre protejate>
<constructori protejati>
<metode protejate>
:
<date membre publice>
<constructori publici>
<destructor public>
<metode publice>
};
Pentru exemplificare vom defini o serie de clase pentru reprezentarea
figurilor geometrice n plan. Se tie c figurile geometrice se
contruiesc pornind de la unele forme simple cum sunt punctul, linia,
etc. Urmeaz un exemplu de declaraie de clas care introduce un tip
nou de date numit Punct. Urmtoarea declaraie se va scrie ntr-un
fiier header cu un numele Point.h.
Point {
:
x, y; //date membre
:
Point(); //constructor
Point(int, int); //consructor
~Point(); //destructor
Print(); //funcie membra
Read(); //funcie membra
};

n limbajul C toate operaiile de intrare-ieire se realizeaz prin


utilizarea funciilor din biblioteca standard stdio. C++ vine cu o nou
bibliotec de I/O numit iostream. Biblioteca nu conine o colecie de
funcii ci o colecie de obiecte care permit accesul la ecran pentru
afiare i la tastatur pentru citirea datelor introduse de utilizator.
Aceste obiecte au definite cte o metod pentru lucrul cu fiecare
tip de date simple (int, long, float, double, char), eliminnd astfel
177
necesitatea precizrii tipului i a formatului datelor care urmeaz a fi
scrise sau citite.
Cnd un program C++ care include headerul iostream.h este
lansat n execuie, atunci sunt create i iniializate automat
urmtoarele patru obiecte:
cin gestioneaz intrarea standard (tastatura);
cout gestioneaz ieirea standard (ecranul);
cerr gestioneaz ieirea ctre dispozitivul standard de eroare
(ecranul), neutiliznd bufere;
clog gestioneaz ieirea ctre dispozitivul standard de eroare
(ecranul), utiliznd bufere.
Cnd este vorba se operaii de intrare/ieire trebuie s avem n vedere
o surs emitent a unui flux de date i o destinaie care recepioneaz
aceste date. n afar de aceastea avem nevoie i de un mijloc de
comunicare ntre surs i destinaie. Aici intervin operatorii.
S vedem, n continuare, cum se face afiarea i citirea tipurilor
de date standard n limbajul C++ folosind obiectele de mai sus.

x = 33; f = 1.5;
Printf("x = %d f = %f", x, f);
x = 33; f = 1.5;
cout << "x=" << x <<"f ="<<f ;
Printf("\n"); cout << endl;
Printf("%c", 'C'); cout << 'C';
Printf("%s", "Limbajul C\n"); cout<<"Limbajul C++"<< endl;
x; scanf("%d", &x); x; cin >> x;
f; scanf("%f" &f); f; cin >> f;
ch; scanf("%c", &ch); ch; cin >> ch;
sir[25]; scanf("%s", sir); sir[25]; cin >> sir;

Din tabelul de mai sus reiese c cout ine locul lui stdout, cin
nlocuiete stdin i operatorii << i >> a fost redefiniti n scopul
introducerii/extragerii datelor.
Se observ c nu mai este necesar precizarea tipului i
formatului datelor deoarece operatorii care lucreaz cu fluxuri sunt
capabili s depisteze tipul fiecrei variabile transferate. Mai mult,
orientarea operatorului ne indic sensul n care are loc transferul
datelor.
178
n exemplul de mai sus afiarea s-a produs utiliznd de fiecare dat un
format implicit. Exist posibilitatea modificrii formatului implicit
prin precizarea alinierii, umplerii, a dimensiunii spaiului ocupat, a
bazei de numeraie i a preciziei. O baz de numeraie odat stabilit
se menine pn cnd se face o nou precizare n acest sens.
Instruciunile urmtoare:
# <iostream.h>
# <iomanip.h>
main(){
cout<<setw(8)<<setfill('*')<<12345<<endl;
cout<<setw(8)<<setprecision(3)<<6.0231<<endl;
cout<<setw(8)<<setfill('0')<<oct<<12345<<endl;
cout<<setw(8)<<setfill('0')<<dec<<123456<<endl;
cout<<setw(8)<<hex<<123456<<endl;
}
produc urmtorul rezultat:
***12345
6.023
00030071
00123456
0001e240
ncapsularea nu presupune numai simpla combinare a metodelor i a
datelor ca o singur entitate ci i o posibilitate de a limita accesul la
datele i metodele membre unei clase mai ales n situaii n care se
dorete prevenirea modificrii accidentale a datelor aparinnd unui
obiect. n cadrul declarrii unei clase, prin folosirea unor modificatori
de acces, se poate preciza unul din cele trei niveluri de acces la datele
i metodele clasei, astfel:
private este modul implicit, membrii de acest tip sunt accesibili
numai metodelor membre i a funciilor de tip friend, aceste
elemente sunt considerate proprii, intime clasei n care au fost
declarate i nu vor fi accesibile n clasele derivate;
protected este similar modului private, n plus membrii sunt
accesibili i n metodele claselor derivate (n cazul motenirii
publice), acest modificator este recomandat s se foloseasc n
clasele ce urmeaz s fie extinse;
179
public toate atributele i metodele publice pot fi accesate sau
apelate din orice punct din program exterior clasei, unde este
cunoscut clasa.
Trebuie s reinem c limbajul C++ nu impune o anumit ordine de
folosire a acestor modificatori, iar atributele i metodele fr
modificator de acces sunt considerate private. Seciunile unei clase pot
aprea de mai multe ori n cadrul declaraiei unei clase. n cele mai
multe situaii datele membre se vor plasa n seciunile protejate pentru
a permite accesul acestora din cadrul claselor derivate. De asemenea
se recomand evitarea plasrii datelor n seciunea public. Se reco-
mand folosirea funciilor membre pentru iniializarea i prelucrarea
datelor membre. Clasele pot avea mai muli constructori (de obicei
publici) i cel mult un destructor public.
n cazul nostru metodele care urmeaz imediat dup cuvntul
public sunt publice, cu alte cuvinte acestea pot fi accesate din exterior
oriunde n program unde clasa Point este accesibil. Cu alte cuvinte
domeniul de vizibilitate al atributelor i metodelor este acelai cu
domeniul de vizibilitate al clasei.

Definirea unui nou tip de date este format din dou pri: declaraia i
definiia (implementarea) metodelor declarate ca aparinnd clasei.
Faptul c o metod aparine unei clase, este specificat prin plasarea
prototipului acesteia n cadrul declaraiei clasei respective. n mod
normal corpul metodei va fi definit n afara declaraiei clasei.
Implementarea metodelor n afara clasei va trebui s foloseasc
numele clasei pentru care se definesc metodele mpreun cu operatorul
de apartenen "::", aa cum se poate observa n exemplul ce urmeaz.
Se recomand ca implementarea urmtoare s fie introdus ntr-un
fiier cu extensia "cpp" (exemplu: Point.cpp).
Point::Point(){x=0; y=0;}
Point::Point( x0, y0){x=x0; y=y0;}
Point::~Point(){ }
Point::Print(){
cout<<Point: <<" x = "<< x; cout<<" y = "<<y<<endl;
}
Point::Read(){
cout<<"x = "; cin >> x; cout<<"y = "; cin >> y;
}
180
Exist situaii n care unei funcii membre a unui obiect trebuie s-i
transferm ca parametru chiar o referin sau un pointer la obiectul
respectiv. Un alt caz este acela n care o funcie trebuie s returneze un
pointer la obiectul din care face parte sau o copie a obiectului. Pentru
astfel de situaii limbajul C++ a definit un pointer special numit .
Acest pointer conine ntotdeauna adresa n memorie a obiectului
pentru care se apeleaz metoda, deci return this; ntoarce un pointer
la obiectul curent iar return *this; intoarce o referin sau obiectul
nsui. Acest pointer se poate folosi i n interiorul metodelor pentru a
deosebi datele membre de parametrii formali, aa cum se poate obser-
va n definiia funciei membre Set(int, int) din exemplul de mai jos.
Uneori se dorete ca o anumit metod s fie definit chiar n
interiorul clasei aa cum este metoda getX, aceasta devenind o funcie
Astfel de funcii se pot defini i n afara clasei, dar n acest caz
la declaraie trebuie precedate de cuvntul cheie inline.
Point{
x,y;
:

getX(){ x;}
getY(){ y;}
Set( , );
Area();
};
Point::Set( x, y){
->x=x;
->y=y;
}
Point::Area(){ 0.0;}
Datorit ncapsulrii se poate limita accesul la datele membre ale unei
clase. n astfel de situaii inspectarea din exterior a datelor protejate se
va face prin funcii de acces, declarate ca fiind publice, care vor
returna valorile datelor protejate i vor asigura protecia la modificri
nedorite. Se tie c accesul la un element membru al unei structuri este
mult mai eficient n comparaie cu apelul unei funcii deoarece apelul
este mare consumator de timp.
Aici intervin funciile . Aceste funcii reprezint o
combinaie ntre funcii i macrodefiniii, iar aceast proprietate
special face ca orice apel al unei funcii inline s fie substituit de
corpul acesteia. Pentru a reui substituirea, compilatorul trebuie s
181
cunoasc forma i coninutul exact al funciei n momentul compilrii.
Acest lucru nu este valabil pentru funciile care conin bucle iterative.
Exist un numr destul de mare de aplicaii n care programatorul are
nevoie s foloseasc date membre care aparin conceptual mai mult
claselor dect instanelor acestora. Aceste date membre pot fi utile n
urmtoarele situaii:
cnd se urmrete numrul de instane ale unei clase;
cnd se dorete alocarea unui bloc special de memorie sau
deschidera unui fiier pentru diferite obiecte ale clasei;
cnd toate instanele partajeaz un tablou de structuri, folosit ca o
baz de date miniatural;
cnd un set de date membre trebuie s aib aceleai valori
indiferent de instan, cum ar fi coordonatele mouse-ului sau
cursorului.
Pentru toate aceste cazuri, C++ ofer soluia membrilor statici.
Folosirea membrilor statici n definirea unei clase implic respectarea
urmtoarelor reguli:
declararea unui membru static se face prin specificarea cuvntului
cheie static n faa tipului datei membre;
accesarea membrilor statici ai unei clase din interiorul funciilor
membre se face la fel ca accesarea membrilor obinuii (nestatici);
este obligatorie iniializarea membrilor statici n afara declaraiei
clasei chiar dac acetia au fost declarai n seciunile private sau
protected, iniializarea se va face n fiierul n care este imple-
mentat clasa niciodat n headerul clasei i nu va fi precedat de
cuvntul cheie ;
membrii statici exist separat de celelalte date membre ale unei
clase i pot fi accesai chiar i fr a declara un obiect de acel tip,
accesul facndu-se pe baza numelui clasei ca n exemplul de mai
jos:
Mouse{
:
xPos, yPos;
Mouse(){};
SetPos( x, y){
xPos = x; yPos = y;
}
};
182
Mouse::xPos = 0; Mouse::yPos = 0;
main(){
Mouse m;
m.SetPos(10,15);
cout<<Mouse::xPos<<" "<< Mouse::yPos<<endl;
}

Funciile membre statice se declar la fel ca membrii statici prin


plasarea cuvntului cheie static n faa declaraiei funciei. Accesul la
o metod static se realizeaz n mod identic cu cel la un membru
static. Adic putem apela o metod static a oricrui obiect, dar o
putem apela i far s avem un obiect declarat, folosind n acest caz
numele clasei umat de operatorul "::". Funciile membre statice se
deosebesc de cele nestatice prin faptul c nu posed pointerul this. Ca
urmare, nu poate ntoarce pointerul this sau obiectul *this i nu va
putea accesa n mod direct dect alte elemente (date i funcii) statice
ale clasei. Deci o funcie static nu poate s apeleze o funcie membr
nestatic i nu poate citi sau modifica datele nestatice ale clasei din
care face parte (dect dac i se transfer ca parametru un obiect sau o
referin/pointer la acesta).
Cursor{
xo, yo; //originea
x, y;
:
Cursor( x1, y1) {x = x1, y = y1;}
SetOrigin( x1, y1) {
xo = x1, yo = y1;
}
GetPos( & xp, &yp) {
xp = xo + x; y = yo + y;
}
};//Sfrit Cursor
Cursor::xo = 0; Cursor::yo = 0;
main(){
Cursor::SetOrigin(10,10);
Cursor c(5,2);
x,y; c.GetPos(x,y);
cout<<" x = "<<x<<" y = "<<y<<endl;
}
183
n limbajul C++ constructorii sunt funcii membre speciale care
asigur crearea i distrugerea corect a obiectelor. Constructorul unei
clase este prima metod care este apelat la declararea unui obiect,
imediat dup alocarea memoriei necesare datelor membre.
Constructorul este apelat imediat ce o variabil intr n domeniul ei de
vizibilitate, adic atunci cnd execuia unui program "atinge"
instruciunea n care aceasta este declarat. Un constructor poate
indeplini o mare varietate de sarcini, ca de exemplu iniializarea
variabilelor interne, alocri dinamice de memorie, deschidere de fiiere,
etc. Avem urmtoarele reguli privind constructorii:
numele unui constructor trebuie s fie identic cu numele clasei;
constructorii nu returneaz nimic, nici mcar tipul ;
constructorul poate apela alte funcii membre sau nu;
constructorul nu poate fi virtual;
constructorul, ca orice alt metod poate fi suprancrcat, pot s
existe, deci, mai muli constructori ntr-o clas, avnd acelai
nume cu numele clasei, dar deosebindu-se prin lista de parametrii
formali;
o clas poate avea orici constructori, inclusiv nici unul, dac nu
s-a declarat nici un constructor compilatorul genereaz un
constructor implicit, public, fr parametrii;
constructorul implicit, folosit fr parametrii la iniializarea
obiectelor, dac este definit, trebuie s fie definit fr parametrii
sau s foloseasc valori prestabilite ale parametrilor formali;
n mod normal constructorii sunt declarai ca fiind publici, n
cazuri speciale acetia pot fi declarai private i nu vor putea fi
apelai dect din cadrul altor funcii membre sau de tip ,
clasele din aceast categorie se numesc clase private;
dac o clas conine date membre constante sau referine la
obiecte, atunci constructorul trebuie scris n aa fel nct s
iniializeze referinele naintea celorlalte date membre;
constructorul de copiere iniializeaz un obiect printr-o operaie de
copiere a datelor dintr-un obiect existent, avnd o referin la
acesta;
dac n cadrul unei clase nu este declarat un constructor de
copiere, compilatorul creaz unul implicit;
se recomand definirea unui constructor de copiere n special cnd
se lucreaz cu clase care manevreaz structuri de date dinamice,
aceti constructori realizeaz o copie profund a obiectelor, care
184
implic i datele alocate dinamic, n timp ce constructorul de
copiere introdus de compilator realizeaz o copie superficial a
obiectelor, copiind doar datele membre ale claselor bit cu bit.
# "Point.h"
# pi 3.14159265
Circle{
:
Circle(){radius = 0;}
Circle( r){radius = r;}
Circle( x, y, r){ Set(x,y,r);}
Circle(Circle&);
Area(){ pi * radius * radius;}
:
Point center; radius;
:
Read(); Print(); Set( , , );
};
Circle::Circle(Circle &a){ center = a.center; radius = a.radius;}
Circle::Set( x, y, r){ center.Set(x,y); radius = r;}
Circle::Read(){center.Read(); cout<<"Raza = "; cin >> radius;}
Circle::Print(){cout<<Circle:<<end;center.Print();
cout<<"Radius = "<<radius<<endl;}
Destructorul este entitatea care dezactiveaz toate funciile unui obiect
nainte de eliberarea memoriei ocupate de acesta. Destructorii ca i
constructorii pot efectua orice fel de operaii, dar de obicei sunt
utilizai n clase care manevreaz structuri de date alocate dinamic sau
care opereaz cu fiiere sau cu fluxuri de comunicaie. Destructorul
este apelat ori de cte ori se "atinge" punctul final al domeniului de
vizibilitate al unei variabile, ca de exemplu: ntoarcerea dintr-o funcie,
terminarea unei bucle (pentru variabilele automatice declarate n
interiorul unei bucle, etc). Perioada dintre momentul crerii unei
variabile i momentul distrugerii sale se numete "durat de via".
Trebuie respectate urmtoarele reguli de folosire a destructorilor:
numele destructorului trebuie s fie identic cu cel al clasei care l
conine i trebuie s fie precedat de caracterul tilda "~";
destructorul nu returneaz nici un tip de date, nici mcar ;
185
destructorul nu poate avea parametrii;
o clas nu poate avea mai mult de un destructor, dac pentru o clas
nu este precizat nici un destructor atunci compilatorul creaz un
destructor pentru clasa respectiv;
dac un obiect conine ca date membre alte obiecte atunci
destructorii obiectelor membre sunt apelai dup ce destructorul
clasei a fost executat, ordinea n care sunt distruse componentele este
invers fa de cea n care au fost create (ordinea din declaraia
clasei);
n timpul execuiei programului este apelat automat destructorul
obiectelor a cror durat de viaa a expirat.
Astfel, durata de via a obiectelor este:
obiectele automatice: sunt locale unei funcii i de aceea sunt
pstrate (create i utlizate) pe stiv, acestea exist atta timp ct
"exist" funcia, se creaz n prologul funciei i se distrug n
epilogul acesteia de ctre destructor;
obiectele statice: sunt declarate n afara funciilor sau n interiorul
funciilor cu ajutorul cuvntului cheie static, acestea sunt create la
nceputul programului i exist pe ntreaga durat de execuie a
programului, la terminarea programului se apeleaz destructorul
fiecrui obiect static;
obiecte dinamice: sunt utilizate prin alocare de locaii din heap o
zona de memorie special - sunt create cu operatorul new i sunt
eliberate explicit cu operatorul delete, pot exista i dup terminarea
funciei n care au fost create cu operatorul new, nu sunt eliberate
automat;
obiecte membre ale altor obiecte sunt create/distruse atunci cnd
obiectul cruia i aparin este creat/distrus.

n limbajele de programare un loc central l ocup conceptul de tip de
date. Fiecare variabil care este prelucrat ntr-un program este de un
"anumit tip" predefinit sau definit de programator.
n limbajele de programare orientate obiect tipurile de date
definite de programator, sau tipurile abstracte sunt mai importante.
Declararea unei variabile de un anumit tip abstract se numete
instaniere, iar variabilele se numesc obiecte sau instane ale clasei.
Sintaxa este asemnatoare cu cea a declaraiilor de variabile.
186
# "Point.h"
# "Circle.h"
main(){
Point A, B(1,2);
Point C = Point(3,3);
A.Set(10,5);
A.Print();
A = C;
A.Print();
Circle C1,C2(10);
Circle C3 = Circle(10,10,10);
Circle C4(C3), C5 = C4;
C1.Read();
C1.Print();
C5.Print();
}
Deoarece declaraia lui C1 nu specific nici un argument compilatorul
apeleaz constructorul fr parametrii, C2 se va iniializa cu ajutorul
constructorului cu doi parametrii, instana C4 va fi o copie lui C3 (primit
ca argument), deci pentru C4 se va utiliza constructorul de copiere.
O alt metod de iniializare folosete listele de instaniere. Lista
membrilor clasei ce urmeaz a fi iniilizai se plaseaz ntre lista de
parametrii a costructorului i corpul acestuia. Lista este format din
constructori cu parametrii specifici, cte unul pentru fiecare membru
ce trebuie iniializat n acest mod. Aceast metod este singura care se
poate folosi la iniializarea clasei ce conine date membre constante,
referine la obiecte sau obiecte fr constructor implicit public. Un
aspect important legat de listele de instaniere este ordinea n care se
face iniializarea n cadrul acesteia, mai ales dac la iniializarea unor
membrii se folosesc valorile altora.
Ordinea de instaniere a datelor membre este dat ntotdeauna de
ordinea n care datele apar n declaraia clasei i nu de ordinea
acestora n lista de instaniere. Dac un obiect membru conine n
declaraia clasei sale constructor implicit atunci acest obiect poate lipsi
din lista de instaniere. n cazul n care un membru al unei clase este
un pointer la un obiect atunci nu putem iniializa pointerul n cadrul
listei de instaniere, constructorii nu pot fi apelai pentru pointeri la
obiecte (n aceast list) ci numai pentru obiecte i referine.
187
# "Point.h"
Rectangle{
:
Point A, B;
:
Rectangle(){ }
Rectangle( x1, y1, x2, y2):
A(x1,y1),B(x2,y2){ }
Rectangle(Point &a, Point &b ):A(a), B(b){ }
Rectangle(Rectangle & r):A(r.A), B(r.B){ }
Area(){return (B.x-A.x)*(B.y-A.y);};
};
Aa cum construim tablouri sau matrici de structuri n limbajul C, tot
aa putem construi tablouri sau masive de obiecte. Iat, de exemplu,
cum putem defini un triunghi:
Point triunghi[3] ;
Pentru fiecare element al tabloului se va apela constructorul implicit.
Triunghiul poate fi iniializat aa cum se iniializeaz tablourile de
structuri dac obiectele componente conin doar membrii publici, nu
conin metode virtuale i nu provin din clase derivate.
Point triunghi[3] = {{0,0},{0,3},{4,0}};
Un alt mod de iniializare a tabloului poate folosi lista de constructori
ntr-un mod asemntor cu utilizarea listei de instaniere, iniializarea
tabloului poate fi parial deoarece pentru restul elementelor se
apeleaz constructorul implicit:
Point triunghi[10] = {Point(), Point(0,3), Point(4,0)};

Pentru alocarea i eliberarea dinamic a memoriei n limbajul C avem


la dispoziie funciile malloc i free. Limbajul C++ introduce doi
operatori noi pentru a facilita operaiile cu memoria alocat dinamic n
contextul programrii orientate obiect. Aceti operatori sunt
pentru alocarea memoriei i pentru eliberarea acesteia.
Avantajele folosirii operatorului new n comparaie cu utilizarea
funciei malloc sunt:
operatorul new tie ce cantitate de memorie trebuie alocat pentru
orice tip de date, n timp ce funciei malloc trebuie s i se specifice
aceast dimensiune;
188
tipul pointerul returnat de operatorul new este acelai cu tipul
pointerului care va memora adresa zonei de memorie alocate de
operator, nu este nevoie de nici un fel de conversie;
operatorul new poate apela un constructor sau poate iniializa
variabila standard alocat, spre deosebire de malloc care nu are
aceast proprietate;
funcia malloc ntoarce un pointer la void ceea ce ne oblig s
facem o conversie la tipul ateptat;
operatorul new poate fi utilizat n manevrarea de masive.
*p = ( *) malloc(sizeof( ));
*m = ( *) malloc(1000* sizeof( ));
*p = ;
*m = [1000] ;
*pzero= (20);//aloc un int i l iniializeaz cu 20
*ch= ('A');//aloc un char i l iniializeaz cu A
Operatorul new a fost special introdus pentru construirea dinamic a
obiectelor, astfel urmtoarea declaraie aloc memorie n heap pentru
a stoca un obiect din clasa Point i apoi apeleaz constructorul cu doi
parametrii pentru iniializarea obiectului.
Point *pPoint = Point(10,10);
n mod asemntor se poate aloca i iniializa un tablou de obiecte, n
acest caz se va apela constructorul implicit (fr parametrii) pentru
fiecare obiect din tablou;
Point * t = Point[1000];
Operatorul este similar cu funcia free din limbajul C, avnd ca
scop eliberarea memoriei din heap alocate cu ajutorul operatorului
. Operatorul apeleaz un constructor pentru iniializarea
memoriei alocate, n mod similar operatorul apeleaz destruc-
torul imediat naintea eliberrii memoriei ocupate de un obiect.
Atenie, pentru eliberarea de masive acest operator are o sintax
diferit. Astfel, dac alocm un tablou prin
atunci nu va elibera ntregul ir ci doar primul octet sir[0].
Pentru a elibera tot tabloul va trebui s scriem .
189
# <iostream.h>
# <stdlib.h>
String{
*data;
len;
Init( * str){
len = strlen(str);
data = [len+1];
strcpy(data,str);
}
:
String(){data = ; len = 0;}
String(String & str){Init(str.data);}
String( *str) {Init(str);}
~String(){ //destructor
(data) {
cout<<"Destructor: "<<data<<endl;
[] data;
}
}
Concat(String &str){ Concat(str.data); }
Concat( *str){
len2 = strlen(str);
data = ( *)realloc(data, len + len2 +1);
data[len]=0;
strcat(data,str);
len += len2;
}
Print(){ (data) cout<<data<<endl; }
};
main(){
String s1 = String("Clasa String in ");
s1.Concat("programarea OOP cu ");
String s2("Limbajul C++ ");
s1.Concat(s2);
s1.Print();
//alocare dinamica
String *s = String();
s->Concat(s4);
190
s->Concat("cu alocare dinamica!");
s->Print();
s;
//alocarea unui tablou de obiecte
String *stab = String[10];
stab[0].Concat(s2);
stab[0].Print();
//eliberarea tabloului de obiecte
[] stab;
//alocarea unui tablou de pointeri la obiecte
String* *ptab = String*[10];
//alocarea fiecarui obiect din tablou
( i=0;i<10;i++) ptab[i] = String("Sir de caractere!");
//afisarea sirurilor
( i=0;i<10;i++) (ptab[i]) ptab[i]->Print();
//eliberarea sirurilor
( i=0;i<10;i++) (ptab[i]) ptab[i];
//eliberarea tabloului de pointeri
[] ptab;
}

Datele private i protejate membre ale unei clase poat fi accesate doar
de funciile membre ale clasei respective. Exist cazuri cnd dorim s
permitem accesul la datele membre (private i protejate) i altor
funcii, care pot fi membre ale altor clase sau nu. Acste funcii se
numesc
191
modificate de toate funciile membre ale clasei prietene. n ambele
variante una dintre clase trebuie s fie predeclarat.
:
# <iostream.h>
Complex;
Scalar{
float nr;
:
Scalar(){nr = 0.0;}
Scalar( s){nr = s;}
Complex;
};
Complex{
float re, im;
:
Complex(){ re = im = 0.0;}
Complex( r, i){
re = r, im = i;}
Complex(Complex & c){
re = c.re, im = c.im;}
Complex Add(Scalar & s);
Complex Mul(Scalar & s);
Complex Add(Complex& c1, Complex & c2);
Complex Mul(Complex& c1, Complex & c2);
Print(Complex & c);
};
Print(Complex &c){
cout<<c.re;
(c.im > 0)
cout << "+"<<c.im<<"i"<<endl;
(c.im < 0)
cout << c.im<<"i"<<endl;
}
Complex Add(Complex& c1, Complex & c2){
Complex rez;
rez.re = c1.re + c2.re;
rez.im = c1.im + c2.im;
rez;
}
192
Complex Mul(Complex& c1, Complex & c2){
Complex rez;
rez.re = c1.re * c2.re - c1.im*c2.im;
rez.im = c1.re*c2.im + c1.im*c2.re;
rez;
}
Complex Complex::Add(Scalar & s){
Complex(re+s.nr, im);
}
Complex Complex::Mul(Scalar & s){
Complex(re * s.nr, im * s.nr);
}
main(){
Complex c1(1,-1); Print(c1);
Complex c2(c1), c3;
c3 = Add(c1,c2); Print(c3);
c3 = Mul(c1,c2); Print(c3);
Scalar sc(1.3);
c3 = c1.Add(sc); Print(c3);
c3 = c1.Mul(sc); Print(c3);
}

Motenirea este unul dintre cele mai importante concepte ale


limbajelor de programare pe obiecte. Acesta permite extinderea
claselor existente i aduce posibilitatea construirii de noi clase ntr-un
mod simplu. Motenirea permite transferul atributelor i a metodelor
unei clase construite anterior, numit clas de baz, ctre o nou clas
numit clas derivat. Deci clasele derivate au toate caracteristicile
claselor de baz i, n plus, pot introduce noi elemente structurale i
funcionale. Motenirea n limbajul C++ este de dou feluri: a) mote-
nire simpl prin care o clas extinde o singur clas de baz; b) mo-
tenire multipl prin motenire multipl trsturile a dou sau mai
multe clase pot fi nglobate i eventual exinse ntr-o clas nou.
La prima vedere motenirea se aseamn cu procesul de includere
a obiectelor n obiecte (refolosire), dar difer de acesta prin urm-
toarele:
codul poate fi comun mai multor clase;
clasele pot fi extinse fr a fi recompilate (extensibilitate);
funciile care prelucreaz obiecte din clasa de baz vor prelucra
automat i obiecte din clasa derivat (abstractizare);
193
sintaxa folosit la derivare este urmtoarea:
class clasaDerivata [tipMostenire]clasaBaza
{
//noi membrii
};
unde tipMostenire este un modificator opional i poate fi unul din
urmtoarele: , , (implicit) sau .

# pi 3.14159265
Circle : Point{
:
radius;
:
Circle() { radius = 0;}
Circle( r){ radius = r;}
Circle( x, y, r):Point(x,y){radius=r;}
Circle::Circle(Circle &c){
Set(c.x,c.y,c.radius);
}
Area (){
2* pi* radius * radius;
}
Circle::Set( x, y, r){
//Point::trebuie precizat
//altfel incearc s se autoapeleze
//i se genereaza eroare: nr de parametrii
Point::Set(x,y);
radius = r;
}
Print(){
cout<<"Circle: "<<endl;
Point::Print(); cout<<"radius = "<<radius<<endl;
}
}; //Clasa Circle
Cylinder: Circle{
:
height;
:
Cylinder(){ height =0;}
Cylinder( r, h):Circle(r){ height = h;}
194
Cylinder( x, y, r, h):
Circle(x,y,r){ height = h;}
Cylinder(Cylinder& c){
//mostenita de la Circle
Set(c.x, c.y,c.radius);
height=c.height;
}
//aria laterala
LArea(){
2*pi*radius*height;
}
//aria totala
Area(){
2*Circle::Area()+LArea();
}
Print(){
cout<<"Cylinder:"<<endl;
Circle::Print();
cout<<"height = "<<height<<endl ;
}
};
main(){
Point p; Circle c; Cylinder cy(1,1,10,10);
p = c = cy;
cy.Print();c.Print(); p.Print();
cout<< "Aria cilindrului = "<<cy.Area()<< endl;
cout<< "Aria cercului = "<<c.Area()<< endl;
}
n exemplu de mai sus se poate observa cum se poate extinde o clas
de baz construind clase derivate n vederea obinerii unor obiecte noi
cu funcionaliti sporite, cum elementele membre ale clasei de baz
devin date membre ale clasei derivate, se mai observ modul n care se
reutilizeaz (atenie la sintaxa unui apel de funcie motenit) codul
unor funcii preexistente fr s mai fie nevoie de recompilarea
acestora.
Din acest exemplu se mai poate desprinde un aspect foarte
interesant: obiectele claselor derivate sunt privite ca fiind obiecte ale
clasei de baz, ceea ce ne permite s atribuim obiectelor din clasa de
baz instane ale clasei derivate fr s fie necesar conversia de tip.
Aceast regul este valabil doar la obiectele care sunt legate prin
195
relaia de motenire i se extinde i asupra pointerilor i referinelor la
astfel de obiecte. Atribuirea este posibil doar n acest sens, o
ncercare de a atribui unui obiect din clasa derivat o instan a clasei
de baz fiind ilegal.
Point p;
Circle c;
Cylinder cy;
Point & pr = p;
Circle & cr = c;
Cylinder & cyr=cy;
pr = cr = cyr;
Point * pp; Circle * pc;
Cylinder *pcy = Cylinder(10,25);
pp = pc = pcy;
Ce rezultat va produce codul urmror ?
Circle * c1 = Cylinder(10,25);
c1->Print();
cout<<"Aria = "<< c1->Area()<<endl;
n exemplul de mai sus am discutat motenirea de tip public, n acest
caz datele publice/protejate n clasa de baz ramn publice/protejate i
n clasa derivat, cele private (intime clasei de baz) sunt inaccesibile
direct, aceste putnd fi manipulate cu ajutorul funciilor de acces.
Mai trebuie menionat faptul c la inializarea obiectelor nti
sunt apelai constructorii claselor de baz dup care se execut corpul
constructorului clasei derivate. Constructorii nu pot fi motenii, deci
nu putem folosi un constructor al clasei de baz pentru a iniializa toi
membrii clasei derivate. n plus, dac toi constructorii clasei de baz
necesit parametrii atunci clasa derivat trebuie s conin un con-
structor care s apeleze (n lista de instaniere) unul din constructorii
clasei de baz cu parametrii potrivii. Deci, prezena constructorilor n
clasele derivate devine, n unele cazuri, obligatorie.
Destructorii claselor de baz sunt apelai n ordine invers fa
de ordinea de iniializare, nti destructorul clasei derivate apoi
destructorii claselor derivate. Destructorul fiind funcie fr parame-
trii, prezena acestuia n clasele derivate este opional.
n continuare urmeaz un tabel n care se poate observa modul n
care se motenesc datele, pe cele trei niveluri de protecie i prin cele
trei tipuri de moteniri mai importante.
196

Tipul motenirii
public n clasa
derivat
protected n
clasa derivat
private n
clasa derivat
Protected n
clasa derivata
protected n
clasa derivat
private n
clasa derivat

n

c
l
a
s
a

d
e

b
a
z


ascuns n clasa
derivat
ascuns n clasa
derivat
ascuns n
clasa derivat


Deseori, prin motenire clasa derivat primete un set de funcii de la
clasa de baz care, din cauza modificrilor de structur a clasei
derivate, nu produc rezultatul dorit atunci cnd sunt apelate pentru
obiecte din clasa derivat. Un astfel de exemplu este funcia Area()
din clasa Point care este motenit de clasa Circle i de la aceasta de
Cylinder. Apelul acestei metode pentru puncte ntoarce ntotdeauna
zero, ceea ce nu este corect i pentru un cerc sau cilindru. De aceea
aceast funcie a fost redefinit (supradefinit) n aceste dou clase.
tim acum c obiectelor clasei de baz (Point) putem s le atribuim
obiecte din clasa derivat (Circle) fr a mai fi necesar o conversie
de tip. Obiectul rezultat dup atribuire aparine tot clasei de baz
(Point), n consecin pentru apelul metodei Area pentru acest obiect
se va executa varianta definit n clasa Point. Aceasta se datoreaz
faptului c apelul metodei este legat de corpul acesteia n
momentul compilrii, compilatorul putnd identifica nc din aceast
faz care variant trebuie asociat apelului i executat:
Point p;
Circle c;
p = c;
cout<<p.Area()<<endl; //afieaz zero
Atunci cnd discutm despre pointeri i referine la obiecte lucrurile
stau altfel. n cazul n care am declarat o referin sau un pointer la un
obiect din clasa de baz avem posibilitatea s le iniializm cu adresele
din memorie a unor obiecte aparinnd claselor derivate, ca n
exemplul de mai jos. Dup o astfel de iniializare avem un singur
197
nume de metod i dou posibiliti, dou forme ale funciei. n acest
moment discutm de .
Point *pp = new Circle(1,1,5);
cout<< pp->Area() << endl;
Noi am dori ca pentru apelul metodei Area() s fie aleas pentru
executare varianta funciei definit n clasa Circle. Dar nu se ntmpl
aa. Pointerul pp conine adresa unui Circle, dar metoda apelat este
Point::Area(), ceea ce va duce la afiarea valorii zero. La rezolvarea
acestei probleme intervin funciile virtuale i mecanismul de legare
. Pentru a fi apelat metod corect n funcie de tipul
obiectului care se afl la adresa stocat n pointer trebuie s declarm
metoda Area() ca fiind virtual. Pentru aceasta va trebui s plasm
cuvntul cheie n faa declaraiei funciei membre Area().
Point{

Area(){ }
};
Prin aceasta anunm compilatorul s nu aleag n momentul compi-
lrii care variant a funciei Area() s fie asociat unui apel prin poin-
teri sau referine. n acest caz compilatorul nu tie n momentul
compilrii care este tipul obiectului la care se refer pointerul sau
referina, iar corpul metodei va fi ales n timpul rulrii programului.
Aceast alegere i asociere din momentul executrii programului
folosete identificarea i legarea dinamic a metodelor.
void PrinArea(Point & p){
cout << p.Area()<<endl;
}
void main(){
Point p(3,3); Circle c(1,1,3);
PrinArea(p); PrinArea(c);
}
Regulile impuse de limbajul C++ cu privire la funciile virtuale sunt:
o funcie membr odat declarat virtual va rmne virtual n
toate clasele derivate;
funciile virtuale nu pot fi suprancrcate;
constructorii nu pot fi virtuali pentru c acetia nu pot fi motenii;
destructorii pot, i de cele mai multe ori, vor fi virtuali pentru a
asigura o distrugere corect a obiectelor aparinnd claselor
derivate;
198
funciile virtuale pot apela funcii obinuite (nonvirtuale) ;
funciile nonvirtuale pot apela funcii viruale;
funciile virtuale pot apela orice alt funcie virtual;
funciile virtuale pot apela funcii redefinite.

Acest tip de motenire permite unei clase s primeasc toate
trsturile (n afar de cele private) a dou sau mai multe clase.
Sintaxa general pentru motenire multipl este urmtoarea:
clasaDerivata [tipMostenire1]clasaBaza1,
[tipMostenire2]clasaBaza2,
{ //noi membrii };
Tipul motenirii (1 i 2) poate fi omis (i atunci este considerat
private), poate fi precizat o singur dat la nceputul listei pentru
pentru toate clasele de baz din list, sau poate fi precizat pentru
fiecare clas de baz n parte (ca n exemplul de mai jos). Accesul la
membrii claselor de baz din funciile membre ale clasei derivate se
supune regulilor precizate n tabelul de mai sus pentru fiecare clas de
baz.
n exemplul care urmeaz am definit o clas Stack care imple-
menteaz funciile i ale unei clase GenericStack, si
folosete o list simplu nlnuit pentru a memora elementele n stiv.
Se poate observa c am precizat clasei Node c GenericStack este o
clas prieten, pentru a facilita accesul direct la membrii privai ai
clasei Node din cadrul funciilor membre clasei GenericStack. Clasa
LinkedList este motenit folosind tipul protejat pentru a mpiedica
apelul metodelor publice InsertHead i ExtractHead din exterior
asupra unui obiect de tip Stack, deoarece aceste metode i pierd
semnificaia n noul context. Funcia f( ) care opereaz cu stive
generice lucreaz n mod corect deoarece metodele i sunt
declarate virtuale. Clasa Stack nu este obligat s redefineasc metode
i , pentru a fora aceasta cele dou metode se vor declara ca
fiind metode abstracte (sau virtuale pure) i clasa GenericStack va
deveni clas abstract.
Node{
inf; Node * next;
public:
Node(int x=0){inf = x;}
LinkedList;
};

199
GenericStack{
protected:
count;
public:
GenericStack(){count=0;}
Push( t){ }
Pop(){ 0; }
};
LinkedList{
Node * head;
:
LinkedList(){ head = NULL; }
InsertHead( t){
Node * p = Node(t);
p->next=head; head=p;
};
ExtractHead(){
t = -1;
(head) {
t= head->inf; Node * p = head;
head= head->next;
p;
}
t;
};
};
Stack:public GenericStack,protected LinkedList{
:
Stack(){}
Push(int t){ count++;InsertHead(t); }
Pop(){count --; ExtractHead();}
};
f(GenericStack & s){
s.Push(2);
cout<<s.Pop()<<endl;
}
main(){
Stack stack; stack.Push(1); cout<<stack.Pop()<<endl;
f(stack);
}
200


1. S se proiecteze o clas pentru implementarea structurii de date:
list liniar simplu nlnuit.
2. S se proiecteze o clas pentru implementarea structurii de date:
list liniar dublu nlnuit.
3. S se proiecteze o clas pentru implementarea structurii de date:
list circular simplu nlnuit.
4. S se proiecteze o clas pentru implementarea structurii de date:
arbore binar.
5. S se proiecteze o clas pentru implementarea structurii de date:
graf orientat.
6. S se proiecteze o clas pentru implementarea structurii de date:
graf neorientat.
7. S se proiecteze o clas pentru implementarea structurii de date:
vector de liste liniare simplu nlnuite.
8. S se proiecteze o clas pentru implementarea structurii de date:
vector de liste liniare dublu nlnuite.
9. S se proiecteze o clas pentru implementarea structurii de date:
vector de liste circulare simplu nlnuite.
10. S se proiecteze o clas pentru implementarea structurii de date:
vector de arbori binari.
11. S se proiecteze o clas pentru implementarea structurii de date:
vector de grafuri orientate.
12. S se proiecteze o clas pentru implementarea structurii de date:
vector de grafuri neorientate.
13. Proiectai o clas pentru manipularea matricelor ptratice. Inclu-
dei metode pentru operaiile de transpunere, schimbare a
semnului elementelor, nmulirea unei matrice cu un numr etc.
14. Proiectai o clas care s reprezinte noiunea de ir de caractere.
Considerai metode pentru implementarea operaiilor de intrare-
ieire utiliznd urmtoarele moduri: standard, fiier, n memorie;
metode pentru: afiarea codificrii ASCII a irului, determinarea
lungimii, concatenarea irului cu un alt ir etc.
15. Proiectai o clas pentru lucrul cu nregistrri. Includei metode de
intrare-ieire, accesarea componentelor etc.
201

6. Teste pentru verificarea cunotinelor


(Bacalaureat , sesiunea iunie 1999; test adaptat)
I. Se consider urmtoarea secvena n pseudocod:
a,b;
aa-b;
ba+b;
ab-a
a,b
a) Ce se va afia pentru valorile citite a = 5, b = 7?
b) Ce realizeaz secvena dat?
Ce metod de programare este folosit de secvena urmtoare de
program? (Procedurile i respectiv tipul se
consider declarate anterior n program);
metoda(p,q:integer,a: );
m:integer;

q-p<=2 nucleu(p,q,a)

m:=(p+q) 2;
metoda(p,m,a);
metoda(m+1,q,a);
sol(p,q,m,a);

;
Rescriei secvena de program de mai jos realizat cu structura ,
utiliznd:
a) o structur repetitiv cu test iniial;
b) o structur repetitiv cu test final;
n
p0; a1;
i<1.6
[pp+i*a; aa*n]
c)Explicai care sunt diferenele dintre structura repetitiv cu test
iniial i cea cu test final.
202
II. Se consider un vector cu n elemente reale.
a) Scriei o funcie recursiv care verific dac vectorul conine,
sau nu, cel puin un element pozitiv.
b) Scriei o procedur de tiprire a elementelor vectorului.
Se consider un fiier text cu numele MULT.IN care are dou
linii. Fiecare linie conine elementele (ce fac parte din mulimea {a
z, AZ, 09}) mulimilor A i B, separate ntre ele prin
cte un spaiu. S se scrie un program care:
a) Scrie pe prima linie din fiierul text MULT.OUT mesajul
DA dac A este inclus n B, respectiv NU n caz contrar.
b) Scrie pe a doua linie din fiierul MULT.OUT elementele
mulimii (A\B)(B\A), adic diferena simetric.
Dac fiierul MULT.IN conine
o a b c x y
9 c d e X g
atunci fiierul MULT.OUT va conine
NU
a b c d e g o x X Y 9
III. Se citete de la tastatur un numr natural n (n<=20), i un numr
natural v. Scriei un program comentat folosind metoda Backtraking
care afieaz toate numerele de la 1 la n n toate modurile posibile,
astfel nct ntre oricare dou numere afiate n poziii nvecinate,
diferena n modul s fie mai mare (>) dect valoarea dat v. Datele de
ieire se vor scrie n fiierul IESIRE.DAT. n cazul n care nu exist
soluie , n fiierul de ieire se va scrie: Nu exist soluie.
Dac n = 4 i v = 1 rezultatul din fiierul de ieire va fi
3 1 4 2
2 4 1 3
IV. Cunoscnd valoarea n < 50, reprezentnd numrul unor persoane
nscrise la un curs, scriei subprograme n Pascal sau n C pentru a
realiza urmtoarele cerine:
a) trebuie s creai o list simplu nlanuit ale crei elemente
trebuie s conin n partea de informaie propriu-zis numele i nota
de absolvire a cursanilor;
b) trebuie s tergei primul element din lista creat;
c) trebuie s afiai lista dat.
BAREM DE NOTARE (10p din oficiu)
: 1. a) 5p b) 2.5p; 2. 2.5p 3. a) 7.5p b)7.5p c)5p
: 1. a)7.5p b)7.5p 1.5; 2. 10p; . 20p; . a)5p b)5p c)5p
203
(Bacalureat simulare- februarie 1999; text adaptat)
1. Se consider urmtoarea secven de program:
N
Z0
n<>0
[ ZZ*10+N 10; NN 10 ]
Z
a) Ce valoare Z se va afia pentru N=11204?
b) Modificai o singur instruciune n aceast secven de program
astfel nct valoarea afiat pentru Z s reprezinte suma cifrelor num-
rului N.
2. Care din urmtoarele afirmaii sunt corecte i care sunt false?
a) Un subprogram este recursiv dac este apelat cnd subprogra-
mul este activ;
b) Recursivitatea este direct cnd apelul subprogramului apare
n instruciunea compus a unui subprogram;
c) Prin utilizarea tehnicilor recursive se obin ntotdeauna soluii
optime;
d) Autoapelul unui subprogram trebuie suspendat n momentul
ndeplinirii anumitor condiii.
3. Scrie secvena de program de mai jos utiliznd o structur repetitiv
cu numr cunoscut de pai.
N
p 1; i 1
i<=N [pp * i; ii + 1]
scrie p
1. Scriei un subprogram care returneaz o valoare logic pentru a
determina dac un numr este prim.
2. Scriei un subprogram recursiv pentru a aranja un ir de n numere
ntregi distincte (n<=25) n toate modurile posibile.
Un grup de n (n<=10) persoane numerotate de la 1 la n sunt aezate pe
un rnd de scaune, dar ntre oricare dou persoane vecine s-au ivit
conflicte. Scriei un program care afieaz toate modurile posibile de
reaezare a persoanelor, astfel nct ntre oricare dou persoane aflate
n conflict s stea una sau cel mult dou persoane.
204
Exemplu: Dac numrul persoanelor (introdus de la tastatur) este 4,
programul trebuie s afieze:
3 1 4 2
2 4 1 3
1. S se scrie un subprogram care concateneaz o list simplu
nlnuit de tip stiv (referit de q) n continuarea altei liste simplu
nlnuite de tip stiv (referit de p).
2. S scrie un subprogram care caut un anumit numr dat, citit de la
tastatur n subprogram i returneaz o valoare logic corespunz-
toare. Lista este definit astfel:
lista = ^nod; Nod = inf:integer; urm:lista ;
3. Se consider dou fiiere de tip text: f1 i f2. S se scrie un sub-
program care verific dac cele dou fiiere sunt identice din punct de
vedere al coninutului. n subprogram se vor scrie toate instruciunile
care testeaz fiierele.
(Bacalaureat- Simulare 2000; text adaptat)
I.1. ncercuii litera corespunztoare rspunsului corect.
Cte numere pot fi reprezentate folosind 8 bii?
a) 128
b) 256
c) 8*8 (5 puncte)
2.Stabilii, ncercuind litera A (adevrat) sau F (fals), valoarea de
adevr a urmtoarelor afirmaii care exprim diferena dintre
variabilele locale i cele globale:
. Variabilele globale sunt declarate n afara oricrui bloc al progra-
mului, n timp ce variabilele locale sunt declarate n interiorul blocului
n care sunt folosite;
(3 puncte)
. Variabilele locale sunt stocate n memorie, n timp ce variabilele
globale sunt stocate pe stiva; (3 puncte)
. Variabilele globale exist pe parcursul executrii ntregului
program, n timp ce variabilele locale nu exist dect n timpul
executrii blocului n interiorul cruia au fost declarate. (3 puncte)
3. n continuare avei prezentate posibile variante ale aceleiai
implementri sub form de subprogram, n Pascal i C, a algoritmului
ce determin numrul de cifre ale unui numr ntreg pozitiv. Stabilii
corectitudinea acestor implementri pentru una din variabilele de mai
jos (Pascal sau C), la alegere. Justificai rspunsul.
205
numar_1(n:Longint):integer;
numar_1:=
trunc(ln(n)/ln(10))+1
;
(5 puncte)

numar_2 (n:Longint):integer;
s: string[20]
str(n,s);numar_2:=length(s);
;
(5 puncte)
numar_3(n:Longint):Integer;
nr:integer;
nr:=0; n>0
nr:=nr+1; n:=n 10
;
numar_3:=nr
; (5 puncte)

numar_1 (long n){

floor (log(n)/log(10)+1;
}
(5 puncte)
numar_2 (long n){
char s[20];
ltoa(n,s,10);
strlen(s);
}
(5 puncte)

numar_3 (long n){
nr=0;
(n) {
nr++;
n/=10;
}
nr;
}
(5 puncte)

4. Definii notiunea de tablou pentru unul din limbajele Pascal sau C i
exemplificai adecvat. (6 puncte)
II Scriei un subprogram recursiv care s returneze valoarea lui n!,
unde nN* este o valoare dat, iar n! este produsul primelor n numere
naturale nenule. (10 puncte)
III Scriei un program, care s afieze toate modalitile prin care se
poate plti o sum s folosind n bancnote de valori b
1
<b
2
<b
3
<<b
n
. Se
presupune c avem la dispoziie oricte bancnote din fiecare tip.
Numerele S i n precum i valorile bancnotelor se citesc de la
tastatur, iar modalitile de plat vor fi scrise n fiierul BANI.OUT.
(25 puncte)
206
IV Scriei un program care citete de la tastatur un numr n. Din
fiierul INTRARE.TXT se citesc n numere reale i creeaz o list
simplu nlnuit pe care o scrie n fiierul IESIRE.TXT. (20 puncte)
(Bacalaureat - Sesiunea iunie-iulie 2000; enun adaptat)
I. Scriei litera sau literele corespunztoare rspunsului sau rspun-
surilor corecte, preciznd la fiecare subpunct care dintre variantele de
limbaj a fost considerat.
1.Care dintre urmtoarele secvene afieaz cel mai mare numr natural
care este mai mic sau egal cu valoarea variabilei reale pozitive x? (10p)
a) m: =0; a) m=0;
m<=x m:=m+1; (m<=x) m++;
writeln(m-1) cout m-1;
b) m:=0; b) m=0;
m:=m+1 m>x; {m+=1} (m<=x);
writeln(m) cout m;
c) m:=1; c) m=1;
m:=m+1 m>x; {m+=1} (m<=x);
writeln(m-1) cout m-1;
d) m:=0 x ; d) (m=0;m<x;m++);
writeln(m-1) cout m-1;
2. Care dintre urmtoarele variante reprezint declararea corect a
dou variabile de tip ntreg? (5p)
Varianta
a) x,y:=integer; a) integer x,y;
b) x:integer; y: longint; b) x; y;
c) float=integer; c) real ;
x,y:float; real x,y;
d) x: [1. .2] integer; d) x[2];
3. Care este valoarea returnat de funcia urmtoare la apelul f(4)? (5p)
f(x:integer):integer; f( x)
{
x<=0 f:=3 (x<=0) 3;
f:=f(x-1)*2 f(x-1)*2;
. }
a)16 b)24 c)48 d)3
207
II. Se consider urmtorul algoritm reprezentat prin programul
pseudocod:
a,b {numere naturale}
a>b ca ab bc
d0
i= a, b, 1
i este divizibil cu 2 dd+1;
m
1. Ce valoare se afieaz pe ecran, conform algoritmului dat pentru
a=18 i b = 33? (5p)
2. Precizai o valoare pentru variabila a i o valoare pentru varlabila b
astfel nct valoarea afiat ca urmare a executrii programului dat s fie
0. (5p)
3. Scriei programul Pascal, C sau C++ corespunztor algoritmului.
(10p)
4. Scriei un program echivalent care s nu conin nici o structur
repetitiv.
Cele dou programe sunt echivalente dac pentru orice valori naturale
citite pentru vanabilele a i b, ele afieaz aceeai valoare.(5p)
III. . In fiierul NUMERE.TXT se afl mai multe numere naturale
din intervalul [0 5000], scrise cu spaii ntre ele. S se creeze fiierul
PARE.TXT care s conin, cte una pe linie, doar acele valori din
fiierul NUMERE.TXT care sunt numere pare.(10p)
Se consider programul:
v: [1. .50] integer; # <stdio.h>
i:integer; v[50],i;
m(a,b:byte):longint; m(int a,int b) {
a>b m:=0 (a>b) 0;
a=b m:=v[a] (a == b) v[a]
m:=m(a, (a+b) div 2)+ return (
m((a+b)div 2+1,b) m(a,a+b)/2)+m((a+b)/2+1,b));
; }
main()
i:=1 10 v[i]:=i; {
writeln(m(3,8)) (i=1;i<11;i++) v[i]=i;
. printf("%ld\n",m(3,8));
}
Ce afieaz programul anterior?(5p)
208
Scriei un program care citete de la tastatur cele 10 numere reale
ce compun vectorul a i apoi cele 8 numere reale ce constituie compo-
nentele vectorului b i afieaz pe ecran cte dintre componentele
vectorului a sunt strict mai mici dect toate componentele vectorului b.
Exemplu: Dac = (4,8,1,9,5,11,3,43,6,20) i b = (9,9,6,9,9,8,6,9),
atunci numrul cutat este 4, deoarece valorile 4, 1, 5 i 3 sunt mai
mici dect toate elementele lui b. (l0p)
IV. Sa se afleze toate numerele formate din cifre distincte cu proprie-
tatea c suma cifrelor este S. Valoarea variabilei S se citete de ia
tastatur. Soluiile vor fi afiate pe ecran.
Exemplu: Pentru S =3, se afieaz valorile 102, 12, 120, 201, 21, 210,
3, 30
(Bacalaureat - Sesiunea august 2000; enun adaptat)
I. Scriei litera sau literele corespunztoare rspunsului sau
rspunsurilor corecte, preciznd la fiecare subpunct care dintre
variantele de limbaj (Pascal sau C, la alegere) a fost considerat.
1. Care dintre urmtoarele secvene de instruciuni atribuie variabilei
ntregi u valoarea ultimei cifre a numrului natural reprezentat de
variabila x? (5p)
a) u:=x 10 a) u=x/10;

b) u:=x; b) u=x;
u>=10 u:=u 10 (u>=10) u%=10;

c) u:=x 10 c) u=x%10;

d) x>=10 x:=x 10; d) (x>=10)x%=10;
u:=x u=x;
2. Care dintre urmtoarele variante reprezint declararea corect a
unei variabile structurate cu dou componente, una de tip ntreg i una
de tip real? (5p)
a) integer x [1..2] real; a) x[2];
b) x: [1. .2] real; b) x[2];
c) x: a:real; b:integer ; c) ( a; b;}x;
d) x: [1. .2] integer; d) x[2];

209
e) inreg = e) {
a: integer; a;
b:real b;
; } INTREG;
x:inreg; INREG x;
Care dintre urmtoarele secvene de instruciuni atribuie variabilei
ntregi x valoarea 10 la puterea n, cu n numr natural, variabila
auxiliar i fiind de tip ntreg? (10p)
a) x := 1; a) x = 1;
i := 1 n X := X*n (i = 1;i <= n;i ++) X *= n;
b) x := 1; b) x = 1;
i := 1 n x := x*10 (i=1;i<n;i++) x*=10;
c) x := 10; c) x = 10;
i:=1 n x:=x*i (i=1;i<n;i++) x*=i;
d) x:=1; i:=0; d) x=1; i=0;
i<n x:=x*10; i:=i+1 (i<n) x*=10; i++;
II. Se consider urmtoarea secven de instruciuni n pseudocod:
n, {numere naturale}
x = 0; i = 1, n x := x+i*i
x
Ce se va afia pe ecran pentru n = 3 i x = 8?(5p)
Scrie o secven echivalent, care s utilizeze structura repetitiv
ct timp.(5p)
Scnei programul Pascal, C sau C++ corespunztor algontmului dat. (l0p)
III. Scriei un program Pascal sau C care citete de la tastatur cele
20 de componente reale ale unui vector a i afieaz pe ecran cte
dintre valorile citite sunt mai mici dect media antmetic a
componentelor vectorului.
Exemplu: dac valorile citite sunt 3.2, 9, -2, 0, 4, -4, -0.5, 7, 1, 0.3 ,14,
0, -7, 2, 2, -1, 3, 6, 0, 1, se va afia pe ecran valoarea 11. (l0p)
n fiierul text BAC.TXT.se afl mai multe numere naturale de cel
mult trei cifre fiecare, numere desprite ntre ele prin cte un spaiu.
Scriei un subprogram care creeaz o list simplu nlnuit folosind
alocarea dinamic a memoriei, list care s conin numerele din
BAC.TXT, n ordinea n care se afl ele n fiier subprogramul trebuie
s retumeze adresa primului element al listei. Se vor defini tipurile de
date utilizate.(15p)
210
Se consider funcia definit recursiv:
ce(i:word):integer; ce( i) {
i=0 ce:=0 (i == 0) 0;
ce:=ce(i-1)+2*i ce(i-1)+2*i;
; }
Ce valoare va returna ce(5)? Dar ce(55)? (10 p)
IV. Se citesc de la tastatur dou numere naturale n i m
(0<n<m<12). S se afieze toate irurile formate din n litere distincte,
litere alese dintre primele m ale alfabetului englez. De exemplu,
pentru n=2 i m=4 se afieaz, nu neaprat n aceast ordine, irurile:
AB, BA, AC, CA, AD, DA, BC, CB, BD, DB, CD, DC. (l5p)
(Bacalaureat-Sesiunea special iunie 2000; enun adaptat)
Scriei litera sau literele corespunztoare rspunsului sau rspun-
surilor corecte, preciznd la fiecare subpunct care dintre variantele de
limbaj a fost considerat.
Dac x, a i b reprezint variabile reale i a<b, ce expresie se
utilizeaz ntr-un program pentru a testa dac valoarea variabilei x este
situat n intervalul nchis [a,b]?(5p)
a) (x>a) and (x<b) a) x>a && x<b
b) (x >=a) or (x<=b) b) x>=a x<=b
c) (x>=a) and (x<=b) c) x>=a && x<=b
d) a>=x<=b d) a>=x<=b
e) a<=x<=b e)a<=x<=b
Dac a, b, c, x reprezint variabile reale, ce instruciune se folosete
pentru a atribui variabilei x suma dintre media aritmetic a valorilor
variabilelor a i b i media aritmetic a valorilor variabilelor b i c?(5p)
a) x:=(a+c)/2+b a) x = (a+c)/2+b;
b) x:=(a+b+c)/3 b) x = (a+b+c)/3;
c) x:=(a+b)/2+(b+c)/2 c) x = (a+b)/2+(b+c)/2;
d) x:=(a+b+c)/3 d) x = (a+b+c)/3;
e) x:=a+b/2+b+c/2 e) x = a+b/2+b+c/2;
Dac valorile variabilelor a, b i x sunt numere naturale, cum se
poate atribui variabilei x restul mpririi valorii variabilei a la
valoarea variabilei b? (5p)

211
a) x:=a b a)x = a%b;
b) x:=a b b)x = a/b;
c) x:=a/b c)x = a/b;
d) a>=b x:=a b d) (a>=b) x=a/b;
x:=b a x= b/a;
e) a>=b x:=a b e) (a>=b) x= a%b;
x:=b a x= b%a;
II. Se consider algoritmul reprezentat prin program pseudocod:
b := 0; c := 0
n {numr natural}
i = 1, n
a {numr ntreg}
a>0 cc+l ; bb+a
c=0 Imposibil
b/c (cu 2 zecimale)
1. Scriei programul Pascal, C sau C++ corespunztor algoritmului. (15p)
2. Ce se afieaz pe ecran, conform algoritmului dat, dac toate valo-
rile citite prin program sunt egale cu 5? (5p)
3. Scriei o valoare pentru variabila n i apoi un ir de valori introduse
succesiv pentru variabila a astfel nct programul dat s afieze
valoarea 5.50. (5p)
III. n fiierul text SERII.TXT se afi, cte una pe linie, seriile crilor
de identitate ale unor persoane, fiecare serie fiind format din exact
dou litere mari de tipar nedesprite prin spaii. n fiierul text
NUMERE.TXT se afl, cte unul pe linie, numerele crilor de identi-
tate ale acelorai persoane, n aceeai ordine, fiecare numr fiind
format din exact 6 cifre nedesprite prin spaii. Se consider c
formatul fiecrei serii i fiecrui numr este respectat de datele din
fiier, nefiind necesare validri ale acestora.
S se verifice dac fiierul SERII.TXT conine tot attea linii cu
serii cte linii cu numere conine fiierul NUMERE.TXT.
Dac aceast condiie este ndeplinit, se vor afia pe ecran, una
sub alta, seriile i numerele crilor de identitate ale persoanelor
respective, ntre serie i numr fiind afiat un spaiu.
Dac fiierele nu conin acelai numr de linii cu serii i
respectiv cu numere, se va afia pe ecran numai mesajul Eroare.
212
Exemplu:
Dac fiierele de date au urmtorul coninut,
SERII.TXT NUMERE.TXT
AH 126045
BR 312469
LL 600495
atunci se vor afia pe ecran liniile
AH 126045
BR 312469
LL 600495
(15p)
2. Se consider o list simplu nlnuit care reine mai multe numere
naturale de cte dou cifre. S se scrie un subprogram care primete ca
parametru adresa de nceput a listei i realizeaz transferul primului
element la sfritul listei. Se tie c adresa transmis nu poate fi
niciodat adresa nul (nil/NULL).
Exemplu:
Dac lista conine iniial elementele 2 51 4 7 14 25 69 (n
aceast ordine), la revenirea din subprogram, coninutul listei este:
51 4 7 14 25 69 2 (n acest ordine).
Se vor preciza:
a) tipurile de date i variabilele globale necesare;
b) definiia complet a subprogramului;
c) instruciunea ce conine apelul subprogramului.(15p)
Civa copii cu vrste ntre 2 i 7 ani trebuie s fie vizitai de
Mo Crciun. Scriei un program Pascal, C sau C++ care determin
toate modurile diferite n care pot ei s fie aezai n lista lui Mo
Crciun, astfel nct s fie vizitai toi copiii i vizitele s se fac n
ordinea cresctoare a vrstei lor.
Se citesc de la tastatur: n, numrul de copii (0<n<10), apoi
numele i vrsta fiecruia dintre cei n copii. Se scriu n fiierul text
CRACIUN.TXT, pe linii diferite, liste cu numele copiilor, n ordinea
n care vor fi vizitai de Mo Crciun. O list este format din toate
cele n nume ale copiilor, ntr-o anumit ordine, orice dou nume
succesive fiind desprite prin spaii.
Explicai metoda folosit prin comentarii incluse n program.
Exemplu: Pentru datele de intrare
n = 4
i
213
Dan 6
Cristina 4
Corina 2
Iulia 4
se scriu n fiierui CRACIUN.TXT urmtoarele soluii:
Corina Iulia Cristina Dan
Corina Cristina Iulia Dan
(20p)
(Bacalaureat-Sesiunea special iunie 2001; enun adaptat)
I. Scriei litera corespunztoare rspunsului corect preciznd la fiecare
subpunct care dintre variantele de limbaj a fost considerat (Pascal sau C).
1. Care este cea mai mare valoare pe care o poate avea variabila
ntreag i pentru ca urmtoarea secven s afieze textul DA? (5p)
i<5-3*i i < 5 ( 5 p ( C t f ( ' ) 6 ( D A ' ) 6 ( ( ; 6 ( 4 ) ] T J E M C / P < < / M C 0 I D 5 > > B D C / T T 1 1 T f - 0 . 0 0 1 7 T c 0 1 2 . 2 2 4 . 3 2 2 - 1 . 0 4 9 e l s e ( i f ) T j / T T 0 1 T f - . 0 0 0 3 T c 0 . 0 0 1 1 T w r ( i l n ( ' ) 6 ( N U ' ) 6 ( ( 5 p - 1 6 8 8 7 ) 3 - t a ) 2 contrt creturneaz urm * 8 ( c a r e ) T f 1 4 0 0 0 9 1 T a - 2 5 . 6 2 0 . 3 2 2 - 1 . 0 4 9 * i
214
c) max(x,y:real):real; c) max( x, y)
{ z=x; if (x<y) z=y;
x>y z:=x z:=y z;
end; }
d) max(x,y) :real; d) max( &x, &y)
max:=x; {
max>y max:=y x>y?y:x;
; }
II. Fie programul pseudocod alturat:
n, m {numere naturale};
n>=m nn-m
n
1. Ce valoare final va avea n dac iniial: n=38 i m=4? (5 p)
2. Scriei programul Pascal, C corespunztor. (10p)
3.Pentru n = 2071, determinai un numr de dou cifre care s
reprezinte valoarea variabilei m astfel nct, n urma executrii
programului, rezultatul afiat s fie 0. (5p)
III. 1. Scriei un program Pascal, C sau C++ care citete de pe prima
linie a fiierului text CUVINTE.TXT un numr natural n (n<20) i
apoi, de pe urmtoarele n linii, cte un cuvnt alctuit numai din litere
(cel mult 30 de litere). Ca urmare a executri programului se va afia
pe ecran un ir de n+1 caractere format astfel: primul caracter din ir
este prima liter a primului cuvnt din fiier, al doilea caracter din ir
este a doua liter a celui de-al doilea cuvnt din fiier, al treilea
caracter al irului este a treia liter a celui de-al treilea cuvnt din
fiier etc. Ultimul caracter va fi . (punct).
Dac vreunul dintre cuvinte nu are suficiente litere, irul rezultat
va conine pe poziia corespunztoare un spaiu. Concepei o prelu-
crare ct mai eficient din punct de vedere al spaiului de memorie
utilizat de program.
De exemplu, pentru datele de intrare:
5
ALMI
COCOR
MASA
DO
MARINA
se va afia pe ecran irul de caractere
AOS N.
(15 p)
215
2. Scriei declarrile necesare pentru definirea unei liste simplu-nln-
uite, tiind c un element al listei memoreaz un numr natural de cel
mult 4 cifre. Scriei un subprogram care efectueaz concatenarea a
dou astfel de liste dup urmtorul procedeu: se adaug lista cu mai
puine elemente n continuarea listei cu mai multe elemente. Subpro-
gramul primete prin doi parametri adresele de nceput ale celor dou
liste i retumeaz printr-un al treilea parametru adresa de nceput a
listei obinute prin concatenarea celor dou liste. Dac cele dou liste
au tot attea elemente, atunci la sfritul listei transmis prin primul
parametru se va aduga cea de-a doua list. (15 p)
IV. Se citesc de la tastatur numerele naturale n i k (0<n < 10000 i
0<k < 10) reprezentate n baza 10. S se afieze n ordine cresctoare
toate numerele naturale de k cifre cu proprietatea c sunt formate
numai cu cifre ale numrului n. De exemplu, pentru n = 216 i k = 2,
se vor afia numerele: 11, 12, 16, 21, 22, 26, 61, 62, 66. (20 p)
(Bacalaureat-Sesiunea iunie-iulie 2001; enun adaptat)
I. Scriei litera corespunztoare rspunsului corect, preciznd la
fiecare subpunct care dintre variantele de limbaj a fost considerat (Pascal
sau C).
1. Care trebuie s fie valoarea iniial a variabilei ntregi i pentru ca
urmtoarea secven s afieze irul XXX?(5p)
(i!=3){
write('XX); i - -;
i:=i-1 printf ("XX");
i = 3 }
a)0 b)1 c)2 d)3 e)4 f)5 g)6 h)nu exist nici o valoare
2. tiind c variabila x este utilizat ntr-un program pentru a memora
numele unui elev, stabilii care este declararea corespunztoare a
variabilei x? (5p)
a) x:byte; a) x;
b) x: [16]of char; b) x[0..16];
c) x:string; c) *x;
d) x: d) x{
nume prenume: boolean nume, prenume;
};
3. Stabilii care dintre urmtoarele variante reprezint antetul corect al
unei funcii reale cu un parametru ntreg.(5p)
216
a) f(x:real); a) f( x)
b) f(x:integer):real; b) f( * x)
c) f( x:real):real; c) f( x)
d) f(x:real):integer; d) f( x)
4. Pentru a atribui variabilei reale x rezultatul expresiei (2ab-
c*c)/0.25 unde a, b i c desemneaz variabile reale, se utilizeaz
instruciunea de atribuire: (5p)
a) x:=(2*a*b)-(c*c)/0.25 a) x=(2*a*b)-(c*c)/0.25
b) x:=2*a*b-c*c/0.25 b) x=2*a*b-c*c/0.25
c) x:=(2*a*b)-(c*c)*4 c) x=(2*a*b)-(c*c)*4
d) x:=(2*a*b-c*c)*4 d) x=(2*a*b-c*c)*4
Se consider urmtorul program pseudocod:
n {numr natural}; m0
mm+1 n[n/2] (ctul mpririi ntregi a lui n la 2)
n < 0
m
1. Ce se va afia pentru n = 51?(5p)
2. Scriei programul Pascal, C sau C++ corespunztor algoritmului dat
(10p)
3. Scriei un program echivalent care s utilizeze o structur repetitiv
cu condiie iniial.(5p)
4. Cte numere naturale exist astfel nct oricare dintre acestea,
introdus ca valoare pentru n, s determine afiarea rezultatului 3?(5p)
. 1. Scriei un program Pascal, C sau C++ care citete din fiierul
text BAC.TXT, 100 000 de numere reale scrise pe prima linie a
fiierului, cu spaii ntre ele i, de la tastatur dou numere ntregi a i
b. Programul trebuie s stabileasc dac toate elementele din fiier se
afl n afara intervalului nchis [a,b]. Programul va afia pe ecran
mesajul DA, n cazul n care toate numerele din fiier se afl n afara
intervalului inchis [a,b] sau mesajul NU, n cazul n care exist cel
puin un numr din fiier aflat n intervalul nchis [a,b]. (15 p)
2. Construii un program care stabilete n mod eficient de cte ori
apare o cifr nenul c n scrierea tuturor numerelor naturale mai mici
sau egale cu un numr dat k. Cifra c i valoarea k se citesc de la
tastatur. De exemplu, pentru c = 6, k = 128, se afieaz valoarea 23
(0, 1, .. 5, 6, 7, ...16, 26, ... 36, ... 46, ... 56, ... 60, ... 66, ... 69,
...76, .. 86, ... 96, ... 106, 116, ... 126, 127, 128). (10 p)
217
Se citesc de la tastatur: dou numere n (0<n<15) i s (0<s<10
6
)i
apoi n valori ntregi distincte, fiecare valoare aparinnd intervalului [-1000,
1000]. S se determine toate mulimile de numere dintre cele date,
fiecare mulime avnd proprietatea c suma elementelor ei este egal
cu s. Fiecare mulime se va afia pe o linie, elementele ei fiind scrise
n ordine cresctoare, desprite prin cte un spaiu sau cte o virgul.
De exemplu, pentru n = 7, s = 61 i valorile 12, 61, 22, 57,10, 4, 23, se
vor afia, pe linii distincte, urmtoarele mulimi:
4,12, 22, 23
4, 57
61
(20 p)
(Bacalaureat-Sesiunea august 2001; enun adaptat)
I. Scriei litera corespunztoare rspunsului corect, preciznd la
fiecare subpunct care dintre vanantele de limbaj a fost considerat (Pascal
sau C).
1. Care dintre variabilele ntregi x, y i z au valori egale la sfritul
executrii urmtoarei secvene de instruciuni? (5p)
y: =x+1; y = x+l;
z:=y-1; z = y-1;
x:=z+1 x = z+1;
a) numai x i y b) numai x i z
c) numai y i z d) x i y i z
e) toate au valori diferite
2. tiind c funcia fmin returneaz cea mai mic dintre valorile celor
doi parametri reali ai si sau retumeaz valoarea comun n cazul n
care cei doi parametri au aceeai valoare, precizai care dintre
urmtoarele instruciuni afieaz cea mai mic dintre valorile variabilelor
reale a, b i c.(5p)
writeln(fmin(a,b,c)) printf(%f,fmin(a,b,c));
writeln(fmin(a,fmin(b,c))) printf(%f,fmin(a,fmin(b,c)));
writeln(fmin(fmin(a,b),c) printf(%f,fmin(fmin(a,b),c);
writeln(fmin(a,b),fmin(b,c)) printf(%f,fmin(a,b),fmin(b,c));
3. Stabilii care dintre urmtoarele variante reprezint declararea
corect a unei variabile de tip tablou cu exact 20 de componente numere
ntregi. (5p)
218
a) x: [1.. 20] real; a) x[1. .20];
b) x: [0..20] integer; b) x[1. .20];
c) x: [0..19] integer; c) x[0. .19];
d) x: [20] integer; d) x[20];
e) x: [19] integer; c) x[19];
4. Ce valoare (n format exponenial) se afieaz ca urmare a executri
instruciunii urmtoare? (5p)
writeln(48.0(32/(2/2)+1)) printf("%f",48.0(32/(2/2)+1))
a) 0 b) 5 c) 8 d) 15 e) 17 f) 24 g) 32 h) 39 i) 41 j) alt valoare
II. Se consider urmtorul program pseudocod:
n (numr naturai)
m0
V
1
(numr natural)
i = 2, n
V
i
(numr natural)
V
i
= V
i-1
atunci mm+1
m
1. Ce se va afia pentru n=5 i V
1
=5, V
2
=3, V
3
=3, V
4
=8, V
6
=8? (5p)
2. Scriei programul Pascal, C sau C++ corespunztor algoritmului dat
(10p)
3. Pentru n=4, determinai un set de valori introduse pentru V
1
, V
2
, V
3
i V
4
astfel nct rezultatul afiat de algoritmul dat s fie 3. (5p)
4. Scriei un program pseudocod, Pascal, C sau C++ care s fie
echivalent cu programul dat i care s nu utilizeze variabile structurate
(tablouri, liste, fiiere etc.) sau adrese de variabile structurate.(5p)
III.1. Fiierul text BAC1.TXT conine 70000 de numere ntregi de cel
mult 3 cifre fiecare scrise cu spaii ntre ele. Scriei un program Pascal,
C sau C++ care creeaz fiierul text BAC2.TXT care s conin numai
valorile strict pozitive din fiierul BAC1 .TXT, exact n aceeai ordine
n care se aflau acestea n fiier.
De exemplu, dac fiierul BAC1 .TXT are urmtorul coninut: 6
-9 11 8 -5 -7 8 4 11 0 2 3 -6 4 -8 .... -8 de 69 987 de
ori fiierul BAC2.TXT creat de program trebuie s aib urmtorul
coninut: 6 11 8 8 4 11 23 4. (l0p)
2. Construii un algoritm eficient care determin toate perechile de
numere naturale cu < , numerele ce formeaz o pereche avnd
proprietatea c nu au nici o cifr comun i suma lor este egal cu S.
219
Valoarea S este un numr natural citit de la tastatur (S<100 000 000).
Fiecare pereche se va scrie pe un rnd al ecranului, cu un spaiu ntre
elementele ce compun perechea.
De exemplu, pentru S16, se vor afia (nu neaprat n aceast
ordine) perechile:
2 14 '\n' 6 10 '\n' 4 12 '\n'
5 11 '\n' 0 16 '\n' 7 9
(15 p)
3. Transformai urmtoarea funcie ntr-o funcie recursiv care s nu
utilizeze nici o structur repetitiv i s retumeze acelai rezultat ca i
funcia dat pentru orice valoare nenul a parametrului i. Scriei
versiunea modificat a acesteia.(5p)
(Bacalaureat-Sesiunea iunie2002; enun adaptat)
I. Scriei litera corespunztoare rspunsului corect, preciznd la
fiecare subpunct care dintre variantele de limbaj a fost considerat
(Pascal sau C/C++).
1. tiind c valoarea iniial a variabilei ntregi i este mai mare dect
10, stabilii care este valoarea expresiei abs(3-i) la sfritul executrii
urmtoarei instruciuni.(5p)
i>4 i:=i-1 (i>4) i--;
a)-1 b) 0 c) 1 d) 2
e) o valoare mai mare dect 2
f) o valoare nedeterminat
2. tiind c variabila x este utilizat ntr-un program pentru a memora
i utiliza n alte calcule rezultatul expresiei 1*2*3...*10, stabilii care
dintre urmtoarele declarri este corect din punct de vedere sintactic
i corespunde scopului propus. (5p)
a) x:string; a) *x;
b) x:integer; b) x;
c) x:longint; c) x;
d) x:byte; d) x;
3. tiind c formula de calcul pentru aria coroanei circulare este (R
1
2
-
R
2
2
), unde R
1
este variabil real strict pozitiv reprezentnd raza
exterioar, iar R
2
este variabila real pozitiv reprezentnd raza
interioar a coroanei, precizai care dintre urmtoarele instruciuni
atribuie variabilei reale S valoarea coroanei circulare.(5p.)
220
a) S:=pi*(sqr(R1)-sqr(r2)) a)S=m_pi*(pow(R1,2)+pow(R2,2));
b) S:=pi*(R1-R2)(R1+R2) b)S=m_pi*(R1-R2)(R1+R2);
c) S:=pi*R1*R1-R2*R2; c)S=m_pi*(R1*R1-R2*R2);
d) S:=pi*(R1*R1+R2*R2) d)S=m_pi*R1*R1-R2*R2;
4. tiind c x, y i z reprezint trei variabile ntregi, stabilii care dintre
urmtoarele secvene de instruciuni este corect din punct de vedere
sintactic.(5p.)
a)x:=14;y:=x-7;z:=x/y a) x=14;y=x-7;z=x/y;
b)x:=14; (x<10) y:=x-1 b) x=14; x<10 y=x-1;
c)x:=y:=14;z:=x+y; c) x=y=14;y=x++y;
d)x:=14; 0<x<100 y:=x+1 d) x=14; 0<x<100 y=x+1;
II. Se consider programul pseudocod:
a,b (numere ntregi)
a<0 atunci a-a
b<0 atunci b-b
h0
ab
hh+1
aa-b
h
1. Ce se afieaz dac valorile citite pentru a i b sunt 6 i, respectiv 2?
(5p.)
2. Scriei programul Pascal, C sau C++ corespunztor algoritmului dat
(10p.)
3. Determinai o valoare pentru variabila a i o valoare pentru b, astfel
nct rezultatul afiat s fie 1.(5p.)
4. Scriei un algoritm echivalent cu cel dat (la aceleai date de intrare
s furnizeze acelai rezultat), algoritm care s nu utilizeze nici o structu-
r repetitiv. (5p.)
III. 1. Se citesc de la tastatur trei numere naturale f, a i b, fiecare
numr avnd cel mult trei cifre. S se afieze o "tabl" cu toate
nmulirile de doi factori naturali dintre care unul este obligatoriu f i
care dau ca rezultate numai numere cuprinse ntre a i b inclusiv.
nmulirile vor fi afiate cte una pe linie, n ordinea cresctoare a
rezultatelor. De exemplu, pentru f=5, a=8 i b=25 se va afia tabla
nmulirilor cu 5astfel: 2*5=10; 3*5=15; 4*5=20; 5*5=25 (5p.)
221
2. Scriei un program prin care se citete de la tastatur o valoare
natural n (0<n<200) i apoi se citesc cele n componente numere
ntregi ale vectorului v, orice element al vectorului avnd cel mult 4
cifre. S se realizeze sortarea cresctoare a elementelor pare ale
vectorului avnd grij n plus ca fiecare element impar s rmn
exact pe poziia pe care se afla iniial.
Vectorul se va afia pe ecran cu spaii ntre elementele ce-l
formeaz. Pentru n=7 i vectorul v=(10,2,5,11,6,5,8) se va afia irul
de valori: 2 6 5 11 8 5 10. Se observ c elementele impare i-au
pstrat locul, n timp ce elementele pare (10,2,6,8) se afl acum n ordine
cresctoare (2,6,8,10).
Alegei un algoritm de rezolvare care s utilizeze eficient memo-
ria intern.(10p.)
3. Scriei un subprogram care primete prin primul parametru a o
valoare natural (1< a < 1000) i returneaz prin al doilea parametru b
valoarea real reprezentnd inversul numrului a cu dou zecimale
importante exacte, urmtoarele zecimale fiind 0.
Numim dou zecimale importante prima pereche de cifre zeci-
male succesive (pornind de la virgula zecimal ctre dreapta), astfel
nct prima cifr s fie nenul.
De exemplu, pentru a = 2 se va returna b = 0.5 (cele dou
zecimale importante fiind 5 i 0); pentru a =14 se va returna b=0.071
(cele dou zecimale importante fiind 8 i 1), iar pentru a = 121 se va
returna b=0.0082 (cele dou zecimale importante fiind 8 i 2) (10p.)
IV. Se citesc de la tastatur un numr natural s(0 < s < 5000) reprezen-
tnd o sum de bani exprimat n mii de lei. S se determine un mod
de plat a sumei s tiind c avem la dispoziie 9 monede de o mie, 8
monede de 5 mii, 5 de bacnote de 10 mii, 8 bacnote de 50 de mii i 45
de bacnote de 100 de mii de lei. Alegei o metod eficient de rezolva-
re i scriei programul Pascal, C sau C++ corespunztor. Se va afia pe
ecran modalitatea de plat n formatul sugerat prin exemplul urmtor
sau mesajul IMPOSIBIL dac nu este posibil plata sumei cu
monedele disponibile.
Pentru s=3076 (3076 mii lei) se poate afia soluia:
3076=30x100+1x50+2x10+6x1
Se observ c exist i alte posibiliti de plat, ns problema solicit
determinarea doar a uneia dintre posibiliti. Explicai pe scurt i
justificai algoritmul folosit (maximum 4 rnduri). (20p.)


222


1. [Numr deosebit - Problema E25
1
] Se tie c m este un numr
deosebit dac exist n numr natural nenul astfel ca m = n+s(n), unde
s(n) reprezint suma cifrelor numrului n. O persoan dorete s tie
dac vrsta sa (n zile) este un numr deosebit. Scriei un program
care solicit data naterii, afl vrsta n zile i afieaz rspunsul sub
forma: "Da" (resp. "Nu") dac vrsta reprezint un numr deosebit
(resp. vrsta nu este un numr deosebit).
2. [Manipulator - Olimpiada de Informatic, Faza pe municipiu, 5
III 1995, Bucureti, Clasa a IX-a] Pe o platform industrial se
afl n depozite D
1
, D
2
, , D
m
(n: 2..100), fiecare depozit avnd
capacitatea m (m:1..50) i un manipulator cu capacitatea maxim
p (p: 2..200). Modul de aezare a pieselor n timpul transportului
nu este important. tiind c:
Iniial, n fiecare din cele n depozite se afl m piese aranjate
oricum, fiecare pies fiind marcat cu indicele depozitului
specializat n pstrarea sa.
Manipulatorul se poate deplasa, nainte i napoi, numai ntre
depozite cu numere de ordine succesive (de la D
i
la D
i+1
i de
la D
i+1
la D
i
, i = 1, 2, , n-1.)
Iniial manipulatorul ncarc piese din depozitul D
1
, iar dup
efectuarea tuturor micrilor rmne n dreptul depozitului D
1
. )
Deplasarea manipulatorului de la un depozit la altul necesit t
uniti de timp (t numr natural nenul).
Timpul necesar pentru ncrcarea/descrcarea pieselor, nu se
ia n considerare.
S se elaboreze un program care indic micrile ce trebuie s le
efectueze manipulatorul pentru a realiza aranjarea tuturor pieselor
n timp minim.
3. [Secven de numere prime] Sciei un program care citete numerele
naturale n
1
, n
2
, , n
p
i tiprete cea mai lung secven n
s
, n
s+1
, ,
n
d
(cu s i d n domeniul 1..p, sd) care conine numai numere prime.
S se proiecteze aplicaia astfel nct s utilizeze subprograme.
4. [Becuri - ONI 2002, Brila, Clasa a IX-a - enun parial
modificat] Un panou publicitar, de form dreptunghiular conine
becuri, unul lng altul. Aliniate pe linii i coloane. Fiecare linie i

1
R. Niculescu, G. Albeanu, V. Domoco; Programarea calculatoarelor.
Probleme rezolvate n limbajul Pascal, Ed. Tempus, 1992.
223
fiecare coloan are un comutator care schimb starea tuturor
becurilor de pe aceea linie sau coloana, din starea curent n starea
opus. Iniial panoul are toate becurile stinse. S se realizeze un
program care, acionnd asupra unui numr minim de linii i
coloane, aduce panoul din starea iniial, la o configuraie dat,
dac acest lucru e posibil.
5. [Codificare - ONI 2002, Brila, Clasa a IX-a - enun parial
modificat] Se consider cuvintele formate numai cu literele mici
ale alfabetului englez. Dintre toate aceste cuvinte se consider
numai cele ale cror caractere sunt n ordine strict lexicografic i
se realizeaz urmtorul sistem de codificare:
Se ordoneaz cuvintele n ordinea cresctoare a lungimii
acestora.
Cuvintele de aceeai lungime se ordoneaz lexicografic.
Cuvintele sunt codificate prin numerotarea lor (n irul obinut
dup ordonare): 1 - a; 2 - b; , 26 - z; 27 - ab, , 51 - az; 52
- bc, , 83681 - vwxyz, .
Dndu-se un cuvnt, s se precizeze, prin intermediul unui
program Pascal, c sau C++, dac poate fi codificat conform
sistemului descris. n caz afirmativ s se precizeze codul su.
6. [Structur arborescent - Problema S26
1
] ntr-un graf G cu n
noduri i A o mulime de muchii, se alege un nod, numit nodul
central al grafului. Fiecare muchie are stabilit un anumit cost
(numr real strict pozitiv). Se cere determinarea unui subarbore al
grafului G astfel nct drumurile de la nodul central la toate
celelalte noduri s aib lungime minim.
7. [Pavaj - Problema S27
1
] Se consider un dreptunghi de dimensiuni
ntregi m i n. Avnd la dispoziie dale dreptunghiulare de dimensiuni
ntregi pxq s se paveze n ntregime dreptunghiul dat astfel nct
laturile dalelor s nu formeze nici o linie paralel i egal cu una din
laturile dreptunghiului.
8. [Labirint - Problema S29
1
] Se consider un labirint de form
dreptunghiular, avnd perei verticali i orizontali. S se gseasc
drumul cel mai scurt dintre dou puncte date.
9. [Cititori prieteni - Problema S30
1
] Se consider un grup de n
persoane. Fiecare persoan are cel puin n/2 prieteni n grup. Una
dintre persoane are o carte pe care fiecare dorete s o citeasc. Se
cere s se determine o modalitate prin care cartea s circule pe la
fiecare persoan exact o dat, transmiterea ei efectundu-se numai
ntre doi prieteni, iar n final cartea s ajung la proprietarul ei.
224


- Algoritmic i programare n limbajul
Pascal, Editura FRM, Bucureti, 2001.
. - Algoritmi i limbaje de programare, Editura FRM,
Bucureti, 2000.
- Programarea n Pascal i Turbo Pascal. Culegere de
probleme. Editura Tehnic, Bucureti, 1994.
- Concursuri de informatic. Probleme propuse, Editura Petrion, 1995.
- Introducere n
algoritmi, Ed. Computer Press Agora, 2000.
- Tehnici de
Programare, Editura Teora, 1999
7. . Thinking in C++, Prentice Hall Inc., 2000
- Bazele Infor-
maticii (Grafuri i elemente de combinatoric), Editura Petrion, 1997.
Totul despre C i C++, Ed. Teora, 2000.
333
probleme de programare, Editura Teora 1994.
Curs rapid de Borland C++ 4, Editura Teora,
Bucureti, 1996.
- Programarea calculatoarelor.
Probleme rezolvate n limbajul Pascal, Editura Tempus, Bucureti, 1992.
Popovici D. M., Popovici I. M., Tnase I. Tehnologia orientat pe
obiecte. Aplicaii, Editura Teora, 1996.
The C++ Programming Language, Third Edition,
Addison Wesley Longman, Inc., 1997.
Tehnici de programare, Ed. L&S INFOMAT, 1996.
*** Gazeta de Informatic

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