Documente Academic
Documente Profesional
Documente Cultură
Tehnici de Programare
Tehnici de Programare
(coordonator)
EDITURA FUNDAIEI ROMNIA DE MINE,
BUCURETI, 2003
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
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.
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
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.
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;
}
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