You are on page 1of 224

UNIVERSITATEA SPIRU HARET

FACULTATEA DE MATEMATIC INFORMATIC

GRIGORE ALBEANU (coordonator) LUMINIA RPEANU, LUMINIA RADU, ALEXANDRU AVERIAN

TEHNICI DE PROGRAMARE
- Lucrri practice de programarea calculatoarelor -

EDITURA FUNDAIEI ROMNIA DE MINE, BUCURETI, 2003

Descrierea CIP a Bibliotecii Naionale a Romniei Tehnici de programare / Grigore Albeanu, Luminia Rpeanu, Luminia Radu, Alexandru Averian. - Bucureti: Editura Fundaiei Romnia de Mine, 2003 224 p., 20,5 cm Bibliogr. ISBN 973-582-665-8 I. Albeanu, Grigore II. Rpeanu, Luminia III. Radu, Luminia IV. Averian, Alexandru 004.42

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

Coperta: Marilena BLAN Bun de tipar: 24.01.2003; Coli tipar: 14 Format: 16/61 x 86 Editura i Tipografia Fundaiei Romnia de Mine Splaiul Independenei, nr. 313, Bucureti, S. 6, O. P. 83 Tel.: 410 43 80; Fax. 410 51 62; www.spiruharet.ro

CUPRINS

Prefa ... 1. Operaii de intrare/ieire n limbajele Pascal i C 1.1. Fiiere n limbajul Pascal ... 1.2. Fiiere n limbajul C ...... 2. Structuri de date .. 2.1. Liste simplu nlnuite ... 2.2. Liste dublu nlnuite . 2.3. Liste circulare .... 2.4. Stive ... 2.5. Cozi .... 2.6. Grafuri .... 2.7. Arbori ..... 3. Metode pentru rezolvarea problemelor .... 3.1. Metoda Divide et Impera 3.2. Metoda programrii dinamice 3.3. Metoda Greedy 3.4. Metoda backtracking 3.5. Metoda Branch and Bound 4. Programare modular n Turbo Pascal ... 5. Introducere n programarea orientat obiect folosind limbajul C++ 6.Teste pentru verificarea cunotinelor ... 6.1. Teoria i practica programrii .... 6.2. Probleme pentru concursuri ... Bibliografie ...

5 7 7 17 31 32 46 50 53 55 62 87 101 101 107 116 125 135 145 173 201 201 222 224

Capitolele lucrrii au fost elaborate dup cum urmeaz: Prof. univ. dr. Grigore ALBEANU Prefaa, Cap. IV, Cap. V 2, Cap VI 2, Bibliografia Prof. gr. 2 Luminia RPEANU Cap. II, Cap. III, 2, Cap. VI 1. Prof. Luminia RADU Cap. I Prep. Alexandru AVERIAN 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.

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 nvarea 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 specializrile 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 5

1. Operaii de intrare/ieire n limbajele Pascal i C


1.1. Fiiere n limbajul Pascal Definiia 1.1.1. Se numete fiier, o structur de date ale crei componente, numite nregistrri, de dimensiune fix sau variabil, sunt stocate (depuse), de obicei, pe un suport magnetic (band sau disc) de pe care pot fi citite/scrise direct din program. Observaia 1.1.1. Dac nregistrrile din fiier au o dimensiune variabil, se impune existena unor marcaje speciale numite separatori de nregistrare. Observaia 1.1.2. Organizarea datelor n fiiere este necesar, dac: volumul datelor prelucrate este foarte mare i depete capacitatea memoriei interne disponibile. datele trebuie stocate n vederea unei prelucrri ulterioare, n cadrul aceluiai program sau al altora. Observaia 1.1.3. 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). Observaia 1.1.4. 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 componentelor 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.
7

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. Observaia 1.1.5. 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 Efect Apelul Procedure assign (var fiier;nume:string); I se asociaz variabilei de tip fiier din program, numele fiierului fizic de pe suportul extern . assign (fiier, nume); unde fiier reprezint identificatorul variabilei de tip fiier din program, iar nume reprezint o expresie de tip string, a crei valoare este numele fiierului fizic de pe suport extern.

Observaia 1.1.6. Asocierea rmne valabil pn la un alt apel al procedurii assign, asupra aceluiai fiier extern. Apelul se termin cu eroare dac fiierul fizic este deschis n momentul apelului. Prelucrrile admise asupra unui fiier sunt: Crearea fiierului Scrierea componentelor n fiier. Exploatarea fiierului Citirea i prelucrarea componentelor fiierului Actualizarea fiierului Adugarea, modificarea sau tergerea unor componente ale fiierului. Observaia 1.1.7. Oricare ar fi modul de prelucrare a unui fiier, accesul la componentele acestuia este permis numai dac acesta este deschis. Deci orice prelucrare ncepe cu deschiderea fiierului i se ncheie cu nchiderea sa. Deschiderea unui fiier se realizeaz prin comenzile reset (fiier) sau rewrite(fiier). nchiderea fiierului prin comanda close(fiier).
8

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. Observaia 1.1.8. 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. Observaia 1.1.9. 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 nchiderea fiierului prin care operaiile de citire/scriere a componentelor lui sunt interzise pn la o nou deschidere. Definiia 1.1.2. 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). Observaia 1.1.10. Fiierele text se stocheaz pe disc sau sunt asociate unui dispozitiv logic (i se termin cu caracterul ^Z)
9

Observaia 1.1.11. Tipul fiier text se declar conform diagramei: Tip fiier text
text

Dimensiunea zonei tampon asociat unui fiier text este, n general 128 bytes. Un fiier text poate fi deschis prin apelul procedurilor: rewrite - sunt permise numai operaii de scriere reset - sunt permise numai operaii de citire append - sunt permise numai operaii de scriere; realizeaz deschiderea la sfrit a unui fiier creat pe disc i permite adugarea unor noi linii la sfritul fiierului. Observaia 1.1.12. Accesul poate fi numai secvenial (pas cu pas), nu poate fi accesat direct. Procedurile i funciile pentru prelucrarea fiierelor text Procedura read Apelul: Read (fiier, v1 [, v2, , vn]); Efect: Citete din fiierul fizic asociat variabilei fiier n variabila (variabilele) v1[, , vn] unde: fiier este numele variabilei asociate fiierului fizic (dac lipsete se consider INPUT), iar v1, v2, , vn sunt n variabile (n>1) care pot fi de tip: char, string, integer i variantele, real i variantele n virgul mobil. Procedura readln Apelul: Readln (fiier, v1[, v2 ,, vn]); Efect: Citete din fiierul fizic asociat variabilei fiier n variabila v1[, , vn] i trece la linie nou n fiier. Este echivalent cu secvena: read(fiier, v1[, v2 ,, vn]); readln(fiier); Procedura write Apelul: Write(fiier, v1[, v2, , vn]); Efect: Scrie n fiierul fizic asociat variabilei fiier, variabilele v1[, v2, , vn]. Procedura writeln Apelul: Writeln (fiier, v1 [, v2, , vn]); Efect: Scrie n fiierul fizic asociat variabilei fiier, variabilele v1[, v2, , vn] i un marcaj de sfrit de linie n fiierul fizic asociat variabilei fiier. Este echivalent cu secvena: write(fisier, v1[, v2, ..., vn]); writeln(fisier);
10

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. Apel: eof [(var fiier)] Funcia seekoln este de tip boolean, deci ntoarce dou valori: true, dac avem sfrit de linie, respectiv false, n caz contrar Apel: seekeoln[(fiier)]; Efect: 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. Apel: eoln[(fiier)]; Observaia 1.1.13. Funcia seekeoln difer de funcia eoln 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. Observaia 1.1.14. 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 adugrii 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
11

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. Exemplificare: rename(f,'document.dat') schimb numele fizic asociat lui f cu numele fizic document. Aplicaia 1.1.1. S se afieze numrul cuvintelor citite dintr-un fiier text, introdus de la tastatur (cuvintele sunt separate prin unul sau mai multe spaii). Soluie:
program nr_cuv_din_fis_INPUT; var c:char; n:longint; begin n:=0; write('linia:'); while not eof do begin while seekeoln do begin read(c); while (c<>' ') and not eoln do read(c); n:=n+1 end; readln; write('Introducei linia:') end; writeln('Fiierul cuprinde:',n,'cuvinte') end. {n reine numarul de cuvinte din text}

Exemplu de executare: Intrare: Ana are main Crina are calculator

Ieire: Fiierul are 6 cuvinte.

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

while not eof do begin n:=0; while not seekeoln do begin read(nr); inc(n) end; readln; writeln('din linia', i, 's-au citit' ,n, 'numere'); inc(i); write('linia',i,':') end end.

Exemplu de executare: Intrare: linia 1: 10 20 30 linia 2: 40 50 Fiiere cu tip

Ieire: din linia 1 s-au citit 3 numere din linia 2 s-au citit 2 numere.

Definiia 1.1.3. 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:
FILE OF IDENTIFICATOR DE TIP

Exemplul 1. S declarm un fiier ale crui articole sunt numere ntregi. Soluie: type fisint = file of integer; var a:fisint; sau var a: file of integer; Exemplul 2. S se declare un fiier cu articole de tip record. Soluie: type inreg = record nume:string[30]; varsta:byte; end; fisier = file of inreg; var f:fisier;{f-reprezint fiierul cu tip ce poate conine articole }
13

Observaia 1.1.15. Accesul la datele fiierului cu tip este secvenial sau direct. Citirea i scrierea din/in fiier 1) read(fiier, v1, v2, , vn); - prelucreaz n componente succesive din fiier, ncepand cu componenta situat la poziia indicatorului de articol i se memoreaz n variabilele v1, v2, , vn (valoarea indicatorului de articol crete cu 1, dup citirea unei componente). 2) write(fisier, v1, v2, , vn); - 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. Aplicaia 1.1.3. Se consider fiierul cu nregistrri DATE , care are urmtoarea structur: S se scrie un program care sorteaz fiierul descris anterior dup valorile campului cod material. Soluie:
type inr = record cod_mat:integer; den_mat:string[20]; cod_mag:integer; cant:real; um:string[4]; pu:real; end; fisier = file of inr; var inr1, inr2:inr; f:fisier;ok:boolean; i, j, t, mag:integer; m1,m2:integer; c_er:integer; 14 cod_mat:string[5]; den_m:string[20]; cod_mag:integer; cant:real; um :string[4]; pu:real;

procedure sort1(i,j:integer); var k:integer; begin repeat ok:=true; for k:=i to j-1 do begin seek(f,k); read(f,inr1,inr2); if inr1.cod_mat>inr2.cod_mat then begin seek(f,k); write(f,inr2,inr1); ok:=false end end; until ok; end; {program principal} begin assign(f,'date');reset(f); repeat ok:=true; for i:=0 to filesize(f)-2 do begin seek(f,i); read(f,inr1,inr2); if inr1,cod_mag>inr2.cod_mag then begin seek(f,i); write(f,inr2,inr1);ok:=false end; end until ok; close(f); reset(f);read(f,inr1); mag:=inr1.cod_mag; i:=0; writeln('Magazia:',inr1.cod_mag); while not eof(f) do begin read(f,inr1); with inr1 do if mag=cod_mag then begin j:=filepos(f)-1; sort1(i,j) end else begin i:=filepos(f)-1; mag:=inr1.cod_mag; writeln(Magazia:, cod_mag); end; end; end. 15

Fiiere fr tip Definiia 1.1.4. Fiierele fr tip sunt constituite din blocuri de lungime fix i aceeai pentru fiecare bloc. Observaia 1.1.15. 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. Observaia 1.1.16. Indicatorul de fiier reine numrul blocului curent. Accesul poate fi secvenial sau direct. Observaia 1.1.17. Asemnator cu fiierele cu tip se pot folosi urmtoarele funcii/proceduri: seek, eof, filesize, filepos, erase, rename. Aplicaia 1.1.4. S se creeze un fiier fr tip cu n inregistrri avand cmpurile: nume:string[16]; varsta:integer;
type inregistrare=record nume:string[20]; varsta:integer; end; var f:file;inr:inregistrare; n,i:integer; begin assign(f,'date');write('n=');readln(n); rewrite(f); for i:=1 to n do begin write('Nume=');readln(inr.nume); write('Varsta=');readln(inr.varsta); blockwrite(f,inr,1); end; close(f); end. 16

1.2. Fiiere n limbajul C Fiierul este un grup de octei stocai pe un suport de memorie extern care este tratat n mod unitar de ctre sistemul de operare. Lucrul cu fiiere n C presupune cunoscut modul de lucru cu date de tip struct i cu pointeri. Se utilizeaz conceptul de flux (stream). Un flux se reprezint, n C, printr-un pointer la o entitate de tip FILE care conine informaii despre poziia curent n flux, indicatori de eroare i de sfrit de fiier, zone tampon (eng. buffers) asociate. Limbajul C permite folosirea a dou tipuri de flux: text i binare. Un flux text presupune transferul de caractere organizate n linii de caractere. Fluxul binar reprezint o succesiune de octei care nu suport nici o modificare n timpul transferului. Deschiderea i nchiderea unui fiier Orice fiier nainte de a fi prelucrat trebuie deschis. Dup terminarea prelucrrii unui fiier acesta trebuie nchis. Forma general a funciei pentru deschidere: FILE *fopen(const char *numele_fis, const char *mod); - "deschide un fiier" i-i asociaz numele respectiv; - returneaz un pointer spre tipul FILE (vezi fiierul STDIO.H) sau Null, n caz de eroare unde: numele_fis = pointer ctre numele fiierului ce urmeaz a fi deschis; mod = pointer spre un ir de caractere care definete modul de prelucrare al fiierului, dup deschidere. Se definete astfel: r = deschiderea unui fiier text pentru citire w = deschiderea unui fiier text pentru scriere a = deschiderea unui fiier text pentru adugare r+ = deschiderea unui fiier text pentru modificare r+b = citire/scriere binar rb = citire binar wb = scriere binar Observaia 1.2.1. Cu funcia fopen, un fiier inexistent se poate "deschide" n modul r, w sau a, iar n acest caz este i creat. Observaia 1.2.2. Dac se deschide un fiier existent n modul w atunci se va crea unul nou cu acelai nume, vechiul coninut se pierde. Apelul: fp = fopen("INPUT.TXT") - la apel se deschide fiierul cu numele INPUT.TXT i se stabilete o legtur logic ntre pointerul fp i fiierul INPUT.TXT.
17

Observaia 1.2.3. Deschiderea unui fiier n modul a pentru adugarea de nregistrri dup ultima nregistrare existent n fiier. Observaia 1.2.4. Fiierele corespunztoare dispozitivelor standard nu se deschid de ctre utilizator, ntruct ele sunt deschise automat la lansarea programului. Observaia 1.2.5. Fiierele disc i dispozitivele periferice sunt gestionate de variabila pointer. Prelucrarea pe caractere a unui fisier Fiierele standard pot fi scrise i citite caracter cu caracter, folosind dou funcii simple: putc i getc. Forma general: int putc(int c, FILE *pf); returneaz valoarea lui c, reprezentand codul ASCII al caracterului scris n fiier sau -1, dac este eroare; pf reprezint pointer spre tipul FILE a crui valoare a fost returnat de funcia fopen la deschiderea fiierului n care se scrie. Observaia 1.2.6. n particular pf poate fi unul din pointerii: stdout ieire standard; stderr - ieire pe terminal n caz de eroare; stdaux ieire serial; stdprn - ieire paralel la imprimant. Forma general: int getc(FILE *pf); returneaz codul ASCII al caracterului citit sau EOF la sfrit de fiier; pf - pointer spre tipul FILE a crui valoare a fost returnat de funcia fopen la deschiderea fiierului. n particular pf poate fi pointerul stdin (citire (intrare) de la tastatur). nchiderea unui fiier (eliberarea spaiului de memorie alocat folosind fopen i ntreruperea legturii logice) se realizeaz cu funcia fclose care are prototipul int fclose (FILE *pf); i returneaz valoarea: 0, la nchidere normal sau -1, n caz de eroare. Aplicaia 1.2.1. S se elaboreze un program pentru a copia intrarea standard la ieirea standard folosind funciile putc i getc. Soluie: #include <stdio.h> void main(void) { int c; c= getc (stdin); while (c != EOF) {putc(c, stdout); c=getc(stdin);} }
18

Aplicaia 1.2.2. Cum se copiaz intrarea standard la imprimant? Soluie: # include <stdio.h> void main(void){ int c; c= getc (stdin); while (c != EOF){putc(c, stdprn); c=getc(stdin);} } Operaii de intrare/ieire cu iruri de caractere Biblioteca standard a limbajului C conine funciile: fgets i fputs care permit citire dintr-un, repectiv scrierea ntr-un fiier ale crui nregistrri sunt iruri de caractere. Prototipul: char *fgets (char *s, int n, FILE *pf); returneaz valoarea pointerului s sau NULL la ntlnirea sfritului de fiier; s - pointerul spre zona n care se pstreaz caracterele citite (numele unui tablou de tip char de dimensiune cel puin n); n - dimensiunea n octei a zonei n care se citesc caracterele din fiier; pf - pointerul spre tipul FILE a crui valoare s-a definit la deschiderea fiierului. Observaia 1.2.7. Citirea se oprete la ntlnirea caracterului '\n' sau dup citirea a cel mult n-1 caractere. n acest caz, n zona receptoare se transfer caracterul '\n' i apoi caracterul '\0' (NULL) Funcia fputs scrie ntr-un fiier un ir de caractere care se termin prin '\0' i are prototipul int fputs(const char *s, FILE *pf); Returneaz codul ASCII al ultimului caracter scris n fiier sau 1 la eroare; pf - pointer spre tipul FILE care definete fiierul n care se scrie; s-pointerul spre zona care conine irul de caractere, care se scrie. Observaia 1.2.8. Pentru a citi de la intrarea standard stdin, se poate folosi funcia gets, care nu mai are parametrii pf i n. Parametrul pf este implicit stdin. Observaia 1.2.9. La fiierele text, cnd este ntalnit caracaterul '\n', acesta este transformat ntr-o secven "newline". Fiierele binare nu produc transformri. Operaii de intrare-ieire cu format Acest lucru se realizeaz folosind funciile: fscanf- citire cu format dintr-un fiier; fprintf - scriere cu format n fiier. Opereaz la fel ca printf i scanf cu excepia faptului c lucreaz cu fiiere, nu cu consola.
19

Apelul lui fscanf: fscanf(FILE *pf, char *format, par1, par2, ,parn) citete date, conform formatului, din stream; returneaz valoare EOF, la ntalnirea sfaritului de fiier; pf - pointer spre tipul FILE, a crui valoare a fost definit prin apelul funciei fopen; format - conine texte i/sau specificatori de format (_). Parametrii par1, par2, ,parn definesc zonele receptoare ale datelor citite prin intermediul funciei fscanf. Exemplificare: Apelul fscanf(pf, "%d %c %f", &i, &n, &c); Apelul fprintf(FILE *pf, char *format, par1, parn) - scrie date, n stream, conform formatului. Poziionarea ntr-un fiier Pan acum am citit/scris datele unui fiier n mod secvenial de la nceput pn la sfarit. Utiliznd funcia fseek se poate accesa orice articol al unui fiier (acces aleator). Cu ajutorul ei se poate deplasa capul de citire/scriere al discului n vederea prelucrrii ntregistrrilor fiierului ntr-o ordine oarecare, diferit de cea secvenial. Prototipul Returneaz Int fseek(FILE *pf, long deplasament, int origine); 0, la poziia corect sau o valoare diferit de 0, n caz de eroare;

unde: deplasament reprezint numrul de octei peste care se va deplasa capul de citire/scriere al discului, iar origine ia una din valorile: 0 1 2 Deplasamentul se consider de la nceputul fiierului; Deplasamentul se consider din poziia curent a capului de citire/scriere; Deplasamentul se consider de la sfaritul fiierului.

O alt funcie util n cazul accesului aleator este funcia ftell, care indic poziia capului de citire/scriere din fiier. Prototip Returneaz Long ftell(FILE *pf); O valoare de tip long care definete poziia curent a capului de citire/scriere, i anume reprezint deplasamentul n octei a poziiei capului fa de nceputul fiierului .

Aplicaia 1.2.3. Folosind funcia fseek( ) cutai i citii orice byte dintr-un fiier specificat
20

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

1.3. Probleme rezolvate R1.3.1. Se consider un fiier text IN.txt ce conine numere ntregi dispuse pe mai multe linii i separate prin spaii. Scriei un program care creeaz un fiier OUT.txt ce conine pe fiecare linie media aritmetic a numerelor situate pe aceeai linie n fiierul IN.txt. Media aritmetic va fi scris cu doua zecimale
Varianta Pascal program medie; var x,s,i:integer; f,g:text; begin assign(f,'IN.TXT'); RESET(f); assign(g,'out.TXT'); REWRITE(g); while not eof(f) do begin s:=0; i:=0; repeat read(f,x); i:=i+1; s:=s+x; until eoln(f); writeln(g,s/i:4:2); writeln(s/i:4:2); readln(f); end; close(f); close(g); end.
Varianta C #include <stdio.h> #include <string.h> void main (void){FILE *fin, *fout; char sir[256],sn[256]; long int n,i,j1,j2,suma; float media; if (!(fin=fopen("IN.txt","r"))){ printf("\n Nu pot deschide sursa!"); exit(1);} if (!(fout=fopen("OUT.TXT","w"))){ printf("\n Nu pot crea fisierul destinatie!"); exit(1);} while (!feof(fin)){ fgets(sir,256,fin); n=0;i=0;j1=0;j2=0;suma=0; while(sir[i]){ if (sir[i]=' ') {sn=substr(sir,j1,j2); suma=suma+atoi(sn); j1=j2=i+1;sn=' ';i++; } else {i++; j2++;}} media=suma/n; fprintf(fout, "%10.2f\n",media); } fclose(fin);fclose(fout); } char substr(char sir[256]; int j1,j2){ char ss[]="';int i; if ((j1>strlen(sir)||(j2>strlen(sir)) return 1; for(i=j1;i<j2;i++) ss[i-j1]=sir[i]; return ss; } 22

R1.3.2. Scriei un program care verific dac dou fiiere Input1.txt i Input2.txt au coninut identic. Soluie: Varianta Pascal Varianta C Var i:integer; #include <stdio.h> f,g:text; #include <string.h> s,s1:string; void main (void){ identic:boolean; char sir1[256],sir2[256]; Begin FILE *f1, *f2; assign(f.Input1.txt); int ind; reset(f); if ((f1=fopen("Input1.txt","r")) assign(g.Input2.txt); ==NULL) reset(g); { Identic:=true; printf("\n Nu pot deschide fis1!"); While exit(1); (not eof(f)) } and if((f2=fopen("Input2.txt","r")) (not eof(g)) ==NULL) and (identic) { do printf("\n Nu pot deschide fis2!"); Begin exit(1); readln(f,s); } readln(g,s1); ind=0; If s<>s1 then identic:=false; End; while if eof(f) and not eof(g) then ((!feof(f1))&&(!feof(f2))){ Identic:=false; fgets(sir1,f1); if eof(g) and not eof(f) then fgets(sir2,f2); Identic:=false; if (strcmp(sir1,sir2)!=0) if identic then ind=1 write(Fiierele sunt identice) } else clrscr(); write(Fisierele nu sunt identice); if (ind=0) close(f); printf("\n Fisierele sunt identice!"); close(g); else end. printf("\n Fisierele nu sunt
identice!") fclose(f1); fclose(f2); } 23

R1.3.3. Creai un program care transform toate literele mici din fiierul INPUT.txt n majuscule. Soluie: program pr; uses crt; var f,f1:text;i:integer; s,s1:string; begin clrscr; assign(f,'in.txt'); reset(f); assign(f1,'in1.txt'); rewrite(f1); while not eof(f) do begin readln(f,s); s1:=''; for i:=1 to length(s) do s1:=s1+upcase(s[i]); writeln(f1,s1); end; close(f);close(f1); end.

Exerciiu: S se traduc programul de mai sus n limbajul C. R1.3.4. Se consider o matrice a cu n linii i n coloane stocat n fiierul Matrice.txt (pe prima linie este scris valoarea n, iar pe urmtoarele n linii matricea a, linie cu linie). Se cere s se afieze n fiierul SUMA.TXT, suma elementelor de pe diagonala principal. program matrice; uses crt;type mat = array[1..10,1..10] of integer; var a:mat; i,j,s,n:integer; f,g:text; begin assign(f,'Matrice.txt'); reset(f); assign(g,'Suma.txt'); rewrite(f); readln(f,m); readln(f,n); for i:=1 to m do begin for j:=1 to n do read(f,a[i,j]); readln(f) end; s:=0; for i:=1 to n do s:=s+a[i,i]; writeln(g,s); close(f);
24

close(g); readln; end.

Aplicaii propuse AP1. n fiierul SECVENTE.TXT sunt scrise mai multe linii. Fiecare linie conine cate o secven, secven format din primele patru numere prime (fiecare secven conine cel puin odat fiecare numr prim, fr spaii ntre ele), ir format din cel mult 255 de cifre. Se cere s se scrie n fiierul PERECHI.TXT, pe cate o linie, desprite prin spaii, indicii elementelor ce reprezint capetele secvenei determinate din cea curent din fiierul de intrare astfel ncat secvena din ir s aib lungime maxim i s conin un numr egal de cifre din fiecare numr prim din cele date. Exemplu: Pentru fiierul SECVENTA.TXT 55552753275325732357223 253257322 Atunci fiierul PERECHI.TXT va conine 5 20 47 AP2. n fiierul NUMERE.TXT sunt scrise dou numere cu maxim dou cifre fiecare. Se cere s se scrie n fiierul RASPUNS.TXT mesajul DA, dac unul dintre cuvintele este anagrama celuilalt (conin exact acelai cifre eventual n alt ordine) sau NU, n caz contrar. AP3. n fiierul MATRICE.TXT se afl o matrice n format ptratic astfel: pe prima linie dimensiunea matricei, iar pe urmtoarele linii despite prin spaii elementele matricei. Pe ultima linie se afl un numr ce reprezint linia k. Se cere s se afieze n fiierul ORDONAT.TXT matricea cu elementele n linia k ordonate descrescator. AP4. Se citesc doi vectori deja ordonai cresctor (dou linii) din fiierul VECTORI.TXT; numerele pe linie sunt desprite prin spaii. Se cere s se scrie n fiierul INTERCLASARE.TXT vectoul obinut prin interclasarea celor doi. Exemplu: Pentru fiierul VECTORI.TXT 257 3 4 9 11 Atunci fiierul INTERCLASARE.TXT va conine 2 3 4 5 7 9 11 AP5. Se citesc mai multe numere reale din fiierul INTRARE.TXT Ele sunt dispuse pe mai multe linii, desprite prin spaii n cadrul
25

fiecrei linii. S se scrie n fiierul IESIRE.TXT pe prima linie numrul de numere distincte, iar pe urmtoarele linii, desprite prin spaii, aceste numere ordonate cresctor. Exemplu: Dac fiierul INTRARE.TXT conine 2 3.7 2 5 8 5 Atunci fiierul IEIRE.TXT conine
4 2 3.7 5 8

AP6. Se cere s se scrie n fiierul OUT.TXT numrul de numere prime de pe fiecare linie din fiierul IN.TXT i pe urmtoarea linii numerele prime din fiierul de intrare. AP7. Se dau dou fiiere MULT1.TXT i MULT2.TXT care conin, desprite prin cate un spaiu mai multe numere reale reprezentand cate o mulime fiecare. Se cere s se scrie n fiierul INT_REUN.TXT pe prima linie, intersecia celor 2 mulimi, iar urmtoarea linie reuniunea lor. Exemplu: Dac fiierul MULT1.TXT conine 5.5 6 8 7.6 i fiierul MULT2.TXT conine 5.5 8 7 atunci fiierul INT_REUN.TXT 5.5 8 5.5. 6 7 7.6 8 AP8. Fiierul text FIS.DAT conine numere i cuvinte pe mai multe linii, fiecare avand maximum 255 de caractere. S se realizeze un program care inventariaz coninutul fiierului, afisand pentru fiecare linie i pentru ntregul fisier numrul de caractere, numrul de cuvinte i numrul de valori numerice. AP9. S se ordoneze descresctor dup medii, nregistrrile unui fiier care conine datele i rezultatele candidaiilor la un examen de admitere n clasa a IX-a (sau la facultate). Fiecare nregistrare este compus din cinci cmpuri: un nume (variabil de tip string cu 20 de caractere), trei note reale reprezentand notele la cele dou probe, media obinut la examen i un cmp logic ce memoreaz rezultatul final (ADMIS sau RESPINS). Programul va afia rezultatul examenului de admitere n funcie de un numr citit de la tastatur reprezentnd numrul de locuri posibile.
26

AP10. Fiierul PRODUSE.DAT conine informaii despre produsele dintr-un magazin alimentar: numele produsului (maxim 20 de caractere), preul unitar (numr ntreg, maxim 100.000), cantitatea (numar real) i termenul de garanie (sub forma zi-luna-an cnd expir termenul de folosin al produsului). S se afieze n funcie de data (i s se elimine din fiier) produsele expirate i costul lor. AP11. S se determina frecvena apariiei caracterelor (date de codul lor ASCII) dintr-un fiier precizat. AP12. S se afieze pe ecran toate caracterele unui fiier text existent, caracterele netiparibile (cu cod ASCII mai mic dect 32) fiind nlocuite la scriere cu codul lor ASCII, precedat de caracterul '#'. AP13. S se creeze un fiier text avand ca surs dou fiiere text, al doilea fiind adugat n continuarea primului. AP14. [Numere mari] Se consider dou numere naturale n i m care au cel puin 200 de cifre. S se determine produsul celor dou numere. Pe prima linie a fiierului de intrare INPUT.TXT este scris numrul n, avand cifrele desprite prin cate un spaiu; pe a doua linie este scris numarul m, n mod similar. n fiierul OUTPUT.TXT se va scrie pe fiecare linie cate o cifra din rezultat. AP15. [Goldbach] Se consider un numr n>6 par. S se determine toate reprezentrile lui n ca sum de numere prime (sum cu numr minim de termeni). Rezultatele vor fi scrise n fiierul OUTPUT.TXT, fiecare linie coninand toi termenii dintr-o reprezentare. Exmplu: Pentru n = 8, atunci OUTPUT.TXT conine 35 53 Nu se consider perechile (1, 7) i (7, 1) din cauza numrului 1. AP16. [Factor prim] Se consider un ir de n numere ntregi. S se determine factorul prim care apare la puterea cea mai mare n descompunerea produsului celor n numere. Pe prima linie a fiierului INPUT.TXT este scris numrul n, reprezentand numrul de elemente din ir; pe urmtoarea linie sunt scrise cele n numere. Rspunsul se va afia pe ecran sub forma: i^j cu semnificaia: factorul i la puterea j Exemplu: INPUT.TXT pe ecran se va afia : 4 3^4 24 9 17 21
27

AP17. [Cel mai mare divizor comun] Se consider n numere scrise n baza 16. S se determine cel mai mare divizor comun al celor n numere. Pe prima linie a fiierului INPUT.TXT este scris numrul de numere n; pe urmtoarele n linii se gsesc numerele scrise n hexazecimal. Numrul care reprezint c.m.m.d.c. al celor n numere, se va afia pe ecran. Exemplu: INPUT.TXT se va afisa : 4\n 1A \n 8 \n 10 \n 2 2 AP18. [Cifre romane] S se scrie un program care transform un numr scris cu cifre romane n scrierea cu cifre arabe. n fiierul INPUT.TXT sunt scrise mai multe numere n scriere romana (corecte), fiecare pe cte o linie. Este posibil ca unele din cifrele romane sa fie scrise cu litere mici. Rspunsurile se vor afia pe ecran, fiecare numr pe cte o noua linie. Exemplu: INPUT.TXT pe ecran se va afia: CDLIV 454 MMMMDLXXIII 4573 MCLXVI 1166 CMXLLVIII 948 AP19. [Propoziii] Se consider un text scris pe n linii (n fiierul de intrare INPUT.TXT). Fiecare linie constituie o propoziie. Cuvintele sunt formate doar din litere mari i litere mici i sunt desprite prin: spaiu, virgul i punct. Nici o propozitie nu are mai mult de 250 de caractere. Textul nu conine cuvinte n care s apar liniua de desprire (exemplu: "ntr-un"). S se determine propoziia cu cele mai multe cuvinte i s se afieze pe ecran scriind fiecare cuvnt pe linie nou avnd prima liter majuscul; separatorii nu se vor afia. Exemplu: INPUT.TXT Ce faci Unde esti O sa reusim buna dimineata Alo, este ora sapte si treizeci de minute, fix. se va afisa Alo Este Ora Sapte Si Treizeci De

28

Minute Fix AP20. [Matrice] Se d matricea A cu m linii i n coloane. S se scrie un program care prin intermediul unui meniu realizeaz urmtoarele operaii: Elimin din matrice linia L i coloana k fr a folosi o nou matrice; Ordoneaz cresctor elementele de pe o coloan oarecare j prin interschimbri de linii. Datele de intrare se vor citi dintr-un fiier text. AP21. [Ordonare] Se consider un tablou bidimensional ptratic de dimensiune n*n de numere ntregi. Se cere s se inverseze liniile i coloanele acestuia astfel nct tabloul obinut s conin elemente de pe diagonala principal n ordine cresctoare. Datele de intrare se citesc din fiierul de intrare INPUT.TXT sub forma urmtoare: pe prima linie este scris numrul n, reprezentnd numrul de linii i coloane, iar pe urmtoarele n linii, se gsesc elementele tabloului linie dup linie. Rezultatul va fi scris n fiierul OUTPUT.TXT. Pe fiecare linie a fiierului se va scrie o linie a tabloului obinut. Exemplu: INPUT.TXT OUTPUT.TXT 3 -1 8 7 243 234 156 165 -1 7 8 AP22. [Frecvene] Se consider un fiier INPUT.TXT care conine un text. Se cere determinarea listei cu frecvena de apariie maxim. In cazul cand exist mai multe soluii se vor afia toate. Fiierul de intrare conine pe fiecare linie cel mult 250 de caractere. Nu se va face distincie ntre litera mic i litera mare. Rezultatul se va afia pe ecran. Exemplu: INPUT.TXT pe ecran se va afisa: Mama si cu tata merg la piata A apare de 7 ori Memoriu, memoriu! M apare de 7 ori

29

AP23. [Ordonare n matrice] Se consider o matrice de dimensiune n*m. S se reaeze elementele n matrice astfel nct ele s apar n ordine cresctoare att pe linii ct i pe coloane. Matricea A se gsete n fiierul de intrare INPUT.TXT, fiecare linie a matricei pe cte o linie din fiier. Nu sunt specificate valoarile pentru n i m. Matricea obinut se va scrie, n mod similar, n fiierul OUTPUT.TXT. n cazul n care exist mai multe soluii se va scrie n fiier numai una. Exemplu: INPUT.TXT OUTPUT.TXT 3 2 5 44 3 1 122222 6 7 55 4 3 2 333334 4 10 4 2 4 5 444445 34 5 6 8 2 4 555667 5 3 2 4 41 3 8 10 34 41 44 55 AP24. O matrice cu elemente ntregi este memorat n fiierul text in.txt sub urmtorul format: pe prima linie numrul n de linii i numrul m de coloane. Pe urmtoarele n linii, elementele de pe fiecare linie a matricii. Citii matricea i tiprii-o pe coloane n fiierul out.txt. AP25. Citii un text scris pe mai multe linii n fiierul text.txt. Calculai, pentru fiecare liter a alfabetului, procentul de cuvinte care ncep cu acea liter. Separatori ntre cuvinte vor fi considerai: blancul, punctul, virgula i sfritul de linie. AP26. Creai cu editorul Pascal un fiier text pe mai multe linii. Scriei un program care calculeaz: a) Numrul de cuvinte din fiier. Ca separatori ntre cuvinte se vor considera blancurile i sfritul de linie. b) Tiprii liniile care conin cel puin o vocal. c) Cte linii conin mai mult de n cuvinte, n citit de la tastatur?

30

2. Structuri de date
O structur de date este o mulime de date organizate ntr-un anumit mod mpreun cu relaiile dintre acestea. n funcie de modul de alocare, structurile de date se clasific n: structuri de date statice : tabloul, nregistrarea, mulimea, fiierul. Structurile de date statice ocup o zon de memorie constant pe toat durata de executare a blocului n care apare declaraia i elementele ocup poziii fixe. Fiierele sunt structuri de date externe (vezi capitolul 1). structuri de date semistatice: stiva alocat static, coada alocat static. Structurile de date semistatice ocup o zon de memorie de dimensiune constat, alocat pe toat durata executrii blocului n care apare declaraia de structur, iar elementele ocup poziii variabile pe parcursul executrii programului. structuri de date dinamice: lista nlnuit, structuri arborescente. Structurile de date dinamice ocup o zon de memorie de dimensiune variabil, alocat dinamic. Alocarea dinamic permite gestionarea memoriei n timpul executrii programului. Ele sunt mult mai flexibile dect cele statice i din aceast cauz sunt extrem de avantajoase. Liste: O list este o colecie de elemente de informaie (noduri) aranjate ntr-o anumit ordine. Lungimea unei liste este numrul de noduri din list. Structura corespunztoare de date trebuie s ne permit s determinm eficient care este primul/ultimul nod n structur i care este predecesorul/succesorul (dac exist) unui nod dat. Limbajele Pascal sau C(++) ofer posibiliti de implementare a acestor structuri att static ct i dinamic. Operaiile curente care se fac n liste sunt: inserarea unui nod, tergerea (extragerea) unui nod, concatenarea unor liste, numrarea elementelor unei liste etc. Implementarea unei liste se poate face n principal n dou moduri: Implementarea secvenial, n locaii succesive de memorie, conform ordinii nodurilor n list. Avantajele acestei tehnici sunt accesul rapid la predecesorul/succesorul unui nod i gsirea rapid a primului/ultimului nod. Dezavantajele sunt inserarea/tergerea relativ complicat a unui nod i faptul c nu se folosete ntreaga memorie alocat listei. Implementarea nlnuit. Fiecare nod conine dou pri: informaia propriu-zis i adresa nodului succesor. Alocarea
31

memoriei fiecrui nod se poate face n mod dinamic, n timpul rulrii programului. Accesul la un nod necesit parcurgerea tuturor predecesorilor si, ceea ce poate lua ceva mai mult timp. Inserarea/tergerea unui nod este, n schimb, foarte rapid. Listele se pot clasifica dup numrul de legturi n: liste simple liste duble liste circulare O list simpl are o singur legtur, legtura ultimului element este adresa NIL/NULL. Pentru a accesa lista avem nevoie de o variabil care s pstreze adresa primului element (cap sau prim). O list dubl are dou legturi: legtura de tip urmtor i legtura de tip precedent sau anterior. O lista circular este o lista n care, dup ultimul nod, urmeaz primul, deci fiecare nod are succesor i predecesor. Listele se pot clasifica dup locul n care se fac operaiile de adugare/eliminare astfel: stive cozi 2.1. Liste simplu nlnuite ntre nodurile unei liste simplu nlnuite este definit o singur relaie de ordonare. Fiecare nod conine un pointer a crui valoare reprezint adresa nodului urmtor din list.
Limbajul Pascal

type lista

= ^nod nod=record inf:tip ; urm: lista; end;

Limbajul C(++) typedef struct nod { tip inf; struct nod *urm; }lista;

unde urm este adresa urmtorului nod (pointer ctre urmtorul nod), iar inf este un cmp de informaie util. Operaii asupra listei simplu nlnuite Crearea unei liste simplu nlnuite: 1. Se iniializeaz pointerul prim cu Nil/NULL, deoarece lista la nceput este goal; 2. Se rezerv zon de memorie n memoria heap pentru nodul curent;
32

3. Se ncarc nodul curent cu date; 4. Se determin adresa ultimului nod i se realizeaz legtura cu nodul creat; 5. Se reia cu pasul 2 dac se introduce un nod nou. Inserarea unui element x al crui cmp cheie a fost iniializat n faa unei liste nlnuite LISTA-INSEREAZA(p,x) 1: urm(x) p 2: dac p<>NIL atunci px Cutarea ntr-o list nlnuit p a elementului x se realizeaz prin subprogramul LISTA-CAUTA i returneaz pointerul la acest obiect. LISTA-CAUTA(p,x) 1. qp 2. ct timp q<>NIL i cheie(q)<>x execut qurm(q) 3. returneaz q Probleme rezolvate 1. Fiind dat o list simplu nlnuit cu elemente numere ntregi s se realizeze un program care s execute urmtoarele operaii: crearea, parcurgerea, adugarea unui nod la nceputul listei, adugarea unui nod la sfritul listei, tergerea unui nod de pe o poziie dat. Observaii:
Limbajul Pascal: Procedura NEW(pointer)- alocarea dinamic a memoriei pentru variabila dinamic pointer. Procedura DISPOSE(pointer)eliberarea memoriei ocupate de ctre variabila dinamic pointer. Limbajul C(++) Funcia MALLOC se folosete pentru a rezerva octei din memoria heap. Trebuie inclus fiierul antet: stdlib.h sau alloc.h

Rezolvare: 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, prelucrm informaiile din nod etc.
33

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. Implementare n Pascal:
type lista=^nod; nod=record inf:integer; urm:lista end; var p,x:integer;cap:lista;{adresa primului nod al listei} procedure adaug(var cap:lista;x:integer); {adaugarea la sfarsitul listei} var nou,q:lista; begin new(nou);nou^.inf:=x;nou^.urm:=nil; if cap=nil then cap:=nou else begin q:=cap; while q^.urm<> nil do q:=q^.urm; q^.urm:=nou; end; end; procedure adaug_inc(var cap:lista;x:integer); {adaugarea la inceput} var nou:lista; begin new(nou);nou^.inf:=x;nou^.urm:=nil; {crearea nodului nou} if cap=nil then cap:=nou else begin nou^.urm:=cap;cap:=nou; {realizarea legaturii si primul nod devine nodul creat} end; end; procedure listare(cap:lista);{listarea listei} var t:lista; begin t:=cap; while t<>nil do begin write(t^.inf,' '); {prelucrarea informatiei} t:=t^.urm; {trecerea la urmatorul nod} end; end; procedure sterge(var cap:lista; p:integer); 34

{stergerea nodului de pe pozitia p} var q,w,t:lista;i:integer; begin if cap=nil then writeln('Lista vida !!! ') else if p=1 then begin {stergere la inceputul listei} q:=cap; cap:=cap^.urm; dispose(q); end else if (cap<> nil) then begin t:=cap; i:=1; while (t^.urm<> nil) and (i+1<p) do begin inc(i) ;t:=t^.urm end; if t^.urm=nil then write('nu exista suficiente pozitii') else begin w:=t^.urm; t^.urm:=t^.urm^.urm; dispose(w) end end end; begin read(x); while x<>0 do begin adaug_inc(cap,x); read(x); end; listare(cap); write('pozitia');read(p);sterge(cap,p); listare(cap); write('informatia adaugata la sfarsit');read(x);adaug(cap,x); listare(cap) end.

Implementare n C:
#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); 35

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

2. Inversarea legturilor ntr-o list simplu nlnuit. Rezolvare: 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. Implementare Pascal: program invers; type lista=^nod; nod=record inf:integer; urm:lista end; var i,n,x:integer; p:lista; procedure creare(var p:lista; x:integer); var q:lista; begin if p=nil then begin new(p); p^.inf:=x; p^.urm:=nil end else begin q:=p; while q^.urm<>nil do q:=q^.urm; new(q^.urm); q^.urm^.inf:=x; q^.urm^.urm:=nil; end; end; procedure listare(p:lista); var q:lista; begin q:=p; while q<>nil do begin write(q^.inf,' '); q:=q^.urm end; end; function inversare(p:lista):lista; Subprogramul de inversare n C: lista* invers(lista*p){ var p1,p2,p3:lista; lista *p1,*p2,*p3; begin p1=p; p1:=p; p2=p->urm; p2:=p^.urm; p->urm=NULL; p^.urm:=nil; while (p2){ while p2<>nil do begin p3=p2->urm; p3:=p2^.urm; p2->urm=p1; p2^.urm:=p1; p1=p2; p1:=p2; p2=p3; p2:=p3; } end; return p1; inversare:=p1; } end;
37

begin read(n); for i:=1 to n do begin read(x); creare(p,x) end; listare(p);writeln; p:=inversare(p); listare(p) end. 3. S se efectueze suma a dou polinoame rare (polinom cu foarte muli coeficieni egali cu zero) folosind liste simplu nlnuite. Rezolvare: 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. Implementare Pascal: type lista=^nod; nod=record grad:1..5000; coef:integer; urm:lista end; var a,b,p,q,r:lista; i,n,m:integer; procedure creare(var p:lista); begin 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} for i:=2 to n do begin new(a); write('coef ',i,':');readln(a^.coef); write('grad ',i,':');readln(a^.grad); b^.urm:=a; b:=a; b^.urm:=nil end end; procedure listare(p:lista); var a:lista; begin a:=p; while a<>nil do begin write(a^.coef,'x^', a^.grad,' +'); a:=a^.urm end; writeln(#8,' '); end;
38

procedure aduna(p,q:lista;var r:lista); var a,b,c,d:lista; begin a:=p;b:=q; {c este adresa ultimului nod pentru lista suma} while (a<>nil) and (b<>nil) do if a^.grad=b^.grad then begin if r=nil then begin new(c);c^.grad:=a^.grad; c^.coef:=a^.coef +b^.coef; r:=c; r^.urm:=nil; end else begin new(d); d^.grad:=a^.grad; d^.coef:=a^.coef+b^.coef; c^.urm:=d;c:=d;c^.urm:=nil end; a:=a^.urm;b:=b^.urm; end else if a^.grad<b^.grad then begin if r=nil then begin new(c); c^.grad:=a^.grad; c^.coef:=a^.coef ; r:=c; r^.urm:=nil; end else begin new(d); d^.grad:=a^.grad; d^.coef:=a^.coef; c^.urm:=d;c:=d;c^.urm:=nil; end; a:=a^.urm; end else begin if r=nil then begin new(c);c^.grad:=b^.grad; c^.coef:=b^.coef;r:=c;r^.urm:=nil; end else begin new(d); d^.grad:=b^.grad; d^.coef:=b^.coef; c^.urm:=d;c:=d;c^.urm:=nil; end; b:=b^.urm; end;
39

end; begin creare(p);creare(q);listare(p);listare(q); r:=nil; aduna(p,q,r); listare(r); readln; end. 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. Indicaie: Calcularea produsului se va face prin parcurgerea tuturor perechilor de termeni astfel: -fiecare pereche genereaz un nod n polinomul produs -gradul noului nod va fi suma gradelor nodurilor din pereche -coeficientul noului nod va fi produsul coeficienilor termenilor din pereche -se elimin nodurile din lista de termeni prin pstrarea fiecrui grad o singur dat astfel: dac exist dou noduri cu acelai grad unul din ele va fi eliminat, iar coeficientul celuilalt va avea valoarea sumei coeficienilor celor doi termeni. Valoarea unui polinom se va calcula prin parcurgerea listei i adugnd la valoare produsul dintre coeficient i valoarea dat la puterea gradului din nod. 4.Dndu-se dou liste simplu nlnuite cu elemente numere intregi distincte, s se afiseze diferena celor dou liste i elementele comune celor dou liste. Rezolvare: Diferena celor dou liste conine elementele primeia care nu sunt n cea de-a doua. Se parcurge prima list i pentru fiecare nod se verific dac este n cea de-a doua list, dac nu se afl atunci se adaug listei trei. Intersecia celor dou liste se determin parcurgnd
40

if a<>nil then c^.urm:=a; if b<>nil then c^.urm:=b;

prima list i pentru fiecare nod se verific dac elementul se afl i n cea de-a doua list, dac da atunci se adaug n cea de-a treia list. Implementare Pascal: type lista=^nod; nod = record inf:integer; urm:lista end; var q,cap1,cap2,cap3:lista; gasit:boolean; procedure creare(var cap:lista); var n,i:integer; nou,q:lista; begin write('nr elem'); read(n); new(cap); read(cap^.inf); cap^.urm:=nil; for i:=2 to n do begin new(nou); read(nou^.inf); nou^.urm:=nil; q:=cap; while q^.urm<>nil do q:=q^.urm; q^.urm:=nou end end; procedure diferenta(cap1,cap2:lista); var x:integer; q2:lista; begin q:=cap1; while q<>nil do begin x:=q^.inf; gasit:=false; q2:=cap2; while q2<>nil do begin if q2^.inf=x then gasit:=true; q2:=q2^.urm end; if not gasit then write(x, ' '); q:=q^.urm end end; procedure afisare(cap:lista); var q:lista; begin q:=cap; while q<>nil do begin write(q^.inf,' '); q:=q^.urm end; writeln; end;
41

procedure intersectie(cap1,cap2:lista; var cap3:lista); var q,q2,nou,q3:lista; x:integer; begin q:=cap1; while q<>nil do begin x:=q^.inf; gasit:=false; q2:=cap2; while q2<>nil do begin if q2^.inf=x then gasit:=true; q2:=q2^.urm; end; if gasit then if cap3=nil then begin new(cap3); cap3^.inf:=x; cap3^.urm:=nil end else begin new(nou); nou^.inf:=x ; nou^.urm:=nil; q3:=cap3; while q3^.urm<> nil do q3:=q3^.urm; q3^.urm:=nou end; q:=q^.urm end end; begin creare(cap1); creare(cap2); afisare(cap1); afisare(cap2); diferenta(cap1,cap2); writeln; diferenta(cap2, cap1); writeln('intersectie'); intersectie(cap1,cap2,cap3); afisare(cap3); end. Exerciiu: S se implementeze aplicaia de mai sus in C. 5. S se creeze o list simplu nlnuit, cu informaie numeric astfel nct la orice moment al inserrii lista s fie ordonat cresctor dup informaie. Rezolvare: Paii: -crearea unui nod nou -dac informaia care se adaug este mai mic dect informaia din capul listei atunci se insereaz n faa primului nod -altfel se parcurge lista pn la primul nod a crei informaie este mai mare dect informaia noului nod i se insereaz.
42

Implementare C: #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); void main(){ lista *prim; prim=creare(); parcurgere(prim); } lista *creare(){ int n,inf; lista *prim,*p,*q,*nou; printf("nr. de elemente");scanf("%d",&n); prim=NULL; for(int i=1;i<=n;i++){ printf("informatia nod");scanf("%d",&inf); nou=(lista *)malloc(sizeof(lista)); nou->inf=inf; if (prim==NULL){ prim=nou;prim->urm=NULL; } else if (prim->inf>inf){ nou->urm=prim;prim=nou; } else { p=q=prim; while(p&&p->inf<inf){q=p; p=p->urm;} if (p) {q->urm=nou; nou->urm=p;} else{q->urm=nou; nou->urm=NULL;} } } return prim; } void parcurgere(lista *p){ lista *q; for (q=p;q;q=q->urm) printf("%d ",q->inf); }
43

Exerciiu: S se implementeze aplicaia de mai sus n Pascal. 6. S se scrie un program pentru interclasarea a dou liste ordonate simplu nlnuite. Rezolvare: Se va parcurge simultan cele dou liste urmnd ca introducerea unui nod n lista final s fie fcut din lista care are valoarea informaiei din nod mai mic. Implementare C: #include <stdio.h> #include <stdlib.h> #include <alloc.h> typedef struct nod {int inf; struct nod*urm;}lista; lista *inter(lista *prim1, lista*prim2){ lista *prim,*ultim; if (prim1->inf>prim2->inf){ prim=prim2;prim2=prim2->urm; } else { prim=prim1; prim1=prim1->urm; } ultim=prim; while(prim1&&prim2) if (prim1->inf>prim2->inf){ ultim->urm=prim2; ultim=prim2; prim2=prim2->urm; } else {ultim->urm=prim1; ultim=prim1; prim1=prim1->urm; } if (prim1) ultim->urm=prim1; else ultim->urm=prim2; return prim; } lista *creare(void); void parcurgere(lista *p);
44

void main(){ lista *prim1,*prim2,*prim; prim1=creare(); prim2=creare(); /* parcurgere(prim1) */; prim=inter(prim1,prim2); parcurgere(prim1); } lista *creare(){ int n,inf; lista *prim,*p,*q,*nou; printf("nr. de elemente");scanf("%d",&n); prim=NULL; for(int i=1;i<=n;i++){ printf("informatia nod");scanf("%d",&inf);; nou=(lista *)malloc(sizeof(lista)); nou->inf=inf; if (prim==NULL){ prim=nou; prim->urm=NULL; } else if (prim->inf>inf){ nou->urm=prim;prim=nou; } else { p=q=prim; while(p&&p->inf<inf){q=p;p=p->urm;} if(p) {q->urm=nou;nou->urm=p;} else { q->urm=nou;nou->urm=NULL; } } } return prim; } void parcurgere(lista *p){ lista *q; for (q=p;q;q=q->urm) printf("%d ",q->inf); } Exerciiu: S se implementeze aplicaia de mai sus n limbajul Pascal.
45

2.2. Liste dublu nlnuite Pentru liste duble create dinamic modul de definire a unui nod este:
Limbajul Pascal type lista=^nod; nod=record inf:tip; urm, ant:lista; end; typedef struct nod{ inf tip; struct nod *urm; struct nod *ant; }lista;

Operaiile care se pot defini asupra listelor dublu nlnuite sunt aceleai ca i n cazul listelor simplu nlnuite: - crearea unei liste dublu nlnuite; - accesul la un element al unei liste dublu nlnuite; - inserarea unui nod ntr-o list dublu nlnuit; - tergerea unui nod dintr-o list dublu nlnuit; - tergerea unei liste dublu nlnuite. Probleme rezolvate 1. S se scrie un program care va conine un meniu cu principale operaii asupra listei dublu nlnuite. Implementarea Pascal a soluiei: type lista=^nod; nod=record inf:integer; urm,ant:lista end; var cap:lista; x:integer; procedure creare(var cap:lista); begin new(cap); write('inf=');readln(cap^.inf); cap^.urm:=nil;cap^.ant:=nil; end; procedure adaugare(var cap:lista); var q,nou:lista; begin new(nou);readln(nou^.inf);nou^.urm:=nil; q:=cap; while q^.urm <> nil do q:=q^.urm; q^.urm:=nou;nou^.ant:=q; end;
46

procedure inserare(var cap:lista); var nou,q:lista; k,i:integer; begin writeln('unde inserezi? '); read(k);new(nou); write('ce? ');readln(nou^.inf); if k=1 then begin cap^.ant:=nou; nou^.urm:=cap; nou^.ant:=nil; cap:=nou; end else begin q:=cap; i:=1; while (q^.urm<>nil) and (i<k) do begin q:=q^.urm; inc(i) end; if i=k then begin nou^.ant:=q^.ant; q^.ant^.urm:=nou; nou^.urm:=q; q^.ant:=nou; end else begin write('nu exista'); readln end end end; procedure stergere(var cap:lista); var q,p:lista; k,i:integer; begin write('unde stergi? '); readln(k); if cap<>nil then if k=1 then begin q:=cap; cap:=cap^.urm; dispose(q); cap^.ant:=nil; end else begin p:=cap;i:=1; while (p^.urm<>nil) and(i<k) do begin p:=p^.urm; inc(i); end;
47

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

if i=k then begin q:=p; p^.ant^.urm:=p^.urm; p^.urm^.ant:=p^.ant; dispose(q); end else begin write('nu exista'); readln end

2. Crearea i parcurgerea listei dublu nlnuite n limbajul C: #include<stdio.h> #include<stdlib.h> typedef struct nod{int inf; struct nod*urm,*ant; } lista; lista*prim ,*ultim; void creare(int n); void parcurg(lista*prim); void parcurg1(lista*ultim); void main(){ int n; printf("numarul de elemente:");scanf("%d",&n); creare(n); puts("\n Parcurgere directa");parcurg(prim); puts("\n Parcurgere indirecta");parcurg1(ultim); } void 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; for(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; } } void parcurg(lista*p){ if (p){ printf("%d ",p->inf); parcurg(p->urm); } } void parcurg1(lista *p){ lista *q; for (q=p;q;q=q->ant) printf("%d ",q->inf); }
49

2.3. Liste circulare 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> typedef struct nod{ int inf; struct nod *urm;}lista; void 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); for (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); for (q=prim->urm;q!=prim;q=q->urm) printf("%d ",q->inf); } Problem rezolvat: 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.
50

Rezolvare: 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. Implementarea Pascal (Lista circular este simpl.) type lista=^nod; nod=record inf:integer; urm:lista end; var i,n,m,j:integer; prim,q,p:lista; procedure creare(var prim:lista;x:integer); begin new(prim); prim^.inf:=x; prim^.urm:=prim end; procedure adaugare(var prim:lista;x:integer); var q,p:lista; begin new(q); q:=prim; while q^.urm<>prim do q:=q^.urm; new(p); p^.inf:=x; q^.urm:=p;p^.urm:=prim; end; procedure listare(prim:lista); var q:lista; begin new(q);q:=prim; write(q^.inf,' '); while q^.urm<>prim do begin q:=q^.urm; write(q^.inf,' ') end; end; begin {program principal} read(n); creare(prim,1); for i:=2 to n do adaugare(prim,i); listare(prim); read(m); p:=prim; for i:=1 to n-1 do begin if i=1 then for j:=1 to m-2 do p:=p^.urm else for j:=1 to m-1 do p:=p^.urm; q:=p^.urm; write(q^.inf,' '); p^.urm:=q^.urm; dispose(q); end; writeln('castigator=',p^.inf); end.
51

Implementarea C (Lista circular este dubl). #include <stdio.h> #include<stdlib.h> typedef struct nod{int inf; struct nod *urm,*ant; }lista; lista *prim,*p,*q; void creare(void); void parcurgere(void); int n,m,i,k; void main(){ creare(); printf("pasul de numarare");scanf("%d",&m); parcurgere(); while (p!=p->ant){ for( 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); } void parcurgere(){ for (p=prim,i=1;i<=n;i++,p=p->urm) printf("%d",p->inf); /* p=p->urm;*/ } void creare(){ printf("nr. de copii");scanf("%d",&n); prim=(lista*)malloc(sizeof(lista));prim->inf=1; prim->urm=prim->ant=NULL; p=prim; for (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; }

52

2.4. Stive O 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.

push pop
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: function push(x, S[1 .. n]) {adauga nodul x in stiva} if top = n then return stiva plina top top+1 S[top] x return succes function pop(S[1 .. n]) {sterge ultimul nod inserat din stiva si il returneaza} if top =0 then return stiva vida x S[top] top top-1 return x Cei doi algoritmi necesit timp constant, deci nu depind de mrimea stivei.
53

Problem rezolvat: Realizai un meniu n limbajul Pascal care s conin operaii asupra stivei.

type stiva=^nod; nod=record inf:integer; urm:stiva end; var cap:stiva; x:integer; procedure adauga(var cap:stiva); var nou:stiva; begin new(nou); writeln('Ce sa adaug? '); readln(nou^.inf); nou^.urm:=nil; if cap=nil then cap:=nou else begin nou^.urm:=cap; cap:=nou; end; end; procedure sterge(var cap:stiva); var q:stiva; begin if cap=nil then writeln('Stiva vida') else begin q:=cap; cap:=cap^.urm; dispose(q) end; end; procedure parcurgere(cap:stiva); var q:stiva; begin q:=cap; while q<> nil do begin writeln('|',q^.inf,'|'); q:=q^.urm end; writeln('___') end;
54

Rezolvare: Implementarea Pascal:

begin while x<> 4 do begin writeln('1.Adaugare'); writeln('2.Stergere'); writeln('3.Listare'); writeln('4.Iesire'); writeln('Dati optiunea'); readln(x); case x of 1:adauga(cap); 2:sterge(cap); 3:parcurgere(cap) end end end. Exerciiu: S se implementeze n limbajul C aplicaia de mai sus. Probleme propuse 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 2.5. Cozi 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. First In First Out). 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
55

atunci cnd coada este vid. Iniial, avem p= u= 0. Inserarea i tergerea (extragerea) unui nod necesit timp constant. Operaii asupra cozii: function insert-queue(x, C[0 .. n-1]) {adauga nodul x in capul cozii} p (p+1) mod n if p=u then return coada plina C[p] x return succes function delete-queue(C[0 .. n-1]) {sterge nodul din coada listei si il returneaza} if p=u then return coada vida u (u+1) mod n x C[u] return 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. Problem rezolvat: Relizarea unui meniu pentru implementarea static a cozii. Rezolvare: 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. Implementarea Pascal: TYPE coada=array[1..50] of integer; var c:coada; p,n,u,o,x:integer; procedure adaugare(var c:coada; var p,u:integer;x:integer); begin if p<>(u mod n)+1 then begin c[u]:=x; u:=u mod n +1 end else writeln('coada plina'); end;
56

procedure stergere(var c:coada; var p,u,x:integer); begin if p<>u then begin x:=c[p]; p:=p mod n+1 end else writeln('coada goala'); end; procedure listare(c:coada;p,u:integer); var i:integer; begin if p=u then writeln('coada goala') else begin i:=p; while i<>u do begin write(c[i],' '); i:=i mod n+1 end; end; end; begin 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); case o of 1: begin write('introduceti numarul adaugat');readln(x); adaugare(c,p,u,x); end; 2: begin stergere(c,p,u,x); if p<>u then writeln(x); end; 3: listare(c,p,u); end; writeln; until o=4; end. Exerciiu: S se implementeze aplicaia de mai sus n limbajul C++.
57

Problem rezolvat: S se creeze un program care s conin un meniu cu operaii asupra unei cozi alocate dinamic. Rezolvare: Implementarea n limbajul C++: #include <conio.h> #include<stdlib.h> #include<iostream.h> // intrri-ieiri n C++ typedef struct nod {int inf; struct nod *urm; }lista; void adaug(lista* &prim, int x){ lista *nou, *p; nou=new 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; for (int i=0;i<n;i++){ cout<<"inf "<<(i+1)<<":"; cin>>x; adaug(prim,x); } return prim; } void parcurgere(lista *prim){ lista *p; clrscr(); p=prim; while (p!=NULL){ cout<<p->inf<<' '; p=p->urm;} cout<<'\n'; getch(); }
58

void sterg(lista *&prim){ lista *p; if (prim==NULL) cout<<"coada este vida"; else { 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); }
59

Exerciiu: S se realizeze programul n Pascal corespunztor aplicaiei de mai sus. Probleme propuse: 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
60

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.

61

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. 2.6. Grafuri 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 (a1, a2), (a2, a3), ..., (an-1, an) sau de forma {a1, a2}, {a2, a3}, ..., {an-1, an} 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
62

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:

8 7 5 2 6 0 1 3 4

0 1 2 3 4 5 6 7 8 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 2 0 0 0 0 0 0 1 0 0 3 0 0 0 0 1 0 0 0 0 4 0 0 0 0 0 1 0 0 0 5 0 0 0 1 0 0 0 1 0 6 0 0 0 0 0 0 0 0 0 7 0 0 1 0 0 0 0 0 1 8 0 0 0 0 0 0 0 0 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

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

Exemplu:

8 7 5 2 6 0 1 3 4

0 1 2 3 4 5 6 7 8

2 6 6 4 5 3

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 1 2 face n ordinea: 1 3 4 5 2 6 Cel mai cunoscut mod de imple3 mentare a parcurgerii DF se realizeaz cu ajutorul unei funcii recursive, dar exist i cazuri n care este recomandat 4 o implementare nerecursiv. 5 Implementarea acestei metode se 6 face folosind o stiv. Aceasta este iniia65

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: procedure DF(G) for fiecare v V do marca[v] nevizitat for fiecare v V do if marca[v] = nevizitat then ad(v) procedure ad(v) {varful v nu a fost vizitat} marca[v] vizitat for fiecare virf w adiacent lui v do if marca[w] = nevizitat then ad(w) Algoritmul iterativ: procedure iterad(v) S stiva vida marca[v] vizitat push(v, S) while S nu este vida do while exista un varf w adiacent lui ftop(S) astfel incat marca[w] = nevizitat do 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,
66

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(n2). 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 nodurilor 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 ct timp 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. procedure lat(v) C coada vida marca[v] vizitat insert-queue(v, C)
67

while C nu este vida do u delete-queue(C) for fiecare virf w adiacent lui u do if marca[w] = nevizitat then marca[w] vizitat insert-queue(w, C) Pentru compararea celor dou metode apelm procedurile iterad i lat din procedura parcurgere(G) procedure parcurge(G) for fiecare v V do marca[v] nevizitat for fiecare v V do if marca[v] = nevizitat then {iterad sau lat} (v) Aplicaia 2.6.1: 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]
68

for i = 1 to n-2 caut cel mai mic D[v] pentru fiecare v S S = S {v} for toate vrfurile u S if (D[u] > D[v] + M[v][u]) then D[u] = D[v] + M[v][u] Implementare n C: #include <stdio.h> #include <string.h> #define FALSE 0 #define TRUE 1 #define MAXN 20 int setupDijkstra (int *nod_p, int a[MAXN][MAXN], int *startnod_p); void doDijkstra (int nod, int a[MAXN][MAXN], int startnod); void traceinfo (int S[MAXN], int D[MAXN], int nod); int main(){ int nod, startnod; int a[MAXN][MAXN]; printf("Algoritmul lui Dijkstra\n"); if (setupDijkstra(&nod, a, &startnod)) return 1; doDijkstra(nod, a, startnod); return 0; } int setupDijkstra (int *nod_p, int a[MAXN][MAXN], int *startnod_p){ int i, j; do{ printf("Introduceti 0 pentru a specifica graful,sau 1 pentru exemple "); scanf("%d", &i); }while ((i < 0) || (i > 1)); if (i == 1){ *nod_p = 5; for (i=0; i<*nod_p; i++) for (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;
69

} void doDijkstra (int nod, int a[MAXN][MAXN], int startnod){ int S[MAXN]; int D[MAXN]; int i, j, urmnod, mic; /* initializare */ for (i=0; i<nod; i++) S[i] = FALSE; S[startnod] = TRUE; for (i=0; i<nod; i++) {D[i] = a[startnod][i]; } printf("Initializare\n"); traceinfo(S, D, nod); for (i=1; i<nod; i++){ urmnod = 999; mic = 999; for (j=0; j<nod; j++){ if (!S[j]){ if (D[j] < mic){ mic = D[j];urmnod = j;} }}
70

} else { printf("Enter number of nod (1-%d) ", MAXN); if (scanf("%d", nod_p) != 1) return 1; if ( (*nod_p < 1) || (*nod_p > MAXN) ) return 2; for (i=0; i<*nod_p; i++){ printf("Introduceti randul %d matricii: ", i+1); for (j=0; j<*nod_p; j++) if (scanf("%d", &a[i][j]) != 1) return 3; } printf("introduceti nodul (1-%d) ", *nod_p); if (scanf("%d", &i) != 1) return 4; if ( (i < 1) || (i > *nod_p) ) return 5; *startnod_p = i-1; } return 0;

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;

if (urmnod >= nod) return; // printf(" D[%c]=%2d, ", 'a'+urmnod, mic); printf("adauga nodul %c to S\n", 'a'+urmnod); S[urmnod] = TRUE; for (j=0; j<nod; j++){ if (!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]); */ if (D[j] > D[urmnod] + a[urmnod][j]){ D[j] = D[urmnod] + a[urmnod][j]; /*printf("D[%c] schimba %2d\n", 'a'+j, D[j]); */ } else /* printf("nu schimba\n"); */ } } traceinfo(S, D, nod); } } void traceinfo(int S[MAXN], int D[MAXN], int nod){ int i; printf(" S = {"); for (i=0; i<nod; i++) if (S[i]) printf("%c", 'a' + i); printf("}\n"); printf(" D = "); for (i=0; i<nod; i++) printf("%3d", D[i]); printf("\n"); } Aplicaia 2.6.2: Algoritmul lui Bellman-Ford (determinarea drumurilor 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,
71

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 i 1,|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: #include <stdio.h> #include <string.h> #define FALSE 0 #define TRUE 1 #define MAXN 26 #define INFINIT 999 int setupBellman(int *nod_p, int a[MAXN][MAXN], int *start_p); int doBellman(int nod, int a[MAXN][MAXN], int start); void traceinfo(int D[MAXN], int nod); int main(){ int nod, start; int a[MAXN][MAXN]; printf("Algoritmul lui Bellman-Ford\n"); if (setupBellman(&nod, a, &start)) return 1; if (doBellman(nod, a, start)){ printf(" Ciclu negativ\n"); return 2;} return 0;}
72

int setupBellman (int *nod_p, int a[MAXN][MAXN], int *start_p){ int i, j; do{ printf("Introduceti 0 pentru graf, or 1 pentru exemple "); scanf("%d", &i); }while ((i < 0) || (i > 1)); if (i == 1){ *nod_p = 5; for (i=0; i<*nod_p; i++) for (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"); 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"); } *start_p = 0; } else{ printf("Introduceti nr. noduri (1-%d) ", MAXN); if (scanf("%d", nod_p) != 1) return 1; if ( (*nod_p < 1) || (*nod_p > MAXN) ) return 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); if (scanf("%d", &i) != 1) return 4; if ( (i < 1) || (i > *nod_p) ) return 5; *start_p = i-1; } return 0; } int doBellman(int nod, int a[MAXN][MAXN], int start){ int D[MAXN]; int i, u, v; /* initializare */
73

/*

for (i=0; i<nod; i++){ if (i == start) D[i] = 0; else 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]); } else printf("nu schimba\n"); } } } traceinfo(D, nod); } for (u=0; u<nod; u++){ for (v=0; v<nod; v++){ if (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]); */ if (D[v] > D[u] + a[u][v]) return 1; else printf("nu exista ciclu negativ\n"); } } } return 0; } void traceinfo(int D[MAXN], int nod){ int i; printf(" D = "); for (i=0; i<nod; i++) printf("%4d", D[i]); printf("\n");}
74

Probleme rezolvate R2.6.1. 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: var a:array[1..100,1..100] of integer; viz:array[1..100] of integer; f:text;n,i,j:integer; procedure df(X:integer); var i:byte; begin write(x, ' '); viz[x]:=1; for i:=1 to n do if (a[x,i]=1) and (viz[i]=0) then df(i); end; procedure citire; begin assign(f,'matrice.txt'); reset(f); readln(f,n); for i:=1 to n do begin for j:=1 to n do read(f,a[i,j]); readln(f); end; end; begin citire; for i:=1 to n do viz[i]:=0; for i:=1 to n do if viz[i]=0 then begin df(i);writeln end; end. Exerciiu: Implementai n lumbajul C aplicaia de mai sus folosind funcia Df (iterativ) de mai jos. void df(int x){ int i,k,y,s[10],gasit; k=1;
75

s[1]=x;viz[x]=1;printf("%d ",x); while (k>=1) /*cat timp stiva este nevida */ { y=s[k];gasit=0; for(i=1;i<=n;i++) if (viz[i]==0&&a[y][i]==1) { printf("%d ",i); //vecin nevizitat viz[i]=1; s[++k]=i; gasit=1; break; } if (!gasit) k--; } } R2.6.2. S se parcurg un graf reprezentat prin matricea sa de adiacen folosind parcurgerea BF. Rezolvare: Implementare n limbajul Pascal: Var a:array[1..100,1..100] of integer; viz,c:array[-2..100] of integer; f:text; n,i,j,v,p,u,x:integer; procedure citire; begin assign(f,'matrice.txt'); reset(f); readln(f,n); for i:=1 to n do begin for j:=1 to n do read(f,a[i,j]); readln(f); end; write('Dati nodul de plecare '); readln(v); end; procedure bf(v:integer); begin viz[v]:=1;write(v,' '); c[1]:=v; p:=1; u:=1;
76

while p<=u do begin x:=c[p]; p:=p+1; for i:=1 to n do if (viz[i]=0) and (a[i,x]=1) then begin write(i,' '); viz[i]:=1; u:=u+1; c[u]:=i; end; end; end; begin citire; for i:=1 to n do viz[i]:=0; bf(v) end. Exerciiu: S se implementeze aplicaia de mai sus n limbajul C. R2.6.3. S se determine componentele tari conexe ale unui graf orientat. Rezolvare: Componenta tare conex care va conine vrful i va fi dat de subgraful indus de multimea nodurilor j pentru care a[i,j]=a[j,i]=1, unde a este matricea drumurilor . Implementare Pascal: program tare_conexe; const nmax=100; type graf = array[1..nmax,1..nmax] of byte; marcaj = array[1..nmax] of boolean; var a:graf; i,j,k,n:integer; m:marcaj; modificare:boolean; begin write('Dati nr de noduri: '); readln(n); writeln('dati arcele grafului (i,j) :'); writeln('0 0 pentru sfarsit '); readln(i,j); while i*j<>0 do begin a[i,j]:=1; readln(i,j); end; for k:=1 to n do for i:=1 to n do for j:=1 to n do if a[i,j]=0 then a[i,j]:=a[i,k]*a[k,j]; k:=1; for i:=1 to n do if not m[i] then begin
77

end.

write('componenta tare conexa ',k,':',i,' '); for j:=1 to n do if (j<>i) and (a[i,j]<>0)and (a[j,i]<>0) then begin write(j,' '); m[j]:=true; end; inc(k); writeln; end;

Implementare n limbajul C: #include <stdio.h> int n, a[10][10],viz[10]; void citire(){ int m,i,j,x,y; printf("n=");scanf("%d",&n); printf("m=");scanf("%d",&m); for(i=1;i<=n;i++) for(j=1;j<=n;j++)a[i][j]=0; /*citirea arcelor si construirea matricei de adiacenta */ for(i=1;i<=m;i++) { scanf("%d %d",&x,&y);a[x][y]=1;} } void main(){ int k,i,j,m[10]; citire(); //se construieste matricea drumurilor for (k=1;k<=n;k++) for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(a[i][j]==0) a[i][j]=a[i][k]&&a[k][j]; k=1; for (i=1;i<=n;i++)m[i]=0; for(i=1;i<=n;i++) if(!m[i]) { /* daca varful i nu a fost introdus intr- componenta tare conexa */ printf("componenta tare conexa %d: %d ",k,i); for (j=1;j<=n;j++) if (j!=i&&a[i][j]==1&&a[j][i]==1){ printf("%d ",j); m[j]=1; } k++; printf("\n"); } }
78

R2.6.4. Dndu-se dou grafuri reprezentate prin matricea de adiacen s se precizeze dac cel de-al doilea graf este graf parial sau subgraf al primului graf. Rezolvare: Implementarea Pascal este: uses crt; type mat=array[1..100,1..100] of integer; var a,b:mat; n,m,n1,m1,i,j:integer; procedure creare; var x,y,i,j:integer; begin writeln(' MARTICEA 1'); write('Dati numarul de varfuri'); readln(n); write('Dati numarul de muchii'); readln(m); for i:=1 to n do for j:=1 to n do a[i,j]:=0; for i:=1 to m do begin 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 end end; procedure creare1; var x,y,i,j:integer; begin WRITELN(' MATRICEA 2'); write('Dati numarul de varfuri');readln(n1); write('Dati numarul de muchii');readln(m1); for i:=1 to n1 do for j:=1 to n1 do b[i,j]:=0; for i:=1 to m1 do begin 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; end; end;
79

procedure subgraf; var s:boolean; begin s:=true;if n1>n then s:=false; for i:=1 to n1 do for j:=1 to n1 do if (a[i,j]=1) and (b[i,j]=0) then s:=false; if s=false then writeln(' B nu e subgraf al lui A.') else writeln(' B e subgraf al lui A.'); end; procedure graf_p; var g:boolean; begin g:=true;if n<> n1 then g:=false; for i:=1 to n do for j:=1 to n do if (a[i,j]=0) and (b[i,j]=1) then g:=false; if g=false then writeln(' B nu e graf partial al lui A.') else writeln(' B e graf partial al lui A.'); end; begin clrscr; creare;creare1; graf_p;subgraf; end. Exerciiu: S se implementeze aplicaia de mai sus n limbajul C. R2.6.5. Determinarea drumurilor minime ntre oricare dou noduri. Rezolvare: Se folosete algoritmul lui ROY-FLOYD. Se pornete de la matricea costurilor C. pentru k=1,n execut pentru i=1,n execut pentru j=1,n execut 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 mulimea predesesorilor lui j pentru drumul minim de la i la j. Implementare Pascal: Var c:array[1..100,1..100] of longint; v:array[1..100]of integer; d:array[1..100,1..100] of set of 1..10; n,m,i,j,k,nr:integer; x,y:integer;
80

procedure citire; var cost,x,y:integer; begin write('nr. de noduri');readln(n); write('nr. de muchii');readln(m); for i:=1 to n do for j:=1 to n do if i<>j then c[i,j]:=maxint else c[i,j]:=0; for i:=1 to m do begin write('Dati capetele arcului si costul '); readln(x,y,cost); c[x,y]:=cost; end; end; procedure initializare; {determina multimea predecesorilor, initializeaza multimea D} begin for i:=1 to n do for j:=1 to n do if (i<>j) and (c[i,j]<maxint) then d[i,j]:=[i] else d[i,j]:=[]; end; procedure drum(i,j:integer); {reconstituirea drumului} var k:integer; begin if i<>j then for k:=1 to n do if k in d[i,j] then begin inc(nr); v[nr]:=k; drum(i,k); dec(nr); end else begin for k:=nr downto 1 do write(v[k], ' '); writeln; end; end; begin citire;initializare; for k:=1 to n do for i:=1 to n do for j:=1 to n do if c[i,j]>c[i,k]+c[k,j] then begin c[i,j]:=c[i,k]+c[k,j]; d[i,j]:=d[k,j] end else if c[i,j]=c[i,k]+c[k,j] then d[i,j]:=d[i,j]+d[k,j];
81

end.

for i:= 1 to n do begin for j:=1 to n do write(c[i,j]:4); writeln end; write('Dati doua noduri'); readln(x,y); writeln('costul minim= ', c[x,y], ' drumurile minime=' ); for x:=1 to n do for y:=1 to n do begin writeln('drum de la ',x,'la ',y); if c[x,y]=maxint then write('nu exista') else begin nr:=1;v[1]:=y; drum(x,y) end end

Exerciiu: S se implementeze algoritmul Roy-Floyd n limbajul C. R2.6.6. 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. Implementare Pascal: type lista=^nod; nod= record inf:integer; urm:lista end; var bl:array[1..100] of lista; f:text; i,n,x:integer; complet:boolean; procedure adaugare (var p:lista;x:integer); var t,q:lista; begin new(q);q^.inf:=x;q^.urm:=nil; if p=nil then p:=q else begin t:=p;while t^.urm<>nil do t:=t^.urm; t^.urm:=q; end; end;
82

procedure listare(p:lista); var t:lista; begin t:=p; while t<> nil do begin write(t^.inf,' '); t:=t^.urm end; writeln; end; procedure df(i:integer); var q,t,st:lista; viz:array [1..100] of integer; conex,gasit:boolean; j:integer; begin for j:=1 to n do viz[j]:=0;viz[i]:=1;write(i,' ');new(q);q^.inf:=i; q^.urm:=nil;st:=q; while st<>nil do begin x:=st^.inf; t:=bl[x]; gasit:=false; while t<> nil do begin if viz[t^.inf]=0 then begin new(q); q^.inf:=t^.inf; q^.urm:=nil; viz[t^.inf]:=1; write(t^.inf,' '); q^.urm:=st; gasit:=true; st:=q; break; end; t:=t^.urm; end; if not gasit then begin t:=st; st:=st^.urm; dispose(t) end; end; conex:=true; for j:=1 to n do if viz[j]=0 then conex:=false; if conex then write('conex') else write('nu este conex'); end; function numarare( p:lista):integer; var nr:integer; t:lista; begin nr:=0;t:=p; while t<>nil do begin nr:=nr+1; t:=t^.urm end; numarare:=nr end;
83

begin assign(f,'in.txt');reset(f); readln(f,n); for i:=1 to n do begin while not eoln(f) do begin read(f,x); adaugare(bl[i],x) end; readln(f); end; writeln; df(1); complet:=true; for i:=1 to n do if numarare(bl[i])<>n-1 then complet:=false; if complet then write('complet') else write ('incomplet'); end. Exerciiu: S se implementeze aplicaia de mai sus n limbajul c. R2.6.7. 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. Implementare Pascal: Var f:text; a:array[1..1000]of integer; n:integer; nume:string; procedure ciclic; var i,j,k:integer; begin writeln('Care este numele fisierului de intrare ?'); readln(nume); assign(f,nume); reset(f); readln(f,n); for i:=1 to n do a[i]:=i; while not seekeoln(f) do begin readln(f,i,j);
84

end; begin ciclic end.

if a[i]=a[j] then begin writeln('Graful din fisierul ',nume,' contine cel putin un ciclu'); close(f); halt; end; for k:=1 to n do if a[k]=a[j] then a[k]:=a[i]; end; writeln('Graful din fisierul ',nume,' nu contine cicluri'); close(f);

Implementare C: #include <stdlib.h> #include <iostream.h> #include <stdio.h> #include <conio.h> FILE *f; int n,a[10]; void ciclic(){ int i,j,k; fscanf(f,"%d",&n); for(i=1;i<=n;i++)a[i]=i; fscanf(f,"%d %d",&i,&j); if (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"; } void main(void){ f=fopen("in.txt","r");clrscr(); ciclic(); }
85

R2.6.8. Se d un graf i un nod - considerat ca nodul nr. 1; se cere s se determine toate nodurile accesibile din acest nod.
Rezolvare: Implementare Pascal: var a: array[1..20,1..20] of integer; {matricea de adiacenta} c: array[1..20] of integer; {vectorul unde pastram nodurile accesibile} n,i,j,k,p:integer; gasit:boolean; begin write('dati numarul de noduri; n=');readln(n); writeln('dati matricea de adiacenta:'); for i:=1 to n do for j:=1 to n do read(a[i,j]); c[1]:=1; k:=1; gasit:=true; i:=1; while i<=k do begin for j:=1 to n do if a[i,j]=1 then begin for p:=1 to k do if c[p]=j then gasit:=false; if gasit then begin k:=k+1; c[k]:=j end end; i:=i+1 end; if k=n then writeln('Toate nodurile sunt accesibile.') else for i:=1 to k do write(c[i],','); end. Exerciiu:S se implementeze aplicaia de mai sus n limbajul C. R2.6.9. Determinarea ciclului de lungime 3 dintr-un graf. Rezolvare: Implementarea Pascal: var i,j,n,k:integer; a:array[1..50,1..50] of integer; f:text; begin assign(f,'c:\lucru\graf.txt'); reset(f); read(f,n);
86

end.

for i:=1 to n do for j:=1 to n do a[i,j]:=0; while not eof(f) do begin readln(f,i,j); a[i,j]:=1; a[j,i]:=1 end; for i:=1 to n-2 do for j:=i+1 to n-1 do for k:=j+1 to n do if (a[i,j]=1) and (a[j,k]=1) and (a[k,i]=1) then writeln(i,' ',j,' ',k);

2.7. Arbori 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 (valoarea 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 2k. Un arbore binar de nlime i are cel mult 2i+1-1 vrfuri, iar dac are exact 2i+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, , 2i+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[2k], T[2k+1], , T[2k+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.
87

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 subexpresia 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 descendentul 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

Parcurgerea arborilor binari preordine:se viziteaz rdcina, se traverseaz subarborele stng n preordine, se traverseaz subarborele drept n preordine; inordine: se traverseaz subarborele stng n inordine, se viziteaz rdcina, se traverseaz subarborele drept n inordine; postordine: se traverseaz subarborele stng n postordine, se traverseaz subarborele drept n postordine, se traverseaz rdcina. Aplicaia 2.7.1. 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: Implementare Pascal: program arb_binar; type arbore=^nod; nod =record st,dr:arbore; inf:integer end; var p:arbore;k,x,y,max,z:integer;a:array[1..100] of integer; {Procedura creare arbore binar} procedure creare(var p:arbore); var x:integer; begin read(x); if x=0 then p:=nil else begin new(p); p^.inf:=x; write('Dati stanga lui ',x); creare(p^.st); write('Dati dreapta lui ',x); creare(p^.dr); end; end; {Procedura parcurgere arbore binar - prin preordine} procedure preordine(p:arbore); begin if p<>nil then begin write(p^.inf,' '); preordine(p^.st); preordine(p^.dr); end; end;
89

{Cautarea unui nod din arbore} function cautare(p:arbore; x:integer):boolean; begin if p=nil then cautare:=false else if x=p^.inf then cautare:=true else cautare:= cautare(p^.st,x) or cautare(p^.dr,x); end; {Afisarea tuturor cheilor de pe nivelul dat} procedure nivel(p:arbore;k,x:integer); begin if p<>nil then begin if k=x then write(p^.inf,' '); nivel(p^.st,k+1,x); nivel(p^.dr,k+1,x); end; end; {Drumurile de la radacina la frunze} procedure drum_frunze(p:arbore;k:integer); var i:integer; begin if (p^.st=nil)and(p^.dr=nil) then begin a[k]:=p^.inf; for i:=1 to k do write(a[i],' '); writeln end else if p<>nil then begin a[k]:=p^.inf; drum_frunze(p^.st,k+1); drum_frunze(p^.dr,k+1); end; end; {Afisarea numarului maxim de nivele} procedure adancime(p:arbore;k:integer; var max:integer); begin if p<>nil then begin if k>max then max:=k; adancime(p^.st,k+1,max); adancime(p^.dr,k+1,max); end end;
90

begin 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); end. Implementare n C++ : #include <stdio.h> #include <alloc.h> #include <iostream.h> #include <conio.h> typedef struct nod{ int inf; struct nod *st, *dr; }arbore; arbore *rad; int a[10], max=0; arbore *creare(){ int x;arbore *p; cout<<"inf"; cin>>x; if (x==0) return NULL; else { (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(); } return p; } void preordine(arbore *p){ if (p){ printf("%d ",p->inf); preordine(p->st); preordine(p->dr); } }
91

void inordine(arbore *p){ if (p){ inordine(p->st); printf("%d",p->inf); inordine(p->dr); } } void postordine(arbore *p){ if (p){ postordine(p->st); postordine(p->dr); printf("%d",p->inf); } } int cautare(arbore *p, int x){ if(p){ if (p->inf==x) return 1; return cautare(p->st,x)||cautare(p->dr,x); } else return 0; } void nivel(arbore*p, int k,int x){ if(p){ if (k==x) printf("%d ",p->inf); nivel(p->st,k+1,x); nivel(p->dr,k+1,x); } } void drum_frunze(arbore*p,int k){ int i; if ((p->st)&&(p->dr)) { a[k]=p->inf; for (i=1;i<=k;i++) printf("%d ",a[i]);printf("\n"); } else{ if(p) { a[k]=p->inf; drum_frunze(p->st,k+1); drum_frunze(p->dr,k+1); } } } void adancime(arbore *p, int k){ if (p) { if (k>max) max=k; adancime(p->dr,k+1) ;adancime(p->st,k+1); }}
92

void main(){ int x; rad=creare(); preordine(rad); printf("inf cautata:");scanf("%d", &x); if (cautare(rad,x)) printf("exista");else 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. Aplicaia 2.7.2. Program pentru crearea i exploatarea unui arbore binar de cutare. Rezolvare: Implementare Pascal: type arbore=^nod; nod = record inf:integer; st,dr:arbore end; var p:arbore;x:integer;
93

procedure inserare(var p:arbore;x:integer); var q:arbore; begin new(q); q^.inf:=x; q^.st:=nil; q^.dr:=nil; if p=nil then p:=q else if p^.inf=x then write('Exista') else if p^.inf<x then inserare(p^.dr,x) else inserare(p^.st,x) end; procedure srd(p:arbore); begin if p<>nil then begin srd(p^.st); write(p^.inf,' '); srd(p^.dr) end end; procedure stergere(var p:arbore;x:integer); var t:arbore; begin if p=nil then write('nu exista') else if p^.inf<x then stergere(p^.dr,x) else if p^.inf>x then stergere(p^.st,x) else if p^.st=nil then begin t:=p; p:=p^.dr; dispose(t) end else if p^.dr=nil then begin t:=p;p:=p^.st;dispose(t); end else begin t:=p^.st; while t^.dr^.dr<>nil do t:=t^.dr; p^.inf:=t^.dr^.inf; dispose(t^.dr); t^.dr:=nil end end; begin read(x); while x<>0 do begin inserare(p,x); read(x) end; srd(p);read(x);stergere(p,x);srd(p); end.
94

Implementare C++: #include<iostream.h> #include<conio.h> #include<stdio.h> typedef struct nod {int inf; nod *st,*dr;}arbore; arbore *rad; arbore *q; void adaug(arbore* &p,int x){ if (p==NULL){ p=new nod; p->inf=x; p->st=p->dr=NULL; } else if (p->inf>x) adaug(p->st,x); else if (p->inf<x) adaug(p->dr,x); else cout <<"informatia exista"; } void creare(arbore* &p){ int x,n,i; cout <<"n=";cin>>n; for (i=1;i<=n;i++){ cout<<"inf";cin>>x; adaug(p,x); } } void inordine(arbore *p){ if (p){ inordine(p->st); printf("%d",p->inf); inordine(p->dr); } } arbore *cauta(arbore*p, int x){ if (p==NULL) return NULL; else if (p->inf<x) { q=p;p=p->st;cauta(p,x); } else if (p->inf>x){ q=p;p=p->st; cauta(p,x); } else return p; }
95

void sterge(arbore *&r,int x){ arbore *t,*q1,*p; int a; t=cauta(r,x); if(t==NULL){ cout<<"informatia nu se gaseste"; getch(); } else if (t->dr==t->st){ if (t->inf<q->inf) q->st=NULL; delete t; } else if (t->st==NULL&&t->st){ if (q->inf<t->inf) q->dr=t->st; else q->st=t->st; delete t; } else if (t->st==NULL&&t->dr){ if(q->inf>t->inf) q->st=t->dr; else q->dr=t->dr; delete t; } else { p=t; while (p->st!=NULL){q=p;p=p->st;} } q1=t; t->inf=p->inf; if (p->dr==p->st){ q->st=NULL; delete p; } else { q->st=p->dr; delete p; } while (q1->st&&q1->inf<q1->st->inf){ a=q1->inf; q1->inf=q1->st->inf; q1->st->inf=a; q1=q1->st; } }
96

void main(){ int x; arbore *rad=0; creare(rad); inordine(rad); sterge(rad,2); } Probleme rezolvate n limbajul Pascal R2.7.1. S se scrie un subprogram pentru afiarea numrului cheilor negative i pozitive dintr-un arbore binar. procedure p3(p:arbore); begin if p<>nil then begin p3(p^.st); if p^.inf<0 then nr1:=nr1+1; if p^.inf>=0 then nr2:=nr2+1; p3(p^.dr); end; end; R2.7.2. S se scrie un subprogram pentru afiarea cheilor impare dintr-un arborele binar. procedure p2(p:arbore); begin if p<>nil then begin if p^.inf mod 2 =1 then write(p^.inf,' '); p2(p^.st); p2(p^.dr) end end; R2.7.3. S se scrie un subprogram pentru aflarea produsului cheilor pozitive dintr-un arborele binar. function p4(p:arbore):longint; begin if p<>nil then if p^.inf >0 then p4:=p^.inf*p4(p^.st)*p4(p^.dr) else p4:=p4(p^.st)*p4(p^.dr) else p4:=1 end;
97

R2.7.4. S se scrie un subprogram pentru aflarea numrului de frunze dintr-un arborele binar . function p5(p:arbore):integer; begin if p=nil then p5:=0 else if (p^.st=nil) and (p^.dr=nil) then p5:=1 else p5:=p5(p^.st)+p5(p^.dr) end; R2.7.5.. S se scrie un subprogram pentru afiarea nodurilor care au un succesor dintr-un arbore binar. procedure p6(p:arbore); begin if p<>nil then begin if ((p^.st=nil) and (p^.dr<>nil)) or ((p^.st<>nil) and (p^.dr=nil)) then write(p^.inf,' '); p6(p^.st); p6(p^.dr) end end; R2.7.6. S se scrie un subprogram pentru aflarea numrului de noduri de pe un nivel dat dintr-un arbore binar. function p7(p:arbore;k:integer):integer; begin if p<>nil then if k=l then p7:=1+p7(p^.st,k+1)+p7(p^.dr,k+1) else p7:=p7(p^.st,k+1)+p7(p^.dr,k+1) else p7:=0 end; 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).
98

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

12. Fie G un graf orientat n care fiecare arc are asociat un cost pozitiv. 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 modalitate 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 reprezentat 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 obinnduse 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.
100

3. Metode pentru rezolvarea problemelor


3.1. Metoda 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. function divimp(X: problema) if (X este suficient de mica) then y rezolv(X) else{ descompune problema x n subproblemele X1, X2,, Xk for i 1 to k do yi divimp(Xi) /* combin y1, y2, , yk pentru a obine y soluia problemei X */ y combin(y1, y2, , yk) return 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 R3.1.1. [Cel mai mare divizor comun] Fie n numere naturale nenule x1, x2,,xn. S se calculeze cmmdc pentru numere date.
101

Rezolvare: program divizor_comun; var x:array[1..25] of integer; n, i:integer; function Divizor(a,b:integer):integer; begin while a<>b do if a>b then a:=a-b else b:=b-a; Divizor := a end; function cmmdc(lo,hi:integer):integer; var m:integer; begin if (hi-lo<=1) then cmmdc := Divizor(x[lo],x[hi]) else begin m:=(lo+hi) div 2; cmmdc:= Divizor(cmmdc(lo,m), cmmdc(m+1,hi)); end; end; begin write('n = '); readln(n); writeln('Introduceti numerele'); for i:=1 to n do begin write('x[',i,'] = '); readln(x[i]) end; writeln('cmmdc:= ', cmmdc(1,n)); end. R3.1.2. [Cutare binar] Fie x1, x2,,xn 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: program cautare; uses crt; var x:array[1..100] of integer; nr:integer; function cauta(lo,hi:integer):integer; var m:integer; begin if (lo<=hi) then begin m:=(lo+hi) div 2; if nr=x[m] then cauta:=m else if nr<x[m] then cauta:=cauta(lo,m-1) else cauta:=cauta(m+1,hi) end else cauta:=0 end;
102

var n,i,pos:integer; ch:char; begin write('n = ');readln(n); writeln('Introduceti numerele'); for i:=1 to n do begin write('x[',i,'] = '); readln(x[i]) end; repeat writeln; write('Numarul cautat = '); readln(nr); pos := cauta(1,n); if pos <> 0 then writeln(nr,' se afla in sir la pozitia ', pos) else writeln(nr,' nu se afla in sir!'); write('Continuati (y/n) ?[y] '); ch:=UpCase(readkey); until ch = 'N'; end. R3.1.3. [Sortare rapid] Fie n N* i numerele x1, x2,,xn. S se scrie o procedur recursiv de sortare (quicksort) n ordine cresctoare a numerelor date. Rezolvare: #include <stdio.h> void QSort (int *table, int left,int right){ int leftp,rightp,aux; unsigned type = 1; leftp =left; rightp=right; do{ if ( table[leftp]>table[rightp] ){ type ^= 1; aux = table[leftp]; table[leftp] = table[rightp]; table[rightp] = aux; } else type ? rightp--: leftp++; }while (leftp < rightp); if ( leftp-left > 1) QSort(table,left,leftp-1); if ( right-rightp >1) QSort(table,rightp+1,right); }
103

void main(){ int n,i; int x[100]; printf(n = ); scanf(%d,&d); for (i=0;i<n;i++) scanf(%d,&x[i]); Qsort(x,0,n-1); for (i=0;i<n;i++) printf(%8d,x[i]); } R3.1.4. [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: #include<stdio.h> void Hanoi(int n, int a, int b){ if (n==1) printf("\%d - %d\n",a,b); else { Hanoi(n-1, a, 6-a-b); printf("\%d - %d\n",a,b); Hanoi(n-1, 6-a-b,b); } } void main(){ int n; printf("Numarul de discuri = "); scanf("%d",&n); Hanoi(n,1,2); } R3.1.5. [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: #include <stdio.h> #define MAX 100
104

void MSort(int tabel[],int temp[], int lo, int hi){ int mid, k, t_lo, t_hi; if (lo >= hi) return; mid = (lo+hi) / 2; MSort(tabel,temp, lo, mid); MSort(tabel,temp, mid+1, hi); t_lo = lo; t_hi = mid+1; for (k = lo; k <= hi; k++) if ( (t_hi > hi || tabel[t_lo] < tabel[t_hi]) && (t_lo <= mid) ) temp[k] = tabel[t_lo++]; else temp[k] = tabel[t_hi++]; for (k = lo; k <= hi; k++) tabel[k] = temp[k]; } void main(){ int n, i; int tabel[MAX]; int temp[MAX]; printf("n = "); scanf("%d",&n); printf("Introduceti numerele:\n"); for(i=0;i<n;i++){ printf("tabel[%d] = ",i); scanf("%d",&tabel[i]); } MSort(tabel, temp, 0, n-1); for(i=0;i<n;i++) printf("%d ",tabel[i]); } 3.1.3. Probleme propuse 1. Fie x1, x2,,xn un ir de numere reale. S se determine max{x1, x2,,xn}. 2. Se d x1, x2,,xn (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.
105

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 coficieni reali. S se evalueze polinomul n punctul x0 folosind metoda Divide et Imera. 8. Scriei o procedur Divide et Impera pentru inversarea unui ir de caractere. 9. Se d un dreptunghi prin dimensiunile sale numere naturale. Dreptunghiul trebuie descompus n ptrate cu laturi numere naturale, paralele cu laturile dreptunghiului iniial. Se cere numrul minim de ptrate n care se poate descompune dreptunghiul. 10. Se dau un ptrat i un cerc. Se cere s se calculeze aria lor comun cu precizie de o zecimal. Coordonatele se citesc de la tastatur i sunt numere reale. Aria se va afia pe ecran. 11. Un arbore cartezian al unui vector este un arbore binar definit recursiv astfel: rdcina arborelui este elementul cel mai mic din vector; subarborele stng este arborele cartezian al subvectorului stng (fa de poziia elementului din rdcin); subarborele drept este arborele cartezian al subvectorului drept. Se d un vector de dimensiune n. S se afieze arborele su cartezian.

106

3.2. Metoda programrii dinamice 3.2.1. Principii fundamentale ale programrii dinamice Programarea dinamic, ca i metoda divide et impera, rezolv problemele "combinnd" soluiile subproblemelor. Un algoritm bazat pe programare dinamic rezolv fiecare subproblem o singur dat i, apoi, memoreaz soluia ntr-un tablou, prin aceasta evitnd recalcularea soluiei dac subproblema mai apare din nou i subprobemele care apar n descompunere nu sunt independente. Metoda programrii dinamice se aplic problemelor de optimizare. n problemele de optim metoda const n determinarea soluiei pe baza unui ir de decizii d1, d2, d3....dn, unde di transform problema din starea si-1 n starea si. Paii pentru rezolvarea unei probleme folosind programarea dinamic: 1. Caracterizarea structurii unei soluii optime; 2. Definirea recursiv a valorii unei soluii optime; 3. Calculul valorii unei soluii optime 4. Construirea unei soluii optime din informaia calculat. Principii fundamentale ale programrii dinamice: 1. Dac d1, d2, ... dn este un ir optim de decizii care duc un sistem din starea iniial n starea final, atunci pentru orice i (1in) d1, d2, ... di este un ir optim de decizii. 2. Dac d1, d2, ... dn este un ir optim de decizii care duc un sistem din starea iniial n starea final, atunci pentru orice i (1in) di, di+1, ... dn este un ir optim de decizii. 3. Dac d1, d2, ... , di, di+1 ... dn este un ir optim de decizii care duc un sistem din starea iniial n starea final, atunci pentru orice i (1in) d1, d2,... , di i di, di+1, ... dn sunt dou iruri optime de decizii. 3.2.2. Probleme rezolvate R3.2.1. [Subir cresctor maximal] Se consider un ir de n numere ntregi. S se determine cel mai lung subir cresctor din acesta. Exemplu: n=8 7 1 8 2 11 4 12 3 Subirul cresctor maximal: 7 8 11 12 cu lungimea 4 Rezolvare: Se construiete tabloul L reprezentnd lungimea maxim a unui subir maximal care l conine ca prim element pe a[i] astfel
107

L[n]=1 i L[i]=1+max{L[j]/ j>i i a[j]>a[i]} pentru i de la n-1 la 1 (metoda nainte - deoarece soluia unei subprobleme se afl pe baza subproblemelor din urm). Implementare Pascal: var i,j,n,poz,max:integer; l,a:array[1..30] of integer; begin write('n=');read(n); for i:=1 to n do begin write('a[',i,']='); read(a[i]) end; for i:=1 to n do l[i]:=0; l[n]:=1; for i:=n-1 downto 1 do begin max:=0; for j:=1+i to n do if (a[j]>a[i]) and (max<l[j]) then max:=l[j]; l[i]:=1+max end; max:=0; for i:=1 to n do if max<l[i] then begin max:=l[i]; poz:=i end; write(a[poz],' '); i:=poz; while max>1 do begin if (a[i]>a[poz]) and (l[i]=max-1) then begin poz:=i; write(a[poz],' '); max:=max-1 end; i:=i+1 end end. Implementare C: #include<stdio.h> void main(){ int n,i,j,poz,max,a[100],l[100]; printf("n=");scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]);
108

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

for(i=1;i<=n;i++) l[i]=0; l[n]=1; for (i=n-1;i>0;i--){ max=0; for (j=i+1;j<=n;j++) if ((max<l[j])&&(a[j]>a[i])) max=l[j]; max=max++; l[i]=max; } max=0; for(i=1;i<=n;i++) if (l[i]>max) {max=l[i];poz=i;} printf(" %d ",a[poz]); i=poz; while (max>1){ if ((a[i]>a[poz]) &&(l[i]==max-1)) { poz=i; printf("%d ",a[poz]); max=max-1; } i++; }

end. Implementare C: #include<stdio.h> void main(){ int n,i,j,poz,max,a[100],l[100]; printf("n=");scanf("%d",&n); for (i=1;i<=n;i++) scanf("%d",&a[i]); for (i=n;i>0;i--){ max=0; for (j=i+2;j<=n;j++) if (max<l[j]) max=l[j]; max=max+a[i]; l[i]=max; } max=l[1];poz=1; for(i=1;i<=n;i++) if (l[i]>max) {max=l[i];poz=i;} printf("suma maxima %d\n",l[1]); max=l[1];poz=1; while (max>0){ printf("%d ",a[poz]); i=poz+2;
110

for i:=1 to n do read(a[i]); for i:=n downto 1 do begin max:=0; for j:=i+2 to n do if (max<l[j]) then max:=l[j]; max:=max+a[i]; l[i]:=max end; max:=l[1];poz:=1; for i:=1 to n do if l[i]>max then begin max:=l[i]; poz:=i end; writeln('suma maxima este: ',l[1]); max:=l[1];poz:=1;write('sirul: '); repeat write(a[poz],' '); i:=poz+2; while (i<n ) and (l[i]<>max-a[poz]) do i:=i+1; max:=max-a[poz]; poz:=i; until max=0

while ((i<n) && (l[i]!=max-a[poz])) i++ ; max=max-a[poz]; poz=i; }

R3.2.3. [Subiruri comune] Dndu-se dou iruri comune s se determine cel mai lung subir comun. Rezolvare: Implementarea Pascal (varianta mersului napoi): Se construiete tabloul c care reine lungimea maxim a celui mai lung subir comun a celor dou iruri pn la i respectiv j. var a,b,d:string; i,j,n,m,max,t,v:integer; c:array[1..50,1..50] of integer; begin write('primul sir:');readln(a);write('sirul doi:');readln(b); n:=length(a);m:=length(b); for i:=1 to m do if a[1]=b[i] then c[1,i]:=1 else c[1,i]:=0; for i:=1 to n do if a[i]=b[1] then c[i,1]:=1 else c[i,1]:=0; for i:=2 to n do for j:=2 to m do if a[i]=b[j] then c[i,j]:=c[i-1,j-1]+1 else c[i,j]:=0; max:=0; for i:=1 to n do for j:=1 to m do if max<c[i,j] then begin max:=c[i,j]; t:=i; v:=j end; writeln('secventa maxima are lungimea :',max); d:=a[t]; while max>1 do begin dec(max); dec(t); d:=a[t]+d end; writeln(d); end. Exerciiu: S se implementeze n C aplicaia de mai sus. R3.2.4. [Partiii] S se determine numrul de moduri n care se poate descompune un numr natural n suma de numere. Exemplu: n=4, numrul de moduri = 5 Rezolvare: Se construiete tabloul a unde a[n][0] reprezint numrul de moduri n care se poate descompune:
111

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

if l[i-1,j]>l[i,j-1] then l[i,j]:=l[i-1,j]+a[i,j] else l[i,j]:=l[i,j-1]+a[i,j]; writeln(l[n,m]); max:=l[n,m];p:=n;q:=m; write(a[n,m],' '); while (p<>1) and (q<>1) do begin if l[p-1,q] = l[p,q]-a[p,q] then p:=p-1 else q:=q-1; write(a[p,q],' '); end; write(a[1,1]); end. Exerciiu: S se implementeze aplicaia de mai sus n C. 3.2.3. Probleme propuse 1. [Triunghi] Se consider un triunghi de numere. S se calculeze cea mai mare dintre sumele numerelor ce apar pe drumurile ce pleac din vrf i ajung la baz i s se reconstituie drumul de sum maxim. n punctul (i,j) se poate ajunge numai din (i-1,j) sau (i-1,j-1). Exemplu: N=3 6 3 8 8 4 1 suma maxim este 18 i drumul 6 8 4 Indicaie: Se construiete tabloul c astfel c[i,j]=max{a[i,j]+ c[i+1,j], a[i,j]+ c[i+1,j+1]} (varianta mersului nainte). c[1,1] este suma maxim cerut. 2. [nmulirea optim a unui ir de matrice] Se dau n matrice. Asociativitatea nmulirii a dou matrice ne ofer mai multe posibiliti de a calcula produsul i care au un numr diferit de operaii. S se determine o posibilitate de asociere a nmulirii matricelor astfel nct numrul de operaii s fie minim. Indicaie: Se construiete tabloul bidimensional L, unde l[i,j] reprezint numrul minim de nmuliri pentru a efectua produsul AiAi+1.....Aj. 3. [Triangularizarea optim a poligoanelor] Se d un poligon convex i o funcie de pondere p definit pe triunghiurile formate de laturile i diagonalele poligonului. S se gseasc o triangulare care minimizeaz suma ponderilor triunghiurilor din triangularizare. Indicaie Exist o coresponden ntre triangularizarea unui poligon i parantezarea unei expresii cum ar fi produsul unui ir de matrici. 4.[ Tiprirea uniform] Textul de intrare este o succesiune de n cuvinte de lungimi l1, l2,...ln, lungimea fiind msurat n caractere. Se dore113

te tiprirea uniform a paragrafului pe un anumit numr de linii, fiecare linie avnd cel mult m caractere astfel: dac o linie conine cuvintele de la cuvntul i la cuvntul j, cu i j iar ntre cuvinte se las exact un spaiu. S se minimizeze suma cuburilor numrului de spaii suplimentare de la sfritul liniilor, n raport cu toate liniile, mai puin ultima. 5. [Problema patronului] Un patron a cumprat un calculator i dorete s nvee s lucreze cu el. Pentru aceasta va umple un raft de cri din colecia Informatica n lecii de 9 minute i 60 secunde. Raftul are lungimea L cm (L numr natural). Seria dispune de n titluri 1, 2, ,n avnd grosimile g1, g2, ..., gn cm (numere naturale). S se selecteze titlurile pe care le poate cumpra patronul, astfel nct raftul s fie umplut complet (suma grosimilor crilor cumprate s fie egal cu lungimea raftului) i numrul crilor achiziionate s fie maxim. Olimpiada Naional de Informatic 1996 Indicaie: Se construiete tabloul bidimensional a unde a[i,j] reprezint numrul maxim de cri dintre primele i (n ordinea dat la intrare) cu lungimea total j sau, 0 dac nu exist nici o submulime a mulimii primelor i cri cu lungimea total j. 6. [Planificarea unei recepii] Corporaia AMC are o structur ierarhic, relaiile de subordonare formeaz un arbore n care rdcina este preedintele. Fiecare angajat are un coeficient de convieuire (numr real). Preedintele dorete s organizeze o petrecere astfel nct nici un angajat s nu se ntlneasc cu seful su direct. Informaticianul Tom trebuie s alctuiasc lista invitailor astfel nct suma coeficienilor de convieuire a invitailor s se maximizeze i preedintele s participe la propia petrecere. 7. [Mouse] Un experiment urmrete comportarea unui oricel pus ntr-o cutie dreptunghiular, mprit n mxn cmrue egale de form ptrat. Fiecare cmru conine o anumit cantitate de hran. oricelul trebuie s porneasc din colul (1,1) al cutiei i s ajung n colul opus, mncnd ct mai mult hran. El poate trece dintr-o camer n una alturat (dou camere sunt alturate dac au un perete comun), mnnc toat hrana din cmru atunci cnd intr i nu intr niciodat ntr-o camer fr hran. Stabilii care este cantitatea maxim de hran pe care o poate mnca i traseul pe care l poate urma pentru a culege aceast cantitate maxim. Se d n, m i cantitatea de hran existent n fiecare cmeru (numere ntre 1 i 100). Olimpiada judeean de informatic, 2002
114

Exemplu: 24 1263 3412 Ieire: 7 21 1 1 --> 2 1 --> 2 2 --> 1 2 --> 1 3 --> 1 4 -->2 4 8. [Semne] Pentru n numr natural, s se gseasc o combinaie de semne + i - (adic un vector x = (x(1), x(2), ..., x(k)), x(i) se afl n <-1, 1>) i un numr k natural nenul astfel nct: n = x(1)*12+x(2)*22+...+x(k)*k2. Datele se citesc dintr-un fiier text ce conine pe fiecare linie cte un numr ce reprezint valorile lui n pentru care se doresc reprezentri ca mai sus. Datele de ieire vor fi introduse ntr-un fiier text pe cte o linie combinaia de semne corespunztoare. Exemplu: Intrare: 2 4 8 5 Ieire: ---+ --+ --++--+ ++--+ Indicaie: Pentru k ncepnd de la 1, se gsesc ntr-o list numerele care se pot obine cu k semne; lista pentru k se obine din cea pentru k-1. Pentru unele numere k este foarte mare i programul nu ar intra n timp. O alt soluie ar fi folosirea observaiei: (n+3)2-(n+2)2-(n+1)2+n2=(n+3+n+2)*1-(n+1+n)*1=2n+5-2n-1=4 Prin adugarea secvenei + - - + se ajunge de la un numar n la n+4. Dac am obine secvenele pentru n = 0, 1, 2 i 3, am rezolva problema. Acestea sunt: 0 secvena vid 1+ 2 - - - + (dat n exemplu) 3 - (pentru -1), apoi + - - +

115

9. [ah] a) Dndu-se dou poziii pe o tabl de ah de dimensiune ptratic nxn, s se determine cel mai scurt drum dintre acestea utiliznd mutrile calului. b) Determinai numrul minim de cai care pot fi amplasai pe o tabl de ah de dimensiune nxm astfel nct s nu se atace. 10. [Linii navale] Pe malul de nord i cel de sud al unui fluviu exist n orae. Fiecare ora are un unic ora prieten pe cellalt mal; nu exist dou orae pe un mal avnd acelai priten pe cellalt mal. Intenia este ca oraele prietene s se lege printr-o linie naval. Se impune ns restricia ca s nu existe linii navale care s se intersecteze. S se determine numrul maxim de linii navale care pot fi nfiinate, cu respectarea condiiei de mai sus. Pe prima linie a fiierului de intrare apare numrul n de perechi de orae prietene, iar pe urmtoarele n linii apar perechile de orae prietene (primul pe malul de nord, iar al doilea pe malul de sud), fiecare ora fiind specificat prin distana sa (cel mult egal cu 6000) fa de kilometrul 0 al fluviului. Indicaie: Se ordoneaz posibilele linii navale dup primul argument i se determin cel mai lung subir cresctor format din coordonatele celui de-al doilea argument. (vezi problema rezolvat 1). 11. [Drumuri minime] Se consider un graf orientat, fiecare arc avnd un cost ataat. Se cere s se determine pentru fiecare pereche de vrfuri ( i, j) i s se tipreasc lungimea drumului minim de la i la j. 12. [Submulimi de sum dat] S se determine pentru un vector dat dac un numr k se poate scrie ca sum de numere din vector, un element din vector se poate folosi o dat. Indicaie: Se construiete un tablou a cu valori logice, unde a[i] este true dac i se poate scrie ca sum de elemente din vectorul dat i false n caz contrar.

3.3. Metoda Greedy


3.3.1. Prezentarea metodei Algoritmii de tip Greedy sunt folosii la probleme de optimizare i sunt n general simpli i eficieni. Un astfel de algoritm determin soluia optim n urma unei succesiuni de alegeri. La fiecare moment decizional, din algoritm se va alege opiunea care pare a fi cea mai potrivit pe baza unui criteriu de optim local, n ideea c la final se va obine o soluie optim global.
116

n general, datele de intrare pentru un algoritm Greedy se prezint sub forma unei mulimi finite, iar soluia este o submulime sau o permutare a datelor de intrare n aa fel nct s fie ndeplinite anumite condiii de optim. Condiiile de optim cer determinarea unei soluii care maximizeaz sau minimizeaz o funcie dat, numit funcie obiectiv. Dac un element este inclus n soluie el va rmne n aceast mulime, nu se face nici o revenire asupra unei decizii luate. Selectarea unui element la un moment dat poate depinde de elementele alese pn la acel moment dar nu depinde de cele care urmeaz s fie alese ulterior. Dac un element a fost selectat, dar nu poate face parte din soluie atunci acest element nu va mai fi luat n calcul la alegerile urmtoare. n acest fel se poate ajunge rapid la o soluie, dar nu se asigur (pentru toate problemele) optimalitatea global. Exist i probleme pentru care o astfel de metod nu conduce la soluie, dei aceasta exist. Problemele care se pot rezolva folosind algoritmi de tip Greedy trebuie s verifice dou proprieti: proprietatea alegerii Greedy i substructura optimal. Proprietatea alegerii Greedy spune c se poate ajunge la o soluie de optim global dac la fiecare pas de decizie se selecteaz un element care ndeplinete criteriul de optim local. Proprietatea de structur optimal spune c soluia optimal a problemei conine soluiile optimale ale subproblemelor. O problem care se va rezolva folosind o strategie Greedy este dat de: O mulime finit de candidai care reprezint datele de intrare; O funcie care verific dac o anumit mulime de elemente constituie o soluie posibil, nu neaparat optim, a problemei; O funcie care verific dac o submulime a datelor de intrare este o soluie parial a problemei; O funcie de selecie care alege la orice moment cel mai potrivit candidat dintre elementele nefolosite nc; O funcie obiectiv care trebuie minimizat sau maximizat. Un algoritm Greedy nu furnizeaz dect o singur soluie. n contiunare este prezentat forma general a metodei.
117

function greedy(C) {C este mulimea datelor de intrare } S {S este multimea care va conine soluia} while not Soluie(S) and C do begin x select(C) C C \ {x} if Posibil(S {x}) then S S {x} end if Solutie(S) then return S else return write(nu exista soluie) Aceast metod i gsete multe aplicaii n teoria grafurilor la determinarea unui arbore parial de cost minim (Kruskal, Prim), la determinarea drumurilor de cost minim de la un vrf la celelalte vrfuri ale unui graf (Dijkstra), compresia datelor (arbori Huffman) .a. 3.3.2. Probleme rezolvate R3.3.1. [Problema continu a rucsacului] Avem la dispoziie un rucsac cu care se poate transporta o greutate maxim G. Trebuie s alegem din n obiecte pentru care se cunoate greutatea gi i profitul pi care se obine prin transportul obiectului i cu rucsacul. S se determine obiectele care trebuiesc alese pentru transport astfel nct profitul obinut s fie maxim, iar greutatea total a acestora s nu depeasc G tiind c putem lua orice parte dintr-un obiect. Rezolvare: Programul n C este: #include <stdio.h> #define MAX 25 void main(){ int p[MAX]; int g[MAX]; int n,i,j,aux,nr[MAX]; float G, gr,profit,sol[MAX]; printf("Greutatea maxima G = ");scanf("%f",&G); printf("Numarul de obiecte: "); scanf("%d", &n); for (i=0; i<n; i++){ printf("Obiectul nr. %d:\n",i+1); printf("Greutatea = "); scanf("%d",&g[i]); printf("Profitul = "); scanf("%d",&p[i]); sol[i] = 0.0; nr[i] = i; }
118

/* ordonare descrescatoare dupa raportul p/g */ for (i=0;i<n-1;i++) for (j=i+1;j<n;j++) if(p[i]/g[i] < p[j]/g[j]){ aux=p[i]; p[i]=p[j]; p[j]=aux; aux=g[i]; g[i]=g[j]; g[j]=aux; aux=nr[i]; nr[i]=nr[j]; nr[j]=aux; } /*alegere */ gr = G; for (i=0; i<n && g[i]<gr; i++){ sol[i] = 1.0; //100% gr -= g[i]; } if (i < n) sol[i] = gr/g[i]; /*afisare zezultate */ profit = 0.0; for (i=0;i<n;i++) if(sol[i] > 0){ printf("Obiect %d - %5.2f%%\n", nr[i]+1, sol[i] *100); profit += sol[i] * p[i]; } printf("Profit = %5.2f", profit); } R3.3.2.[Planificarea activitilor] ntr-o sal, ntr-o zi trebuie planificate n activiti, pentru fiecare activitate se cunoate intervalul n care se desfoar [s, f). Se cere s se planifice un numr maxim de activiti astfel nct s nu se suprapun. Rezolvare:Programul Pascal este: program Activitati; uses crt; const max=100; var n,i,j,aux:integer; s,f:array[1..max] of integer; sol:array[1..max] of 0..1; nsol, finish:integer; begin { citire date }
119

write('Nr de activitati = '); readln(n); for i:=1 to n do begin writeln('Activitatea nr. ',i,':'); write('Start = '); readln(s[i]); write('Finish = '); readln(f[i]); sol[i]:=0; end; {ordonare dup termenul final} for i := 1 to n-1 do for j := i + 1 to n do if ( f[i] > f[j]) then begin aux:=s[i]; s[i]:=s[j]; s[j]:=aux; aux:=f[i]; f[i]:=f[j]; f[j]:=aux; end; {calcul} finish := 0; for i := 1 to n do if (s[i] >= finish ) then begin sol[i]:=1; finish := f[i]; end; {afisare rezultate} writeln('Solutie:'); j := 1; for i := 1 to n do if sol[i]=1 then begin writeln('Activitatea nr. ',j,': ', s[i], ' - ' ,f[i]); j := j + 1; end; end. R3.3.3. [Schimbarea banilor] Presupunem c a avem la dispoziie k tipuri de monede cu valorile c0, c1, ck-1 unde cN*, s se scrie un program care s determine o modalitate de schimb a unei sume S folosind un numr minim de monede (numrul de monede din fiecare tip fiind nelimitat). Rezolvare: Programul C este:
120

#include<stdio.h> #include<conio.h> void main(){ int i,j,k,c,S; int sol[100]; int x,xmax; /*citire date */ printf("k = "); scanf("%d",&k); printf("c = "); scanf("%d",&c); printf("S = "); scanf("%d",&S); /*calcul */ xmax=1; for(i=1; i<k; i++) xmax*=c; x = xmax; for(i=0; S>0; i++){ sol[i] = S / x; S %= x; x /= c; } /*afisare */ x = xmax; for(j=0; j<i; j++,x/=c) if(sol[j]>0) printf("%d monede cu valoarea %d\n", sol[j], x); getch(); } R3.3.4. [Numere frumoase] Numerele frumoase sunt acele numere care au n descompunerea lor numai factori primi de 2, 3 i 5. Fiind dat un numr natural n<1000, s se afieze pe ecran primele n numere frumoase. Rezolvare: Programul Pascal este: program nrFrumoase; const max = 1000; function min(a,b:integer):integer; begin if a <= b then min:=a else min:=b end; var t,n2,n3,n5:integer; f:array[1..max] of longint; i,j,k,l,n:integer; begin write('n = '); readln(n); n2:=2; i:=1; n3:=3; j:=1; n5:=5; k:=1; t:=1; l:=1; f[1]:=1; while(l<=n) do begin t:=min(n2,min(n3,n5)); l:=l+1; f[l]:=t; if t = n2 then begin inc(i); n2 := 2*f[i] end; if t = n3 then begin inc(j); n3 := 3*f[j] end;
121

end.

if t = n5 then begin inc(k); n5 := 5*f[k] end end; for i:=1 to n do write(f[i],' '); readln;

R3.3.5. [Copaci i ciori] Pe n copaci aezai n cerc se afl n-1 ciori, maxim una pe fiecare copac. Dndu-se o configuraie iniial i una final a ciorilor i tiind c la un moment dat o singur cioar poate zbura de pe copacul ei pe cel liber, s se scrie un program care s determine o secven de zboruri pentru a ajunge la configuraia final. Rezolvare: Programul C este: #include <stdio.h> #define MAX 10 int initial[MAX]; int final[MAX]; int n; int CopacLiber(){ int i=0; while(initial[i]!=0) i++; return i; } int Copac(int c){ int i=0; while(initial[i] != c) i++; return i; } void Zboara(int s,int d){ printf("Cioara %d zboara de pe copacul %d pe %d !\n", \ initial[s], s+1,d+1); initial[d] = initial[s]; initial[s] = 0; } void main(){ int i, k; printf("n = "); scanf("%d",&n); printf("Introduceti configuratia initiala (0 pt. liber):\n"); for(i=0;i<n;i++) {printf("initial[%d] = ",i+1); scanf("%d",&initial[i]);} printf("Introduceti configuratia finala (0 pt. liber):\n"); for(i=0;i<n;i++) {printf("final[%d] = ",i+1);scanf("%d",&final[i]);} for(i=0;i<n;i++) if (final[i] && initial[i] != final[i]){ if(initial[i]) { k = CopacLiber(); Zboara(i,k); } k = Copac(final[i]); Zboara(k,i); } }
122

R3.3.6. [Problema comis-voiajorului] Un comis-voiajor trebuie s viziteze un numr de n orae i s revin n oraul de plecare. Cunoscnd legturile dintre oricare dou orae se cere s se afieze cel mai scurt traseu posibil pe care poate s-l parcurg comisvoiajorul tiind c nu trebuie s treac de dou ori prin acelai ora. Rezolvare: Programul Pascal este: program comis; const max = 25; var harta:array[1..max,1..max] of integer; traseu:array[1..max] of integer; v:array[1..max] of 0..1; i,j,k,min,n,lungime,pos:integer; begin write('n = '); readln(n); for i:=1 to n-1 do for j:=i+1 to n do begin write('distanta[',i,', ', j,'] = '); readln(harta[i,j]); harta[j,i]:=harta[i,j]; end; write('Orasul de pornire = '); readln(k); lungime:=0; traseu[1]:=k; v[k]:=1; for i:=2 to n do begin min:=maxint; for j:=1 to n do if v[j] = 0 then if harta[k, j] < min then begin min := harta[k, j]; pos := j end; inc(lungime,min); traseu[i]:=pos; v[pos]:=1; k:=pos end; inc(lungime,harta[k,1]); for i:=1 to n do write(traseu[i]:3); writeln(traseu[1]:3); writeln('lungimea = ', lungime); readln; end.
123

3.3.3. Probleme propuse 1. [Problema planificrii optime a lucrrilor] Se presupune c avem de executat un numr de n lucrri, cunoscndu-se pentru fiecare lucrare i termenul de finalizare ti i penalizarea pi pltit n cazul n care lucrarea nu este predat la termen. tiind c fiecare lucrare este executat ntr-o unitate de timp i c nu se pot executa mai multe lucrri simultan, s se planifice ordinea de execuie a lucrrilor astfel nct penalizarea total s fie minim. 2. [Amplasarea canalelor] n jurul unui ora avem N bazine cu ap ce trebuiesc unite ntre ele prin canale. Fiecare bazin poate fi unit prin cte un canal cu mai multe bazine. Perechile de bazine ce vor fi unite sunt date ntr-o list. Un canal poate trece doar prin interiorul sau exteriorul cercului format de bazine. Se cere modul de amplasare al fiecrui canal. 3. Se dau numerele ntregi nenule a1, a2, , an i b1, b2, , bm cu n m. S se determine o submulime {x1, x2, , xm} a mulimii {a1, a2, , an} care s maximizeze expresia E = b1x1 + b2x2 + + bmxm. 4. ntr-un depozit al monetriei statului sosesc n saci cu monezi. Se cunoate numrul de monezi din fiecare sac i se dorete mutarea monezilor dintr-un sac n altul n aa fel nct n fiecare sac s apar acelai numr de monezi. Scriei un program care rezolv problema efectund un numr minim de mutri. 5. Fie n iruri ordonate cresctor S1, S2, , Sn cu lungimile L1, L2, , Ln. S se interclaseze cele n iruri obinndu-se un singur ir cresctor de lungime L1 + L2 + + Ln cu un numr minim de comparaii ntre elementele irurilor. 6. Fie X = {x1, x2, ,xn} o mulime de numere reale. S se detmine o mulime de cardinal minim de intervale de lungime 1 a cror reuniune s includ mulimea X. 7. Se cunosc poziiile oraelor unei ri date prin coordonatele lor. S se determine configuraia unei reele telefonice astfel nct toate oraele s fie conectate la reea i costul reelei s fie minim. 8. Se dau n i k, naturale, kn. S se construiasc un tablou nn care ndeplinete simultan condiiile: conine toate numerele de la 1 la n2 o singur dat; pe fiecare linie numerele sunt aezate n ordine cresctoare, de la stnga la dreapta; suma elementelor de pe coloana k s fie minim. 9. Un instructor de schi trebuie s distribuie n perechi de schiuri la n elevi nceptori. Descriei un algoritm care s fac distribuirea n aa
124

fel nct suma diferenelor absolute dintre nlimea elevului i lungimea schiurilor s fie minim. 10. Se d un polinom P(X) cu coeficieni ntregi. S se afle toate rdcinile raionale ale polinomului. 11. Se dau n puncte n plan prin coordonatele lor numere ntregi. S se construiasc, dac este posibil, un poligon convex care s aib ca vrfuri aceste puncte. 12. Fiind dat o hart cu n ri, descriei un algoritm euristic care s determine o modalitate de colorare a hrii astfel nct dou ri care se nvecineaz s fie colorate diferit. 13. Descriei un algoritm euristic care s determine o modalitate prin care un cal aflat n colul stnga-sus s strbat ntreaga tabl de ah fr a trece de dou ori prin aceeai poziie. 14. Descriei un algoritm euristic care s schimbe o sum S dat folosind un numr minim de monete avnd valorile v1, v2, , vn.

3.4. Metoda backtracking


3.4.1.Prezentarea metodei Aceast tehnic se folosete la rezolvarea problemelor a cror soluie se poate reprezenta sub forma unui vector S = x1x2...xn cu x1 S1, x2 S 2, , xn S n, iar mulimile S1, S2, , Sn, care pot coincide, sunt mulimi finite ordonate liniar (pentru orice element, cu exceptia ultimului este cunoscut succesorul). Pentru fiecare problem concret sunt precizate relaiile dintre componentele vectorului care memoreaz soluia, numite condiii interne. Mulimea S = S1 S1 se numete spaiul soluiilor, iar elementele produsului cartezian care satisfac i condiiile interne se numesc soluii rezultat. Metoda evit generarea tuturor combinaiilor completnd pe rnd componentele vectorului soluie cu valori ce ndeplinesc condiiile de continuare, scurtndu-se astfel timpul de calcul. Vectorul x este privit ca o stiv, lui xk nu i se atribuie o valoare dect dup ce x1, , xk-1 au primit valori. La nceput xk este iniializat la o valoare (cu ajutorul unei funcii init) al crei succesor este primul element din Sk. Cu ajutorul unei funcii succesor xk ia valoarea primului element din Sk. Dup ce xk a primit o valoare, nu se trece direct la atribuirea unei valori lui xk+1 ci se verific mai nti anumite condiii de continuare referitoare la x1, , xk cu ajutorul unei funcii valid de tip logic. Dac aceste condiii sunt satisfcute se verific dac s-a obinut o soluie caz n care se trece la afiarea acesteia.
125

Nendeplinirea condiiilor de continuare exprim faptul c oricum am alege xk+1, , xn, nu vom ajunge la o soluie. n acest caz se face o nou alegere pentru xk sau, dac Sk a fost epuizat, se micoreaz k cu o unitate i se ncearca o nou alegere pentru xk (k >0) din restul elementelor lui Sk nc nealese folosind funcia succesor. Ca urmare se trece la atribuirea unei valori lui xk+1 doar dac sunt ndeplinite condiiile de continuare. Algoritmul se termin n momentul n care au fost luate n calcul toate elementele mulimii S1. Metoda backtracking poate fi descris prin urmtoarea procedur (n varianta iterativ): k := 1; init(k, st); while k > 0 do begin repeat succesor(as, st, k); if as then valid(ev, st, k); until (not as) or (as and ev); if as if solutie(k) then tipar else begin k := k + 1; init(k, st) end else k := k 1; end; Rezolvarea problemelor prin aceast metod necesit un timp mare de execuie, motiv pentru care metoda este recomandat numai n cazurile n care spaiul soluiilor este destul de redus, sau dac nu se cunoate un alt algoritm mai rapid. Metoda admite i o variant recursiv n care stiva nu este gestionat explicit de programator. n continuare este dat forma general a procedurii backtracking n variant recursiv (care se va apela cu Back(1)): procedure Back(k); var i:integer; begin if solutie(k) then tipar(x) else begin init(k,x); while succesor(x,k) do begin x[k]:=i; if valid(x,k) then Back(k+1) end; end end;
126

3.4.2. Probleme rezolvate R3.4.1. [Permutri] Se d un numr n N, se cere s se genereze toate permutrile mulimii {1, 2, ,n}. Rezolvare: program permutari; uses crt; type stack = array[1..25] of integer; var st: stack; n:integer; k:integer; as, ev: boolean; procedure init(k:integer; var st: stack); begin st[k]:=0 end; procedure succesor(var as:boolean; var st: stack; k:integer); begin if st[k] < n then begin st[k] := st[k] + 1; as := true end else as:=false; end; procedure valid(var ev:boolean; st: stack; k:integer); var i:integer; begin ev:=true; for i:=1 to k-1 do if st[k] = st[i] then ev:=false end; function solutie(k:integer) :boolean; begin solutie:=(k=n) end; procedure tipar; var i:integer; begin for i:=1 to n do write(st[i],' '); writeln end; begin write ( ' n = ' ); readln(n) ; k:=1; init(k,st); while (k>0) do begin repeat succesor (as, st, k) ; if as then valid(ev,st,k); until (not as) or (as and ev) ; if as then if solutie(k) then tipar else begin k:=k+1; init(k,st) end else k:=k-1 end; end.
127

R3.4.2. [Descompunere ca sum de numere prime] S se descompun un numr natural n n toate modurile posibile ca sum de numere prime. Rezolvare: program desc_prime; var Prime, x :array[1..100] of integer; n,k,i,p,S:integer; function Prim(nr:integer):boolean; var i:integer; begin Prim:=true; i:=2; while i*i <= nr do if nr mod i = 0 then begin Prim:=false; break; end else inc(i); end; procedure Tipar; var i:integer; begin for i:=1 to k do write(Prime[x[i]],' '); writeln end; begin write('n = '); readln(n); p:=0; for i:=2 to n do if Prim(i) then begin inc(p); Prime[p]:=i end; S:=0; k:=1; x[k]:=0; while k>0 do begin inc(x[k]); if (x[k] <= p) and (S + Prime[x[k]] <= n) then if S + Prime[x[k]] = n then Tipar else begin inc(S,Prime[x[k]]); inc(k); x[k] := x[k-1]-1 end else begin dec(k); Dec(S,Prime[x[k]]); end end end.
128

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

Rezolvare: program Culori; uses crt; type stack = array[1..25] of integer; var st: stack; i,j,k,n:integer; as, ev: boolean; a:array[1..25,1..25] of integer; procedure init(k:integer;var st: stack); begin st[k]:=0 end; procedure succesor(var as:boolean; var st: stack; k:integer); begin if st[k] < 4 then begin st[k] := st[k] + 1; as := true end else as:=false; end; procedure valid(var ev:boolean; st: stack; k:integer); var i:integer; begin ev:=true; for i:=1 to k-1 do if (st[k]=st[i]) and (a[i,k]=1) then ev:= false; end; function solutie(k:integer) :boolean; begin solutie:=(k=n) end; procedure tipar; var i:integer; begin for i:=1 to n do write(st[i],' '); writeln end; begin write (' n = '); readln(n); for i:=1 to n do for j:=1 to i-1 do begin write('a[',i,',',j,']= '); readln(a[i,j]); a[j,i]:=a[i,j] end; k:=1; init(k,st); while (k>0) do begin repeat succesor (as, st, k) ; if as then valid(ev,st,k); until (not as) or (as and ev) ; if as then if solutie(k) then tipar else begin k:=k+1; init(k,st) end else k:=k-1; end; end.
130

R3.4.5. [Sritura calului] Se consider o tabl de ah n x n i un cal plasat n colul din stnga sus. Se cere s se afieze toate posibilitile de mutare a calului astfel nct s treac o singur dat prin fiecare ptrat al tablei. Rezolvare: #include <stdio.h> #include <conio.h> typedef int tabla[25][25]; int linT[8] = {-1,+1,+2,+2,+1,-1,-2,-2}; int colT[8] = {+2,+2,+1,-1,-2,-2,-1,+1}; tabla tab; int n; void tipar(){ int i,j; for(i = 0; i < n; i++){ printf("\n"); for(j = 0; j < n; j++) printf("%3d", tab[i][j]); } printf("\n"); getch(); } void cal(int lin, int col, int k){ int i,lin2,col2; if (tab[lin][col]) return; k++; tab[lin][col]=k; if (k==n*n) tipar(); else for (int i = 0; i < 8; i++){ lin2 = lin + linT[i]; col2 = col + colT[i]; if (lin2>=0 && lin2<n && col2>=0 && col2<n) cal(lin2,col2,k); } tab[lin][col] = 0; } void main(){ int i,j; printf("n = "); scanf("%d",&n); for(i = 0; i < n; i++) for(j = 0; j < n; j++) tab[i][j]=0; cal(0,0,0); printf("\n%d solutii",t); }
131

3.4.3. Probleme propuse 1. Se dau numerele naturale n i k, s se genereze toate aranjamentele (funciile injective) de elemente din mulimea {1, 2, , n} luate cte k. 2. Fie dou numere naturale n i k cu n k, se cere s se genereze toate submulimile (combinrile) de k elemente din mulimea {1, 2, ,n}. 3. Se dau mulimile A1 = {1, 2, , p1}, A2 = {1, 2, , p2}, , An = {1, 2, , pn} se cere s se genereze produsul cartezian al mulimilor A1, A2, , An. 4. S se descompun un numr natural n n toate modurile posibile ca sum de numere naturale. 5. Se consider mulimea {1, 2, , n}. Se cer toate partiiile acestei mulimi. 6. Se d o sum S i n tipuri de monede avnd valorile v1, v2, , vn lei. Se cer toate modalitile de plat a sumei S utiliznd aceste monede. 7. Considerndu-se o tabl de ah de dimensiuni n n, s se determine toate modalitile de amplasare a n ture pe aceast tabl n aa fel nct s nu se atace ntre ele. 8. Un ntreprinztor ce dispune de un capital C trebuie s leag dintre n oferte la care trebuie avansate fonfurile fi i care aduc profiturile pi pe acelea pe care le poate onora cu capitalul de care dispune i care i aduc profitul total maxim. 9. S se determine toate delegaiile de n persoane din care p femei care se pot forma din t persoane din care v femei. 10. Avem la dispoziie 6 culori: alb, negru, rou, albastru, verde, galben. S se genereze toate steagurile ce se pot forma cu trei culori diferite avnd la mijloc alb sau negru. 11. Un comis-voiajor trebuie s viziteze un numr de n orae i s revin n oraul de plecare. Cunoscnd legturile dintre orae se cere s se afieze toate drumurile posibile pe care poate s le parcurg comis-voiajorul tiind c nu trebuie s treac de dou ori prin acelai ora. 12. ntr-un grup de persoane fiecare persoan se cunoate pe sine i cunoate eventual i alte persoane din grup. S se determine toate modurile n care cele N persoane se pot repartiza n echipe astfel nct orice persoan din grup s fie cunoscut de cel puin un membru al fiecrei echipe.
132

13. Cei doi fii ai unei familii motenesc prin testament, n mod egal, o avere format din monede avnd ca valori numere ntregi pozitive. O condiie din testament cere ca fraii s mpart monezile n dou pri avnd valori egale pentru a intra n posesia lor, altfel suma va fi donat unei biserici. Scriei un program care s i ajute pe cei doi frai s intre n posesia motenirii. 14. Pe malul unui ru se gsesc c canibali i m misionari. Ei urmeaz s treac rul cu o barc cu dou locuri. Dac pe unul dintre maluri se vor afla mai muli canibali dect misionari acetia din urm vor fi mncai de canibali. Se cere un program care s afieze toate modalitile de trecere a rului n care misionarii s nu fie mncai. 15. Pentru elaborarea unui test de aptitudini avem un set de n ntrebri, fiecare fiind cotat cu un numr de puncte. S se elaboreze toate chestionarele avnd ntre a i b ntrebri distincte, fiecare chestionar totaliznd ntre p i q puncte. ntrebrile sunt date prin numr i punctaj. 16. 2n + 1 persoane particip la discuii (mas rotund) care dureaz n zile. S se gseasc variantele de aezare la mas astfel ca o persoan s nu aib n dou zile diferite acelai vecin. 17. S se determine 5 numere de cte n cifre fiecare cifr putnd fi 1 sau 2, astfel nct oricare dintre cele 5 numere s coincid n m poziii i s nu existe nici o pozitie care s conin aceeai cifr n toate cele 5 numere. 18. S se genereze o secven binar de lungime 2n+n+1 astfel nct orice dou secvente consecutive de n biti s fie diferite. 19. Se dau x1, x2, , xn numere naturale cu cel mult 9 cifre i n 100. Fiecare numr xi este reprezentat n baza bi (2 bi 10) care nu este cunoscut. S se gaseasc baza bi pentru fiecare numr xi astfel nct intervalul [a, b] n care sunt cuprinse cele n numere (dup transformarea n baza 10) s fie de lungime minim. 20. Numrul 123456789 nmulit cu 2, 4, 7 sau 8 d ca rezultat tot un numr de nou cifre distincte (fr 0). Aceast proprietate nu funcioneaz pentru numerele 3, 6 sau 9. Exist totui multe numere de nou cifre distincte (fr 0) care nmulite cu 3 au aceeai proprietate. S se listeze toate aceste numere n care ultima cifr este 9. 21. S se dispun pe cele 12 muchii ale unui cub toate numerele de la 1 la 12, astfel nct suma numerelor aflate pe muchiile unei fee s fie aceeai pentru toate feele.
133

22. Toate oraele unei ri sunt legate la o reea de linii feroviare. Dou orae i i j pot fi legate prin cel mult o legtur direct prin care circul un singur tren pe zi ntre orele p(i, j) i s(i, j). Dac se dau dou orae A i B, s se afieze traseul, staiile de schimbare a trenurilor i timpii de ateptare n aceste staii astfel nct durata total a cltoriei s fie minim. 23. Configuraia unui teren este specificat printr-o gril gen tabl de ah de dimensiune nn, fiecare careu avnd o anumit nlime. ntr-un careu precizat al grilei se plaseaz o minge. tiind c mingea se poate deplasa ntr-unul din cele maxim 8 careuri vecine doar dac acesta are o cot strict mai mic, s se genereze toate trasele pe care le poate urma mingea pentru a prsi terenul. 24. Un cal i un rege se afl pe o tabl de ah. Unele cmpuri ale tablei sunt "arse", poziiile lor fiind cunoscute. Calul nu poate clca pe cmpuri "arse", iar orice micare a calului face ca respectivul cmp s devin "ars". S se afle dac exist o succesiune de mutri permise (cu restriciile de mai sus), prin care calul s poat ajunge la rege i s revin la poziia iniial. Poziia iniial a calului, precum i poziia regelui sunt considerate "nearse". 25. Fie o matrice n x m cu valori de 0 i 1. Dndu-se o poziie iniial (i,j) s se gseasc toate ieirile din matrice mergnd doar pe elemente cu valoarea 1. 26. O fotografie alb-negru este dat printr-o matrice cu valori 0 i 1. Fotografia prezint unul sau mai multe obiecte. Punctele fiecrui obiect sunt marcate cu 1. Se cere un program care s calculeze numrul de obiecte din fotografie. 27. Se d o matrice binar n care elementele cu valoarea 1 delimiteaz o suprafa marcat cu elemente de zero. Dndu-se coordonatele unui punct n cadrul matricei s se coloreze suprafaa n interiorul creia cade punctul. 28. Se dau n puncte albe i n puncte negre n plan prin perechi (i,j) de numere ntregi. Fiecare punct alb se va uni cu un singur punct negru asttfel nct segmentele formate s nu se intersecteze. S se gseasc o soluie tiind ca oricare 3 puncte sunt necoliniare. 29. Se dau n puncte n plan prin perechi (i,j) de numere ntregi. S se selecteze 4 puncte ce reprezint colurile ptratului care cuprinde numrul maxim de puncte din cele n puncte date.

134

30. Se d un cuvnt si o matrice de caractere de dimensiune m x n. S se gseasc n matrice prefixul de lunginme maxim al cuvntului dat. 31. Se d un numr natural par n. S se afieze toate irurile de n paranteze care se nchid corect. 32. Se consider o bar de lungime n i k repere de lungimi l1, l2,, lk. Din bar trebuiesc tiate buci de lungimea reperelor date, astfel nct s avem cel puin cte o bucat de lungime li cu i = 1..k i pierderile s fie nule. 33. Se consider un numr nelimitat de piese dreptunghiulare de dimensiuni a 2a. Piesele se vor folosi la pavarea fr fisuri a unei zone rectangulare de dimensiuni ka pa. Se cer toate soluiile (reprezentare grafic).

3.5. Metoda Branch and Bound


3.5.1. Prezentarea metodei Metoda branch and bound foloseste la rezolvarea problemelor la care domeniul n care se caut soluia este foarte mare i nu se cunoate un alt algoritm care s conduc mai rapid la rezultat. Problemele care pot fi abordate prin aceast metod pot fi modelate ntr-un mod asemntor celui folosit la metoda backtracking. Se pleac de la o configuraie iniial i se reine irul de operaii prin care aceasta este transformat ntr-o configuraie final dac aceasta este dat, n alte cazuri se cere configuraia final tiind c trebuie s verifice anumite condiii de optim. Diferena dintre cele dou metode const n faptul c metoda backtracking la fiecare etap selecteaz un singur succesor dup care se face verificarea condiiilor de continuare, iar metoda branch and bound genereaz la fiecare pas toate configuraiile posibile (toi succesorii) care rezult din cea curent i le stocheaz ntr-o list. Se alege apoi un element din list dup un criteriu ce depinde de problem i se reia procesul de expandare. Alegerea optim a unui element din aceast list pentru expandare se face cu ajutorul unei funcii f = g + h n care g este o funcie care msoar lungimea drumului parcurs de la configuraia iniial pn la nodul curent, iar h este o funcie (euristic) care estimeaz efortul necesar pan se ajunge la soluie i este specific fiecrei probleme. Alegerea funciei h este foarte important din punct de vedere a vitezei de execuie a programului.
135

Se lucreaz cu dou liste: lista open n care se rein configuraiile neexpandate nc i lista close care le memoreaz pe cele expandate. Soluia se construiete folosind un arbore care se parcurge pe baza legturii tat. Nodurile sunt nregistrri care cuprind urmtoarele informaii: 1. configuraia la care s-a ajuns, t; 2. valorile funciilor g si h, 3. adresa nodului 'tat'; 4. adresa nregistrrii urmtoare n lista open sau close; 5. adresa nregistrrii urmtoare n lista succesorilor. Algoritmul este urmtorul: A. nregistrarea corespunztoare configuraiei iniiale este ncrcat n open cu g=0 i f=h; B. att timp ct nu s-a selectat spre expandare nodul corespunztor configuraiei finale i lista open este nevid, se execut urmtoarele: 1. se selecteaz din lista open nodul t cu f minim; 2. se expandeaz acest nod obinnd o list liniar simplu nlnuit cu succesorii si; 3. pentru fiecare succesor din aceast list se execut: 3.1. se ataeaz noul g, obinut ca sum ntre valoarea lui g a configuraiei t i costul expandrii (de obicei 1); 3.2. se testeaz dac acest succesor aparine listei open sau close i n caz afirmativ, se verific dac valoarea lui g este mai mic dect cea a configuraiei gsite n list: 3.2.1. n caz afirmativ, nodul gsit este direcionat ctre actualul printe (prin fixarea legturii tat) i se ataeaz noul g, iar dac acest nod se gsete n close, este trecut n open; 3.2.2. n caz c acest nod nu se gsete n open sau close, este introdus n lista open; C. dac s-a selectat pentru expandare nodul corespunztor configuraiei finale atunci se traseaz folosind o procedur recursiv drumul de la configuraia iniial la cea final utiliznd legtura 'tat'; D. dac ciclul se ncheie deoarece lista open este vid nseamn c problema nu are soluie. Observaie. Algoritmul se poate implementa folosind o singur list, iar diferenierea dintre nodurile expandate i cele neexpandate se va face dup un cmp special. Apare ns dezavantajul c operaiile de
136

cutare se fac ntr-o list mai lung. Acest dezavantaj se poate elimina folosind o structur special numit tabel hash. n unele cazuri se poate folosi un arbore binar. 3.5.2. Probleme rezolvate R.3.5.1. [Problema discret a rucsacului] Se d un rucsac de capacitate M i un numr de n obiecte, specificndu-se masele obiectelor i profiturile ce se obin prin transportul lor cu rucsacul. Se cere un program care s determine obiectele alese astfel nct s se obin un profit maxim. Soluia se va da sub forma unui vector definit astfel: xk=0 dac obiectul k nu este luat n rucsac, xp = 1 dac obiectul p este luat n rucsac. Rezolvare: n rezolvarea acestei probleme nu vom folosi dou liste ci un arbore binar. Algoritmul face, n prealabil, o ordonare descresctoare a obiectelor dup raportul profit/mas. Se pornete de la configuraia iniial n care nici obiect nu a fost nc ales. Se parcurge iterativ lista de obiecte. La fiecare iteraie se decide includerea sau nu a obiectului curent n rucsac i se expandeaz configuraia curent n dou configuraii corespunztoare celor doi subarbori. Nodul corespunztor fiului drept se obine din nodul tat la care se adaug obiectul curent, iar cel corespunztor fiului stng se obine din nodul tat ns fr adugarea obiectului analizat. Analiza continu numai pe una din cele dou ramuri ale arborelui binar, iar opiunea pentru una din cele dou ramuri se face pe baza unei funcii H care estimeaz profitul. program RucsacBB; uses crt; const max = 25; type TObiect = record masa, profit:integer; nr:integer end; PNod= ^Nod; Nod = record nivel,luat:integer; p_estimat,profit,masa:integer; tata,drept,stang:PNod; end; var n: integer; obiect: array[1..max] of TObiect; G, profitmax,masatotala:integer; solutie:array[1..max] of 0..1;
137

procedure Sort; var i,j:integer; aux:TObiect; begin for i:=1 to n-1 do for j:=i+1 to n do if (obiect[i].profit/obiect[i].masa < obiect[j].profit/obiect[j].masa) then begin aux:= obiect[i]; obiect[i]:=obiect[j]; obiect[j]:=aux; end; end; function H(pn:PNod):integer; var i,k:integer; p,m:integer; begin p := pn^.profit; m := pn^.masa; k := pn^.nivel; if m <= G then begin for i:= k + 1 to n do if m + obiect[i].masa <= G then begin p := p + obiect[i].profit; m := m + obiect[i].masa end; H := p end else H:=-1; end; procedure Branch; var k:integer; nodc,stang,drept:PNod; begin k:=0; new(nodc); nodc^.tata:= nil; nodc^.nivel:=k; nodc^.luat:=0; nodc^.masa:=0; nodc^.profit:=0; repeat inc(k); new(stang); new(drept); nodc^.stang:=stang; nodc^.drept:=drept; stang^.tata:=nodc; stang^.nivel:=k; stang^.luat:=0; stang^.masa:=nodc^.masa; stang^.profit:=nodc^.profit; stang^.p_estimat:= H(stang); drept^.tata:=nodc; drept^.nivel:=k; drept^.luat:=1; drept^.masa:=nodc^.masa + obiect[k].masa; drept^.profit:=nodc^.profit + obiect[k].profit; drept^.p_estimat:=H(drept); if stang^.p_estimat > drept^.p_estimat then nodc:=stang else nodc:=drept; until k=n;
138

var i:integer; begin {main} write('Capacitatea rucsacului = '); readln(G); write('Numarul obiectelor = '); readln(n); for i:= 1 to n do begin write('Masa[',i ,'] = '); readln(obiect[i].masa); write('Profitul[',i ,'] = '); readln(obiect[i].profit); obiect[i].nr := i; end; Sort; Branch; writeln('Solutie:'); for i:= 1 to n do if solutie[i]=1 then write(obiect[i].nr,' '); writeln; writeln('Profitul obtinut = ', profitmax); writeln('Masa totala = ', masatotala); readln; end. R3.5.2. [Jocul Perspico] Se consider o tabl cu 4 x 4 csue, fiecare csu conine un numr ntre 1 si 15 si o csut conine zero (este liber). tiind c 0 i poate schimba poziia cu orice numr natural aflat deasupra, la dreapta, la stnga sau jos, n raport cu pozii n care se afl numrul 0, se cere s se precizeze irul de mutri prin care se poate ajunge de la o configuraie iniial dat la o configuraie final. Se cere de asemenea ca acest sir s fie optim, n sensul c trebuie s se ajung la configuraia final ntr-un numr minim de mutri. Rezolvare: #include<stdio.h> #include<stdlib.h> #include<conio.h> #define MAX 4 #define maxop 4
139

end;

profitmax := nodc^.profit; masatotala := nodc^.masa; while nodc^.tata<>nil do begin solutie[nodc^.nivel]:=nodc^.luat; nodc:=nodc^.tata; end

typedef struct Nod{ char conf[MAX][MAX]; int h, g; struct Nod *down, * up; }Nod, *PNod; PNod New(PNod p){ PNod pnod = (PNod) malloc( sizeof(Nod) ); if (pnod==NULL){ printf("\nNot enough memory !\n"); exit(0); } *pnod = *p; return pnod; } void Insert(PNod * list, PNod pnod){ pnod->down = *list; *list = pnod; } void RemoveAll(PNod *list){ PNod p; while(*list){ p = *list; *list = (*list)->down;free(p); } } PNod Expand(PNod pnod){ int i, j, k, ii, jj; static int lin[maxop] = {-1, 0, 1, 0}; static int col[maxop] = { 0, 1, 0,-1}; PNod list = NULL; PNod newNod = NULL; for(i=0; i < MAX; i++) for(j=0; j < MAX; j++) if (pnod->conf[i][j]==0) ii=i,jj=j; for(k = 0; k < maxop; k++){ i = ii + lin[k]; j = jj + col[k]; if(i >= 0 && i < MAX && j >= 0 && j < MAX){ newNod = New(pnod); newNod->conf[ii][jj] = newNod->conf[i][j]; newNod->conf[i][j] = 0; Insert(&list,newNod); } } return list; }
140

int Equals(PNod n1, PNod n2){ int i, j; if (n1->h != n2->h) return 0; for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++) if (n1->conf[i][j] != n2->conf[i][j]) return 0; return 1; } PNod Extract(PNod * list, PNod p){ PNod temp = *list, spy = *list; if (p==NULL || p == *list){ *list = (*list)->down; return temp;} while(temp != p){ spy = temp; temp = temp->down;} spy->down = temp->down; return temp; } void PrintNod(PNod pnod){ int i,j; for(i = 0; i < MAX; i++){ printf("\n|"); for(j = 0; j < MAX; j++) printf("%3d", pnod->conf[i][j]); printf(" |"); } printf("\nApasati orice tasta ...); getch(); } void Print(PNod pnod){ if (pnod->up) Print(pnod->up); PrintNod(pnod);} PNod Choice(PNod list){ int f, min = 32000; PNod pmin = NULL; while (list){ f = list->h + list->g; if ( f < min ){pmin = list; min = f;} list=list->down;} return pmin; } void ComputeH(PNod t, PNod fin){ int i, j, k, r, s; t->h = 0; for(i = 0; i < MAX; i++) for(j = 0; j < MAX; j++) for(r = 0; r < MAX; r++) for(s = 0; s < MAX; s++) if (t->conf[i][j] == fin->conf[r][s]) t->h += abs(r-i) + abs(s-j); } PNod Search(PNod list, PNod pnod){ while (list && !Equals(list,pnod)) list = list->down; return list;}
141

void Branch(Nod *in, Nod *fin){ PNod Open = NULL; PNod Close = NULL; PNod TempList = NULL; PNod theOne, temp, found; PNod initial = New(in); Pnod final = New(fin); int ok = 0; initial->g = 0; ComputeH(initial,final); final->h = 0; Insert(&Open,initial); while(Open){ theOne = Choice(Open); Extract(&Open,theOne); Insert(&Close,theOne); if (Equals(theOne, final)){ok = 1; break;} TempList = Expand(theOne); while(TempList){ temp = Extract(&TempList,NULL); temp -> g = theOne->g + 1; if( found = Search(Open, temp) ){ if(temp->g < found->g){ found->g = temp->g; found->up = theOne;} free(temp); } else if( found = Search(Close, temp) ){ if(temp->g < found->g){ found-> g = temp->g; found->up = theOne; Extract(&Close, found); Insert(&Open, found);} free(temp); } else{ temp->up = theOne; ComputeH(temp,final); Insert(&Open,temp);} } } if (ok){ printf("\nSolutie:\n"); Print(theOne);} else printf("Nu am avem solutii !"); RemoveAll(Open); RemoveAll(Close); } void main(){ Nod in = {{ 5, 1, 3, 4, 9, 7, 8, 0, 6, 2, 10, 11, 13, 14, 15, 12}, 0, 0, NULL,NULL}; Nod fin ={{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12, 13,14,15, 0},0,0, NULL,NULL}; clrscr(); Branch(&in,&fin); getch(); }
142

3.5.3. Probleme propuse 1. [Generalizare] S se rezolve problema Perspico pentru o tabl de dimensiuni n x n cu numere de la 1 la n2-2 i cu dou zerouri (locuri libere). 2. [Diamante] Se d o tabl sub form de cruce pe care sunt aejate 32 de piese de diamant () aa cum se poate observa n figura de mai jos. Poziia din centru este liber. O pies se poate muta doar srind peste o alt pies ntr-un loc liber, numai pe orizontal sau pe vertical iar piesa peste care se sare trebuie luat. Se cere s se gaseasc un ir de mutri astfel nct (s lum ct mai multe piese de diamant) pornind de la configuraia iniial s se ajung la o configuraie final care s conin numai o singur pies i aceasta s se afle n centru.

Configuraia iniial

Configuraia final

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

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

144

4. Programare modular n Turbo Pascal


4.1. Uniti de translatare Pentru un program realizat conform principiului modularizrii, trebuie avute n vedere att consistena, ct i cuplajul modulelor. Consistena unui modul este o mrime ce caracterizeaz relaiile dintre elementele unui modul, iar cuplajul exprim interconexiunile dintre module. Orice modul are trei atribute fundamentale: funcia, interfaa i logica intern. Funcia modulului descrie transformarea care are loc la apelarea modulului, interfaa indic modul de apelare a elementelor modulului, iar logica intern indic fluxul n cadrul modulului. Conform principiului consistenei, elementele unui program care sunt strns legate ntre ele trebuie s fac parte din acelai modul, iar elementele nelegate trebuie s fie introduse n module diferite (a se vedea uniturile Turbo Pascal i fiierele antet utilizate de mediile de programare C sau C++). Cuplajul modulelor caracterizeaz mecanismul de transmitere a datelor i a atributelor acestora ntre module. Dac se urmrete maximizarea independenei modulelor atunci va crete i consistena modulelor. Totui, de multe ori, programul este organizat n module, nu neaprat independente, unele dintre acestea fiind legate ntre ele printr-un graf de cuplare. Dintre dou module cuplate, la un moment dat, unul este modul apelant (client), iar cellalt este modul apelat (furnizor de serviciu). Exist mai multe modaliti de cuplare: cuplare prin coninut, cuplare prin date comune, cuplare prin fiiere de date, cuplare prin indicatori de control i cuplare prin structuri de date. Cuplajul bazat pe coninut apare cnd modulul apelant folosete elemente ale modulului apelat: date declarate n modulul apelat care nu au fost declarate globale sau externe, coninutul unui modul este fizic inclus n alt modul (ncuibarea subprogramelor n Pascal) etc. Cuplajul prin date comune este caracteristic acelor module care folosesc o structur de date declarat global. Cuplarea prin fiiere de date asigur independena modulelor de numrul i ordinea fizic a datelor. Indicatorii de control sunt date care transmise unui modul determin modul de executare a acestuia: variabile logice, identificatori de funcii etc. Cuplarea prin structuri de date apare atunci cnd modulul apelant transmite modulului apelat, ca parametru, o ntreag structur de date.
145

Modulele Turbo Pascal se mai numesc i uniti de translatare (pot fi compilate separat; vezi i metodele de proiectare C, C++ i Java) sau unituri. Un modul Turbo Pascal este o colecie de constante, tipuri definite, variabile, proceduri i funcii care sunt compilate separat i pot fi folosite de alte module sau de programul principal. Modulele Turbo Pascal, cele mai importante, sunt: SYSTEM - implementeaz operaiile de nivel cobort; DOS - implementeaz funciile sistemului de operare MS-DOS; CRT - permite controlul tastaturii i al monitorului; GRAPH - implementeaz funciile grafice uzuale; PRINTER permite controlul imprimantei; OVERLAY - permite segmentarea programelor. Un avantaj major al introducerii unitilor de translatare const n facilitarea lucrului n echip. O unitate de translatare Turbo Pascal are structura: unit <id_unit>; interface uses <lista_unitilor_de_translatare_apelate>; declaraii globale lista_funciilor_i_procedurilor_publice; implementation declaraii_locale proceduri_i_funcii (definiii ale subprogramelor publice i locale) begin secven_de_iniializare end. i are patru seciuni: antet, interfa, implementare i iniializare. Antetul specific numele modulului <id_unit> care trebuie s coincid cu numele fiierului surs. Partea de interfa conine declararea funciilor i procedurilor care sunt definite n modul i pot fi folosite (apelate) de alte module. Descrierea algoritmului fiecrui subprogram declarat n interfa este realizat n seciunea implementation. Constantele, tipurile, variabilele, procedurile i funciile declarate n partea de implementare sunt obiecte interne modului, fiind ascunse altor module. Deoarece dimensiunea unui modul este n general limitat (iar pentru Turbo Pascal, limita maxim este de 64KB), un proiect este compus din mai multe module, produsul final putnd avea o dimensiune mult mai mare de 64KB.
146

4.2. Probleme rezolvate R4.1. [LU] Se consider sistemul de ecuaii liniare Ax=b, unde A este o matrice ptratic de dimensiune n, iar b este un vector coloan n dimensional. S se determine soluia x = A-1b (n ipoteza existenei i unicitii soluiei), prin metoda descompunerii matricei A n produsul a dou matrice triunghiulare. Rezolvare: Un sistem de ecuaii liniare, Ax=b, poate fi rezolvat astfel: Se descompune matricea coeficienilor n produsul a dou matrice triunghiulare i apoi se rezolv dou sisteme triunghiulare. Cutm matricele L i U astfel nct: u1,1 u1, 2 L u1,n 0 M 0 0 1 0 u L u i A =LU. l 1 M 0 0 2 , 2 2 , n 2 , 1 L= ,U= L L O L L O L 1 0 0 l 0 0 u n ,n n ,1 l n , 2 L l n ,n 1 1 La pasul 1, calculm u1,j i li,1 cu ajutorul relaiilor: u1,j = a1, j, 1j n; li,1 = ai,1 /u1,1, 1 i n. La paii urmtori se determin ui,j i li,j astfel: Dac i j atunci relaia: ai,j = li,1u1,j + li,2u2,j + + li,i-1ui-1,j + ui,j conduce la: ui,j = ai,j -

l
k =1

i 1

i ,k

u k , j , 2 i j.

Dac i>j atunci relaia: ai,j = li,1u1,j + li,2u2,j + +li,j-1uj-1,j + li,juj,j conduce la: li,j = (ai , j

l
k =1

j 1

i ,k

u k , j ) u j , j , 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 uj,j =0 atunci procedeul nu mai poate continua. De asemenea, cnd uj,j este mic, acurateea rezultatelor scade deoarece erorile de rotunjire se nmulesc cu 1/uj,j. Este necesar astfel, interschimbarea ecuaiilor sistemului astfel nct la pasul j, valoarea uj,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 In=i,j=(if i = j then 1 else 0), prin
147

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 ridicat. Textul surs al unitii MATH este descris n finalul seciunii. Programul Pascal este urmtorul: program R4_1; uses math; var 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; begin writeln; write('Dimensiunea sistemului');readln(n); writeln('Matricea sistemului este :'); for i:=1 to n do begin write('Linia',i:2,' '); for j:=1 to n do read(a[i,j]); writeln end; writeln; writeln('Termenul liber este :'); for i:=1 to n do read(b[i]); writeln; ludesc(n,a); if not succes {variabil definit n math} then writeln(' Sistemul este LUDESC incompatibil') else begin lusistem(n,a,b,x); writeln; writeln(' Solutia sistemului este :');writeln; for i:=1 to n do writeln(x[i]:10:6); writeln;
148

end.

ludet(n,a,det); writeln('LU-Determinantul matricei sistemului este: ',det); writeln; writeln('Matricea inversa - pe coloane este:'); for j:=1 to n do begin write(' Coloana ',j,' '); for i:=1 to n do e[i]:=0; e[j]:=1; lusistem(n,a,e,y); for i:=1 to n do begin write(y[i]:10:4,' '); if i mod 6 = 0 then writeln end; writeln end end

R4.2. [LLT] O matrice cu numere reale, simetric este pozitiv definit, dac se poate scrie ca produsul dintre matricea inferior triunghiular 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 LLT, unde prin LT 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 matrice inferior triunghiular L, astfel nct A=LLT. Elementele matricei L se obin prin scrierea egalitii : a 1,1 a1, 2 L a1,n l1,1 0 L 0 l1,1 l 2,1 L l n ,1 a 2,1 a 2, 2 L a 2,n = l 2,1 l 2, 2 L 0 0 l 2, 2 L l n , 2 , M M O M M O M M M O M M a 0 L l n,n n,1 a n , 2 L a n ,n l n ,1 l n, 2 L l n, n 0 prin urmtoarele relaii:

l1,1 = a1,1 ;

li ,1 = ai ,1 l1,1 ; i>1;
149

n l j, j = a j, j l 2 , j>1; j ,k k =1 j 1 li , j = a l j , j , i>j>1. i , j l i ,k l j ,k k =1

12

Procedeul se blocheaz cnd exist 1 j n astfel nct rezultatul 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 LTx=y care se rezolva prin substitutie (eliminare) nainte, respectiv napoi. Procedura LLTD verific dac matricea, primit ca argument, este pozitiv definit i obine descompunerea LLT, 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. program r4_2; uses math; var a:matrice;n,i,j:integer; b,x,y:vector; begin writeln; write('Dimensiunea sistemului:');read(n); for i:=1 to n do begin write('Linia ',i); for j:=1 to n do read(a[i,j]); writeln end; writeln('Termenul liber :'); for i:=1 to n do read(b[i]); writeln; lltd(n,a); if not nenul then write('Eps este prea mare ') else if not pozdef then write('Matricea nu este pozitiv definita') else begin writeln('Matricea sistemului este pozitiv definita'); llsistem(n,a,b,x); writeln('Solutia sistemului este :'); for i:=1 to n do writeln (x[i]:8:4); end end.
150

R4.3. [Iterativitate]. S se utilizeze metodele iterative Iacobi i GaussSeidel pentru a rezolva un sistem de ecuaii liniare (numrul ecuaiilor fiind egal cu numrul necunoscutelor). Rezolvare: Considerm sistemul Ax=b, unde A este o matrice ptratic, de dimensiune n, cu elemente reale. Presupunem c ai,i 0 pentru oricare 1 i n . Atunci sistemul ai,1 x1 + ai,2 x2 + + ai,n xn = bi , i=1,2, ... ,n; se mai poate scrie astfel :

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

(m) ai ,i , i = 1, 2, , n; m 0. xi( m +1) = b a x i i , j j j i


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 1 ( m +1) xi( m +1) = b i ai , j x j j =1

j =i +1

i, j

x (jm ) ai ,i , i=1, 2, .., n; m 0.

Cele dou metode converg n cazul unui sistem liniar cu matrice diagonal dominant: a i ,i > ai , j , i =1, 2, , n.

j i

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

program r4_3; uses math; var a:matrice; b,x:vector; i,j,n,niter:integer; begin writeln; write('Dimensiunea sistemului>');read(n); writeln('Coloanele matricei --- b '); for i:=1 to n do begin for j:=1 to n do read(a[i,j]); read (b[i]); writeln end; write('Numar-iteratii >');read(niter); if diag_dom(n,a) then begin for i:=1 to n do x[i]:=0; iacobi(n,a,b,niter,x); writeln; writeln('Solutia obtinuta prin metoda Iacobi :'); for i:=1 to n do writeln (x[i] ); for i:=1 to n do x[i]:=0; Seidel(n,a,b,niter,x); writeln; writeln('Solutia obtinuta prin metoda Gauss-Seidel:'); for i:=1 to n do writeln(x[i]) end else write(' Algoritmii Iacobi i Gauss-Seidel nu converg.') end. R4.4. [Prelucrarea datelor prin metoda celor mai mici ptrate] Fie ARxR, A = {(x1 ,y1), (x2 ,y2), ..., (xn ,yn)}. Presupunem c yi sunt valorile n xi ale unei funcii reale a crei expresie analitic nu este cunoscut. Se cere identificarea unui model f, care s minimizeze suma ptratelor erorilor:

S = ( y i f ( xi ) ) .
2 i =1

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 xb (putere); y = a bx (exponential); y = c1 +c2 x+...+ ck+1xk(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 trebuie rezolvat este urmtorul:
n n + = na b x yi ; i i =1 i =1 n n n a xi + b xi2 = xi y i . i =1 i =1 i =1

Determinarea parametrilor modelului putere se bazeaz pe rezolvarea urmtorului sistem:


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

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


n n + = n ln a ln b x ln y i ; i i =1 i =1 n n n ln a xi + ln b xi2 = xi ln y i i =1 i =1 i =1

cu necunoscutele ln a i ln b. n cazul modelului polinomial, trebuie rezolvat urmtorul sistem cu k+1 ecuaii i k+1 necunoscute {c0 ,c1,...,ck}:
n n n k c c x c x yi ; L + + + = k i 0 1 i i =1 i =1 i =1 n n n n k +1 2 c x c x c x xi y i ; L + + = i k i 1 0 i =1 i i =1 i =1 i =1 L n n n n c0 xik + c1 xik +1 + L + c k xi2 k = xik y i . i =1 i =1 i =1 i =1

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

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

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 considerate. Dac datele sunt corecte din punctul de vedere al modelului atunci se afieaz i parametrii acestuia. Programul Pascal este urmtorul: program r4_4; uses math; var 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; begin 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

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); for i:=1 to n do begin readln(x,y); xnegativ:=x <= 0; ynegativ:=y <= 0; xzero:= abs(x) < eps; if not xnegativ then begin slogx:=slogx+ln(x); s2logx:=s2logx+ln(x)*ln(x) end; if not ynegativ then begin slogy:=slogy+ln(y); sxlogy:=sxlogy+x*ln(y) end; if not xzero then begin s1px:=s1px+1/x; s1px2:=s1px2+1/(x*x); sypx:=sypx+y/x end; sx:=sx+x; sy:=sy+y; sxy:=sxy+x*y; s2x:=s2x+x*x; if (x>0) and (y>0) then slogxy:=slogxy+ln(x)*ln(y); end; close(input); writeln('---------------------------------------------'); writeln; writeln(' L liniar H - hiperbolic'); writeln(' P putere E - exponential'); writeln(' A polinomial');
155

writeln; assign(input,'con'); reset(input); repeat if eoln then readln; read(c); writeln('S-a selectat ',c); until c in ['l','L','H','h','p','P','e','E','a','A']; close(input); repeat k:=1; suma:=0; if c in ['l','L'] then begin 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 } if succes then begin lusistab(2,a,b,coef) ; { rezolva sistem } assign(input,'reg.dat'); reset(input); for i:=1 to n do begin readln(x,y); suma:=suma+sqr(y-coef[1]-coef[2]*x) end; close(input) end else writeln('Erori mari in date.', 'Sistem ru condiionat'); end; if c in ['h','H'] then if xzero then writeln ('Modelul nu se aplica') else begin 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); if succes then begin lusistab(2,a,b,coef) ;
156

assign(input,'reg.dat'); reset(input); for i:=1 to n do begin readln(x,y); suma:=suma+sqr(y-coef[1]-coef[2]/x) end; close(input); end else begin suma:=-1; writeln('Erori mari in date.', 'Sistem ru conditionat'); end; end; if c in ['p','P'] then if xnegativ or ynegativ then writeln('Modelul nu se aplica') else begin 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); if succes then begin lusistab(2,a,b,coef) ; coef[1]:=exp(coef[1]); assign(input,'reg.dat'); reset(input); for i:=1 to n do begin readln(x,y); suma:=suma+sqr(y-coef[1]*exp(coef[2]*ln(x))) end; close(input); end else begin suma:=-1; writeln('Erori mari n date.', 'Sistem ru condiionat'); end; end; if c in ['e','E'] then if ynegativ then writeln('Modelul nu se aplica') else begin
157

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); if succes then begin lusistab(2,a,b,coef) ; coef[1]:=exp(coef[1]); coef[2]:=exp(coef[2]); if coef[2]<=0 then begin suma:=-1; writeln(' Erori n date ') end else begin assign(input,'reg.dat'); reset(input); for i:=1 to n do begin readln(x,y); suma:=suma+sqr(y-coef[1]*exp(x*ln(coef[2]))) end; close(input) end end else begin suma:=-1 ; writeln('Erori mari n date.', 'Sistem ru condiionat'); end; end; if c in ['a','A'] then begin write('Gradul polinomului:'); assign(input,'con'); reset(input); read(k); close(input); writeln(' ... ',k); for i:=1 to 2*k do s[i]:=0; for i:=1 to k+1 do b[i]:=0; assign(input,'reg.dat'); reset(input);
158

for i:=1 to n do begin readln(x,y); putere[1]:=1; for l:=2 to 2*k+1 do putere[l]:=putere[l-1]*x; for l:=1 to 2*k do s[l]:=s[l]+putere[l+1]; for l:=1 to k+1 do b[l]:=b[l]+putere[l]*y end; a[1,1]:=n; for i:=2 to k+1 do a[1,i]:=s[i-1]; {ncarc matricea sistemului} for j:=2 to k+1 do a[j,1]:=s[j-1]; for i:=2 to k+1 do for j:=2 to k+1 do a[i,j]:= s[i+j-2]; lustab(k+1,a,b); if succes then begin lusistab(k+1,a,b,coef); assign(input,'reg.dat'); reset(input); for i:=1 to n do begin readln(x,y); putere[1]:=1; for l:=2 to k+1 do putere[l]:=x*putere[l-1]; ss:=coef[1]; for l:=2 to k+1 do ss:=ss+coef[l]*putere[l]; suma:=suma+sqr(y-ss) end; close(input) end else begin suma:=-1; writeln('Erori mari in date. Sistem ru conditionat'); end; end; writeln; writeln('Suma patratelor erorilor',suma); writeln; if suma <> -1 then begin writeln('Parametrii modelului :'); for i:=1 to k+1 do write(coef[i]); end; writeln;
159

writeln(' L - liniar H - hiperbolic'); writeln(' P - putere E - exponential'); writeln(' A - polinomial O - Oprire'); writeln; assign(input,'con'); reset(input); if eoln then readln; read(c) ; writeln; writeln('S-a selectat ',c); close(input) until c in ['o','O'] end. R4.5. [Unitatea Math.tpu] Descriei un text surs pentru unitatea Math aetfel nct s ofere serviciile descrise n aplicaiile anterioare. Rezolvare: unit 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 . }
160

interface const maxlin=30; maxcol=30; Eps=1E-10; type matrice = array[1..maxlin,1..maxcol] of real; vector = array[1..maxcol] of real; var succes,pozdef,nenul:boolean; procedure vdif(n:integer; x,y:vector; var z:vector ); procedure prodmv(n:integer; a:matrice; x:vector; var y:vector); procedure vadd(n:integer; var x:vector; y:vector); procedure ludesc(n:integer; var a:matrice); procedure lusistem(n:integer; a:matrice; b:vector; var x:vector); procedure ludet(n:integer; a:matrice; var det:real); procedure lustab(n:integer; var a:matrice; var b:vector); procedure lusistab(n:integer; a:matrice; var b,x:vector ); procedure lltd(n:integer; var a:matrice); procedure llsistem(n:integer; a:matrice; b:vector; var x:vector); function diag_dom(n:integer;a:matrice):boolean; function norma(n:integer; x:vector):real; procedure Iacobi(n:integer;a:matrice; b:vector; niter:integer; var x:vector); procedure Seidel(n:integer;a:matrice;b:vector; niter:integer; var x:vector); implementation {--------------------------------------------------------} procedure vdif(n:integer; x,y:vector; var z:vector); var i:integer; begin for i:=1 to n do z[i]:=x[i]-y[i] end; {--------------------------------------------------------} procedure prodmv(n:integer;a:matrice;x:vector;var y:vector); var i,j:integer; begin writeln('Prodmv'); for i:=1 to n do begin y[i]:=a[i,1]*x[1]; for j:=2 to n do y[i]:=y[i]+a[i,j]*x[j]; end end;
161

{--------------------------------------------------------} procedure vadd(n:integer;var x:vector;y:vector); var i:integer; begin for i:=1 to n do x[i]:=x[i]+y[i] end; {--------------------------------------------------------} procedure ludesc(n:integer;var 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. } var i,k,j:integer;s:real; begin succes:=true; for i:=1 to n do a[i,1]:=a[i,1]/a[1,1]; i:=2; while (i <= n) and succes do begin s:=0; for k:=1 to i-1 do s:=s+a[i,k]*a[k,i]; a[i,i]:=a[i,i]-s; succes:=abs(a[i,i]) > eps; if succes then begin for j:=i+1 to n do begin s:=0; for k:=1 to i-1 do s:=s+a[i,k]*a[k,j]; a[i,j]:=a[i,j]-s end; for j:=i+1 to n do begin s:=0; for k:=1 to i-1 do s:=s+a[j,k]*a[k,i]; a[j,i]:=(a[j,i]-s)/a[i,i] end end; i:=i+1 end end; {-----------------------------------------------------}
162

procedure lusistem(n:integer; a:matrice; b:vector; var 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. } var i,j:integer; b1,y:vector; s:real; begin { Rezolvare sistem inferior triunghiular; } y[1]:=b[1]; for i:=2 to n do begin s:=0; for j:=1 to i-1 do s:=s+a[i,j]*y[j]; y[i]:=b[i]-s end; writeln; { Rezolvare sistem superior triunghiular; } x[n]:=y[n]/a[n,n]; for i:=n-1 downto 1 do begin s:=0; for j:=i+1 to n do s:=s+a[i,j]*x[j]; x[i]:=(y[i]-s)/a[i,i] end; end; {-----------------------------------------------------}
163

procedure ludet(n:integer;a:matrice; var 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. } var i:integer; p:real; begin p:=1; for i:=1 to n do p:=p*a[i,i]; det:=p end; {-----------------------------------------------------} procedure lustab(n:integer; var a:matrice; var 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. } var i,j,k:integer; s:real; procedure max(i:integer; var k:integer); var j:integer; valmax:real; begin valmax:=abs(a[i,i]); k:=i;
164

for j:=i+1 to n do if valmax < abs(a[j,i]) then begin valmax:=abs(a[j,i]); k:=j end end; {MAX} procedure perlin(i,k:integer); var s:real; j:integer; begin for j:=1 to n do begin s:=a[i,j]; a[i,j]:=a[k,j]; a[k,j]:=s end; s:=b[i]; b[i]:=b[k]; b[k]:=s end;{PERLIN} begin max(1,j); if j <> 1 then perlin(1,j); i:=2; succes:=abs(a[1,1])>eps; while (i <= n) and succes do begin max(i,j); if j <> i then perlin(i,j); a[i,1]:=a[i,1]/a[1,1]; for j:=2 to i-1 do begin s:=0; for k:=1 to j-1 do s:=s+a[i,k]*a[k,j]; a[i,j]:=(a[i,j]-s)/a[j,j] end; for j:=i to n do begin s:=0; for k:=1 to i-1 do s:=s+a[i,k]*a[k,j]; a[i,j]:=a[i,j]-s end; succes:=abs(a[i,i]) > eps ; i:=i+1 end; end; {----------------------------------------------------} procedure lusistab(n:integer; a:matrice; var b,x:vector); { Apel: LUsistab(n,a,b,x,p); Descriere parametri:
165

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. } var i,j:integer; y:vector; s:real; begin { Rezolvare sistem inferior triunghiular; } y[1]:=b[1]; for i:=2 to n do begin s:=0; for j:=1 to i-1 do s:=s+a[i,j]*y[j]; y[i]:=b[i]-s end; writeln; { Rezolvare sistem superior triunghiular; } x[n]:=y[n]/a[n,n]; for i:=n-1 downto 1 do begin s:=0; for j:=i+1 to n do s:=s+a[i,j]*x[j]; x[i]:=(y[i]-s)/a[i,i] end end; {-----------------------------------------------------} procedure lltd(n:integer; var a:matrice); { Apel: LLtd(n,a); Descrierea parametrilor: n - dimensiunea matricei; a - matrice patratica cu elemente reale. Funcia:
166

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. } var i,j,k:integer; sim:boolean; begin pozdef:= true; i:=1; while (i <= n) and pozdef do begin j:=i+1; while (j <= n) and pozdef do begin pozdef :=a[i,j]=a[j,i]; j:=j+1 end; i:=i+1; end; pozdef:= (a[1,1] > 0) and pozdef; if pozdef then begin a[1,1] :=sqrt(a[1,1]); nenul:= a[1,1] >= eps; if nenul then begin for j:=2 to n do begin a[j,1]:=a[j,1]/a[1,1]; a[1,j]:= a[j,1] end; i:=2; while (i <= n) and pozdef and nenul do begin for k:=1 to i-1 do a[i,i]:=a[i,i]-sqr(a[i,k]); pozdef:=a[i,i] > 0; if pozdef then begin a[i,i]:=sqrt(a[i,i]); nenul := a[i,i] >= eps; if nenul then for j:=i+1 to n do begin for k:=1 to i-1 do 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] end end; i:=i+1 end end end end;
167

{-----------------------------------------------------} procedure llsistem(n:integer;a:matrice; b:vector; var x:vector); { Apel: LLsistem(n,a,b,x); Descrierea parametrilor: n - dimensiunea sistemului; a - matricea ce conine descompunerea LLT b - termenul liber; x - soluia sistemului. Funcia: Rezolv dou sisteme triunghiulare conform celor prezentate la problema R4.2. } var i,j,k:integer; y:vector; begin y[1]:=b[1]/a[1,1]; for i:=2 to n do begin y[i]:=b[i]; for k:=1 to i-1 do y[i]:=y[i]-a[i,k]*y[k]; y[i]:=y[i]/a[i,i] end; x[n]:=y[n]/a[n,n]; for i:=n-1 downto 1 do begin x[i]:=y[i]; for j:=i+1 to n do x[i]:=x[i]-a[i,j]*x[j]; x[i]:=x[i]/a[i,i] end; end; {-----------------------------------------------------} function 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 } var i,j:integer; v:boolean; s:real;
168

begin v:=true; i:=1; while (i <= n) and v do begin s:=0; for j:=1 to n do if j <> i then s:=s + abs(a[i,j]); if s >= abs (a[i,i]) then v:=false else i:=i+1; end; diag_dom:=v end; {-----------------------------------------------------} function norma(n:integer; x:vector):real; { Apel : norma(n,x) Descrierea parametrilor: n - dimensiunea vectorului; x - vector cu n componente. Functia: Calculeaza norma uniform. } var v, p:real; i:integer; begin v:=abs(x[1]); for i:=2 to n do begin p:=abs(x[i]); if v < p then v:=p end; norma:=v end; {-----------------------------------------------------} procedure Iacobi(n:integer; a:matrice; b:vector; niter:integer; var 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. } var i,j,k:integer; y,e:vector; s:real;
169

begin for i:=1 to n do y[i]:=x[i]; k:=1; while ( k<= niter) or (norma(n,e) > eps) do begin for i:=1 to n do begin s:=0; for j:=1 to n do if j <> i then s :=s+a[i,j]*y[j]; x[i]:=(b[i]-s)/a[i,i] end; vdif(n,x,y,e); for i:=1 to n do y[i]:=x[i]; k:=k+1 end end; {-----------------------------------------------------} procedure Seidel(n:integer; a:matrice; b:vector; niter:integer;var 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. } var y,e:vector;i,j,k:integer; begin for i:=1 to n do y[i]:=x[i]; k:=1; while (k <= niter) or (norma(n,e) > eps) do begin for i:=1 to n do begin x[i]:=b[i]; for j:=1 to n do if i <> j then x[i]:=x[i]-a[i,j]*x[j]; x[i]:=x[i]/a[i,i]; end; vdif(n,x,y,e); for i:=1 to n do y[i]:=x[i]; k:=k+1 end end; begin Writeln; Writeln('Unitul Math - GA2003'); Writeln end.
170

4.3. Probleme propuse 1. O bibliotec de grafic bidimensional, trebuie s ofere programatorului 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 Desenare.tpu care s utilizeze unitatea graph i care s ofere ct mai multe din facilitile anunate mai sus. 2. Se consider declaraiile: unit MatProg10; interface const max_lin=10; max_col=10; type matrice= array[1..max_lin,1..max_col] of real; vector_linie= array[1..max_col] of real; vector_coloana=array[1..max_lin] of real; procedure copy_lin_vector (a:matrice; i:integer; var x:vector_linie); procedure copy_col_vector (a:matrice; i:integer; var x:vector_coloana); procedure copy_diag_vector(a:matrice; var x:vector_coloana); procedure add_number(var a:matrice; x:real); procedure subtract_number(var a:matrice; x:real); procedure divide_by_number(var a:matrice; x:real); procedure replace_diag_vector(var a:matrice; x:vector_coloana); procedure mul_linie_add(var a:matrice; i:integer; x:real; j:integer); procedure mul_col_add(var a:matrice; i:integer; x:real; j:integer); procedure interschimba_lin(var a:matrice; i,j:integer); procedure interschimba_col(var a:matrice; i,j:integer); procedure sum_lin_vector(a:matrice; var x:vector_coloana); procedure sum_col_vector(a:matrice; var x:vector_linie); procedure generare(var a:matrice); procedure tiparire(a:matrice); a) S se implementeze unitatea conform urmtoarelor specificaii:
171

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 implementate operaii precum: adunare, scdere, mprire ntreag, determinarea restului mpririi a dou numere ntregi, calculul rdcinii ptrate.
172

5. Introducere n programarea orientat obiect folosind limbajul C++


5.1. Fundamente La prima vedere orice program poate fi perceput ca o colecie de date i de operaii care se execut asupra datelor. n programarea procedural 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 reutilizarea 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 programului. 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 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
173

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 analiza, proiectarea i implementarea programelor complexe. n C++ instrumentul de baz pentru abstractizare este clasa. ncapsularea ncapsularea este conceptul complementar abstractizrii. Dac rezultatul operaiei de abstractizare pentru un anumit obiect este identificarea interfeei, atunci ncapsularea trebuie s defineasc reprezentarea (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 implementrii fa de exterior. Separarea interfeei de reprezentarea unui obiect i de implementarea metodelor sale permite modificarea structurii obiectului i a metodelor fr a afecta n nici un fel programul care folosete obiectul, ntruct acesta depinde doar de interfa. ncapsularea permite modificarea programelor ntr-o manier eficient, cu un efort limitat i bine localizat. Modularizarea 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
174

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 directivele "#include". Referitor la modularizare, cititorul poate observa asemnri i deosebiri ale modularizrii la nivelul C, C++, n raport cu modularizarea permis de implementarea Borland a limbajului Pascal. Motenirea Nu de puine ori, scriind programe n maniera clasic, eram pui n situaia de a adapta sau rescrie funcii scrise anterior. Aceast etap de implementare consuma mai mult timp dect era necesar i, n plus, exista riscul apariiei a numeroase erori. O variant mult mbuntit de reutilizare a codului este motenirea. Motenirea este unul dintre cele mai importante concepte ale limbajelor de programare pe obiecte. Aceasta permite extinderea obiectelor existente i construirea de noi obiecte ntr-un mod simplu. Astfel, o clas poate moteni toate caracteristicile uneia sau a mai multor clase create anterior la care poate aduga trsturi noi i, n anumite condiii, poate redefini unele din metodele motenite. Polimorfismul Polimorfismul este o facilitate a programrii orientate obiect care ofer instanelor unor clase posibilitatea de a reaciona ntr-un mod specific la un mesaj (la un apel de funcie). Spre exemplu, ntr-o ierarhie de clase obinut prin motenire, care reprezint forme geometrice (puncte, linii, dreptunghiuri, cercuri) fiecare obiect are o funcie Draw(). Apelul acestei funcii avnd o referin la un obiect grafic generic trebuie s se comporte corespunztor obiectului referit. Clasele Conceptul fundamental din programarea orientat pe obiecte l reprezint noiunea de clas ca tip de date definit de utilizator. Cuvntul cheie class ne permite s intrm n universul programrii orientate pe obiecte, cu ajutorul lui putem defini tipuri abstracte de date. Variabilele declarate pe baza unui tip abstract se numesc obiecte. Putem spune c: Clasa = Date + Operaii. Spre deosebire de structurile cunoscute din limbajul C, clasele conin nu numai date membre ci i funcii membre, constructori i cel mult un destructor. n general o clas se definete astfel:
175

class nume{ private: <date membre private> <constructori privati> <metode private> protected: <date membre protejate> <constructori protejati> <metode protejate> public: <date membre publice> <constructori publici> <destructor public> <metode publice> }; Pentru exemplificare vom defini o serie de clase pentru reprezentarea figurilor geometrice n plan. Se tie c figurile geometrice se contruiesc pornind de la unele forme simple cum sunt punctul, linia, etc. Urmeaz un exemplu de declaraie de clas care introduce un tip nou de date numit Punct. Urmtoarea declaraie se va scrie ntr-un fiier header cu un numele Point.h. class Point { protected: int x, y; //date membre public: Point(); //constructor Point(int, int); //consructor ~Point(); //destructor void Print(); //funcie membra void Read(); //funcie membra }; Operaii cu fluxuri standard n limbajul C toate operaiile de intrare-ieire se realizeaz prin utilizarea funciilor din biblioteca standard stdio. C++ vine cu o nou bibliotec de I/O numit iostream. Biblioteca nu conine o colecie de funcii ci o colecie de obiecte care permit accesul la ecran pentru afiare i la tastatur pentru citirea datelor introduse de utilizator. Aceste obiecte au definite cte o metod pentru lucrul cu fiecare tip de date simple (int, long, float, double, char), eliminnd astfel
176

necesitatea precizrii tipului i a formatului datelor care urmeaz a fi scrise sau citite. Cnd un program C++ care include headerul iostream.h este lansat n execuie, atunci sunt create i iniializate automat urmtoarele patru obiecte: cin gestioneaz intrarea standard (tastatura); cout gestioneaz ieirea standard (ecranul); cerr gestioneaz ieirea ctre dispozitivul standard de eroare (ecranul), neutiliznd bufere; clog gestioneaz ieirea ctre dispozitivul standard de eroare (ecranul), utiliznd bufere. Cnd este vorba se operaii de intrare/ieire trebuie s avem n vedere o surs emitent a unui flux de date i o destinaie care recepioneaz aceste date. n afar de aceastea avem nevoie i de un mijloc de comunicare ntre surs i destinaie. Aici intervin operatorii. S vedem, n continuare, cum se face afiarea i citirea tipurilor de date standard n limbajul C++ folosind obiectele de mai sus. n limbajul C Int x = 33; float f = 1.5; Printf("x = %d f = %f", x, f); Printf("\n"); Printf("%c", 'C'); Printf("%s", "Limbajul C\n"); Int x; scanf("%d", &x); Float f; scanf("%f" &f); Char ch; scanf("%c", &ch); Char sir[25]; scanf("%s", sir); n limbajul C++ int x = 33; float f = 1.5; cout << "x=" << x <<"f ="<<f ; cout << endl; cout << 'C'; cout<<"Limbajul C++"<< endl; int x; cin >> x; float f; cin >> f; char ch; cin >> ch; char sir[25]; cin >> sir;

Din tabelul de mai sus reiese c cout ine locul lui stdout, cin nlocuiete stdin i operatorii << i >> a fost redefiniti n scopul introducerii/extragerii datelor. Se observ c nu mai este necesar precizarea tipului i formatului datelor deoarece operatorii care lucreaz cu fluxuri sunt capabili s depisteze tipul fiecrei variabile transferate. Mai mult, orientarea operatorului ne indic sensul n care are loc transferul datelor.
177

Formatarea datelor n C++ n exemplul de mai sus afiarea s-a produs utiliznd de fiecare dat un format implicit. Exist posibilitatea modificrii formatului implicit prin precizarea alinierii, umplerii, a dimensiunii spaiului ocupat, a bazei de numeraie i a preciziei. O baz de numeraie odat stabilit se menine pn cnd se face o nou precizare n acest sens. Instruciunile urmtoare: #include<iostream.h> #include<iomanip.h> void main(){ cout<<setw(8)<<setfill('*')<<12345<<endl; cout<<setw(8)<<setprecision(3)<<6.0231<<endl; cout<<setw(8)<<setfill('0')<<oct<<12345<<endl; cout<<setw(8)<<setfill('0')<<dec<<123456<<endl; cout<<setw(8)<<hex<<123456<<endl; } produc urmtorul rezultat: ***12345 6.023 00030071 00123456 0001e240 Modificatori de access ncapsularea nu presupune numai simpla combinare a metodelor i a datelor ca o singur entitate ci i o posibilitate de a limita accesul la datele i metodele membre unei clase mai ales n situaii n care se dorete prevenirea modificrii accidentale a datelor aparinnd unui obiect. n cadrul declarrii unei clase, prin folosirea unor modificatori de acces, se poate preciza unul din cele trei niveluri de acces la datele i metodele clasei, astfel: private este modul implicit, membrii de acest tip sunt accesibili numai metodelor membre i a funciilor de tip friend, aceste elemente sunt considerate proprii, intime clasei n care au fost declarate i nu vor fi accesibile n clasele derivate; protected este similar modului private, n plus membrii sunt accesibili i n metodele claselor derivate (n cazul motenirii publice), acest modificator este recomandat s se foloseasc n clasele ce urmeaz s fie extinse;
178

public toate atributele i metodele publice pot fi accesate sau apelate din orice punct din program exterior clasei, unde este cunoscut clasa. Trebuie s reinem c limbajul C++ nu impune o anumit ordine de folosire a acestor modificatori, iar atributele i metodele fr modificator de acces sunt considerate private. Seciunile unei clase pot aprea de mai multe ori n cadrul declaraiei unei clase. n cele mai multe situaii datele membre se vor plasa n seciunile protejate pentru a permite accesul acestora din cadrul claselor derivate. De asemenea se recomand evitarea plasrii datelor n seciunea public. Se recomand folosirea funciilor membre pentru iniializarea i prelucrarea datelor membre. Clasele pot avea mai muli constructori (de obicei publici) i cel mult un destructor public. n cazul nostru metodele care urmeaz imediat dup cuvntul public sunt publice, cu alte cuvinte acestea pot fi accesate din exterior oriunde n program unde clasa Point este accesibil. Cu alte cuvinte domeniul de vizibilitate al atributelor i metodelor este acelai cu domeniul de vizibilitate al clasei. Declararea funciilor membre 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(int x0, int y0){x=x0; y=y0;} Point::~Point(){ } void Point::Print(){ cout<<Point: <<" x = "<< x; cout<<" y = "<<y<<endl; } void Point::Read(){ cout<<"x = "; cin >> x; cout<<"y = "; cin >> y; }
179

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 this. 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 observa 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 inline. Astfel de funcii se pot defini i n afara clasei, dar n acest caz la declaraie trebuie precedate de cuvntul cheie inline. class Point{ int x,y; public: int getX(){ return x;} int getY(){ return y;} inline void Set(int, int); inline float Area(); }; void Point::Set(int x, int y){ this->x=x; this->y=y; } float Point::Area(){return 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 inline. 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
180

cunoasc forma i coninutul exact al funciei n momentul compilrii. Acest lucru nu este valabil pentru funciile care conin bucle iterative. Membrii statici 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 implementat clasa niciodat n headerul clasei i nu va fi precedat de cuvntul cheie static; 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: class Mouse{ public: static int xPos, yPos; Mouse(){}; void SetPos(int x, int y){ xPos = x; yPos = y; } };
181

Mouse::xPos = 0; Mouse::yPos = 0; void main(){ Mouse m; m.SetPos(10,15); cout<<Mouse::xPos<<" "<< Mouse::yPos<<endl; } Funcii membre statice Funciile membre statice se declar la fel ca membrii statici prin plasarea cuvntului cheie static n faa declaraiei funciei. Accesul la o metod static se realizeaz n mod identic cu cel la un membru static. Adic putem apela o metod static a oricrui obiect, dar o putem apela i far s avem un obiect declarat, folosind n acest caz numele clasei umat de operatorul "::". Funciile membre statice se deosebesc de cele nestatice prin faptul c nu posed pointerul this. Ca urmare, nu poate ntoarce pointerul this sau obiectul *this i nu va putea accesa n mod direct dect alte elemente (date i funcii) statice ale clasei. Deci o funcie static nu poate s apeleze o funcie membr nestatic i nu poate citi sau modifica datele nestatice ale clasei din care face parte (dect dac i se transfer ca parametru un obiect sau o referin/pointer la acesta). class Cursor{ static int xo, yo; //originea int x, y; public: Cursor(int x1, int y1) {x = x1, y = y1;} static void SetOrigin(int x1, int y1) { xo = x1, yo = y1; } void GetPos(int & xp, int &yp) { xp = xo + x; y = yo + y; } };//Sfrit Cursor Cursor::xo = 0; Cursor::yo = 0; void main(){ Cursor::SetOrigin(10,10); Cursor c(5,2); int x,y; c.GetPos(x,y); cout<<" x = "<<x<<" y = "<<y<<endl; }
182

Constructorii n limbajul C++ constructorii sunt funcii membre speciale care asigur crearea i distrugerea corect a obiectelor. Constructorul unei clase este prima metod care este apelat la declararea unui obiect, imediat dup alocarea memoriei necesare datelor membre. Constructorul este apelat imediat ce o variabil intr n domeniul ei de vizibilitate, adic atunci cnd execuia unui program "atinge" instruciunea n care aceasta este declarat. Un constructor poate indeplini o mare varietate de sarcini, ca de exemplu iniializarea variabilelor interne, alocri dinamice de memorie, deschidere de fiiere, etc. Avem urmtoarele reguli privind constructorii: numele unui constructor trebuie s fie identic cu numele clasei; constructorii nu returneaz nimic, nici mcar tipul void; constructorul poate apela alte funcii membre sau nu; constructorul nu poate fi virtual; constructorul, ca orice alt metod poate fi suprancrcat, pot s existe, deci, mai muli constructori ntr-o clas, avnd acelai nume cu numele clasei, dar deosebindu-se prin lista de parametrii formali; o clas poate avea orici constructori, inclusiv nici unul, dac nu s-a declarat nici un constructor compilatorul genereaz un constructor implicit, public, fr parametrii; constructorul implicit, folosit fr parametrii la iniializarea obiectelor, dac este definit, trebuie s fie definit fr parametrii sau s foloseasc valori prestabilite ale parametrilor formali; n mod normal constructorii sunt declarai ca fiind publici, n cazuri speciale acetia pot fi declarai private i nu vor putea fi apelai dect din cadrul altor funcii membre sau de tip friend, clasele din aceast categorie se numesc clase private; dac o clas conine date membre constante sau referine la obiecte, atunci constructorul trebuie scris n aa fel nct s iniializeze referinele naintea celorlalte date membre; constructorul de copiere iniializeaz un obiect printr-o operaie de copiere a datelor dintr-un obiect existent, avnd o referin la acesta; dac n cadrul unei clase nu este declarat un constructor de copiere, compilatorul creaz unul implicit; se recomand definirea unui constructor de copiere n special cnd se lucreaz cu clase care manevreaz structuri de date dinamice, aceti constructori realizeaz o copie profund a obiectelor, care
183

implic i datele alocate dinamic, n timp ce constructorul de copiere introdus de compilator realizeaz o copie superficial a obiectelor, copiind doar datele membre ale claselor bit cu bit. Exemplu: #include "Point.h" #define pi 3.14159265 class Circle{ public: Circle(){radius = 0;} Circle(int r){radius = r;} Circle(int x, int y, int r){ Set(x,y,r);} Circle(Circle&); float Area(){return pi * radius * radius;} protected: Point center; int radius; public: void Read(); void Print(); void Set(int, int, int); }; Circle::Circle(Circle &a){ center = a.center; radius = a.radius;} void Circle::Set(int x, int y, int r){ center.Set(x,y); radius = r;} void Circle::Read(){center.Read(); cout<<"Raza = "; cin >> radius;} void Circle::Print(){cout<<Circle:<<end;center.Print(); cout<<"Radius = "<<radius<<endl;} Destructorul Destructorul este entitatea care dezactiveaz toate funciile unui obiect nainte de eliberarea memoriei ocupate de acesta. Destructorii ca i constructorii pot efectua orice fel de operaii, dar de obicei sunt utilizai n clase care manevreaz structuri de date alocate dinamic sau care opereaz cu fiiere sau cu fluxuri de comunicaie. Destructorul este apelat ori de cte ori se "atinge" punctul final al domeniului de vizibilitate al unei variabile, ca de exemplu: ntoarcerea dintr-o funcie, terminarea unei bucle (pentru variabilele automatice declarate n interiorul unei bucle, etc). Perioada dintre momentul crerii unei variabile i momentul distrugerii sale se numete "durat de via". Trebuie respectate urmtoarele reguli de folosire a destructorilor: numele destructorului trebuie s fie identic cu cel al clasei care l conine i trebuie s fie precedat de caracterul tilda "~"; destructorul nu returneaz nici un tip de date, nici mcar void;
184

destructorul nu poate avea parametrii; o clas nu poate avea mai mult de un destructor, dac pentru o clas nu este precizat nici un destructor atunci compilatorul creaz un destructor pentru clasa respectiv; dac un obiect conine ca date membre alte obiecte atunci destructorii obiectelor membre sunt apelai dup ce destructorul clasei a fost executat, ordinea n care sunt distruse componentele este invers fa de cea n care au fost create (ordinea din declaraia clasei); n timpul execuiei programului este apelat automat destructorul obiectelor a cror durat de viaa a expirat. Astfel, durata de via a obiectelor este: obiectele automatice: sunt locale unei funcii i de aceea sunt pstrate (create i utlizate) pe stiv, acestea exist atta timp ct "exist" funcia, se creaz n prologul funciei i se distrug n epilogul acesteia de ctre destructor; obiectele statice: sunt declarate n afara funciilor sau n interiorul funciilor cu ajutorul cuvntului cheie static, acestea sunt create la nceputul programului i exist pe ntreaga durat de execuie a programului, la terminarea programului se apeleaz destructorul fiecrui obiect static; obiecte dinamice: sunt utilizate prin alocare de locaii din heap o zona de memorie special - sunt create cu operatorul new i sunt eliberate explicit cu operatorul delete, pot exista i dup terminarea funciei n care au fost create cu operatorul new, nu sunt eliberate automat; obiecte membre ale altor obiecte sunt create/distruse atunci cnd obiectul cruia i aparin este creat/distrus. Declaraii de obiecte. Instanieri n limbajele de programare un loc central l ocup conceptul de tip de date. Fiecare variabil care este prelucrat ntr-un program este de un "anumit tip" predefinit sau definit de programator. n limbajele de programare orientate obiect tipurile de date definite de programator, sau tipurile abstracte sunt mai importante. Declararea unei variabile de un anumit tip abstract se numete instaniere, iar variabilele se numesc obiecte sau instane ale clasei. Sintaxa este asemnatoare cu cea a declaraiilor de variabile.

185

#include "Point.h" #include "Circle.h" void main(){ Point A, B(1,2); Point C = Point(3,3); A.Set(10,5); A.Print(); A = C; A.Print(); Circle C1,C2(10); Circle C3 = Circle(10,10,10); Circle C4(C3), C5 = C4; C1.Read(); C1.Print(); C5.Print(); } Deoarece declaraia lui C1 nu specific nici un argument compilatorul apeleaz constructorul fr parametrii, C2 se va iniializa cu ajutorul constructorului cu doi parametrii, instana C4 va fi o copie lui C3 (primit ca argument), deci pentru C4 se va utiliza constructorul de copiere. O alt metod de iniializare folosete listele de instaniere. Lista membrilor clasei ce urmeaz a fi iniilizai se plaseaz ntre lista de parametrii a costructorului i corpul acestuia. Lista este format din constructori cu parametrii specifici, cte unul pentru fiecare membru ce trebuie iniializat n acest mod. Aceast metod este singura care se poate folosi la iniializarea clasei ce conine date membre constante, referine la obiecte sau obiecte fr constructor implicit public. Un aspect important legat de listele de instaniere este ordinea n care se face iniializarea n cadrul acesteia, mai ales dac la iniializarea unor membrii se folosesc valorile altora. Ordinea de instaniere a datelor membre este dat ntotdeauna de ordinea n care datele apar n declaraia clasei i nu de ordinea acestora n lista de instaniere. Dac un obiect membru conine n declaraia clasei sale constructor implicit atunci acest obiect poate lipsi din lista de instaniere. n cazul n care un membru al unei clase este un pointer la un obiect atunci nu putem iniializa pointerul n cadrul listei de instaniere, constructorii nu pot fi apelai pentru pointeri la obiecte (n aceast list) ci numai pentru obiecte i referine.

186

#include "Point.h" class Rectangle{ protected: Point A, B; public: Rectangle(){ } Rectangle(int x1,int y1,int x2,int y2): A(x1,y1),B(x2,y2){ } Rectangle(Point &a, Point &b ):A(a), B(b){ } Rectangle(Rectangle & r):A(r.A), B(r.B){ } int Area(){return (B.x-A.x)*(B.y-A.y);}; }; Aa cum construim tablouri sau matrici de structuri n limbajul C, tot aa putem construi tablouri sau masive de obiecte. Iat, de exemplu, cum putem defini un triunghi: Point triunghi[3] ; Pentru fiecare element al tabloului se va apela constructorul implicit. Triunghiul poate fi iniializat aa cum se iniializeaz tablourile de structuri dac obiectele componente conin doar membrii publici, nu conin metode virtuale i nu provin din clase derivate. Point triunghi[3] = {{0,0},{0,3},{4,0}}; Un alt mod de iniializare a tabloului poate folosi lista de constructori ntr-un mod asemntor cu utilizarea listei de instaniere, iniializarea tabloului poate fi parial deoarece pentru restul elementelor se apeleaz constructorul implicit: Point triunghi[10] = {Point(), Point(0,3), Point(4,0)}; Operatorii new i delete Pentru alocarea i eliberarea dinamic a memoriei n limbajul C avem la dispoziie funciile malloc i free. Limbajul C++ introduce doi operatori noi pentru a facilita operaiile cu memoria alocat dinamic n contextul programrii orientate obiect. Aceti operatori sunt new pentru alocarea memoriei i delete pentru eliberarea acesteia. Avantajele folosirii operatorului new n comparaie cu utilizarea funciei malloc sunt: operatorul new tie ce cantitate de memorie trebuie alocat pentru orice tip de date, n timp ce funciei malloc trebuie s i se specifice aceast dimensiune;

187

tipul pointerul returnat de operatorul new este acelai cu tipul pointerului care va memora adresa zonei de memorie alocate de operator, nu este nevoie de nici un fel de conversie; operatorul new poate apela un constructor sau poate iniializa variabila standard alocat, spre deosebire de malloc care nu are aceast proprietate; funcia malloc ntoarce un pointer la void ceea ce ne oblig s facem o conversie la tipul ateptat; operatorul new poate fi utilizat n manevrarea de masive. Varianta C: int *p = (int *) malloc(sizeof(int)); int *m = (int *) malloc(1000* sizeof(int)); Varianta C++: int *p = new int; int *m = new int[1000] ; int *pzero=new int(20);//aloc un int i l iniializeaz cu 20 char *ch=new char('A');//aloc un char i l iniializeaz cu A Operatorul new a fost special introdus pentru construirea dinamic a obiectelor, astfel urmtoarea declaraie aloc memorie n heap pentru a stoca un obiect din clasa Point i apoi apeleaz constructorul cu doi parametrii pentru iniializarea obiectului. Point *pPoint = new Point(10,10); n mod asemntor se poate aloca i iniializa un tablou de obiecte, n acest caz se va apela constructorul implicit (fr parametrii) pentru fiecare obiect din tablou; Point * t = new Point[1000]; Operatorul delete este similar cu funcia free din limbajul C, avnd ca scop eliberarea memoriei din heap alocate cu ajutorul operatorului new. Operatorul new apeleaz un constructor pentru iniializarea memoriei alocate, n mod similar operatorul delete apeleaz destructorul imediat naintea eliberrii memoriei ocupate de un obiect. Atenie, pentru eliberarea de masive acest operator are o sintax diferit. Astfel, dac alocm un tablou prin char *sir = new char[80]; atunci delete sir; nu va elibera ntregul ir ci doar primul octet sir[0]. Pentru a elibera tot tabloul va trebui s scriem delete [] ir.
188

Exemplu: #include <iostream.h> #include <stdlib.h> class String{ char *data; int len; void Init(char * str){ len = strlen(str); data = new char[len+1]; strcpy(data,str); } public: String(){data = NULL; len = 0;} String(String & str){Init(str.data);} String(char *str) {Init(str);} ~String(){ //destructor if (data) { cout<<"Destructor: "<<data<<endl; delete[] data; } } void Concat(String &str){ Concat(str.data); } void Concat(char *str){ int len2 = strlen(str); data = (char *)realloc(data, len + len2 +1); data[len]=0; strcat(data,str); len += len2; } void Print(){ if (data) cout<<data<<endl; } }; void main(){ String s1 = String("Clasa String in "); s1.Concat("programarea OOP cu "); String s2("Limbajul C++ "); s1.Concat(s2); s1.Print(); //alocare dinamica String *s = new String(); s->Concat(s4);
189

s->Concat("cu alocare dinamica!"); s->Print(); delete s; //alocarea unui tablou de obiecte String *stab = new String[10]; stab[0].Concat(s2); stab[0].Print(); //eliberarea tabloului de obiecte delete [] stab; //alocarea unui tablou de pointeri la obiecte String* *ptab = new String*[10]; //alocarea fiecarui obiect din tablou for (int i=0;i<10;i++) ptab[i] = new String("Sir de caractere!"); //afisarea sirurilor for (int i=0;i<10;i++) if(ptab[i]) ptab[i]->Print(); //eliberarea sirurilor for (int i=0;i<10;i++) if(ptab[i]) delete ptab[i]; //eliberarea tabloului de pointeri delete [] ptab;

Funcii i clase prietene Datele private i protejate membre ale unei clase poat fi accesate doar de funciile membre ale clasei respective. Exist cazuri cnd dorim s permitem accesul la datele membre (private i protejate) i altor funcii, care pot fi membre ale altor clase sau nu. Acste funcii se numesc funcii prietene (sau de tip friend). Declararea unor funcii prietene se face n interiorul clasei i este precedat de cuvntul cheie friend. Definiia funciei se face n exteriorul clasei i nu trebuie s fie precedat de friend i nici de numele clasei creia i este prieten, este o funcie obinuit. Singura diferen dintre funciile membre i cele prietene este aceea c acestea din urm nu pot ntoarce o referin la clasa prieten. Funciile prietene pot facilita implementarea unor operaii care sunt dificil sau imposibil de ndeplinit prin intermediul funciilor membre. Un alt tip se funcii prietene sunt funciile membre ale altor clase, crendu-se astfel o punte de legtur ntre clase. Exist dou moduri de a preciza acest lucru. Prima variant const n precizarea funciei membru ca fiind de tip friend mpreun cu numele clasei din care face parte, iar a dou variant const n declararea unei clase ca fiind prieten, ceea ce spune c toate datele protejate pot fi accesate i
190

modificate de toate funciile membre ale clasei prietene. n ambele variante una dintre clase trebuie s fie predeclarat. Exemplu: #include <iostream.h> class Complex; class Scalar{ float nr; public: Scalar(){nr = 0.0;} Scalar(float s){nr = s;} friend class Complex; }; class Complex{ float re, im; public: Complex(){ re = im = 0.0;} Complex(float r, float i){ re = r, im = i;} Complex(Complex & c){ re = c.re, im = c.im;} Complex Add(Scalar & s); Complex Mul(Scalar & s); friend Complex Add(Complex& c1, Complex & c2); friend Complex Mul(Complex& c1, Complex & c2); friend void Print(Complex & c); }; void Print(Complex &c){ cout<<c.re; if (c.im > 0) cout << "+"<<c.im<<"i"<<endl; else if (c.im < 0) cout << c.im<<"i"<<endl; } Complex Add(Complex& c1, Complex & c2){ Complex rez; rez.re = c1.re + c2.re; rez.im = c1.im + c2.im; return rez; }
191

Complex Mul(Complex& c1, Complex & c2){ Complex rez; rez.re = c1.re * c2.re - c1.im*c2.im; rez.im = c1.re*c2.im + c1.im*c2.re; return rez; } Complex Complex::Add(Scalar & s){ return Complex(re+s.nr, im); } Complex Complex::Mul(Scalar & s){ return Complex(re * s.nr, im * s.nr); } void main(){ Complex c1(1,-1); Print(c1); Complex c2(c1), c3; c3 = Add(c1,c2); Print(c3); c3 = Mul(c1,c2); Print(c3); Scalar sc(1.3); c3 = c1.Add(sc); Print(c3); c3 = c1.Mul(sc); Print(c3); } Motenirea Motenirea este unul dintre cele mai importante concepte ale limbajelor de programare pe obiecte. Acesta permite extinderea claselor existente i aduce posibilitatea construirii de noi clase ntr-un mod simplu. Motenirea permite transferul atributelor i a metodelor unei clase construite anterior, numit clas de baz, ctre o nou clas numit clas derivat. Deci clasele derivate au toate caracteristicile claselor de baz i, n plus, pot introduce noi elemente structurale i funcionale. Motenirea n limbajul C++ este de dou feluri: a) motenire simpl prin care o clas extinde o singur clas de baz; b) motenire multipl prin motenire multipl trsturile a dou sau mai multe clase pot fi nglobate i eventual exinse ntr-o clas nou. La prima vedere motenirea se aseamn cu procesul de includere a obiectelor n obiecte (refolosire), dar difer de acesta prin urmtoarele: codul poate fi comun mai multor clase; clasele pot fi extinse fr a fi recompilate (extensibilitate); funciile care prelucreaz obiecte din clasa de baz vor prelucra automat i obiecte din clasa derivat (abstractizare);
192

sintaxa folosit la derivare este urmtoarea: class clasaDerivata:[tipMostenire]clasaBaza { //noi membrii }; unde tipMostenire este un modificator opional i poate fi unul din urmtoarele: public, protected, private (implicit) sau virtual. Exemplu de motenire simpl public: #define pi 3.14159265 class Circle :public Point{ protected: int radius; public: Circle() { radius = 0;} Circle(int r){ radius = r;} Circle(int x,int y,int r):Point(x,y){radius=r;} Circle::Circle(Circle &c){ Set(c.x,c.y,c.radius); } float Area (){ return 2* pi* radius * radius; } void Circle::Set(int x, int y, int r){ //Point::trebuie precizat //altfel incearc s se autoapeleze //i se genereaza eroare: nr de parametrii Point::Set(x,y); radius = r; } void Print(){ cout<<"Circle: "<<endl; Point::Print(); cout<<"radius = "<<radius<<endl; } }; //Clasa Circle class Cylinder: public Circle{ protected: int height; public: Cylinder(){ height =0;} Cylinder(int r, int h):Circle(r){ height = h;}
193

Cylinder(int x, int y, int r, int h): Circle(x,y,r){ height = h;} Cylinder(Cylinder& c){ //mostenita de la Circle Set(c.x, c.y,c.radius); height=c.height; } //aria laterala float LArea(){ return 2*pi*radius*height; } //aria totala float Area(){ return 2*Circle::Area()+LArea(); } void Print(){ cout<<"Cylinder:"<<endl; Circle::Print(); cout<<"height = "<<height<<endl ; } }; void main(){ Point p; Circle c; Cylinder cy(1,1,10,10); p = c = cy; cy.Print();c.Print(); p.Print(); cout<< "Aria cilindrului = "<<cy.Area()<< endl; cout<< "Aria cercului = "<<c.Area()<< endl; } n exemplu de mai sus se poate observa cum se poate extinde o clas de baz construind clase derivate n vederea obinerii unor obiecte noi cu funcionaliti sporite, cum elementele membre ale clasei de baz devin date membre ale clasei derivate, se mai observ modul n care se reutilizeaz (atenie la sintaxa unui apel de funcie motenit) codul unor funcii preexistente fr s mai fie nevoie de recompilarea acestora. Din acest exemplu se mai poate desprinde un aspect foarte interesant: obiectele claselor derivate sunt privite ca fiind obiecte ale clasei de baz, ceea ce ne permite s atribuim obiectelor din clasa de baz instane ale clasei derivate fr s fie necesar conversia de tip. Aceast regul este valabil doar la obiectele care sunt legate prin
194

relaia de motenire i se extinde i asupra pointerilor i referinelor la astfel de obiecte. Atribuirea este posibil doar n acest sens, o ncercare de a atribui unui obiect din clasa derivat o instan a clasei de baz fiind ilegal. Exemplu: Point p; Circle c; Cylinder cy; Point & pr = p; Circle & cr = c; Cylinder & cyr=cy; pr = cr = cyr; Point * pp; Circle * pc; Cylinder *pcy = new Cylinder(10,25); pp = pc = pcy; Ce rezultat va produce codul urmror ? Circle * c1 = new Cylinder(10,25); c1->Print(); cout<<"Aria = "<< c1->Area()<<endl; n exemplul de mai sus am discutat motenirea de tip public, n acest caz datele publice/protejate n clasa de baz ramn publice/protejate i n clasa derivat, cele private (intime clasei de baz) sunt inaccesibile direct, aceste putnd fi manipulate cu ajutorul funciilor de acces. Mai trebuie menionat faptul c la inializarea obiectelor nti sunt apelai constructorii claselor de baz dup care se execut corpul constructorului clasei derivate. Constructorii nu pot fi motenii, deci nu putem folosi un constructor al clasei de baz pentru a iniializa toi membrii clasei derivate. n plus, dac toi constructorii clasei de baz necesit parametrii atunci clasa derivat trebuie s conin un constructor care s apeleze (n lista de instaniere) unul din constructorii clasei de baz cu parametrii potrivii. Deci, prezena constructorilor n clasele derivate devine, n unele cazuri, obligatorie. Destructorii claselor de baz sunt apelai n ordine invers fa de ordinea de iniializare, nti destructorul clasei derivate apoi destructorii claselor derivate. Destructorul fiind funcie fr parametrii, prezena acestuia n clasele derivate este opional. n continuare urmeaz un tabel n care se poate observa modul n care se motenesc datele, pe cele trei niveluri de protecie i prin cele trei tipuri de moteniri mai importante.
195

Public n clasa de baz Public Protected Private public n clasa derivat Protected n clasa derivata ascuns n clasa derivat

Tipul motenirii Protected protected n clasa derivat protected n clasa derivat ascuns n clasa derivat

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

Polimorfism i funcii virtuale 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 static 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
196

nume de metod i dou posibiliti, dou forme ale funciei. n acest moment discutm de polimorfism. 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 dinamic. 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 virtual n faa declaraiei funciei membre Area(). class Point{ virtual float Area(){ } }; Prin aceasta anunm compilatorul s nu aleag n momentul compilrii care variant a funciei Area() s fie asociat unui apel prin pointeri 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. Exemplu: 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;
197

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.

Motenire multipl 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: class 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 implementeaz funciile Push i Pop 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 Push i Pop sunt declarate virtuale. Clasa Stack nu este obligat s redefineasc metode Pop i Push, pentru a fora aceasta cele dou metode se vor declara ca fiind metode abstracte (sau virtuale pure) i clasa GenericStack va deveni clas abstract. class Node{ int inf; Node * next; public: Node(int x=0){inf = x;} friend class LinkedList; };
198

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

5.2. Exerciii i probleme propuse


1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14.

15.

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

200

6. Teste pentru verificarea cunotinelor


6.1. Teoria i practica programrii Test 1 (Bacalaureat , sesiunea iunie 1999; test adaptat) I.1. Se consider urmtoarea secvena n pseudocod: Citete a,b; a a-b; b a+b; a b-a Scrie a,b a) Ce se va afia pentru valorile citite a = 5, b = 7? b) Ce realizeaz secvena dat? 2. Ce metod de programare este folosit de secvena urmtoare de program? (Procedurile Sol i Nucleu, respectiv tipul vector se consider declarate anterior n program); procedure metoda(p,q:integer,a:vector); var m:integer; begin if q-p<=2 then nucleu(p,q,a) else begin m:=(p+q) div 2; metoda(p,m,a); metoda(m+1,q,a); sol(p,q,m,a); end end; 3. Rescriei secvena de program de mai jos realizat cu structura pentru, utiliznd: a) o structur repetitiv cu test iniial; b) o structur repetitiv cu test final; citete n p 0; a 1; pentru i<1.6 executa [p p+i*a; a a*n] stop c)Explicai care sunt diferenele dintre structura repetitiv cu test iniial i cea cu test final.
201

II.1. 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. 2. 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. Exemplu: Dac fiierul MULT.IN conine oa b c x y 9c 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. Exemplu: 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) I: 1. a) 5p b) 2.5p; 2. 2.5p 3. a) 7.5p b)7.5p c)5p II: 1. a)7.5p b)7.5p 1.5; 2. 10p; III. 20p; IV. a)5p b)5p c)5p
202

Test 2 (Bacalureat simulare- februarie 1999; text adaptat) Subiectul I 1. Se consider urmtoarea secven de program: citete N Z0 ct timp n<>0 execut [ ZZ*10+N mod 10; NN div 10 ] scrie 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 numrului N. 2. Care din urmtoarele afirmaii sunt corecte i care sunt false? a) Un subprogram este recursiv dac este apelat cnd subprogramul 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. citete N p 1; i 1 ct timp i<=N execut [pp * i; ii + 1] scrie p Subiectul II 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. Subiectul III 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.
203

Exemplu: Dac numrul persoanelor (introdus de la tastatur) este 4, programul trebuie s afieze: 3142 2413 Subiectul IV 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 corespunztoare. Lista este definit astfel: Type lista = ^nod; Nod = record inf:integer; urm:lista end; 3. Se consider dou fiiere de tip text: f1 i f2. S se scrie un subprogram care verific dac cele dou fiiere sunt identice din punct de vedere al coninutului. n subprogram se vor scrie toate instruciunile care testeaz fiierele. Test 3 (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: A.F. Variabilele globale sunt declarate n afara oricrui bloc al programului, n timp ce variabilele locale sunt declarate n interiorul blocului n care sunt folosite; (3 puncte) A.F. Variabilele locale sunt stocate n memorie, n timp ce variabilele globale sunt stocate pe stiva; (3 puncte) A.F. 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.
204

Varianta Pascal: function numar_1(n:Longint):integer; begin numar_1:= trunc(ln(n)/ln(10))+1 end; (5 puncte) function numar_2 (n:Longint):integer; var s: string[20] begin str(n,s);numar_2:=length(s); end; (5 puncte) function numar_3(n:Longint):Integer; var nr:integer; begin nr:=0; while n>0 do begin nr:=nr+1; n:=n div 10 end; numar_3:=nr end; (5 puncte)

Varianta C: int numar_1 (long n){ return floor (log(n)/log(10)+1; } (5 puncte) int numar_2 (long n){ char s[20]; ltoa(n,s,10); return strlen(s); } (5 puncte) int numar_3 (long n){ int nr=0; while (n) { nr++; n/=10; } return 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 b1<b2<b3<<bn. 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)
205

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) Test 4 (Bacalaureat - Sesiunea iunie-iulie 2000; enun adaptat) I. Scriei litera sau literele corespunztoare rspunsului sau rspunsurilor 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) Varianta Pascal Varianta C++ a) m: =0; a) m=0; while m<=x do m:=m+1; while (m<=x) m++; writeln(m-1) cout m-1; b) m:=0; b) m=0; repeat m:=m+1 until m>x; do {m+=1} while (m<=x); writeln(m) cout m; c) m:=1; c) m=1; repeat m:=m+1 until m>x; do {m+=1} while (m<=x); writeln(m-1) cout m-1; d) for m:=0 to x do; d) for(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 Pascal Varianta C a) var x,y:=integer; a) integer x,y; b) var x:integer; y: longint; b) int x; long y; c) type float=integer; c) typedef real int; var x,y:float; real x,y; d) var x:array[1. .2]of integer; d) int x[2]; 3. Care este valoarea returnat de funcia urmtoare la apelul f(4)? (5p) Varianta Pascal Varianta C function f(x:integer):integer; int f(int x) begin { if x<=0 then f:=3 if (x<=0) return 3; else f:=f(x-1)*2 else return f(x-1)*2; end. } a)16 b)24 c)48 d)3
206

II. Se consider urmtorul algoritm reprezentat prin programul pseudocod: Citete a,b {numere naturale} dac a>b atunci [ ca ab bc ] d 0 Pentru i= a, b, 1 execut Dac i este divizibil cu 2 atunci dd+1; Scrie 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. 1. 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) 2. Se consider programul: Varianta Pascal Varianta C var v:array[1. .50] of integer; #include <stdio.h> i:integer; int v[50],i; function m(a,b:byte):longint; long m(int a,int b) { begin if a>b then m:=0 if (a>b) return 0; else if a=b then m:=v[a] else if (a == b) then v[a] else m:=m(a, (a+b) div 2)+ else return ( m((a+b)div 2+1,b) m(a,a+b)/2)+m((a+b)/2+1,b)); end; } begin void main() for i:=1 to 10 do v[i]:=i; { writeln(m(3,8)) for (i=1;i<11;i++) v[i]=i; end. printf("%ld\n",m(3,8)); } Ce afieaz programul anterior?(5p)
207

3. Scriei un program care citete de la tastatur cele 10 numere reale ce compun vectorul a i apoi cele 8 numere reale ce constituie componentele 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 proprietatea 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 (20p) Test 5 (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) Varianta Pascal Varianta C a) u:=x div 10 a) u=x/10; b) u:=x; b) u=x; while u>=10 do u:=u mod 10 while (u>=10) u%=10; c) u:=x mod 10 c) u=x%10;

d) while x>=10 do x:=x div 10; d) while (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) Varianta Pascal Varianta C a) integer x array[1..2] of real; a) int float x[2]; b) x:array[1. .2] of real; b) float x[2]; c) x:record a:real; b:integer end; c) struct (float a; int b;}x; d) x:array[1. .2] of integer; d) int x[2];
208

e) type inreg = record e) typedef struct { a: integer; int a; b:real float b; end; } INTREG; var 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) Varianta Pascal Varianta C a) x := 1; a) x = 1; for i := 1 to n do X := X*n for(i = 1;i <= n;i ++) X *= n; b) x := 1; b) x = 1; for i := 1 to n do x := x*10 for(i=1;i<n;i++) x*=10; c) x := 10; c) x = 10; for i:=1 to n do x:=x*i for(i=1;i<n;i++) x*=i; d) x:=1; i:=0; d) x=1; i=0; while i<n do x:=x*10; i:=i+1 while (i<n) x*=10; i++; II. Se consider urmtoarea secven de instruciuni n pseudocod: citete n, x {numere naturale} x = 0; pentru i = 1, n execut x := x+i*i scrie x 1. Ce se va afia pe ecran pentru n = 3 i x = 8?(5p) 2. Scrie o secven echivalent, care s utilizeze structura repetitiv ct timp.(5p) 3. Scnei programul Pascal, C sau C++ corespunztor algontmului dat. (l0p) III. 1. 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) 2. 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)
209

3. Se consider funcia definit recursiv: Varianta Pascal Varianta C function ce(i:word):integer; int ce(int i) { begin if i=0 then ce:=0 if (i == 0) return 0; else ce:=ce(i-1)+2*i else return ce(i-1)+2*i; end; } 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) Test 6 (Bacalaureat-Sesiunea special iunie 2000; enun adaptat) I. Scriei litera sau literele corespunztoare rspunsului sau rspunsurilor corecte, preciznd la fiecare subpunct care dintre variantele de limbaj a fost considerat. 1. 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) Varianta Pascal Varianta C 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 2. 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) Varianta Pascal Varianta C 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; 3. 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)
210

Varianta Pascal Varianta C a) x:=a mod b a)x = a%b; b) x:=a div b b)x = a/b; c) x:=a/b c)x = a/b; d) if a>=b then x:=a div b d)if (a>=b) x=a/b; else x:=b div a else x= b/a; e) if a>=b then x:=a mod b e)if (a>=b) x= a%b; else x:=b mod a else x= b%a; II. Se consider algoritmul reprezentat prin program pseudocod: b := 0; c := 0 citete n {numr natural} pentru i = 1, n execut citete a {numr ntreg} dac a>0 atunci cc+l ; bb+a dac c=0 atunci scrie Imposibil altfel scrie 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 valorile 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 identitate 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.

211

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

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) Test 7 (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) Varianta Pascal Varianta C if i<5-3*i then writeln('DA') if (i<5-3*i) printf('DA'); else writeln ('NU') else printf('NU'); a)-2 b)-1 c)0 d)1 e)2 f)3 g)4 h)5 2. Se tie c variabila x va fi utilizat ntr-un program pentru a memora cu o precizie de 10 la (puterea) -3 i pentru a utiliza n calcule valoarea numrului de aur (5-1)/2. Care dintre urmtoarele declarri este corect i corespunde inteniilor propuse? (5p) Varianta Pascal Varianta C a) var x:real; a) int x; b) var x:integer; b) float x; c) var x:string; c) char *x; d) var x:array[1. .10,1. .3] of char; d) char x[10] [3]; 3. Stabilii care dintre urmtoarele variante reprezint un subprogram corect care returneaz programului apelant cea mai mare dintre dou valori reale transmise prin parametrii reali x i y. (10p) Varianta Pascal Varianta C a) function max(x,y:real); a) float max(float x,float y) begin { if x>y then max:=x else max:=real max=x>y?x:y; end; } b)function max(var x,y:real):real; b) float max(float &x, float &y) begin max:=x; {if (x>y) return x; if x<y then max:=y end; else return y;}
213

c)function max(x,y:real):real; c) void max(float x, float y) begin { int z=x; if (x<y) z=y; if x>y then z:=x else z:=y return z; end; } d)function max(x,y) :real; d) void max(float&x, float&y) begin max:=x; { if max>y then max:=y return x>y?y:x; end; } II. Fie programul pseudocod alturat: citete n, m {numere naturale}; cat timp n>=m execut nn-m scrie 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 prelucrare 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)
214

2. Scriei declarrile necesare pentru definirea unei liste simplu-nlnuite, 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. Subprogramul 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) Test 8 (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) Varianta Pascal Varianta C repeat while (i!=3){ write('XX); i - -; i:=i-1 printf ("XX"); until 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) Varianta Pascal Varianta C a) var x:byte; a) int x; b) var x:array[16]of char; b) char x[0..16]; c) var x:string; c) char *x; d) var x:record d) struct x{ nume prenume: boolean int nume, prenume; end }; 3. Stabilii care dintre urmtoarele variante reprezint antetul corect al unei funcii reale cu un parametru ntreg.(5p)
215

Varianta Pascal Varianta C a)function f(x:real); a) void f(float x) b)function f(x:integer):real; b) int f(f1oat* x) c)function f(var x:real):real; c) float f(int x) d)function f(x:real):integer; d) float f(float x) 4. Pentru a atribui variabilei reale x rezultatul expresiei (2abc*c)/0.25 unde a, b i c desemneaz variabile reale, se utilizeaz instruciunea de atribuire: (5p) Varianta Pascal Varianta C 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 II. Se consider urmtorul program pseudocod: citete n {numr natural}; m0 repeta mm+1 n[n/2] (ctul mpririi ntregi a lui n la 2) pn cnd n < 0 scrie 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) III. 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)
216

VI. Se citesc de la tastatur: dou numere n (0<n<15) i s (0<s<106)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) Test 9(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) Varianta Pascal Varianta C 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) Varianta Pascal Varianta C a) writeln(fmin(a,b,c)) a) printf(%f,fmin(a,b,c)); b) writeln(fmin(a,fmin(b,c))) b) printf(%f,fmin(a,fmin(b,c))); c) writeln(fmin(fmin(a,b),c) c) printf(%f,fmin(fmin(a,b),c); d) writeln(fmin(a,b),fmin(b,c)) d) 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)
217

Varianta Pascal Varianta C a) var x:array[1.. 20] of real; a) float x[1. .20]; b) var x:array[0..20] of integer; b) int x[1. .20]; c) var x:array[0..19] of integer; c) int x[0. .19]; d) var x:array[20] of integer; d) int x[20]; e) var x:array[19] of integer; c) int x[19]; 4. Ce valoare (n format exponenial) se afieaz ca urmare a executri instruciunii urmtoare? (5p) Varianta Pascal Varianta C 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: citete n (numr naturai) m0 citete V1 (numr natural) pentru i = 2, n execut citete Vi (numr natural) dac Vi = Vi-1 atunci mm+1 scrie m 1. Ce se va afia pentru n=5 i V1=5, V2=3, V3=3, V4=8, V6=8? (5p) 2. Scriei programul Pascal, C sau C++ corespunztor algoritmului dat (10p) 3. Pentru n=4, determinai un set de valori introduse pentru V1, V2, V3 i V4 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 a, b, cu a < b, numerele ce formeaz o pereche avnd proprietatea c nu au nici o cifr comun i suma lor este egal cu S.
218

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) Test 10 (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) Varianta Pascal Varianta C while i>4 do i:=i-1 while (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) Varianta Pascal Varianta C a) var x:string; a) char *x; b) var x:integer; b) int x; c) var x:longint; c) long x; d) var x:byte; d) char x; 3. tiind c formula de calcul pentru aria coroanei circulare este (R12R22), unde R1 este variabil real strict pozitiv reprezentnd raza exterioar, iar R2 este variabila real pozitiv reprezentnd raza interioar a coroanei, precizai care dintre urmtoarele instruciuni atribuie variabilei reale S valoarea coroanei circulare.(5p.)
219

Varianta Pascal Varianta C 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.) Varianta Pascal Varianta C a)x:=14;y:=x-7;z:=x/y a) x=14;y=x-7;z=x/y; b)x:=14;if(x<10) then y:=x-1 b) x=14;if x<10 y=x-1; c)x:=y:=14;z:=x+y; c) x=y=14;y=x++y; d)x:=14;if 0<x<100 then y:=x+1 d) x=14;if 0<x<100 y=x+1; II. Se consider programul pseudocod: citete a,b (numere ntregi) dac a<0 atunci a-a dac b<0 atunci b-b h 0 ct timp ab execut hh+1 aa-b scrie 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 structur 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.)
220

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 memoria 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 zecimale 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) reprezentnd 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 rezolvare 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.)

221

6.2. Probleme pentru concursuri 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 D1, D2, , Dm (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 Di la Di+1 i de la Di+1 la Di, i = 1, 2, , n-1.) Iniial manipulatorul ncarc piese din depozitul D1, iar dup efectuarea tuturor micrilor rmne n dreptul depozitului D1. ) 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 n1, n2, , np i tiprete cea mai lung secven ns, ns+1, , nd (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. 222

5.

6.

7.

8. 9.

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. [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. [Structur arborescent - Problema S261] 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. [Pavaj - Problema S271] 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. [Labirint - Problema S291] Se consider un labirint de form dreptunghiular, avnd perei verticali i orizontali. S se gseasc drumul cel mai scurt dintre dou puncte date. [Cititori prieteni - Problema S301] 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.
223

Bibliografie

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16.

Albeanu G., Lumina Radu - Algoritmic i programare n limbajul Pascal, Editura FRM, Bucureti, 2001. Albeanu G. - Algoritmi i limbaje de programare, Editura FRM, Bucureti, 2000. Albeanu G. - Programarea n Pascal i Turbo Pascal. Culegere de probleme. Editura Tehnic, Bucureti, 1994. Atanasiu A. - Concursuri de informatic. Probleme propuse, Editura Petrion, 1995. Cormen T. H., Charles E. Leiserson, Rivest R. R. - Introducere n algoritmi, Ed. Computer Press Agora, 2000. Cristea V., Irina Athanasiu, Eugenia Kalisz, Iorga V. - Tehnici de Programare, Editura Teora, 1999 Eckel B. - Thinking in C++, Prentice Hall Inc., 2000 Ivac Cornelia, Mona Prun, Emanuela Mateescu - Bazele Informaticii (Grafuri i elemente de combinatoric), Editura Petrion, 1997. Jamsa K., Klander L. Totul despre C i C++, Ed. Teora, 2000. Mocanu M. , Ghoerghe Marian, Costin Bdic, Carmen Bdic 333 probleme de programare, Editura Teora 1994. Namir C. Shammas Curs rapid de Borland C++ 4, Editura Teora, Bucureti, 1996. Niculescu R., Albeanu G., Domoco V. - 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. Stroustrup B. The C++ Programming Language, Third Edition, Addison Wesley Longman, Inc., 1997. Tudor S. Tehnici de programare, Ed. L&S INFOMAT, 1996. *** Gazeta de Informatic

224

You might also like