Sunteți pe pagina 1din 113

C apito lul V:

T a b lo u ri

V . 1. V ec to r i (t a b l o u ri u n i di m e n si o n a l e )

V . 1 .1 . N o Ń i u n i i n t r o d uc t i v e

NoŃiunea de vector

În practică, apare deseori necesitatea de a prelucra un set de valori de


acelaşi tip, aşezate într-o anumită ordine. O astfel de structură se numeşte şir, iar
valorile respective se numesc elementele şirului. De exemplu, cu mediile
generale ale elevilor unei clase putem alcătui un şir de numere reale.
De la început trebuie observat faptul că ar fi total ineficient să declarăm
câte o variabilă pentru fiecare element al şirului, deoarece numărul acestor
elemente poate fi foarte mare. De aceea, limbajul Pascal oferă posibilitatea de a
memora toate elementele unui şir într-o singură variabilă, în care elementele sunt
dispuse într-o anumită ordine şi fiecare element ocupă o anumită poziŃie bine
determinată. O astfel de variabilă se numeşte tablou unidimensional sau vector.

Exemplu: Considerăm şirul de numere întregi -3, 6, -5, 14.

poziŃiile (indicii) elementelor


în cadrul vectorului
0 1 2 3
-3 6 -5 14

elementele vectorului
Aşa cum am spus, putem memora toate elementele şirului într-o variabilă
numită vector, pe care o notăm cu v. Elementele şirului vor ocupa poziŃii
succesive în vectorul v, începând cu poziŃia 0 (0,1,2,3,...).
Pentru a referi un anumit element din vector, trebuie să scriem numele
variabilei vector urmat de poziŃia elementului, cuprinsă între paranteze pătrate.
Astfel, pentru vectorul ilustrat mai sus, poziŃiile elementelor sunt 0,1,2,3, şi:
 Elementul de pe poziŃia 0 în vector este primul element al şirului,
adică -3, şi se notează v[0];

274
 Elementul de pe poziŃia 1 în vector este al doilea element al şirului,
deci v[1]=6.
 Analog, v[2]=-5, v[3]=14.
Pe caz general, dacă variabila vector este v, atunci prin v[i] înŃelegem
elementul de pe poziŃia i în vector.

Aici trebuie observat un aspect foarte important. PoziŃia (indicele) unui


element NU arată al câtelea este elementul respectiv în vector, deoarece
numerotarea poziŃiilor începe de la 0. Astfel, în exemplul anterior, elementul
v[3], de pe poziŃia 3 (sau de indice 3), nu este al treilea element al vectorului, ci
al patrulea, înaintea sa aflându-se trei elemente, şi anume v[0], v[1] şi v[2].
Majoritatea lucrărilor de specialitate asimilează complet noŃiunea de poziŃie cu cea
de indice, chiar dacă acest fapt contravine sensului lingvistic al cuvântului
”poziŃie”. Dacă vrem să păstrăm concordanŃa avem o soluŃie foarte simplă: nu
folosim elementul v[0] ! Dacă am utiliza elementele doar începând cu v[1],
atunci v[1] ar fi primul element, v[2] ar fi al doilea, ş.a.m.d., iar poziŃia fiecărui
element ar indica într-adevăr al câtelea este el în vector. În capitolul de faŃă vom
adopta această soluŃie în unele aplicaŃii, acolo unde ne va ajuta să urmărim mai
uşor parcurgerea şi prelucrarea vectorului.
PoziŃia unui element se mai numeşte şi indicele sau rangul elementului,
iar elementele se mai numesc şi componente ale vectorului.

Declararea unui vector


Un vector trebuie declarat, la fel ca orice variabilă, în secŃiunea de
declaraŃii a programului.
Orice vector se caracterizează printr-un număr maxim de elemente.
Acesta este o valoare constantă, reprezentând cel mai mare număr de elemente
care s-ar putea memora în vectorul respectiv. Acesta trebuie precizat la declararea
vectorului, între paranteze pătrate. PoziŃiile elementelor vor fi numerotate
începând de la 0 până la ”numărul maxim de elemente minus 1” (de exemplu,
dacă vrem să declarăm un vector cu maxim 20 de elemente, atunci poziŃiile
elementelor vor fi 0,1,2,...,19).
Pe lângă numărul maxim de elemente, în declararea unui vector mai trebuie
să apară: identificatorul vectorului, (numele variabilei-vector) şi tipul elementelor.
Ex e mp l u : int v[20];

Am declarat un vector v cu maxim 20 de elemente numere întregi;


 identificatorul v reprezintă numele variabilei-vector;
 cuvântul cheie int desemnează tipul elementelor vectorului, adică elementele sunt numere întregi.
 Elementele vectorului sunt v[0],v[1],...,v[19], având indicii (poziŃiile)
0,1,2,...,19.

275
Cu aceste precizări, putem prezenta sintaxa generală a declarării unui vector:
Sintaxa: <tip_elem> <nume>[nr_max_de_elem];
unde:
− <tip_elem> → tipul de date al elementelor;
− <nume> → numele (identificatorul) variabilei-vector;
− <nr_max_de_elem> → numărul maxim al elementelor vectorului.

Tipul elementelor poate fi orice tip predefinit sau definit de utilizator.

Numărul real (efectiv) de elemente

Aşa cum am spus, din declararea unui vector reiese numărul maxim de
elemente ale acestuia, adică cel mai mare număr de elemente care s-ar putea
memora în vector.
În urma declarării unui vector, compilatorul rezervă pentru elementele sale
o zonă fixă de memorie, care să poată memora numărul maxim de elemente.
Astfel, dimensiunea zonei de memorie alocată este egală cu numărul maxim de
elemente înmulŃit cu numărul de octeŃi necesari pentru un element.
Spre exemplu, pentru vectorul declarat prin
int v[25];
se alocă în memorie 50 de octeŃi, deoarece vectorul are maxim 25 de
elemente şi fiecare element, fiind un număr întreg, ocupă 2 octeŃi.
Să presupunem că am scris un program în care am declarat vectorul de
mai sus, cu maxim 25 de elemente. Este oare necesar ca de fiecare dată când
executăm programul să folosim toate cele 25 de elemente ? Fireşte că nu ! La
fiecare execuŃie a programului, ar trebui să putem memora în vector un alt şir,
alcătuit din alte elemente. Pentru aceasta, introducem o altă noŃiune: numărul real
de elemente într-un vector.
Numărul elementelor efectiv folosite într-un vector se numeşte numărul
real (efectiv) de elemente şi se declară ca variabilă, deoarece diferă de la o
execuŃie la alta. De obicei, pe acesta îl vom nota cu n.
În plus, la fiecare execuŃie a programului, elementele pot primi alte valori.
De aceea, în general, numărul real de elemente precum şi elementele vectorului se
citesc de la tastatură.
Exemplu:
Să considerăm un vector v cu maxim 25 de elemente numere întregi.
• Aşa cum am arătat deja, vectorul trebuie declarat ca variabilă
specificând numărul maxim de elemente:
int v[25];

276
• Dacă notăm cu n numărul real (efectiv) de elemente ale vectorului v,
atunci:
 n se declară ca variabilă de tip întreg (int sau long), şi se va citi în
corpul programului.
 Elementele efectiv utilizate vor fi v[0],v[1],...,v[n-2],
v[n-1], şi ocupă în cadrul vectorului poziŃiile 0,1,...,n-2,n-1.
Cu alte cuvinte, dacă de exemplu am declarat un vector cu maxim 25
elemente numere întregi, atunci, pentru el se alocă în memorie 25 de
"căsuŃe" (locaŃii) de memorie, deci vor fi definite elementele
(v[0],v[1],...,v[24]), dar din el folosim efectiv numai primele
n elemente, în speŃă (v[0],v[1],...,v[n-1]) (n≤≤ 25 ).
PoziŃii 0 1 .... n-1 .... 23 24
Elemente v[1] v[2] .... v[n-1] .... v[23] v[24]

Prin v[i] se înŃelege elementul de pe poziŃia i în vector, unde variabila i


parcurge pe rând valorile 1,2,...,n.

Elementele unui vector se comportă ca nişte variabile simple, deci


pot fi citite, afişate şi folosite în expresii.
Exemplu:
Pentru vectorul v ilustrat grafic mai sus, iată câteva exemple de instrucŃiuni care
folosesc elemente ale vectorului:
♥ cout << v[2];
Afişează elementul v[2], adică elementul de pe poziŃia 2 în vectorul v.
♥ x=(v[3]+v[5])/2;
Calculează media aritmetică a elementelor v[3] şi v[5], pe care o atribuie
variabilei x.
♥ if (v[0]>0) cout << "primul element este pozitiv";
Testează dacă elementul v[0] este pozitiv, iar în caz afirmativ afişează un mesaj.

IniŃializarea unui vector la declarare

Un vector v poate fi iniŃializat la declarare, adică în momentul declarării


sale putem preciza nişte valori iniŃiale ale elementelor.
În C++, pentru a iniŃaliza un vector, este suficient ca la sfârşitul declaraŃiei
vectorului să scriem caracterul "egal", urmat de enumerarea între două acolade a
valorilor iniŃiale ale elementelor, în ordinea naturală a indicilor, separate între ele
prin "virgulă". Evident, respectivele elemente pot fi modificate ulterior în cursul
programului, prin atribuiri sau citiri.
Nu este necesar să iniŃializăm toate elementele ! Acele elemente care nu
primesc valori la declarare vor fi iniŃializate automat de către compilator cu
valoarea zero.

277
Iată în continuare un mini-program sugestiv:
Exemplu:
#include <iostream.h>
void main()
{
int v[8]={7,-3,5,-1};
v[2]++;
cout << v[1] << " " << v[2] << " " << v[5];
}

− InstrucŃiunea {int v[8]={7,-3,5,-1};} declară un vector v cu maxim opt


elemente, toate numere întregi, dintre care primele patru sunt iniŃializate în ordine astfel:
v[0]=7, v[1]=-3, v[2]=5 şi v[3]=-1. Restul elementelor vor fi
v[4]=v[5]=v[6]=v[7]=0, iniŃializate automat de către compilator.
− Ulterior, în corpul programului, elementul v[2] este modificat prin
incrementare cu o unitate, deci va rezulta v[2]=5+1=6.
− Ultima instrucŃiune afişează elementele v[1], v[2] şi v[5] separate printr-un
spaŃiu, adică tipăreşte valorile -3, 6 şi 0.
ObservaŃie:
♥ Tipul valorilor iniŃiale înşiruite între paranteze rotunde la declararea
vectorului, trebuie să fie compatibil cu tipul elementelor specificat în cadrul
declaraŃiei. În caz contrar, compilatorul va face conversiile implicite cunoscute.
Exemplu: int v[8]={7,-3.92,5,-1};

Tipul elementelor vectorului v este int, iar una din valorile iniŃiale, în speŃă
-3.92 conferită elementului v[1], este un număr real cu parte zecimală. În acest caz,
compilatorul pur şi simplu va tăia partea zecimală, "forŃând" numărul real -3.92 la
întregul -3. Aşadar în final vom avea v[1]=-3.

AplicaŃie R.V.1 DeclaraŃii de vectori


(Bacalaureat iulie 2008, varianta 97)
Dacă x este o variabilă ce trebuie să memoreze toŃi divizorii unui număr
natural nenul de cel mult trei cifre, stabiliŃi care dintre următoarele linii de
program reprezintă o declaraŃie corectă a lui x.
a) int x[3]; b) long x[50];
c) int x; d) char x[50];

Rezolvare
:
Din capul locului trebuie observat faptul că, fiind vorba despre mai mulŃi divizori,
aceştia vor putea fi memoraŃi doar într-o variabilă indexată de tip vector. În consecinŃă,

278
varianta c), în care se declară o variabilă simplă x de tipul int, este eronată. Celelalte trei
variante de răspuns reprezintă declararea unui vector x, dar:
− în varianta a) se alocă pentru vectorul x doar trei "căsuŃe", în vreme ce un
număr natural cu maxim trei cifre poate avea mai mult de trei divizori;
− în varianta d) se declară un vector x cu maxim 50 de elemente, având poziŃiile
numerotate cu 0,1,...,49, ceea ce este suficient de acoperitor în privinŃa spaŃiului de
memorie necesar (nu există nici un număr de maxim trei cifre care să aibă mai mult de 50
de divizori); în schimb, tipul elementelor acestui vector este char, adică elementele ar
trebui să fie caractere, în vreme ce divizorii unui număr întreg sunt tot numere !
Prin urmare, răspunsul corect este b). Aici se declară un vector care are tot maxim
50 de elemente, ale căror poziŃii sunt numerotate începând cu 0, iar tipul elementelor este
long (divizorii unui număr sunt într-adevăr valori întregi; nu era necesară folosirea tipului
"întreg lung", era suficient int, dar nici greşit nu este.
Răspuns corect: b)

AŃi înŃeles ? Probleme cu răspuns scurt


► 1. Pentru fiecare dintre afirmaŃiile de mai jos, stabiliŃi dacă sunt adevărate sau false:
a) PoziŃiile elementelor pot fi orice numere întregi.
b) PoziŃiile elementelor trebuie numerotate obligatoriu începând cu 0, până la o anumită
valoare.
c) Din declaraŃia unui vector trebuie să rezulte câte elemente pot fi memorate în el.
d) La declararea unui vector se precizează câte elemente vom folosi efectiv în cadrul
programului.
e) La declararea unui vector, la precizarea numărului maxim de elemente putem folosi
constante simbolice, dar nu putem folosi variabile.
f) Elementele unui vector pot fi de tipuri diferite.
► 2. Dacă v este un vector cu maxim cinci elemente numere întregi, în care
poziŃiile elementelor sunt 0,1,...,4, scrieŃi instrucŃiunile de atribuire prin care
elementele de pe poziŃiile pare vor primi ca valori dublul poziŃiilor lor.
► 3. Care este deosebirea dintre numărul maxim şi numărul real (efectiv) de
elemente în cazul unui vector ?
► 4. Fie următoarele declaraŃii de variabile:
int x;
char v[20],c;
Care dintre următoarele atribuiri sunt corecte şi care nu ? JustificaŃi răspunsul.
a) v[2]=’m’;
b) v[’p’]=(x+1)/2;
c) v[’D’]='3';
d) v[1]=floor(sqrt(x));
e) v[3]=c+1;
f) v[x+1]=’m+n’;
g) x=v[4]+v[5];

279
► 5. Se consideră un vector v de numere întregi, având poziŃiile numerotate
succesiv începând cu 0, din care se folosesc efectiv primele n elemente, cu n număr impar.
5.1.) ScrieŃi instrucŃiunea de atribuire prin care elementul situat la mijlocul
vectorului primeşte valoarea 0;
5.2.) Pentru n=41, elementele vecine cu elementul din mijlocul vectorului sunt:
a) v[20] şi v[21] b) v[20] şi v[22] c) v[19] şi v[21] d) v[19] şi v[20]
5.3.) ScrieŃi instrucŃiunea prin care se afişează media aritmetică dintre primul şi
ultimul element.

► 6. Care dintre a) float v[-10][10];


declaraŃiile de vectori sunt b) int v['a','d];
corecte? JustificaŃi răspunsul. c) #define p 5;
#define q 15;
int r;
int v[p][q];
int u[p][r];
d) #define a 1;
int v[0];
e) char a[20];
f) float v[];

► 7. (Bacalaureat iulie 2008, varianta 86)


Într-o variabilă a trebuie să memorăm simultan cele 18 medii semestriale ale unui
elev la disciplinele studiate, împreună cu media generală, calculată ca medie aritmetică a
mediilor semestriale (cu două zecimale exacte). Care este declaraŃia corectă pentru această
variabilă ?
a) double a[18]; b) float a[19]
c) int a[19] d) long a[20]

► 8. (Bacalaureat iulie 2008, varianta 36)


Fie vectorii a şi b, cu elementele a=(1,2,4,5,3) şi b=(4,1,2,3). Atunci
a[b[0]] are valoarea:
a) 5 b) 3 c) 2 d) 1

V . 1 . 2 . P a r c u r g e r e a , c i t i r ea ş i a f i ş a r e a u n u i v e c t o r

În cele ce urmează, considerăm vectorul v=(v[0],v[1],...,v[n-1]),


unde n este numărul real de elemente.
Prin parcurgerea vectorului se înŃelege "vizitarea" elementelor pe rând, şi
prelucrarea acestora. Putem "vizita" toate elementele vectorului sau numai o parte
din ele, după cum proiectăm parcurgerea. Dacă se foloseşte un ciclu, atunci
contorul ciclului va lua pe rând ca valori poziŃiile elementelor pe care dorim să le
prelucrăm. În continuare vom nota contorul cu i.
280
Pentru început, vom ilustra parcurgerea şi prelucrarea tuturor elementelor
vectorului. Această operaŃie poate fi descrisă astfel:
• Contorul ciclului i va lua pe rând valorile 0,1...,n-1,
reprezentând poziŃiile elementelor în vector;
• La fiecare pas, pentru fiecare valoare a lui i, "vizităm" şi prelucrăm
elementul v[i].

Parcurgerea cu ciclu for


Pseudocodul: Paşii ciclului:
pentru (i←←0,1,..,n-1) Pasul 1: i=0 ⇒ prelucrează v[0]
<prelucrează v[i]> Pasul 2: i=1 ⇒ prelucrează v[1]
..............................
Pasul n: i=n-1 ⇒ prelucrează v[n-1]
În cazul în care nu am fi dorit să folosim elementul v[0], s-ar fi prelucrat
succesiv elementele v[1],v[2],..,v[n], iar ciclul de parcurgere ar fi:
←1,2,..,n)
pentru (i←
<prelucrează v[i]>

Citirea unui vector cu n elemente, folosind un ciclu for

Nu putem citi "dintr-o dată" toate elementele vectorului printr-o


instrucŃiune de genul {cin >> v);}, pentru că v este o variabilă indexată
(compusă) care înglobează mai multe valori.
Vom citi mai întâi numărul real de elemente n, apoi citim pe rând
elementele v[0],v[1],....,v[n-1], folosind ciclul de parcurgere prezentat.
Parcurgem în ciclu poziŃiile elementelor i=0,1,...,n-1 şi pentru
fiecare valoare a lui i, citim elementul de pe poziŃia i, adică elementul v[i].
Astfel, pentru i=0 se citeşte elementul v[0], pentru i=1 are loc citirea lui
v[1], ş.a.m.d.
cout << "n=";
cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "\n v[" << i << "]=";
cin >> v[i];
}

Evident, condiŃia de trecere la pasul următor ”i<=n-1” din linia for,


putea fi scrisă şi sub forma ” i<n” (echivalentă din punct de vedere matematic).

281
În secvenŃa de program de mai sus, înainte de citirea elementului v[i] (cu
cin), apare linia {cout << "\n v[" << i << "]=";}, care afişează un
mesaj, cu scopul de a ne spune ce element urmează să citim la pasul respectiv al
ciclului. Desigur că o astfel de comandă nu este obligatorie, dar este
recomandabilă.

cout << "\n v[" << i << "]=";

text text
salt la rând nou valoarea poziŃiei i

De exemplu, înainte de a aştepta introducerea unei valori pentru elementul


v[2], calculatorul va afişa:
cursor în aşteptare
v[2]= _
Desigur că se putea afişa un mesaj mult mai simplu, dar mai puŃin elegant,
de genul:
cout << “\n Dati elementul de pe poziŃia ” << i << “:”;
Astfel, de exemplu, înainte de citirea elementului v[2], se va afişa textul:
Dati elementul de pe pozitia 2: _

ObservaŃie:
Aşa cum am precizat în secŃiunea introductivă, odată ce am declarat un
vector, nu este obligatoriu să folosim toate "căsuŃele" acestuia. Astfel, dacă vrem
să folosim n elemente din vector, acestea pot fi foarte bine
(v[1],v[2],..,v[n]), în loc de (v[0],v[1],..,v[n-1]). Singura
modificare pe care ar suferi-o algoritmul de citire al vectorului în acest caz, se
referă la parcurgerea poziŃiilor cu contorul i: acesta va lua valori de la 1 la n.
Ciclul de citire arată astfel:
for (i=1; i<=n; i++)
{
cout << "\n v[" << i << "]=";
cin >> v[i];
}

Afişarea unui vector cu n elemente, folosind un ciclu for


Nu putem afişa "dintr-o dată" toate elementele vectorului printr-o
instrucŃiune {cout << v;}. Folosim acelaşi ciclu de parcurgere a vectorului:
vom parcurge poziŃiile elementelor din vector i=0,1...n-1 şi pentru fiecare
valoare a lui i, afişăm elementul de pe poziŃia i, adică v[i]:

282
a) Se tipăresc toate elementele pe un b) Se tipăreşte fiecare element pe
singur rând (cu cout): la fiecare pas câte un rând: la fiecare pas, înainte
se afişează un element v[i], urmat de afişarea unui element v[i],
de un caracter "spaŃiu ". cursorul "sare" pe rândul următor.
for (i=0; i<=n-1; i++) for (i=0; i<=n-1; i++)
cout << v[i] << ' '; cout << "\n " << v[i];
Dacă dorim ca elementele efectiv folosite ale vectorului să fie
(v[1],v[2],..,v[n]), atunci cele două cicluri de mai sus se modifică astfel:
for (i=1; i<=n; i++) for (i=1; i<=n; i++)
cout << v[i] << ' '; cout << "\n " << v[i];

Parcurgerea cu ciclu while

Plecăm de la poziŃia primului element {i=0;}; i=0;


Cât timp nu am ajuns la sfârşitul vectorului while (i<=n-1)
{
{i<=n-1}: <prelucrează v[i]>
• prelucrăm elementul v[i] la care suntem; i++;
• trecem la elementul următor, incrementând }
poziŃia i {i++;}.

Paşii ciclului, exemplificare pentru n=3:


IniŃial i=0.
Pas 1: i<=n-1 ? 0<=2 ? da ⇒ prelucrează v[0]; i++, i=0+1=1
Pas 2: i<=n-1 ? 1<=2 ? da ⇒ prelucrează v[1]; i++, i=1+1=2
Pas 3: i<=n-1 ? 2<=2 ? da ⇒ prelucrează v[2]; i++, i=2+1=3
Pas 4: i<=n-1 ? 3<=2 ? nu ⇒ iese din ciclu

Folosim acest algoritm pentru a citi respectiv pentru a afişa un vector v cu n elemente:
Citirea Afişarea
i=0; i=0;
while (i<=n-1) while (i<=n-i)
{ {
cout << endl << "v[" << i << "]="; cout << v[i] << " ";
cin >> v[i]; i++;
i++; }
}

283
Parcurgerea cu ciclu do-while

Citim mai întâi numărul real de elemente n;


Plecăm de la poziŃia primului element {i=0}; i=0;
do
Execută
{
• prelucrăm elementul v[i]; <prelucrează v[i]>
• trecem la elementul următor, incrementând i++;
poziŃia i {i++}; } while (i<=n-1);
Cât timp (i<=n-1).

Paşii ciclului, exemplificare pentru n=3:


IniŃial i:=1;
Pas 1: prelucrează v[0]; i=i+1=0+1=1; i<=n-1 ? 1<=2 ? da ⇒ reia ciclul
Pas 2: prelucrează v[1]; i=i+1=1+1=2; i<= n-1 ? 2<=2 ? da ⇒ reia ciclul
Pas 3: prelucrează v[2]; i=i+1=2+1=3; i<= n-1 ? 3<=2 ? nu ⇒ STOP

AplicaŃie R.V.2. Valori distincte nenule


În secvenŃa de program de mai jos, v este un vector cu n elemente numere
întregi, care iniŃial are toate elementele nule, iar i, j, n şi k sunt variabile de tip întreg.
Câte valori distincte nenule va conŃine vectorul după executarea secvenŃei date ?
n=5; k=3;
for (i=0; i<=n-1; i++)
for (j=0; j<=k-1; j++)
v[i+j]=k+i;
a) patru b) cinci c) trei d) şapte

Rezolvare
:
În primul ciclu contorul i va parcurge pe rând valorile i=0,1,2,3,4. La fiecare
pas, se execută un al doilea ciclu, "dirijat" de contorul j, care va lua valori de la 0 la k-1,
adică j=0,1,2. Vom urmări succesiunea de paşi a acestor două cicluri imbricate, pentru
n=5 şi k=3.
Pasul 1: i=0, j=0,1,2
Pasul 1.1.: j=0, v[i+j]=k+i ⇒ v[0+0]=3+0, v[0]=3
Pasul 1.2.: j=1 ⇒ v[0+1]=3+0, v[1]=3
Pasul 1.3.: j=2 ⇒ v[2]=3
De fapt, observăm deja că, la un pas i al primului ciclu, în cadrul celui de-al
doilea ciclu toate elementele vor primi aceeaşi valoare k+i, independentă de contorul j.
Absolut analog:

284
La pasul 2, pentru i=1, parcurgând al doilea ciclu cu j=0,1,2, obŃinem
v[1]=v[2]=v[3]=4;
La pasul 3, pentru i=2, rezultă v[2]=v[3]=v[4]=5;
La pasul 4, pentru i=3 obŃinem v[3]=v[4]=v[5]=6;
La pasul 5, pentru i=4, se produc ultimele modificări ale elementelor, care conduc la
v[4]=v[5]=v[6]=7.
Plecând de la configuraŃia iniŃială a vectorului v cu toate elementele nule, adică
v=(v[0],v[1],v[2],...)=(0,0,0,0,0,0,0,...) (am evidenŃiat primele şapte
elemente care se modifică în cadrul algoritmului), pentru a afla configuraŃia finală vom
cerceta în ordine inversă succesiunea de atribuiri care modifică elementele. De ce ? Pentru
că ultima modificare va da valoarea finală a fiecărui element ! Astfel:
− la pasul 5 se stabilesc valorile finale v[4]=v[5]=v[6]=7;
− la pasul 4 avem o singură valoare finală, v[3]=6, deoarece elementele v[4] şi
v[5] se vor modifica ulterior, la pasul 5;
− similar, obŃinem ca valori finale v[2]=5 la pasul 3, v[1]=4 la pasul 2 şi
v[0]=3 la pasul 1.
Prin urmare, vectorul va fi v=(3,4,5,6,7,7,7,0,0,0,....,). S-au modificat
doar primele şapte elemente, în vreme ce restul au rămas cu valoare iniŃială 0, deci în final
vectorul va conŃine cinci valori distincte nenule, respectiv 3, 4, 5, 6 şi 7.
Răspuns corect: b)

AplicaŃie R.V.3. Medie aritmetică într-un şir


Se dă un şir v cu n elemente numere întregi. ScrieŃi un program care
determină şi afişează pe ecran media aritmetică a elementelor pare din şir.
Exemplu: Pentru vectorul v=(-3,8,4,-5,10,7,8), cu n=7 elemente,
programul va afişa valoarea 7.5 (adică valoarea expresiei (8+4+10+8)/4)

Rezolvare I:

 Memorăm şirul dat într-un vector v cu maxim 25 de elemente numere


întregi. În secŃiunea de declaraŃii vom declara vectorul împreună cu celelalte variabile:
{int i,n,v[20],S,nr;}. Dacă n este numărul real de elemente, atunci elementele
efectiv folosite vor fi v[0],v[1],...,v[n-1].

 Citim de la tastatură valoarea lui n, apoi, într-un ciclu, citim elementele


vectorului: parcurgem poziŃiile elementelor i=0,1,...,n-1 şi pentru fiecare valoare a lui
i, citim elementul v[i]:
for (i=0; i<=n-1; i++)
{
cout << endl << "v[" << i << "]=";
cin >> v[i];
}

 Fie S şi nr suma respectiv numărul elementelor pare din vector, variabile


care se iniŃializează cu 0. Parcurgem într-un ciclu for poziŃiile elementelor
285
i=0,1,...,n-1. Pentru fiecare valoare a lui i, testăm dacă elementul v[i] (de pe poziŃia
i) este par {"v[i]%2==0", ceea ce înseamnă "!(v[i]%2!=0)", condiŃie care se poate
scrie simplificat "!(v[i]%2")}. În caz afirmativ:
• adăugăm v[i] la suma elementelor pare S {S+=v[i];};
• mărim cu 1 numărul nr al elementelor pare din vector {nr++;}.
nr=0; S=0;
for (i=0; i<=n-1; i++)
if (!(v[i]%2))
{
S+=v[i]; nr++;
}

 În final, dacă există elemente pare în vector (nr>0 ), afişăm media aritmetică
a acestora, care este (float)S/nr (suma elementelor pare împărŃită la numărul
elementelor pare). Verificarea condiŃiei nr>0 este necesară pentru a evita împărŃirea în
cazul în care nu există nici un element par în vector (variabilele S şi nr ar rămâne cu
valoarea iniŃială 0, iar calculatorul nu poate efectua împărŃirea 0/0 !). Cuvântul "float"
plasat înaintea deîmpărŃitului S are rolul de a îl converti de la întreg către flotant (în
absenŃa acestei conversii explicite, compilatorul ar furniza câtul întreg al împărŃirii, fără
partea zecimală, din cauză că ambii operanzi sunt întregi).
if (nr>0)
cout << "\n Media= " << (float)S/nr;

 Prezentăm în continuare programul:


# include <iostream.h>
void main ()
{
int i,n,v[20],S,nr;
// citeste numarul real de elemente n ale vectorului v
cout << endl << "n="; cin >> n;
// citeste elementele vectorului v intr-un ciclu for
for (i=0; i<=n-1; i++)
{
cout << endl << "v[" << i << "]=";
cin >> v[i];
}
// calculeaza suma S si numarul nr al elementelor pare din vector
nr=0; S=0;
for (i=0; i<=n-1; i++)
if (!(v[i]%2))
{
S+=v[i]; nr++;
}
// daca exista elemente pare, afiseaza media aritmetica a lor
if (nr>0)
cout << "\n Media= " << (float)S/nr;
}

286
Rezolvare II:

 În soluŃia anterioară s-au folosit două cicluri for: primul pentru citirea
vectorului, iar al doilea pentru calculul sumei şi numărului elementelor pare. Dar nu
puteam folosi un singur ciclu ? Răspunsul este afirmativ.
 După citirea lui n, iniŃializăm s şi nr cu 0. Apoi scriem un ciclu în care
contorul i ia pe rând valorile 0,1,...,n-1, şi pentru fiecare valoare a lui i:
♦ citim elementul v[i] (de pe poziŃia i);
♦ testăm dacă v[i] este par. În caz afirmativ adăugăm v[i] la suma S a
elementelor pare şi incrementăm numărul nr al acestora.
Astfel, actualizarea lui S şi nr s-a făcut direct în ciclul de citire !

 În final, dacă nr>0, afişăm media aritmetică a elementelor pare S/nr, la fel
ca în varianta anterioară.

# include <iostream.h>
# include <conio.h>

void main ()
{
int i,n,v[20],S,nr;
clrscr();
// citeste numarul real de elemente n ale vectorului v
cout << endl << "n="; cin >> n;
// intr-un ciclu for, citeste elementele vectorului v
// si calculeaza suma S si numarul nr al elementelor pare din vector
nr=0; S=0;
for (i=0; i<=n-1; i++)
{
// citeste un element v[i]
cout << endl << "v[" << i << "]=";
cin >> v[i];
// testeaza daca v[i] este par, iar in caz afirmativ actualizeaza S si nr
if (!(v[i]%2))
{
S+=v[i];
nr++;
}
}
if (nr>0)
cout << "\n Media= " << (float)S/nr;
getch();
}

287
ÎncercaŃi singuri !

► 1. Fiind dat un vector v cu n elemente numere întregi, scrieŃi câte un


program care:
a) determină suma elementelor pozitive din vector;
b) calculează produsul şi numărul elementelor negative aflate pe poziŃii impare
în vector;
c) afişează numărul elementelor pozitive, numărul elementelor negative şi
numărul elementelor nule din vector;
d) tipăreşte elementele pare aflate pe poziŃii divizibile cu 3;
Pentru fiecare dintre programele anterioare, se cer mai multe variante:
V1) folosind cicluri for; V2) folosind cicluri while-do; V3) folosind
cicluri do-while.
► 2. (Bacalaureat iulie 2009, variata 84)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(1≤n≤100 ), un şir de câte n numere întregi, cu cel mult cinci cifre fiecare, notat
a0,a1,a2,…an-1, apoi un al doilea şir de n numere întregi, cu cel mult cinci cifre
fiecare, notat b0,b1,b2,…bn-1. Programul construieşte în memorie şi afişează pe
ecran un şir c format din n numere calculate astfel: ci=ai+bi, pentru
i=0,1,..,n-1. Numerele afişate vor fi separate prin câte un spaŃiu.
Exemplu: pentru n=4 şi şirurile (2,3,7,8) respectiv (43,3,1,8), se
afişează 45 6 8 16.
► 3. (Bacalaureat iulie 2009, variata 85)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(1≤n≤100), un şir de câte n numere întregi, cu cel mult 5 cifre fiecare, notat
a0,a1,a2,…an-1, apoi un al doilea şir de n numere întregi, cu cel mult 5 cifre
fiecare, notat b0,b1,b2,…bn-1. Programul construieşte în memorie şi afişează pe
ecran un şir C format din n numere calculate astfel: ci=ai-bi, pentru
i=0,1,,..,n-1. Numerele afişate sunt separate prin câte un spaŃiu.
Exemplu: pentru n=4 şi şirurile (2,3,7,8) respectiv (43,3,1,8), se
afişează: -41 0 6 0.
► 4. Fiind daŃi doi vectori u şi v, cu câte n elemente fiecare, scrieŃi un
program care calculează produsul scalar al celor doi vectori,
P=u[0]*v[0]+u[1]*v[1]+...+u[n-1]*v[n-1].
Exemplu: pentru n=4 şi vectorii u=(1,2,3,4) şi v=(5,6,7,8),
programul va afişa valoarea 70 (1*5+2*6+3*7+4*8).

288
AplicaŃie R.V.4. Elementele prime ale unui şir
(Bacalaureat iulie 2009, varianta 67)
Se citeşte de la tastatură un şir de n numere întregi. Să se afişeze
elementele prime ale şirului precum şi numărul acestora.
Exemplu: pentru şirul (12,17,8,11,5,26), programul va afişa
elementele prime 17, 11 şi 5, precum şi valoarea 3 (care atestă faptul că în şir
există trei numere prime în şir).

Rezolvare
:
 Memorăm cele n elemente ale şirului într-un vector v=(v[0],
v[1],...,v[n-1]). Astfel, n va reprezenta numărul real de elemente din vector. Citim
mai întâi valoarea lui n, apoi într-un ciclu for citim elementele: contorul i va parcurge pe
rând poziŃiile 0,1,..,n-1 ale elementelor, şi la fiecare pas citim un element v[i].
 Vom număra elementele prime ale vectorului într-o variabilă nr, pe care o
iniŃializăm cu 0. Parcurgem într-un alt ciclu for poziŃiile elementelor i=0,1,..,n-1.
Pentru fiecare element v[i], dacă este diferit de zero, trebuie să testăm dacă este prim. În
caz afirmativ, afişăm v[i] şi să incrementăm nr. Algoritmul prin care verificăm dacă
v[i] este număr prim nu mai reprezintă o noutate:
 Folosim o variabilă ok, de tip întreg dar cu sens logic, a cărei valoare, 1 sau
0, va indica în final dacă elementul v[i] este prim sau nu. Presupunem mai
întâi condiŃia îndeplinită, iniŃializând ok cu 1.
 Într-un nou ciclu for, prin contorul k vor trece pe rând posibilii divizori ai
lui v[i]. Aceştia sunt numerele naturale de la 2 la "parte întreagă din
v[i]/2": k=2,3..,v[i]/2. Pentru fiecare dintre aceste valori ale lui k,
verificăm dacă este efectiv divizor al lui v[i] {"v[i]%2==0", care se poate
scrie mai simplu "!(v[i]%2)"}. În caz afirmativ, găsind un divizor al lui
v[i] "în persoana" acelui k, rezultă că elementul v[i] nu mai poate fi prim,
fapt pe care îl marcăm prin atribuirea ok=0.
ok=1;
for (k=2; k<=v[i]/2; k++)
if (!(v[i]%k))
ok=0;
 Dacă ok a rămas 1 ("if (ok==1)" se poate scrie prescurtat "if (ok)"),
înseamnă că elementul v[i] este prim şi:
• afişăm v[i];
• incrementăm cu 1 numărul nr al elementelor prime din vector {nr++;}.
ObservaŃie: Pentru fiecare element v[i], testarea "v[i]!=0" este necesară
deoarece 0 este "văzut" ca număr prim (prin folosirea operatorului "%").

#include <iostream.h>
#include <conio.h>

289
void main ()
{
clrscr();
int v[50],i,k,n,nr,ok;
cout << endl << "Dati numarul de elemente n: ";
cin >> n;
// citeste cele n elemente ale vectorului v
for (i=0; i<=n-1; i++)
{
cout << "Dati elem de pe pozitia " << i << ": ";
cin >> v[i];
}
cout << endl << "Elementele prime sunt: " << endl;
nr=0; // nr reprezinta numarul elementelor prime
for (i=0; i<=n-1; i++)
if (v[i])
{
// pentru fiecare element v[i], testam daca este prim
ok=1;
for (k=2; k<=v[i]/2; k++)
if (!(v[i]%k))
ok=0;
// daca v[i] este prim, atunci il afisam si incrementam nr
if (ok)
{
cout << v[i] << " ";
nr++;
}
}
cout << endl << "In vector sunt " << nr << " elemente prime";
getch();
}

ÎncercaŃi singuri !

► 1. (Bacalaureat iulie 2008, varianta 71)


ScrieŃi un program care citeşte de la tastatură un număr natural n, apoi n
numere naturale de cel mult nouă cifre, şi afişează pe ecran câte dintre aceste
numere au proprietatea că suma cifrelor lor este un număr prim.
Exemplu: pentru n=8 şi numerele (12,13,20,51,60,122,128,117),
programul va afişa valoarea 3 (reprezentând numărul valorilor subliniate, care
îndeplinesc condiŃia cerută).
► 2. Se citeşte de la tastatură un număr natural n, apoi un şir cu n
elemente numere întregi, cu cel puŃin doua cifre fiecare. ScrieŃi un program care
afişează acele elementele ale şirului care au prima cifră egală cu ultima cifră.
Exemplu: pentru şirul (2412,138,556,363,14,11), programul va
afişa numerele 2412, 363 şi 11.

290
AplicaŃie R.V.5. Pseudocod
(Bacalaureat iulie 2008, citeşte n;
varianta 72) ←0,1,...,n-1)
pentru (i←
În pseudocodul dat, citeşte ai;
(a0,a1,...,an-1) este un vector cu n ←0;
s←
elemente numere naturale. ←0,1,...,n-1)
pentru (i←
a) Ce se va afişa în urma dacă (ai==i)
execuŃiei programului aferent acestui ai←ai+i
pseudocod, dacă pentru n se citeşte altfel
valoare 8, iar cele opt componente ale ←s+1;
s←
vectorului a, citite de la tastatură, sunt, scrie s;
←0,1,...,n-1)
pentru (i←
în ordine (0,1,3,3,5,6,4,7) ?
scrie ai;
b) Pentru n=5, găsiŃi un set de
valori ale elementelor vectorului, astfel încât în urma executării algoritmului
variabila s să aibă valoarea 0.
c) ÎnlocuiŃi în pseudocod expresia "ai←i" cu o altă expresie, astfel încât
valoarea variabilei s să reprezinte numărul componentelor pare ale şirului
memorat în variabila v.
d) RescrieŃi pseudocodul, înlocuind a doua structură repetitivă "pentru"
cu o structură repetitivă echivalentă de alt gen.
Rezolvare
:
Pentru vectorul a vom folosi în această rezolvare notaŃia clasică
a=(a[0],a[1],...,a[n-1]).

a)
În al doilea ciclu "pentru", contorul i parcurge succesiv valorile 0,1,...,n-1,
şi la fiecare pas se testează dacă a[i]==i (adică dacă valoarea elementului a[i] "vizitat"
la pasul respectiv coincide cu poziŃia sa). În caz afirmativ se modifică elementul a[i] prin
atribuirea a[i]← ← a[i]+i, iar în caz contrar se incrementează cu 1 o variabilă s
(iniŃializată cu 0).
Pentru vectorul a=(0,1,3,3,5,6,4,7) cu n=8 elemente, avem i=0,1,...7.
Observăm cu uşurinŃă că valorile lui i din al doilea ciclu pentru care este îndeplinită
condiŃia "a[i]==i" din linia "dacă", sunt: i=0, i=1, i=3 şi i=7. Pentru acestea vom
obŃine prin atribuirea "a[i]← ←a[i]+i" următoarele valori:
− pentru i=0 ⇒ a[0]=a[0]+0=0+0=0;
− pentru i=1 ⇒ a[1]=a[1]+1=1+1=2;
− pentru i=3 ⇒ a[3]=a[3]+3=3+3=6;
− pentru i=7 ⇒ a[7]=a[7]+7=7+7=14;
Pentru celelalte valori ale lui i, respectiv i=2,4,5,6, elementele a[i] aferente
rămân nemodificate, şi, în urma executării execuŃiilor atribuirii "s← ←s+1" de pe ramura
"altfel", va rezulta s=4.

291
La final secvenŃa dată afişează valoarea lui s urmată de elementele vectorului,
deci se vor tipări în ordine următoarele numere:
4 0 2 3 6 5 6 4 14

b)
Pentru ca variabila s să rămână cu valoarea iniŃială 0, este necesar ca atribuirea
← s+1" de pe ramura "altfel" să nu se execute niciodată. Altfel spus, toate elementele
"s←
a[i] (cu i=0,1,...,n-1) să verifice condiŃia "a[i]==i". Pentru n=5, singurul vector
cu această proprietate este: a=(0,1,2,3,4).

c)
Pentru a obŃine în variabila s numărul elementelor pare din vector, este necesar ca
în cadrul celui de-al doilea ciclu, la fiecare pas, pentru fiecare element a[i], să se execute
atribuirea "s←← s+1" numai dacă elementul a[i] este par, adică dacă "a[i]%2==0 ".
Întrucât atribuirea cu pricina se află pe ramura "altfel" a instrucŃiunii de selecŃie, trebuie
să formulăm condiŃia inversă, în speŃă "a[i]%2≠0 ". Rescriem în continuare pseudocodul
cu această modificare.

citeşte n;
pentru (i← ←0,1,...,n-1)
citeşte ai;
← 0;
s←
pentru (i← ←0,1,...,n-1)
dacă (a i %2≠0)
←a[i]+i
a[i]←
altfel
←s+1;
s←
scrie s;
pentru (i← ←0,1,...,n-1)
scrie a[i];

Observăm că în cadrul celui de-al doilea ciclu, pentru fiecare dintre valorile
i=0,1,...,n-1, dacă elementul a[i] este impar atunci îl modifică, iar în caz contrar
incrementează variabila s care va indica numărul valorilor pare din vector.

d)
Vom înlocui a doua structură repetitivă "pentru" cu o structură echivalentă de
tipul "cât timp". Având în vedere faptul că valorile succesive ale contorului i sunt
1,2,...,n, vom opera următoarele modificări:
− înaintea ciclului vom stipula printr-o atribuire valoarea iniŃială a lui i: {i←
←0;};
− condiŃia de continuare a ciclului din linia "cât timp" este {"i<=n-1"};
− la sfârşitul fiecărui pas trebuie să existe o instrucŃiune care să dea valoarea
contorului pentru pasul următor; cum valorile lui i sunt consecutive, această instrucŃiune
va fi atribuirea {i ← i+1;}.
citeşte n;
← 0,1,...,n-1)
pentru (i←
citeşte a[i];
← 0;
s←

292
← 1;
i←
cât timp (i<=n)
început
dacă (a[i]%2≠0)
a[i]←← a[i]+i
altfel
s←← s+1;
← i+1;
i←
sfârşit
scrie s;
pentru (i←← 0,1,…,n-1)
scrie a[i];

ÎncercaŃi singuri !

► 1. (Bacalaureat iulie 2008, varianta 100)


În pseudocodul alăturat, a este un vector de valori întregi.
citeşte n;
←0,1,...,9)
pentru (i←
←0;
a[i]←
execută
început
←n%10;
i←
←a[i]+1;
a[i]←
←[n/10];
n←
sfârşit
cât timp (n≠0);
←9,8,...,0)
pentru (i←
pentru (j←←1,2,...,a[i])
scrie i;
a) Ce se va afişa pe ecran, dacă de la tastatură se citeşte valoarea
n=10220685 ?
b) Câte valori pot fi introduse pentru variabila n, astfel încât rezultatul
afişat în urma executării algoritmului să fie 720 ?
c) ScrieŃi un pseudocod echivalent cu cel dat, care să conŃină o structură
repetitivă cu test iniŃial, în locul celei cu test final;
d) ScrieŃi programul corespunzător algoritmului dat.

► 2. (Bacalaureat iulie 2008, varianta 25)


În pseudocodul dat, s-a notat cu ak elementul de pe poziŃia k în cadrul
tabloului unidimensional a=(a1,a2,...,an) cu n elemente numere întregi şi cu
|x| valoarea absolută a numărului întreg x, şi cu [x] partea întreagă a numărului
real x.

293
citeşte n;
pentru (i←←1,2,...,n)
citeşte ai;
pentru (i←←1,2,...,n-1)
început
←ai+ai+1+|ai-ai+1|;
m←
ai+1←ai+ai+1-[m/2];
ai←[m/2];
sfârşit
scrie an;
a) Ce se afişează, dacă sunt citite, în ordine numerele 6, 3, 5, 8, 1, 7, 2 ?
b) Pentru n=5, scrieŃi o succesiune de valori citite pentru elementele a1,
a2,...,a5, astfel încât să se afişeze prima valoare citită;
c) FormulaŃi un enunŃ scurt care să descrie acŃiunea algoritmului;
d) ScrieŃi programul corespunzător algoritmului dat.
► 3. (Bacalaureat august 2001, varianta 1)
Se consideră următorul program pseudocod, în care V=(V0,V1,...,Vn-1)
este un vector cu n elemente numere întregi.
citeşte n;
m ← 0;
citeşte V0;
pentru (i ← 1,..,n-1)
început
citeşte Vi ;
dacă (Vi==Vi-1)
← m+1;
m←
sfârşit
scrie m;
a) Ce se va afişa pentru n=5 şi V0=5, V1=3, V2=3, V3=8, V4=8 ?
b) ScrieŃi programul Pascal corespunzător algoritmului dat.
c) Pentru n=4, determinaŃi un set de valori introduse pentru V0, V1, V2 şi V3
astfel încât rezultatul afişat de către algoritmul dat să fie 3.
d) ScrieŃi un program pseudocod sau Pascal care să fie echivalent cu
programul dat şi care să nu utilizeze variabile structurate (tablouri liste fişiere,
etc.) sau adrese de variabile structurate.

► 4. Se consideră algoritmul reprezentat în limbaj pseudocod, în care


a=(a[0],a[1],...,a[n-1]) este un vector cu n elemente numere întregi:
citeşte n;
pentru (i=0,1,..,n-1)
citeşte a[i];
k ← 0;

294
pentru (i ← 0,..,n-2)
început
găsit← ← 0;
pentru (j ← i+1,..,n-1)
dacă (a[i]==a[j])
găsit←←1;
dacă (găsit==0)
k ← k+1;
sfârşit
scrie k;

a) Dacă de la tastatură se citeşte vectorul a=(2,8,2,5,11,8,2) cu n=7


elemente, deduceŃi ce valoarea va afişa secvenŃa dată.
b) DaŃi un exemplu de vector a cu cinci elemente citit de la tastatură,
pentru care algoritmul dat va afişa valoarea 0.
c) ScrieŃi programul Pascal corespunzător algoritmului dat.
d) Modificând doar domeniile de valori ale variabilelor-contor i şi j în
cele două linii “pentru”, se poate obŃine un algoritm echivalent cu cel dat (care să
aibă acelaşi efect)?

V . 1 .3 . A l g o r i t m i f u n d ame n t a l i d e p r e l u c r a r e
a t a b l o u r i lo r

Determinarea minimului / maximului dintr-un şir de numere

Considerând un şir de n elemente numere întregi, memorat într-un vector


(v[0], v[1],..,v[n-1]), se pune problema determinării elementului maxim
(cel mai mare) şi a elementului minim (cel mai mic).

Algoritm ► Determinarea minimului dintr-un şir de numere


Memorăm minimul într-o variabilă min. Presupunem iniŃial că minimul
este cel mai mare număr întreg recunoscut de limbaj, MAXINT (o constantă
simbolică predefinită, existentă în header-ul "values.h", cu valoarea 32767)
{min=MAXINT;}. Într-un ciclu, contorul i parcurge poziŃiile elementelor
i=0,1,...,n-1. Pentru fiecare valoare a lui i, comparăm elementul v[i] cu
minimul pe care îl avem în acel moment în variabila min. Dacă v[i] este mai mic
decât minimul min, atunci elementul respectiv v[i] devine noul minim
{min=v[i];}.

295
min=MAXINT;
for (i=0; i<=n-1; i++)
if (v[i]<min)
min=v[i];
Exemplu:
Considerăm vectorul v=(-3,6,-4,-11,7), cu n=5 elemente.
IniŃial min=MAXINT=32767 . Urmărim paşii ciclului:
i=0: v[0]<min ? -3<32767 ? da ⇒ min=v[0] ⇒ min=-3;
i=1: v[1]<min ? 6<-3 ? nu
i=2: v[2]<min ? -4<-3 ? da ⇒ min=v[2] ⇒ min=-4;
i=3: v[3]<min ? -11<-4 ? da ⇒ min=v[3] ⇒ min=-11;
i=4: v[4]<min ? 7<-11 ? nu
În variabila min s-a obŃinut minimul din tot vectorul, care este -11.
Observăm că, indiferent ce valoare ar avea, primul element v[1] va îndeplini
condiŃia din linia if. Prin urmare, la primul pas al ciclului se va face atribuirea min=v[0].
ConsecinŃa ? Este posibil ca ulterior minimul min să devină alt element, dar oricum în mod
sigur el va fi ales din rândul elementelor vectorului.

Algoritm ► Determinarea maximului dintr-un şir de numere


Se actualizează maximul într-o variabilă max. Algoritmul este asemănător
cu cel de minim. IniŃializăm maximul max cu cel mai mic număr întreg recunoscut
de limbaj, -MAXINT. Parcurgem într-un ciclu poziŃiile i=0,1,..,n-1 ale
elementelor. La fiecare pas, dacă elementul v[i] este mai mare decât maximul
max, atunci noul maxim va fi v[i].
max=-MAXINT;
for (i=0; i<=n-1; i++)
if (v[i]>max)
max=v[i];

Prezentăm în continuare o altă variantă a algoritmilor de mai sus, în care


maximul / minimul se iniŃializează cu primul element, apoi se actualizează prin
parcurgerea vectorului începând cu elementul al doilea. Dacă urmăriŃi cu atenŃie
pas cu pas secvenŃele de mai jos, veŃi vedea că efectul este acelaşi !
{ Minim: } { Maxim: }
min=v[0]; max=v[0];
for (i=1; i<=n-1; i++) for (i=1; i<=n-1; i++)
if (v[i]<min) if (v[i]>max)
min=v[i]; max=v[i];

296
AplicaŃie R.V.6. Interschimbare între minim şi maxim
(Bacalaureat, iulie 2009, varianta 25, enunŃ adaptat)
Se citesc de la tastatură un număr natural n (2 ≤ n ≤ 5 0 ), apoi un tablou
unidimensional v, care conŃine n valori naturale. ScrieŃi un program care
interschimbă între ele cel mai mic element par şi cel mai mare element impar din
tabloul dat, tipărind tabloul obŃinut. Dacă în tabloul citit nu există nici un element
par sau nici un element impar, acesta va rămâne nemodificat, şi se va afişa un
mesaj de atenŃionare.
Exemplu: pentru n=6 şi tabloul (12,3,6,1,24,17), programul va
interschimba între ele elementele 6 şi 17, iar tabloul obŃinut va fi
(12,3,17,1,24,6).
Rezolvare
:
 Mai întâi citim valoarea lui n, reprezentând numărul real de elemente ale
vectorului (tabloului unidimensional) v, după care citim elementele propriu-zise, folosind
algoritmul prezentat pe larg în partea de teorie: într-un ciclu, contorul i va parcurge
poziŃiile 0,1,...,n-1 ale elementelor, şi la fiecare pas citim elementul v[i] (aflat pe
poziŃia i în vector)
for (i=0; i<=n-1; i++)
{
cout << "Dati elem de pe pozitia " << i << ": ";
cin >> v[i];
}

 Definim următoarele variabile:


− minpar şi pozpar = minimul dintre elementele pare ale vectorului, respectiv
poziŃia pe care se află acest minim în vector;
− maximp şi pozimp = maximul dintre elementele impare ale vectorului,
respectiv poziŃia pe care se găseşte acest maxim.
De ce avem nevoie şi de poziŃiile minimului şi maximului ? Pentru că la final
aceste două valori trebuie interschimbate între ele, deci noi avem nevoie să ştim pe ce
poziŃii se află (nu uitaŃi că după localizarea acestor elemente, parcurgerea merge mai
departe, până la sfârşitul vectorului !).
Pentru a obŃine un algoritm eficient, cu un număr cât mai mic de operaŃii, vom
actualiza cele două valori extreme în paralel, în cadrul aceluiaşi ciclu. IniŃializăm minimul
elementelor pare cu cea mai mare valoare întreagă pară posibilă, MAXINT-1 (atenŃie, nu cu
MAXINT, pentru că MAXINT are valoarea 32767, care este un număr impar !)
{minpar=MAXINT-1;}. Analog, iniŃializăm maximul elementelor impare cu cea mai mică
valoare întreagă impară posibilă, -MAXINT {maximp=-MAXINT;}.
 În continuare, parcurgem din nou întreg vectorul v. Înt-un ciclu, contorul i va
lua ca valori poziŃiile 0,1,...,n-1 ale elementelor, şi la fiecare pas:
 dacă elementul v[i] este par (v[i]%==0, care se poate scrie mai elegant
"!(v[i]%2)") şi totodată este mai mic decât minimul elementelor pare
existent în acel moment (v[i]<minpar), atunci:

297
– noul minim al elementelor pare devine elementul v[i]
{minpar=v[i];};
– poziŃia pozpar a respectivului minim devine momentan chiar i
{pozpar=i;};
 dacă elementul v[i] este impar (v[i]%2!=0, care se scrie simplu
"v[i]%2") şi totodată este mai mare decât maximul elementelor impare
(v[i]>maximp), atunci:
– noul maxim al elementelor impare devine elementul v[i]
{maximp=v[i];};
– poziŃia pozimp a respectivului maxim devine momentan chiar i
{pozimp=i;};
minpar=MAXINT-1;
maximp=-MAXINT;
for (i=0; i<=n-1; i++)
{
if (!(v[i]%2) && v[i]<minpar)
{
minpar=v[i];
pozpar=i;
}
if (v[i]%2 && v[i]>maximp)
{
maximp=v[i];
pozimp=i;
}
}
 Mai departe, ar trebui interschimbate între ele minimul elementelor pare
minpar (care este de fapt v[pozpar]) cu maximul elementelor impare maximp (adică
v[pozimp]). Numai că există şi posibilitatea ca vectorul v să nu fi avut nici un element
par, sau nici un element impar, caz în care nu avem ce interschimba. În consecinŃă, mai
sunt necesesare nişte testări:
− dacă minpar a rămas cu valoarea iniŃială MAXINT-1, înseamnă că în vector nu
s-a găsit nici un element par, caz în care afişăm un mesaj de avertizare:
− în caz contrar, dacă maximp a rămas cu valoarea iniŃială -MAXINT, rezultă că
vectorul nu conŃine nici un număr impar, deci iarăşi trebuie tipărit un mesaj.
− în sfârşit, dacă nu ne încadrăm în nici unul din cazurile particulare de mai sus,
înseamnă că avem valori concrete pentru minpar şi maximp, care, aşa cum am mai spus,
sunt de fapt elementele v[pozpar] şi v[pozimp].
 Acestea trebuie interschimbate cu "metoda paharelor":
– salvăm v[pozpar] într-o variabilă temporară temp
{v[pozpar]=temp;};
– în locul lui v[pozpar] aducem elementul v[pozimp], prin atribuirea
{v[pozpar]=v[pozimp];};
– în locaŃia lui v[pozimp] memorăm valoarea iniŃială a lui v[pozpar],
pe care o avem salvată în temp {v[pozimp]=temp;}.
 Odată făcută interschimbarea, nu ne rămâne decât să afişăm vectorul în
forma sa finală: într-un ciclu cu i=0,1,...,n-1, la fiecare pas scriem pe
ecran elementul v[i].

298
for (i=0; i<=n-1; i++)
cout << v[i] << " ";

 Programul complet este următorul:

// Bac 2009, II.3 / var 25


#include <iostream.h>
#include <conio.h>
#include <values.h>
void main ()
{
clrscr();
int v[50],i,n,maximp,minpar,pozpar,pozimp,temp;
cout << endl << "Dati numarul de elemente n: ";
cin >> n;
// citeste cele n elemente ale vectorului v
for (i=0; i<=n-1; i++)
{
cout << "Dati elem de pe pozitia " << i << ": ";
cin >> v[i];
}
// minpar = minimul elementelor pare, maximp = maximul elem impare
// pozpar si pozimp = pozitia minimului respectiv maximului in vector
minpar=MAXINT-1;
maximp=-MAXINT;
for (i=0; i<=n-1; i++)
{
// testeaza daca v[i] devine noul minim dintre elem pare, actualizand minpar si pozitia sa
if (!(v[i]%2) && v[i]<minpar)
{
minpar=v[i];
pozpar=i;
}
// testeaza daca v[i] devine noul maxim dintre elem impare, actualizand maximp si pozitia sa
if (v[i]%2 && v[i]>maximp)
{
maximp=v[i];
pozimp=i;
}
}
if (minpar==MAXINT-1)
cout << endl << "Vectorul nu are nici un element par!";
else
if (maximp==-MAXINT)
cout << endl << "Vectorul nu are nici un element impar !";
else
{
// interschimba minimul elementelor pare cu maximul elementelor impare
cout << endl << "Minimul dintre elem. pare este " << minpar;
cout << endl << "Maximul dintre elem. impare este " << maximp;
temp=v[pozpar];
v[pozpar]=v[pozimp];
v[pozimp]=temp;
cout << endl << "Vectorul rezultat dupa interschimbare este: ";

299
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
}
getch();
}

ÎncercaŃi singuri !

► 1. Se citeşte de la tastatură un şir de n numere întregi. ScrieŃi un


program care afişează cea mai mare diferenŃă în modul dintre doi termeni
consecutivi ai şirului.
Exemplu: pentru şirul (3,11,4,20,7,15), programul va afişa valoarea
16 (adică |20-4|).

► 2. RealizaŃi un program care, pentru un şir de n numere întregi citit de


la tastatură, determină cele mai mici două elemente ale şirului. Acestea vor fi
afişate pe un rând de ecran, în ordine descrescătoare, cu un spaŃiu între ele.
Exemplu: pentru şirul (5,-8,11,3,-9,22,47), programul va afişa
valorile -8 şi -9, în această ordine.

Algoritmi de căutare

Algoritm ► Căutarea unei valori într-un vector


Fiind dat un vector v cu n elemente numere întregi, se pune problema de a
stabili dacă o valoare dată x se găseşte sau nu printre elementele vectorului.
Vom folosi o variabilă gasit de tipul int, a cărei valoare va simula
valoarea de adevăr a condiŃiei studiate: 1 dacă x există în vector, respectiv 0 în
caz contrar. Astfel de variabile se întâlnesc frecvent în algoritmi informatici, mulŃi
programatori denumindu-le sugestiv "variabile-semafor".
Folosim metoda reducerii la absurd. Înainte de a începe căutarea,
presupunem că condiŃia testată este falsă, adică valoarea x nu există în vector, deci
iniŃializăm gasit cu 0 (valoare care corespunde stării de "condiŃie falsă").
Parcurgem într-un ciclu poziŃiile elementelor, i=0,1,...,n-1. Pentru fiecare
valoarea a lui i, testăm dacă elementul v[i] este egal cu x: în caz afirmativ
variabila gasit devine 1 (marcând astfel faptul că valoarea x a fost găsită în
vector, pe poziŃia i, adică faptul că acum condiŃia în discuŃie a devenit adevărată).
gasit=0;
for (i=0; i<=n-1; i++)
if (v[i]==x)
gasit=1;

300
Exemplu:
Fie vectorul v=(2,6,-1,4,7), cu n=5 elemente. Urmărim funcŃionarea
algoritmului în cazul în care valoarea căutată este x=-1:
IniŃial găsit=0 şi în ciclu i=0,1,2,3,4;
i=0: v[0]==x ? 2==-1 ? nu
i=1: v[1]==x ? 6==-1 ? nu
i=2: v[2]==x ? -1==-1 ? da ⇒ găsit=1
i=3: v[3]==x ? 4==-1 ? nu
i=4: v[4]==x ? 7==-1 ? nu
Deci la pasul al treilea al ciclului variabila gasit a devenit 1, marcând astfel
faptul că valoarea x=-1 se găseşte pe poziŃia i=2.
Dacă valoarea căutată ar fi fost de exemplu x=5, atunci pentru nici o valoare a lui
i nu s-ar fi îndeplinit condiŃia "v[i]==x" din linia if. În consecinŃă, valoarea variabilei
gasit ar fi rămas cea iniŃială, adică 0.

ObservaŃie:
O greşeală frecvent întâlnită este următoarea variantă a algoritmului de
căutare:
gasit=0;
for (i=0; i<=n-1; i++)
if (v[i]==x)
gasit=1;
else
gasit=0;
Pentru a înŃelege de ce este greşit, să reluăm exemplul anterior: vectorul
v=(2,6,-1,4,7) cu n=5 elemente şi valoarea căutată x=-1.
IniŃial gasit=0 şi în ciclu i=0,1,...,n-1;
i=0: v[1]==x ? 2==-1 ? nu ⇒ execută ramura else ⇒ gasit=0;
i=1: v[1]==x ? 6==-1 ? nu ⇒ execută ramura else ⇒ gasit=0;
i=2: v[2]==x ? -1==-1 ? da ⇒ execută ramura if ⇒ gasit=1;
În continuare valoarea variabilei gasit ar trebui să rămână 1, deoarece această
valoare marchează faptul că x există în vector. Dar iată ce se va întâmpla la pasul următor
al ciclului:
i=3: v[3]==x ? 4==-1 ? nu ⇒ execută ramura else ⇒ gasit=0;
Aşadar variabila gasit a redevenit 0, cu toate că valoarea căutată x există în
vector ("în persoana" lui v[2]). Aceeaşi atribuire gasit=0 se va face şi la ultimul pas,
deci la ieşirea din ciclu valoarea variabilei gasit va fi 0, cu toate că x există în vector.
Care trebuia să fie valoarea variabilei gasit ? Păi 1 dacă x există în vector, respectiv 0 în
caz contrar. Se vede clar că nu e aşa !

301
AplicaŃie R.V.7. IntersecŃia a două mulŃimi
Se dau două mulŃimi cu câte n elemente fiecare, definite ca vectori. Să se
afişeze intersecŃia celor două mulŃimi (elementele lor comune).
Exemplu: pentru mulŃimile A={2,3,5,7,11} şi B={3,7,9,10,12},
memorate în vectorii a şi b cu câte n=5 elemente fiecare, programul va afişa
valorile 3 şi 7, reprezentând elementele comune celor două mulŃimi.

Rezolvare
:
 Declarăm cele două mulŃimi a şi b ca vectori cu maxim 20 de elemente fiecare.
Citim numărul efectiv de elemente al celor doi vectori, în variabila n. Cei doi vectori vor fi
citiŃi "în paralel". Parcurgem într-un ciclu poziŃiile i=0,1,...,n-1 ale elementelor în cei
doi vectori, şi la fiecare pas citim atât elementul a[i], cât şi elementul b[i].
cout << endl << "n=";
cin >> n;
for (i=0; i<=m-1; i++)
{
cout << "a[" << i << "]="; cin >> a[i];
cout << "b[" << i << "]="; cin >> b[i];
}

 Urmează determinarea intersecŃiei propriu-zise a celor două mulŃimi


memorate acum în vectorii a şi b. Parcurgem într-un ciclu poziŃiile i=0,1,...,n-1 ale
elementelor în primul vector şi la fiecare pas:
− verificăm dacă elementul a[i]se găseşte şi în cel de-al doilea vector b, folosind
algoritmul de căutare descris anterior. În urma căutării, variabila booleană gasit
va fi: 1 dacă a[i] se află în vectorul b, respectiv 0 în caz contrar;
for (i=0; i<=n-1; i++)
{
gasit=0;
for (j=0; j<=n-1; j++)
if (b[j]==a[i])
gasit=1;

− testăm variabila gasit şi dacă valoarea sa este 1, înseamnă că a[i] este un


element comun celor doi vectori (adică un element al intersecŃiei mulŃimilor
identificate de către vectori), deci îl afişăm pe patru caractere.
if (gasit)
cout << a[i] << " " ;

# include <iostream.h>
void main ()
{
int i,j,m,n,gasit,a[20],b[20];
cout << endl << "n="; cin >> n;
// citeste intr-un ciclu vectorii a si b, cu m respectiv n elemente
for (i=0; i<=m-1; i++)

302
{
cout << "a[" << i << "]="; cin >> a[i];
cout << "b[" << i << "]="; cin >> b[i];
}
cout << endl;
// parcurgem pozitiile i=0,1,...,n-1 ale elementelor vectorului a
for (i=0; i<=n-1; i++)
{
// la fiecare pas, verificam daca elementul a[i] al vectorului a, se gaseste si in vectorul b
gasit=0;
for (j=0; j<=n-1; j++)
if (b[j]==a[i]) gasit=1;
// daca a[i] se afla si in b, atunci îl afisam ca si element al intersectiei
if (gasit) cout << a[i] << " " ;
}
}

ÎncercaŃi singuri !

►1. ScrieŃi un program care verifică dacă o valoare x se găseşte sau nu


printre cele n elemente ale unui şir dat. În caz afirmativ se va afişa poziŃia /
poziŃiile valorii x în vector, iar în caz contrar se va tipări un mesaj de eroare.
Valorile lui n şi x, precum şi elementele şirului se citesc de la tastatură.
Exemplu: pentru şirul (7,-32,4,7,-11,8,-2,7) şi x=7, programul va
afişa 0, 3 şi 7, adică poziŃiile pe care apare numărul 7 ca element în vector.
►2. Se dau două şiruri de numere întregi, cu m respectiv n elemente
fiecare. ScrieŃi un program care testează dacă elementul maxim al primului şir se
găseşte în cel de-al doilea şir, tipărind mesajul ADEVĂRAT sau FALS.
Exemplu: pentru şirurile (11,-3,18,9) cu m=4 elemente şi
(6,2,0,2,18) cu n=5 elemente, programul va afişa mesajul ADEVĂRAT,
deoarece maximul din primul şir, adică 18, se găseşte şi în cel de-al doilea şir.

►3. Se dau două mulŃimi definite prin intermediul vectorilor u şi v, cu m


respectiv n elemente. Să se memoreze în vectorul w şi apoi să se afişeze diferenŃa
celor două mulŃimi (elementele care se găsesc în prima şi nu se găsesc în cea dea
doua).
Exemplu: pentru mulŃimile A={2,3,5,7,11} şi B={3,7,9,10,12},
memorate în vectorii a şi b cu câte n=5 elemente fiecare, programul va afişa
valorile 3 şi 7, reprezentând elementele comune celor două mulŃimi.

303
Algoritmi de formare a perechilor de elemente într-un vector

AplicaŃie R.V.8. Perechi de elemente într-un şir


Se citeşte de la tastatură un vector v cu n elemente numere întregi. Să se
tipărească toate perechile de elemente cu proprietatea că cel mai mare divizor
comun al elementelor perechii este o valoare dată d.
Exemplu: dacă vectorul este v=(2,3,6,5,8) cu n=5 elemente, atunci:
− pentru d=2, perechile căutate sunt (2,6), (2,8), (6,8);
− pentru d=3, există o singură astfel de pereche, şi anume (3,6).
Rezolvare
:
 Citim mai întâi valoarea lui n, apoi într-un ciclu for citim elementele
vectorului: contorul i va parcurge pe rând poziŃiile 0,1,..,n-1 ale elementelor, şi la
fiecare pas citim un element v[i].
 Pentru a forma perechile de elemente din vector (atenŃie, nu neapărat
consecutive !), vom alcătui perechi cu indicii (poziŃiile) elementelor. Acestea din urmă
sunt perechile distincte de forma (i,j), cu i,j ∈ {0,1,...,n-1}}. Fiecărei perechi de
indici (i,j) îi va corespunde fireşte perechea de elemente (v[i],v[j]).
Să luăm ca exemplu un vector cu n=5 elemente. Perechile distincte pe mulŃimea
de indici {0,1,2,3,4}} sunt
(0,1), (0,2), (0,3), (0,4)
(1,2), (1,3), (1,4)
(2,3), (2,4)
(3,4)
De notat că, dacă am luat perechea (0,1), atunci nu vom mai lua şi perechea
(1,0) pentru că de fapt este acelaşi lucru.
Ca să scriem aceste perechi sub forma (i,j) trebuie să observăm că:
− primul indice al perechii, adică i, evoluează de la 0 la 3, adică pe caz general i
ia valori de la 0 la n-2.
− dacă primul indice i este 0 atunci al doilea indice j ia valorile 1,2,3,4, apoi
dacă i este 1 atunci j ia valorile 2,3,4, etc. Aşadar, pe caz general, j va lua valori de la
i+1 la n-1.

 În două cicluri, cu i=0,1,...,n-2 şi j=i+1,...,n-1, vom forma


perechile de indici (i,j), aşa cum am arătat mai sus. Pentru fiecare pereche (i,j):
♦ Trebuie determinat cel mai mare divizor comun al elementelor corespunzătoare
v[i] şi v[j]. Copiem elementele v[i] şi v[j] în două variabile, a respectiv b. În loc să
calculăm direct c.m.m.d.c. al lui v[i] şi v[j] îl vom afla pe cel al copiilor a şi b. Folosim
algoritmul lui Euclid cu diferenŃe, care a fost prezentat într-un capitol anterior.

304
a=v[i]; b=v[j];
while (a!=b)
if (a>b)
a-=b; // adică a=a-b
else
b-=a; // adică b=b-a
♦ După încheierea ciclului de mai sus, când a şi b au devenit egale, valoarea lor
comună reprezintă c.m.m.d.c. al lui a si b, respectiv c.m.m.d.c. al lui v[i] şi v[j]. Dacă
acesta este egal cu valoarea dată d, înseamnă că am găsit o pereche (v[i],v[j]) care
îndeplineşte proprietatea cerută, deci o afişăm.
 ObservaŃie: Folosirea unor copii ale elementelor v[i] şi v[j] în algoritmul
de calcul al lui c.m.m.d.c. este obligatorie. Ce s-ar fi întâmplat dacă am fi aplicat direct
algoritmul elementelor v[i] şi v[j] ? Acestea s-ar fi modificat prin scăderi repetate. Dar
atât v[i] cât şi v[j] mai pot să facă parte şi din alte perechi, care urmează a fi testate la
paşii următori ai ciclului, deci nu este permisă modificarea valorilor lor !

#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();
int v[50],i,j,n,d,a,b;
cout << endl << "Dati numarul de elemente n: ";
cin >> n;
// citeste cele n elemente ale vectorului v
for (i=0; i<=n-1; i++)
{
cout << "Dati elem de pe pozitia " << i << ": "; cin >> v[i];
}
cout << endl << "d="; cin >> d;
// formam perechile de elemente de forma (v[i],v[j]) cu i=1,...,n-1 si j=i+1,...,n
cout << "Perechile cerute sunt:" << endl;
for (i=0; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
{
// copiem elementele perechii (v[i],v[j]) in variabilele a si b
// determinam cel mai mare divizor comun al lui a si b, respectiv v[i] si v[j]
a=v[i]; b=v[j];
while (a!=b)
if (a>b)
a-=b;
else
b-=a;
// cel mai mare divizor comun al lui v[i] si v[j] este a (sau b)
// verificam daca este egal cu valoarea data d; daca da, afisam perechea (v[i],v[j])
if (a==d)
cout << v[i] << " " << v[j] << endl;
}
getch();
}

305
ÎncercaŃi singuri !
► 1. Se citeşte de la tastatură un vector v cu n elemente numere întregi.
Să se tipărească toate perechile de elemente din vector cu proprietatea că al doilea
element al perechii este divizibil cu suma cifrelor primului.
Exemplu: pentru vectorul v=(235,20,47,30,57,33), perechile cerute
sunt (235,20), (235,30), (20,30), (47,33), (30,33) şi (47,33).
► 2. (Bacalaureat iulie 2009, varianta 64 − enunŃ adaptat)
Se citeşte de la tastatură un tablou unidimensional a=(a0,a1,...,an-1), cu
n elemente numere întregi. ScrieŃi un program care afişează numărul de perechi
(ai,aj), 0≤i<j≤n-1, în care ai este divizor al lui aj, sau aj este divizor al lui ai.
Exemplu: pentru n=5 şi a=(4,8,3,9,4) programul va afişa valoarea 4,
care numără perechile (4,4), (4,8), (8,4) şi (3,9).

Algoritmi de construire a unui vector


pornind de la un set de valori date

AplicaŃie R.V.9. Construirea unui vector


(Bacalaureat, iulie 2009, varianta 49)
ScrieŃi un program care citeşte de la tastatură trei numere naturale a, b şi
n, mai mici decât 30000 fiecare, şi care construieşte în memorie un tablou
unidimensional ale cărui elemente memorează toŃi multiplii lui n din intervalul
închis determinat de a şi b. Programul va afişa pe ecran numerele din tablou în
ordinea crescătoare a lor, separate prin câte un singur spaŃiu, iar dacă nu există
astfel de valori, va afişa pe ecran mesajul NU. Intervalul închis determinat de a şi b
este [a,b] dacă a < b sau [b,a] dacă b ≤ a .
Exemplu: pentru a=31, b=65 şi n=9, tabloul va conŃine valorile: 36 45 54 63
Rezolvare
:
Pentru a genera toŃi multiplii lui n din intervalul [a,b], trebuie mai întâi să-l
localizăm pe primul dintre aceştia. Evident, toŃi multiplii lui n sunt de forma n*x, unde x
este tot un număr natural. Dacă dăm lui x valoarea a/n (câtul împărŃirii întregi a
numărului a la numărul n) prin înmulŃirea acestui x cu n, obŃinem multiplul lui n cel mai
apropiat de a pe axa numerelor (adică cel mai mare multiplu al lui n care este mai mic
decât a). De pildă, pentru valorile n=9, a=31 şi b=65, avem x=a/n=31/9=3 şi multiplul
de forma x*n este 3*9=27. Observăm că următorul multiplu al lui n=9, şi totodată primul
din intervalul [a,b]=[31,65], este 36, adică 4*9. El este tot de forma x*n, doar că de
data asta x este cu 1 mai mare faŃă de valoarea anterioară, adică x=a/n+1. Sintetizând,
306
putem trage concluzia că multiplii lui n din intervalul [a,b] sunt de forma x*n, unde x
pleacă de la valoarea iniŃială a/n+1, iar generarea lor are loc într-un ciclu, care se execută
atâta timp cât multiplul în sine, adică x*n, este mai mic sau egal cu b.
Întrucât cu respectivii multiplii trebuie creat un vector, îi vom adăuga pe rând, în
cadrul ciclului amintit, la sfârşitul unui vector v, iniŃial gol (adică la fiecare pas creăm la
sfârşitul vectorului o ”căsuŃă” nouă, a cărei valoare va fi un astfel de multiplu). Folosim un
contor k, a cărui valoare va reŃine în permanenŃă la ce poziŃie am ajuns în vector în timpul
creării. Evident, valoarea lui k pleacă de la valoarea iniŃială 0, pe ideea că primul multiplu
va fi plasat pe poziŃia 0 în vector (devenind primul element, v[0]). La fiecare pas al
ciclului, generăm un nou multiplu, pe care îl adăugăm la sfârşitul vectorului v, pe poziŃia
dată de valoarea curentă a lui k, după care incrementăm indicele k (pentru a pregăti
”căsuŃa” din vector în care va veni următorul multiplu, la următorul pas).
Dar iată în continuare prezentarea detaliată a algoritmului:
 Mai întâi citim de la tastatură valorile lui a, b şi n. Dacă b≤a , facem
interschimbarea valorilor a şi b între ele, astfel încât valoarea lui a să fie cea mai mică şi
valoarea lui b cea mai mare, deci intervalul să fie de forma [a,b] în loc de [b,a]. Pentru
interschimbare folosim ”metoda paharelor”, prezentată pe larg în capitolul “Elemente de
bază ale limbajului”.
if (b<=a)
{
aux=a; a=b; b=aux;
}
 IniŃializăm variabila x cu valoarea a/n+1, care ne dă primul multiplu de
forma x*n din intervalul [a,b]. De asemenea, iniŃializăm cu 0 variabila k ce reprezintă
poziŃia la care am ajuns cu adăugarea multiplilor în vectorul v (pentru că primul multiplu
va fi primul element v[0] al vectorului). Apoi, pentru a genera toŃi multiplii situaŃi în acest
interval, demarăm un ciclu, care se execută atâta timp cât multiplul de forma x*n este <=b.
La fiecare pas:
– adăugăm efectiv multiplul curent x*n la sfârşitul vectorului, pe poziŃia dată
de valoarea indicelui k, prin simpla atribuire v[k]=x*n;
– incrementăm cu 1 indicele k, pentru a simula crearea unuei noi ”căsuŃe” la
sfârşitul vectorului v (în care va fi memorat următorul multiplu, la următorul
pas al ciclului);
– incrementăm cu 1 valoarea lui x, pentru a pregăti formarea următorului
multiplu de forma x*n, la următorul pas.
x=a/n+1;
k=0;
while (x*n<=b)
{
v[k]=x*n;
k++;
x++;
}
 Acum nu ne-a mai rămas altceva de făcut decât să afişăm vectorul v al
multiplilor, dar pentru asta trebuie să ne dăm seama câte elemente va avea el în final. Ştim
că am plecat de la indicele k=0 şi: la primul pas am memorat primul multiplu în elementul
v[0] iar prin incrementare am făcut k← ←1, apoi la al doilea pas am creat multiplul v[1] şi

307
am făcut k← ←2, la al treilea pas am generat multiplul v[2] iar k a devenit 3, ş.a.m.d. Se
vede foarte clar că valoarea lui k este în permanenŃă egală cu numărul elementelor deja
adăugate în vector. Prin urmare, în final vectorul v va avea k elemente, iar ciclul de afişare
a acestuia este cel cunoscut:
for (i=0; i<=k-1;i++)
cout << v[i] << " ";
 Programul complet este următorul:

// Bac 2009, III.3 / var 49


#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();
int v[50],a,b,i,k,n,x,aux:integer;
cout << " Dati numerele a, b si n, in aceasta ordine: ";
cin >> a >> b >> n;
// daca intervalul este de forma [b,a], atunci interschimba a si b intre ele
// astfel incat intervalul sa devina [a,b]
if (b<=a)
{
aux=a;
a=b;
b=aux;
}
// localizeaza primul multiplu al lui n din intervalul [a,b]
x=a/n+1;
// copiaza in vectorul v, pe pozitiile date de valorile succesive ale lui k, toti multiplii lui n
// din intervalul [a,b]
k=0;
while (x*n<=b)
{
v[k]=x*n;
k++;
x++;
}
// afiseaza vectorul v al multiplilor
cout << "Multiplii lui " << n << " din intervalul [" << a
<< "," << b << "] sunt: ";
for (i=0; i<=k-1;i++)
cout << v[i] << " ";
getch()
}

ÎncercaŃi singuri !
► 1. (Bacalaureat, iulie 2009, varianta 48 − enunŃ adaptat)
ScrieŃi un program care citeşte de la tastatură trei numere naturale nenule
distincte a, b şi n, cu cel mult două cifre fiecare, apoi construieşte în memorie un

308
tablou unidimensional ale cărui elemente memorează, în ordine crescătoare, toate
numerele naturale cuprinse în intervalul închis determinat de a şi b, care nu au
niciun divizor strict mai mare decât 1 comun cu n. Intervalul închis determinat de
a şi b este [a,b] dacă a<b sau [b,a] dacă b≤a .
Exemplu: pentru a=60, b=32 şi n=36 tabloul va conŃine: (35 37 41 43
47 49 53 55 59).

► 2. ScrieŃi un program care citeşte de la tastatură un număr natural n


(n<=1000), apoi construieşte în memorie un tablou unidimensional ale cărui
elemente memorează, în ordine crescătoare, toate numerele naturale mai mici sau
egale cu n care sunt divizibile cu 7 şi au ultima cifră impară.
Exemplu: pentru n=78, tabloul va fi: (7 21 35 49 63 77).

Algoritmi de permutare circulară a unui vector

Algoritm ►Permutarea circulară a unui vector cu o poziŃie la dreapta


Fie un vector v=(v[0],v[1],…,v[n-1]), cu n elemente numere întregi sau
reale. Prin permultarea circulară cu o poziŃie către dreapta a unui astfel de vector,
înŃelegem operaŃia prin care toate elementele, cu exepŃia ultimului, se vor muta cu o poziŃia
mai la dreapta. Cum însă pentru ultimul element v[n-1] nu există noŃiunea de ”poziŃie la
dreapta”, acesta va suferi o rotire circulară în sensul acelor de ceasornic, prin care va
ajunge pe prima poziŃie.
Ilustrăm grafic acest algoritm pentru vectorul v=(2,-3,5,8,-7), cu n=5
elemente.
0 1 2 3 4
v: 2 -3 5 8 -7

Pe acest exemplu, elementele vectorului şi-au schimbat poziŃiile astfel:


→ v[0], v[0]→
v[4]→ →v[1], v[1]→
→v[2], v[2]→
→v[3], v[3]→
→ v[4]. Numai că această
succesiune de mutări nu poate avea loc exact în ordinea prezentată mai sus, pentru că în
felul acesta s-ar pierde nişte elemente. Bunăoară, dacă am încerca să aducem direct
elementul v[4] pe poziŃia 0, prin simpla atribuire v[0]=v[4], numărul care era memorat
în elementul v[0] s-ar pierde definitiv ! De aceea, vom proiecta o altă succesiune de paşi,
pe care o vom descrie în continuare.

Înainte de toate, trebuie să salvăm valoarea iniŃială a elementului de pe ultima


poziŃie într-o variabilă temporară, pe care o vom nota cu temp. De ce facem acest lucru,
vom vedea ceva mai târziu. În figura următoare am ilustrat grafic efectul acestei manevre
pentru vectorul v=(2,-3,5,8,-7), cu n=5 elemente, dat ca exemplu.
0 1 2 3 4
v: 2 -3 5 8 -7 temp
-7
309
Pe caz general, salvarea ultimului element în variabila temp se face prin atribuirea:
temp=v[n-1];

Odată ”pusă la păstrare” valoarea ultimului element v[n-1], putem liniştiŃi să


deplasăm toate celelalte elemente v[0],v[1],…,v[n-2] cu o poziŃie mai la dreapta, dar
facem acest lucru în ordine inversă, de la sfârşit către început. Pe exemplul nostru, pentru
vectorul v=(2,-3,5,8,-7), cu n=5 elemente, această succesiune de deplasări arată
astfel: v[3]→ →v[4] (adică ”v[3] trece în v[4]”), v[2]→ → v[3], v[1]→ →v[2],
v[0]→ → v[1].

La final, vectorul v va arăta ca în figura de mai jos:


0 1 2 3 4
v: 2 2 -3 5 8
temp
-7

Din ilustrarea grafică se vede foarte clar faptul că lanŃul de mutări prezentat mai sus
nu poate avea loc în ordine naturală, de la stânga la dreapta, pentru că s-ar pierde valorile
iniŃiale ale elementelor. De pildă, dacă am începe cu deplasarea v[0]→ →v[1], numărul
memorat în ”căsuŃa” de pe poziŃia 1 s-ar şterge, prin supra-scriere. Pentru a elimina acest
inconvenient, am efectuat lanŃul de mutări în ordine inversă, de la dreapta la stânga. Evident, şi
aşa se produce o supra-scriere: prin primul transfer, v[3]→ →v[4], se şterge valoarea iniŃială a
ultimului element v[4], dar aceasta a fost salvat în variabila temp !

Pe caz general, pentru un vector oarecare v cu n elemente, suita de deplasări ale


elementelor cu o poziŃie mai la dreapta arată astfel:
v[n-2]→ →v[n-1] (vom citi ”v[n-1] trece în v[n]”)
→v[n-2]
v[n-3]→
…………………
→ v[2]
v[1]→
→ v[1]
v[0]→
Fără prea mare efort, putem proiecta un ciclu care să înglobeze deplasările. La
fiecare pas, un element v[i] trece pe poziŃia următoare, devenind astfel elementul
v[i+1], adică v[i]→ →v[i+1], iar contorul i va parcurge pe rând valorile
n-2,n-3,…,1,0.
→ v[i+1]”, adică ”v[i] trece în
AtenŃie însă, operaŃiunea codificată prin ”v[i]→
v[i+1]”, se traduce prin atribuirea {v[i+1]=v[i];} (elementul de pe poziŃia i+1
primeşte valoarea celui de pe poziŃia i). Acum putem scrie secvenŃa de program completă
pentru acest lanŃ de deplasări:
for (i=n-2; i>=0; i--)
v[i+1]=v[i];

Aşadar, până acum am salvat ultimul element v[n-1] în variabila temp, şi am


multat toate celelalte n-1 elemente cu o poziŃie mai la dreapta. Nu ne rămâne altceva de
făcut decât să aducem pe prima poziŃie valoarea care a fost iniŃial memorată în ultimul

310
element, şi pe care evident o luăm din temp. Iată cum arată operaŃiunea pentru exemplul
folosit de-a lungul acestei expuneri:

0 1 2 3 4
v: 2 2 -3 5 8
temp
-7

0 1 2 3 4
v: -7 2 -3 5 8

Pe caz general, atribuirea necesară este: v[0]=temp;

Sintetizând cele trei etape prin care am trecut, algoritmul complet pentru permutarea
circulară cu o poziŃie mai la dreapta a unui vector v=(v[0],v[1],…,v[n-1]) cu n
elemente, este următorul:

{salvarea ultimului element v[n] în variabila temp}


temp=v[n-1];
{deplasarea primelor n-1 elemente cu o poziŃie mai la dreapta}
for (i=n-2; i>=0; i--)
v[i+1]=v[i];
{aducerea pe prima poziŃie a valorii care fusese iniŃial în v[n], luată din temp}
v[0]=temp;

AplicaŃie R.V.10. Permutări circulare cu k poziŃii într-un vector


(Bacalaureat, iulie 2009, varianta 37)
Se citesc de la tastatură numerele naturale nenule n şi k (k ≤ n ≤ 1 0 0 ) şi un
tablou unidimensional cu n elemente numere întregi, fiecare având cel mult patru
cifre. ScrieŃi un program care modifică tabloul, permutând circular cu k poziŃii
spre stânga elementele acestuia, şi afişează pe ecran, pe o singură linie, separate
prin câte un spaŃiu, componentele tabloului obŃinut.
Exemplu: dacă n=4, k=3 şi tabloul v=(1,2,3,4), atunci se vor afişa în
ordine elementele: 4 1 2 3.

Rezolvare
:
 După citirea numărului real de elemente n şi a numărului de permutări k,
trecem la citirea elementelor vectorului (tabloului unidimensional) v, cu algoritmul deja
binecunoscut: într-un ciclu, parcurgem poziŃiile i=0,1,...,n-1 ale elementelor, şi la
fiecare pas citim elementul v[i].

311
 A permuta circular vectorul v cu k poziŃii la stânga, înseamnă de fapt a
efectua k permutări cu câte o poziŃie. Prin urmare, avem nevoie de un ciclu în care
contorul p va număra permutările, de la 1 la k, şi în care la fiecare pas facem o
permutare la stânga (cea cu numărul de ordine p). Algorimul prin care permutăm un
vector v cu o poziŃie la stânga este foarte asemănător cu cel al permutării la dreapta,
prezentat pe larg mai sus:
 salvăm primul element v[0] într-o variabilă temporară temp
{temp:=v[0];};
 mutăm cu o poziŃie mai la stânga toate elementele începând cu al doilea; în
acest scop, vom parcurge într-un alt ciclu poziŃiile i=1,2,...,n-1 ale
elementelor ce vor fi deplasate, şi la fiecare pas aducem elementul v[i] pe
poziŃia anterioară i-1;
for (i=1; i<=n-1; i++)
v[i-1]=v[i];
 aducem pe ultima poziŃie primul element, care a fost salvat în variabila
temp, simulând astfel o rotire a acestuia în sens invers acelor de ceasornic
{v[n-1]:=temp;};
 afişăm vectorul rezultat în urma permutării cu numărul de ordine dat de
valoarea lui p de la pasul respectiv (deşi enunŃul cerea doar afişarea
vectorului obŃinut după k permutări, am preferat să tipărim şi rezultatele
intermediare, pentru o mai mare claritate a evoluŃiei algoritmului).

#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();
int v[50],i,n,p,k,temp;
cout << endl << "Dati numarul de elemente n: ";
cin >> n;
// citeste cele n elemente ale vectorului v
for (i=0; i<=n-1; i++)
{
cout << "Dati elem de pe pozitia " << i << ": ";
cin >> v[i];
}
cout << endl << "Dati numarul de permutari k=";
cin >> k;
for (p=1; p<=k; p++) // contorul p numara permutarile la stanga, de la 1 la k
{
// la fiecare pas face o permutare si afiseaza vectorul rezultat
// salveaza primul element in variabila temp
temp=v[0];
// muta cu o pozitie mai la stanga elementele de pe pozitiile 1,2,...,n-1
for (i=1; i<=n-1; i++)
v[i-1]=v[i];
// aduce pe ultima pozitie primul element, salvat in temp
v[n-1]=temp;
// afiseaza permutarea cu numarul de ordine dat de valoarea curenta a lui p

312
cout << endl << "Permutarea " << p << ": ";
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
cout << endl;
}
getch();
}

ÎncercaŃi singuri !
► 1. Se citesc de la tastatură numerele naturale nenule n şi k (k≤n≤100 ),
apoi un vector cu n elemente numere întregi, fiecare având cel mult patru cifre.
ScrieŃi un program care permută de k ori cu câte o poziŃie mai la dreapta, şi, dintre
toate permutările obŃinute, le afişează doar pe acelea care au valorile în ordine
crescătoare, de la stânga la dreapta
Exemplu: dacă n=4, k=3 şi vectorul v=(3,4,1,2), atunci permutările
generate vor fi (2,3,4,1), (1,2,3,4) şi (4,1,2,3), iar singura cu elementele
în ordine crescătoare, care trebuie afişată, este (1,2,3,4).

Algoritmi de sortare şi interclasare

Algoritm ►Sortarea unui vector prin metoda interschimbărilor directe

Sortarea prin interschimbare directă

Această tehnică de sortare vă este cunoscută încă din clasa a IX-a, motiv pentru care o
reamintim foarte sumar. Considerând un şi memorat în vectorul x=(x[0],x[1],...,
x[n-1]), algoritmul de sortare prin interschimbare directă este următorul:

Fiecare din elementele x[0],x[1],...,x[n-2] va juca pe rând rolul unui aşa-


numit pivot. Parcurgem pivoŃii într-un ciclu în care contorul i ia pe rând valorile
0,1,...,n-2 şi la fiecare pas al ciclului:
− Comparăm pivotul x[i] cu toate elementele aflate după el, x[i+1],...,
x[n-1]. Parcurgem poziŃiile acestor elemente într-un alt ciclu cu contorul j=i+1,...,n-1,
şi, pentru fiecare element x[j], dacă este mai mic decât pivotul x[i], atunci interschimbăm
x[j] cu x[i] (pentru că, dacă x[j] este mai mic decât x[i], atunci x[j] trebuie să fie
înaintea lui x[i] în vectorul sortat).
Interschimbarea lui x[i] cu x[j] se face prin metoda paharelor: salvăm mai întâi x[i]
într-o variabilă temp, {temp=x[i];}, apoi aducem în x[i] valoarea lui x[j] {x[i]=x[j];} şi în
sfârşit, memorăm în x[j] valoarea iniŃială a lui x[i] luată din temp {x[j]=temp;}.
Când un pivot x[i] şi-a încheiat rolul, partea din vector până la elementul x[i]
inclusiv, este sortată crescător. După ce toate elementele x[0],x[1],..., x[n-2] au
fost pivoŃi, vectorul este în întregime sortat.
313
for (i=0; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
if (x[j]<x[i])
{
temp=x[i]; x[i]=x[j]; x[j]=temp;
}

Să urmărim funcŃionarea algoritmului pentru vectorul x=(4,-3,5,-6,1)


cu n=5 elemente:
0 1 2 3 4
4 -3 5 -6 1 vectorul de dinaintea execuŃiei secvenŃei
♦ i=0, x[0] pivot
0 1 2 3 4
• j=1, x[1]< < 4 ? da ⇒ x[1]←
< x[0] ? -3< ← → x[0] -3 4 5 -6 1

• j=2, x[2]<
< x[0] ? 5<
< -3 ? nu
0 1 2 3 4
• j=3, x[3]< <-3 ? da ⇒ x[3]←
<x[0] ? -6< ←→x[0] -6 4 5 -3 1

• j=4, x[4]<
< x[0] ? 1<
< -6 ? nu

♦ i=1, x[1] pivot

• j=2, x[2]<
< x[1] ? 5<
< 4 ? nu
0 1 2 3 4
• j=3, x[3]< < 4 ? da ⇒ x[3]←
< x[1] ? -3< ← → x[1] -6 -3 5 4 1

• j=4, x[4]<
< x[1] ? 1<
< -3 ? nu

♦ i=2, x[2] pivot


0 1 2 3 4
• j=3, x[3]< < 5 ? da ⇒ x[3]←
< x[2] ? 4< ← → x[2] -6 -3 4 5 1
0 1 2 3 4
• j=4, x[4]< < 4 ? da ⇒ x[4]←
< x[2] ? 1< ← → x[2] -6 -3 1 5 4

♦ i=3, x[3] pivot


0 1 2 3 4
• j=4, x[4]< < 5 ? da ⇒ x[4]←
< x[3] ? 4< ← → x[3] -6 -3 1 4 5

Vectorul sortat x=(x[0],x[1],...,x[4]) va conŃine elementele


(-6,-3,1,4,5), în această ordine.

Algoritm ►Sortarea unui vector prin metoda bulelor


Ideea care stă la baza metodei constă în formarea de perechi de elemente
succesive în vectorul dat. Elementele fiecărei perechi vor fi ordonate crescător, iar
prin mai multe parcurgeri ale vectorului se va obŃine un şir în întregime sortat.
Desigur, deocamdată exprimarea este generală astfel încât vom ilustra metoda
referindu-ne la următorul şir de elemente memorate într-un vector x.

314
Exemplu: 0 1 2 3
3 -4 8 -5

La prima parcurgere formăm toate perechile posibile de elemente


consecutive: (x[0],x[1]),(x[1],x[2]),...,(x[n-2],x[n-1]). Pe caz
general, ele sunt de forma (x[i],x[i+1]), cu i=0,1,...,n-2.
În exemplul nostru aceste perechi sunt: (x[0],x[1]), (x[1],x[2]), (x[2],x[3]).
Ordonăm prin comparaŃie şi eventuală interschimbare fiecare pereche
(x[i],x[i+1]). Să urmărim această parcurgere pe exemplul dat:
• i=0,1,..,n-2, deci i=0,1,2; formăm perechile (x[i],x[i+1]) şi pentru
fiecare testăm dacă x[i]<x[i+1] , iar în caz contrar (în speŃă dacă x[i]>x[i+1])
interschimbăm între ele x[i] cu x[i+1].
0 1 2 3
3 -4 8 -5
i=0 ⇒ perechea (x[0],x[1]); x[0]<x[1] ? 3<-4 ? nu ⇒ x[0] ↔ x[1]
0 1 2 3
-4 3 8 -5
i=1 ⇒ perechea (x[1],x[2]); x[1]<x[2] ? 3<8 ? da
i=2 ⇒ perechea (x[3],x[4]); x[2]<x[3] ? 8<-5 ? nu ⇒ x[2] ↔ x[3]
0 1 2 3
-4 3 -5 8

Observăm că după această primă parcurgere vectorul nu este sortat, dar pe


ultima poziŃie a ajuns elementul 8, care este cel mai mare din tot vectorul. În
continuare va trebui să mai facem o parcurgere, într-o manieră similară, în urma
căreia pe penultima poziŃie va fi adus elementul cel mai mare dintre cele rămase,
adică al doilea ca mărime din vector. Analog, după a treia parcurgere vom aduce
pe ante-penultima poziŃie al treilea element ca mărime, ş.a.m.d. Acest mod de
lucru a dat denumirea metodei: aşa cum bulele de aer dintr-un vas cu apă se ridică
la suprafaŃă, la fel elementele "migrează" către capătul din dreapta al vectorului, în
ordinea mărimilor lor.
Credem că procedeul va fi complet înŃeles după descrierea detaliată a celei
de-a doua parcugeri. Desigur, a doua parcurgere se va face numai până la
penultimul element deoarece ultimul este maximul dintre elementele vectorului
(găsindu-şi deja locul pe care trebuie să-l ocupe în vectorul sortat).
• Formăm perechile (x[i],x[i+1]), cu i=0,1,...,n-3, adică i=0,1.
i=0 ⇒ perechea (x[0],x[1]); x[0]<x[1] ? -4<3 ? da
i=1 ⇒ perechea (x[1],x[2]); x[1]<x[2] ? 3<-5 ? nu ⇒ x[1]↔ x[2]
0 1 2 3
-4 -5 3 8

315
În sfârşit, la a treia parcurgere, mergem doar până la ante-penultimul
element, deoarece ultimele două elemente şi-au găsit poziŃiile în urma
parcurgerilor de până acum.
• Avem deci perechile (x[i],x[i+1]), cu i=0,1,...,n-4, adică i=0.
i=0 ⇒ perechea (x[0],x[1]); x[0]<x[1] ? -4<-5 ? nu ⇒ x[0] ↔ x[1]
0 1 2 3
-5 -4 3 8

Acum vectorul este sortat crescător.


În continuare trecem la conceperea unui program care realizează sortarea
unui vector folosind metoda bulelor.
În primul rând vom observa că fiecare parcurgere se face într-un vector
"mai scurt" cu o poziŃie. Acest fapt sugerează utilizarea unui ciclu descrescător.
Notând cu f poziŃia finală, până la care parcurgem vectorul, observăm că: la prima
parcurgere mergem până la sfârşitul vectorului deci f=n-1, la a doua parcurgere
ne oprim la penultimul element deci f=n-2, ş.a.m.d., ultima parcurgere "vizitând"
numai primele două elemente (f=1). Proiectând un ciclu for care să repete
parcurgerile, poziŃia finală f evoluează descrescător de la n-1 la 1.
 La fiecare pas al acestui ciclu are loc o parcurgere a vectorului (x[0],
x[1],...x[f-1]), care se face într-un alt ciclu, ca în ilustrările
anterioare: contorul i ia valori de la 0 la f-1 şi la fiecare pas formăm
perechi de elemente succesive (x[i],x[i+1]), pe care le ordonăm
crescător:
for (i=0; i<=f-1; i++)
if (x[i]>x[i+1])
{
t=x[i]; x[i]=x[i+1]; x[i+1]=t;
}

Programul complet este prezentat în continuare:


# include <iostream.h>
# include <conio.h>
int x[20],i,n,f,t;
void main ()
{
// citeste numarul de elemente n si elementele vectorului x
cout << "\n n="; cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "x[" << i << "]="; cin >> x[i];
}
// sorteaza crescator vectorul prin metoda bulelor
for (f=n-1; f>=1; f--)

316
for (i=0; i<=f-1; i++)
if (x[i]>x[i+1])
{
t=x[i]; x[i]=x[i+1]; x[i+1]=t;
}
// afiseaza vectorul sortat
cout << "\n Sirul sortat este: \n";
for (i=0; i<=n-1; i++) cout << x[i] << " ";
getch();
}

Acest program poate fi optimizat ! Pentru aceasta observăm că este posibil


ca la o anumită parcurgere să nu se facă nici o interschimbare ceea ce nu spune
altceva decât faptul că vectorul este deja sortat. Cu alte cuvinte este posibil ca
ordinea finală să fie obŃinută înainte de ultima parcurgere.
Pentru a vă convinge de acest lucru, urmăriŃi paşii algoritmului pe vectorul
x=(2,3,-5,9,4), şi veŃi constata că:
− după prima parcurgere până la poziŃia f=n-1=4 obŃineŃi vectorul (2,-5,3,4,9);
− după a doua parcurgere până la poziŃia f=3 rezultă vectorul deja sortat (-5,2,3,4,9);
ObservaŃia poate fi materializată astfel:
Parcurgerea prin variabila f se va face printr-un ciclu do-while având
drept condiŃie finală faptul că nu s-a facut nici o interschimbare. Vom folosi aşadar
o variabilă logică gata care, la fiecare parcurgere, va avea valoarea:
− 0 dacă s-a efectuat cel puŃin o interschimbare (adică a fost detectată o
situaŃie în care ordinea naturală este falsă !);
− 1 dacă în cadrul parcurgerii respective nu s-au mai efectuat
interschimbări (algoritmul este gata, după cum sugerează numele variabilei !).
Fireşte contorul f va evolua în ciclul do-while tot de la n-1 la 1.
IniŃializăm f cu prima valoare n-1. La fiecare pas se execută o parcurgere astfel:
− iniŃializăm variabila gata cu 1, presupunând că în cadrul parcurgerii
respective nu vor fi interschimbări;
− facem parcurgerea propriu-zisă: formăm într-un ciclu for perechi de forma
(x[i],x[i+1]), cu i=0,1,...,f-1 (aşa cum s-a arătat anterior); pentru fiecare
astfel de pereche, dacă x[i]>x[i+1], atunci interschimbăm x[i] cu x[i+1] şi
marcăm faptul că s-a făcut o interschimbare dând valoarea 0 variabilei gata.
f=n-1;
do
{
gata=1;
for (i=0; i<=f-1; i++)
if (x[i]>x[i+1])
{
gata=0; t=x[i]; x[i]=x[i+1]; x[i+1]=t;
}
f--;
} while (!gata);

317
În linia while se testează valoarea variabilei gata şi în funcŃie de aceasta
se decide dacă se va relua ciclul cu o nouă parcurgere:
– dacă la parcurgerea făcută am avut cel puŃin o interschimbare,
variabila gata a devenit 0;
– dacă nu a existat nici o interschimbare, atunci gata a rămas 1 şi în
consecinŃă, nemaifiind posibile interschimbări, se abandonează ciclul.
Acum putem scrie algoritmul de sortare complet:
# include <iostream.h>
# include <conio.h>
int x[20],i,n,f,t,gata;
void main ()
{
clrscr();
// citeste numarul de elemente n si elementele vectorului x
cout << "\n n=";
cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "x[" << i << "]="; cin >> x[i];
}
// sorteaza crescator vectorul prin metoda bulelor
f=n-1;
do
{
gata=1;
for (i=0; i<=f-1; i++)
if (x[i]>x[i+1])
{
gata=0; t=x[i]; x[i]=x[i+1]; x[i+1]=t;
}
f--;
} while (!gata);
// afiseaza vectorul sortat
cout << "\n Sirul sortat este: \n";
for (i=0; i<=n-1; i++) cout << x[i] << " ";
getch();
}

Algoritm ►Interclasarea a doi vectori sortaŃi


Se pune problema ca, pornind de la doi vectori x şi y ordonaŃi crescător, să
formăm un vector z care să conŃină elementele celor doi vectori daŃi tot în ordine
crescătoare. De exemplu:
0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2 3 4 5 6 6 7

318
Vectorul z va fi completat pas cu pas. Notăm prin k poziŃia ultimului
element în z; iniŃial k=0 (evident primul element care va fi adăugat în z va veni pe
poziŃia 0). Folosim doi indici cu care parcurgem vectorii daŃi, respectiv i pentru x
şi j pentru y. Evident că iniŃial i=0 şi j=0.
Într-un ciclu, la fiecare pas, comparăm un element x[i], cu un element
y[j]. Cel mai mic dintre aceste două elemente va fi adăugat la sfârşitul vectorului
z, iar în vectorul din care provine (x sau y) vom muta indicele (i sau j) cu o
poziŃie mai la dreapta. Concret:
− dacă x[i]<=y[j] atunci adăugăm pe x[i] la sfârşitul vectorului z pe
poziŃia dată de valoarea curentă a lui k (prin atribuirea z[k]=x[i]), apoi creăm o
nouă poziŃie la sfârşitul lui z prin incrementarea lui k, şi în sfârşit mutăm pe i prin
atribuirea i=i+1;
− în caz contrar adăugăm pe y[j] la sfârşitul vectorului z (z[k]=y[j]),
creăm noua poziŃie k prin incrementarea k++ apoi mutăm pe j prin atribuirea j=j+1;
Ciclul se repetă până când unul dintre indici, i sau j, ajunge la sfârşitul
vectorului său (cât timp i<=m-1 şi j<=n-1).
i=j=k=0;
while (i<=m-1 && j<=n-1)
if (x[i]<y[j])
{
z[k]=x[i]; k++; i++;
}
else
{
z[k]=y[j];
k++;
j++;
}
Vom urmări câŃiva paşi ai algoritmului descris pentru vectorii x şi y de mai sus.
Pentru început i=0, j=0, k=0:

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0

y[0]<=x[0]⇒ z[0]←
← y[0], „avansează” j=1, şi k=1, iar i rămâne 0;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0

x[0]<=y[1] ⇒ z[1]←
←x[0], „avansează” i=1, şi k=2, iar j rămâne 1;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1

y[1]<=x[1] ⇒ z[2]←
←y[1], „avansează” j=2, şi k=3, iar i rămâne 1;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2

319
x[1]<=y[2] ⇒ z[3]←
←x[1], „avansează” i=2, şi k=4, iar j rămâne 2;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2 3

x[2]<=y[2] ⇒ z[4]←
←x[2], „avansează” i=3, şi k=5, iar j rămâne 2;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2 3 4

y[2]<=x[3] ⇒ z[5]←
←y[2], „avansează” j=3, şi k=6, iar i rămâne 3;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2 3 4 5

x[3]<=y[3] ⇒ z[6]←
←x[3], „avansează” i=4, şi k=7, iar j rămâne 3;

0 1 2 3 0 1 2 3 4 0 1 2 3 4 5 6 7 8
x: y: z:
1 3 4 6 0 2 5 6 7 0 1 2 3 4 5 6

Am ajuns la sfârşitul vectorului x, dar observăm că în vectorul y au rămas


ne-parcurse elementele y[4] şi y[5]. Pe de altă parte, se poate observa cu uşurinŃă faptul
că ultima valoare la care a ajuns variabila k reprezintă numărul elementelor adăugate
până în acest moment în vectorul z (7 elemente în exemplul nostru).
Aşadar, după operaŃia descrisă până acum, într-unul din vectorii u şi v au
rămas nişte elemente ne-parcurse. Acestea sunt ordonate crescător, deci pot fi
adăugate "in corpore" la sfârşitul vectorului z. Ne putem da seama care este
vectorul ne-parcurs în totalitate urmărind valorile la care au ajuns contoarele i şi
j: dacă i<=m au rămas ne-parcurse elemente în vectorul x, iar dacă j<=n este
incompletă parcurgerea lui y. În final, porŃiunea de vector ne-parcursă se copiază
la sfârştul vectorului z.
if (i<=m-1)
while (i<=m-1) { z[k]=x[i]; k++; i++; }
if (j<=n-1)
while (j<=n-1) { z[k]=y[j]; k++; j++; }

Acum ultima valoare a lui k reprezintă numărul final de elemente ale


vectorului z după încheierea algoritmului. Prin urmare, poziŃiile elementelor în
vectorul z pot fi parcurse cu un ciclu în care contorul va lua valorile 0,1,...k-1.
Programul propriu-zis începe prin citirea numărului de elemente din cei
doi vectori, m respectiv n. La citirea vectorului x cu m elemente, asigurăm
introducerea acestora în ordine crescătoare, deci fiecare element x[i] citit trebuie
validat, în sensul că este necesar să fie mai mare decât elementul precedent
x[i-1]. Analog se citeşte vectorul y cu n elemente.
În continuare interclasăm vectorii x şi y. În vectorul z vom avea rezultatul
interclasării, iar variabila k reŃine numărul de elemente al vectorului z.
Programul se încheie cu afişarea vectorului z.

320
# include <iostream.h>
# include <conio.h>
int x[30],y[30],z[30],i,j,k,m,n;
void main ()
{
cout << "\n m="; cin >> m; // citeste m si primul element al vectorului x
cout << "\nx[0]="; cin >> x[0];
// citeste elementele vectorului x incepand cu al doilea, in ordine crescatoare
for (i=1; i<=m-1; i++)
do
{
cout << "x[" << i << "]="; cin >> x[i];
} while (x[i]<=x[i-1]);
cout << "\n n="; cin >> n; // citeste n si primul element al vectorului y
cout << "\ny[0]="; cin >> y[0];
// citeste elementele vectorului y incepand cu al doilea
for (i=1; i<=n-1; i++)
do
{
cout << "y[" << i << "]="; cin >> y[i];
} while (y[i]<=y[i-1]);
// interclaseaza vectorii x si y
i=j=k=0;
while (i<=m-1 && j<=n-1)
if (x[i]<y[j])
{ z[k]=x[i]; k++; i++; }
else
{ z[k]=y[j]; k++; j++; }
// adauga elementele ramase neparcurse intr-unul din vectori
if (i<=m-1)
while (i<=m-1) { z[k]=x[i]; k++; i++; }
if (j<=n-1)
while (j<=n-1) { z[k]=y[j]; k++; j++; }
// afiseaza vectorul rezultat dupa interclasare
cout << "\n Vectorul sortat este: \n";
for (i=0; i<=k-1; i++) cout << z[i] << " ";
}

ÎncercaŃi singuri !
►1. Se dă un vector v cu n elemente numere întregi. ScrieŃi câte un
program care ordonează descrescător vectorul, folosind:
a) algoritmul de sortare prin interschimbare directă;
b) algoritmul de sortare prin metoda bulelor.
► 2. Se citesc de la tastatură doi vectori u şi v cu m respectiv n elemente,
sortaŃi descrescător. Folosind algoritmul de interclasare, să se formeze un vector
w, conŃinând elementele celor doi vectori aranjate în ordine descrescătoare.

321
► 3. (Bacalaureat iulie 2008, varianta 59)
ScrieŃi un program care citeşte un număr natural nenul n (n<100) şi un şir
de n numere naturale nenule cu cel mult patru cifre fiecare, apoi afişează pe ecran
şirul ordonat crescător în funcŃie de suma cifrelor corespunzătoare fiecărui termen
al său. Dacă două numere au aceeaşi sumă a cifrelor, se va afişa mai întâi cel mai
mic dintre ele.
Exemplu: pentru n=5 şi şirul (701,1000,44,99,143) se va afişa şirul
(1000,44,143,701,99).

AŃi înŃeles ? Întrebări cu răspuns scurt


►1. (Bacalaureat iulie 2008, varianta 37)
În secvenŃa de program următoare, elementele vectorului a au valorile
(1,2,3,4,5), în acestă ordine. Care va fi rezultatul afişat în urma executării secvenŃei ?
for(i=0; i<=4; i++)
{
s=0;
for (j=0; j<=i; j++)
s+=a[i];
cout << s;
}

►2. (Bacalaureat iulie 2008, varianta 36)


Se consideră tabloul unidimensional a=(0,1,3,2). IndicaŃi tabloul unidimensional
b, astfel încât pentru orice i (0<=i<4) să existe relaŃia a[b[i]]=b[a[i]].
a) (2,1,0,3) b) (3,1,0,2)
c) (2,3,0,1) d) (1,0,2,3)
Fie v un vector cu n=9 componente numere întregi. Următoarele trei probleme se
referă la algoritmul de mai jos:
← 0;
s←
←0,1,...,n-1) execută
pentru(i←
dacă(i%2=1) atunci
s←←s+v[i];
scrie s;

►3. (Bacalaureat iulie 2008, varianta 66)


Ce se va afişa în urma execuŃiei secvenŃei dacă elementele vectorului v sunt, în
ordine, (14,3,7,0,-4,3,10,15,7).
►4. TranscrieŃi în limbajul de programare Pascal structura de selecŃie prezentă în
cadrul algoritmului dat.
►5. ModificaŃi o singură linie în cadrul algoritmului de mai sus, astfel încât elementele
vectorului să fie parcursă în ordine inversă, iar efectul execuŃiei algoritmului să fie acelaşi.

322
►6. În urma execuŃiei secvenŃei de program ok=0;
alăturate, variabila ok, de tip întreg cu sens logic, ar trebui for (i=0; i<n; i++)
să aibă valoarea: 1 dacă x se găseşte printre cele n elemente if (v[i]==x)
ok=1;
ale vectorului v, respectiv 0 în caz contrar. Algoritmul este
else
corect ? JustificaŃi răspunsul, exemplificând pentru x=8 şi ok=0;
vectorul v=(6,3,8,5,1) cu n=5 elemente.

Fie v un vector cu n elemente de tip întreg, unde n este un număr natural nenul.
Următoarele două probleme se referă la secvenŃa de program de mai jos:
i=0;
while (i<n)
{
v[i]=i*i;
i++;
}

►7. (Bacalaureat iulie 2008, varianta 69)


Câte atribuiri se execută în total în timpul rulării secvenŃei de program date.
►8. Pentru n=4, care vor fi elementele vectorului v după execuŃia secvenŃei ?

►9. Care dintre secvenŃele de program de mai jos calculează corect suma
primelor n elemente ale unui vector, S=v[0]+v[1]+...+v[n-1]?
a) b) c)
S=0; S=0; i=0; S=0; i=0;
for (i=0;i<n;i++) while (i<=n) do
S+=v[i]; { {
S+=v[i]; S+=v[i];
i++; i++;
} } while (i<n-1);
d) nici una dintre variantele anterioare

►10. (Bacalaureat iulie 2000, variantele 1 şi 6)


Care dintre următoarele secvenŃe de instrucŃiuni determină în variabila reală max
cel mai mare element dintr-un şir de n numere reale a1,a2,...,an?
a) max=0; b) max=a[1];
for (i=1;i<=n;i++) for (i=2;i<n;i++)
if (max<a[i]) max=a[i]; if (max<a[i]) max=a[i];

c) max=a[1]; d) max=a[n];
for (i=2;i<=n;i++) for (i=2;i<=n;i++)
if (max>a[i]) max=a[i]; if (max<a[i-1]) max=a[i-1];

►11. (Bacalaureat iulie 2008, varianta 25)


Se consideră două tablouri unidimensionale a şi b, cu elementele
a=(1,3,5,9,10), respectiv b=(2,4,6,7). Care vor fi elementele tabloului rezultat în
urma interclasării tablourilor a şi b.

323
►12. (Bacalaureat iulie 2008, varianta 47)
Câte interschimbări trebuie efectuate în total pentru a sorta crescător prin metoda
bulelor un vector cu elementele (10,9,8,7,6,5,4,3,2,1,0) ?
►13. Fie secvenŃa de program for (p=1,k=1;k<n;k++)
alăturată, în care toate variabilele sunt de tip if (v[k]==v[k-1]) p=0;
întreg. cout << p;
SecvenŃa afişează 0 dacă:
a) Toate elementele sunt distincte două câte două.
b) Toate elementele sunt egale.
c) Există două elemente consecutive distincte.
d) Există numai două elemente consecutive egale.

►14. Care dintre afirmaŃiile de mai jos nu sunt adevărate pentru secvenŃa de
program următoare ?
p=0;
for (k=1;k<6;k++)
if (v[k]>v[p]) p=k;
printf("%d",p);

a) Ciclul for are patru paşi.


b) Dacă elementele vectorului (v[0],v[1],...,v[5]) sunt 5,4,-11,9,-12,1, atunci
programul afişează valoarea 4.
c) Dacă elementele vectorului (v[0],v[1],...,v[5]) sunt 3,-2,8,6,11,4, atunci
programul afişează valoarea 4.
d) Indiferent care ar fi elementele vectorului, secvenŃa dată nu poate afişa valoarea 0.

►15. În secvenŃa alăturată, v este un int i,v[6],S;


vector cu cinci elemente numere întregi, iar for(S=5,i=1;i<6;
S-=v[i]-v[i-1],i++);
celelalte variabile sunt de tipul întreg.
cout << S;

Ultima valoare afişată va fi 0 dacă:


a) Primul element al vectorului este 5, iar celelalte elemente sunt nule.
b) Ultimul element al vectorului este 6, iar celelalte elemente sunt nule.
c) Fiecare element începând cu al doilea este mai mare cu 1 decât elementul aflat
înaintea lui în vector.
d) Fiecare element începând cu al doilea este mai mic cu 1 decât elementul aflat înaintea
lui în vector.
e) Toate elementele vectorului au valoarea 5.

►16. Se consideră vectorii u şi v, cu m, k=0;


respectiv, n elemente de tip întreg. for(i=0;i<m;i++)
for(j=0;j<n;j++)
PrecizaŃi care dintre situaŃiile descrise mai if (u[i]==v[j])
jos nu sunt adevărate în urma execuŃiei secvenŃei w[k++]=u[i];
alăturate.

324
a) Pentru vectorii u=(2,-3,1) cu m=3 elemente şi v=(-3,4,2,5) cu n=4 elemente, se va
obŃine în urma execuŃiei secvenŃei vectorul w=(2,-3).
b) Pentru vectorii u=(3,7,3) cu m=3 elemente şi v=(2,7,2,3) cu n=4 elemente, se va
obŃine în urma execuŃiei secvenŃei vectorul w=(3,7).
c) Pentru vectorii u=(1,-2,6) cu m=3 elemente şi v=(3,4,8,9) cu n=4 elemente, la finele
execuŃiei secvenŃei date vectorul w nu va avea nici un element.
d) Dacă înaintea execuŃiei secvenŃei unul dintre vectorii u, v nu conŃine nici un element, atunci
după execuŃia secvenŃei vectorul w nu va conŃine nici un element.

► 17. Fie secvenŃele de program A şi B de mai jos, în care v este un vector cu


elemente întregi, iar x1 şi x2 sunt constante întregi:
{ SecvenŃa A } { SecvenŃa B }
for (i=1; i<=11; i++) for (i=1; i<=11; i++)
v[i]=i; v[i]=i;
ind=1; S1=0; ind=1; S2=0;
while (ind <= x1) do
{ {
S1+=v[ind]; S2+=v[ind];
ind++; ind++;
} } while (ind<=x2);

Cât ar putea fi constantele x1 şi x2 astfel încât diferenŃa dintre valorile finale ale
variabilelor S1 şi S2 (S1-S2) să fie 11 ?
a) 10 şi 10 b) 10 şi 11 c) 11 şi 10 d) 11 şi 11 e) 11 şi 12

► 18. Fie următorul program:


# include <iostream.h>
void main ()
{
int v[20],i,n,E;
cin >> n;
for (i=0; i<n; i++)
v[i]=i%2 ? i : -i;
for (E=1,i=0; i<n; E*=v[i++]); E++;
cout << E ;
}
În urma execuŃiei sale sunt posibile următoarele situaŃii:
a) Programul funcŃionează corect pentru orice valoare întreagă a lui n mai mică sau egală
cu MAXINT.
b) PrezenŃa caracterului ";" după al doilea ciclu for constituie o eroare.
c) Dacă variabila n primeşte prin citire valoarea 5, atunci programul afişează 32.
d) Dacă variabila n primeşte prin citire valoarea 6, atunci elementele vectorului v vor fi,
în ordine (0,1,-2,3,-4,5).

► 19. Ce valoare va fi afişată în urma execuŃiei programului următor ?


#include <iostream.h>
void main()
{
325
int v[]={0,1,2,0,4,5,6};
int i=0, nr=0;
do {
if (i==v[i]) nr++;
} while (i<6 && v[i++]);
cout << nr;
}

Aprofundare

Probleme rezolvate

R.V.9 Elementele distincte ale unui şir


ScrieŃi un program care, pentru un şir dat cu n elemente numere întregi,
formează un alt şir ce va conŃine numai elementele distincte ale şirului dat.
Exemplu: pentru şirul (1,7,2,1,1,7,4), se va forma şirul (1,7,2,4).
Rezolvare
:
Şirul dat este păstrat de vectorul v cu n elemente, pe care îl citim de la tastatură.
Formăm un vector u în care vom copia elementele distincte ale lui v. Concret, parcurgem
într-un ciclu elementele lui v, şi fiecare element va fi adăugat la sfârşitul vectorului u
numai dacă nu a fost adăugat deja (de la un pas anterior).
În variabila k păstrăm poziŃia ultimului element adăugat în vectorul u. IniŃializăm
cu 0 variabila k (pentru că la început vectorul u este "gol", primul element adăugat urmând
a ocupa poziŃia 0).
Parcurgem într-un ciclu poziŃiile i=0,1,...,n-1 ale elementelor în vectorul v
dat, şi pentru fiecare element v[i]:
♦ testăm dacă v[i] a fost deja adăugat în vectorul elementelor distincte u (la
un pas anterior): presupunem că v[i] nu există în u, iniŃializând o variabilă
e cu 0 (variabila e va fi de tip semafor, cu sens logic); într-un alt ciclu,
contorul j va parcurge poziŃiile în vectorul u, acestea fiind 0,1,...,k-1;
dacă găsim un element u[j] egal cu v[i], înseamnă că v[i] există deja în
vectorul elementelor distincte u, deci e ia valoarea 1;
♦ după încheierea căutării, dacă nu am găsit elementul v[i] în vectorul u,
respectiv dacă e a rămas cu valoarea 0, atunci adăugăm pe v[i] la sfârşitul
vectorului u: memorăm efectiv elementul la sfârşitul vectorului, pe poziŃia
dată de valoarea curentă a lui k (u[k]=v[i]) apoi incrementăm k pentru a
crea o nouă locaŃie goală la sfârşitul vectorului u, necesară adăugării
următoare (k++;).

326
Ultima valoare a lui k reprezintă numărul final de elemente al vectorului u, vector
care se afişează la finele programului.

# include <iostream.h>
void main ()
{
int i,j,k,e,n,v[20],u[20];
cout << endl << "n=";
cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "v[" << i << "]="; cin >> v[i];
}
// creaza vectorul u al elementelor distincte din v
k=0; // k=pozitia ultimului element in vectorul u; initial u este gol
for (i=0; i<=n-1; i++)
{
// testeaza daca elementul v[i] exista in vectorul u creat pana in acel moment
for (e=0, j=0; j<=k-1; j++)
if (u[j]==v[i])
e=1;
// daca elementul nu exista in vectorul u, atunci il adauga la sfarsitul acestuia ca
// element distinct
if (!e)
u[k++]=v[i];
}
// afiseaza vectorul u al elementelor distincte din v, vector cu k elemente
for (i=0; i<=k-1; i++)
cout << u[i] << " ";
}

R.V.10 Cel mai mare număr natural cu cifrele lui n


(Bacalaureat iulie 2001, varianta 1)
ConstruiŃi un algoritm care determină şi afişează cel mai mare număr care
se poate forma având exact aceleaşi cifre ca şi un număr natural x citit de la
tastatură (x≤999999999). ScrieŃi programul Pascal corespunzător. De exemplu,
pentru x=306, cel mai mare număr natural având aceleaşi cifre ca şi x este 630.

Rezolvare
:
Mai întâi citim de la tastatură valoarea lui n, care trebuie declarat de tipul
longint. Extragem cifrele lui n, cu algoritmul clasic cunoscut din primul semestru, cifre
pe care le memorăm pe rând în vectorul c. Fiecare cifră va fi adăugată la sfârşitul
vectorului, pe poziŃia dată de variabila k (iniŃializată cu 0 deoarece la început vectorul este
gol, prima cifră urmând a ocupas poziŃia 0).
Într-un ciclu, facem împărŃiri succesive ale unui deîmpărŃit d la 10 (unde iniŃial d
este chiar numărul x), atâta timp cât d este diferit de 0. La fiecare pas:

327
− extragem o cifră pe care o memorăm la sfârşitul vectorului c, pe poziŃia dată de
valoarea curentă a lui k (c[k]=d%10);
− "pregătim" o nouă poziŃie k la sfârşitul vectorului c, pe care va fi adăugată
următoarea cifră la pasul următor (k++;);
− actualizăm deîmpărŃitul pentru împărŃirea următoare (d/=10).
Ultima valoare a lui k va reprezenta numărul de elemente ale vectorului c, pe care
îl memorăm în variabila n {n=k;}.

În continuare sortăm descrescător vectorul cifrelor c, folosind algoritmul prezentat


în acest capitol. Fiecare din primele n-1 elemente, c[0],c[1],...,c[n-2], va juca pe
rând rolul unui aşa numit pivot. Parcurgem pivoŃii într-un ciclu în care contorul i ia pe rând
valorile 0,1,..,n-2 şi la fiecare pas al ciclului comparăm pivotul c[i] cu toate elementele
c[j] aflate după el (j=i+1,...,n-1). Dacă găsim un astfel de element c[j] mai mare
decât pivotul c[i], atunci interschimbăm c[j] cu c[i] prin "metoda paharelor".
Parcurgând de la stânga la dreapta elementele vectorului c sortat descrescător,
vom obŃine cel mai mare număr care se poate forma cu cifrele lui x.

# include <iostream.h>
long x,d;
unsigned int c[9];
int i,j,k,n,temp;

void main ()
{
// citeste x=numarul dat
cout << endl << "x= ";
cin >> x;
// extrage cifrele lui x si le memoreaza in vectorul c=(c[0],c[1],..,c[k-1])
d=x; k=0;
while (d)
{
c[k]=d%10;
d/=10;
k++;
}
n=k;
// sorteaza descrescator vectorul cifrelor c cu n elemente
for (i=0; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
if (c[j]>c[i])
{
temp=c[i];
c[i]=c[j];
c[j]=temp;
}
cout << endl;
// cel mai mare numar avand cifrele lui x se obtine prin parcurgerea vectorului c sortat
// descrescator
for (i=0; i<=n-1; i++)
cout << c[i];
}
328
R.V.11 Platou de lungime maximă
Numim platou de lungime k într-un şir de numere întregi, o secvenŃă de k
elemente identice (cu aceeaşi valoare). ScrieŃi un program care afişează toate
platourile de lungime maximă existente într-un şir dat cu n elemente.
Exemplu: În şirul (1,2,2,2,3,4,4,5,5,5) întâlnim platourile (2,2,2),
(4,4) şi (5,5,5), iar cele de lungime maximă sunt primul şi al treilea.
Rezolvare
:
Citim şirul într-un vector v cu n elemente numere întregi. Identificăm platourile
prin parcurgerea vectorului într-un ciclu while-do, dirijat de contorul i=0,1,..,n-1.
ReŃinem în p şi q poziŃiile elementelor aflate la capetele fiecărui platou determinat, şi
memorăm în lung_max lungimea maximă a platourilor (iniŃializată cu 0). IniŃial i=0 şi cât
timp i<<=n-1:
− căutăm un platou începând cu poziŃia i. Pentru aceasta iniŃializăm p cu i şi
avansăm în vector cât timp întâlnim elemente consecutive egale;
− la finele ciclului anterior, valoarea lui i reprezintă capătul celălalt al platoului,
adică q=i. Desigur că există şi posibilitatea să nu fi întâlnit două elemente consecutive
egale, caz în care nu am avansat în vector şi am obŃinut un platou de lungime 1.
− dacă lungimea platoului astfel determinat, adică q-p+1, este mai mare decât
lungimea maximă lung_max, atunci ea devine noua lungime maximă.
În final, printr-o nouă parcurgere a vectorului, identificăm toate platourile de
lungime maximă şi le afişăm. Într-un ciclu while, pentru fiecare element v[i], testăm
dacă este egal cu v[i+lung_max-1]:
− în caz afirmativ, am identificat un platou de lungime maximă lung_max,
cuprins între i şi i+lung_max-1; afişăm poziŃiile extreme, apoi prin atribuirea
i+=lung_max "sărim" peste platoul reperat;
− în caz contrar, trecem la căutarea platoului de lungime maximă începând cu
următorul element (i++).

# include <iostream.h>
int i,lung,lung_max,p,q,n,v[20];
void main ()
{
// citeste vectorul v cu n elemente
cout << endl << "n=";
cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "v[" << i << "]=";
cin >> v[i];
}
lung_max=0; // lungimea maxima a platourilor
// cauta un platou, parcurgand vectorul intr-un ciclu while; capetele platoului vor fi
// retinute in p si q
329
i=0;
while (i<=n-1)
{
p=i;
while (i<=n-1 && v[i+1]==v[i])
i++;
q=i;
// notam lung=lungimea platoului cuprins intre p si q; daca aceasta lungime este mai
// mare decat cea maxima, atunci ea devine noua lungime maxima
lung=q-p+1;
if (lung>lung_max)
lung_max=lung;
i++;
}
cout << "\n Platourile maxime au lungimea " << lung_max;
// daca exista platouri de lungime maxima, atunci le tipareste, afisand capetele pentru fiecare
i=0;
while (i<=n-1)
if (v[i+lung_max-1]==v[i])
{
cout << "\n Platou maxim intre pozitiile: " << i << " "
<< i+lung_max-1;
i+=lung_max;
}
else
i++;
}

R.V.12 R e - a r a n jă r i de e l e me n t e î n t r - u n ş i r
Se citeşte un şir cu n elemente numere naturale. Să se re-aranjeze
numerele în şir, astfel încât cele pare să ocupe primele poziŃii în ordine
crescătoare, iar cele impare să ocupe restul poziŃiilor în ordine descrescătoare.
Exemplu: dacă şirul iniŃial este (5,8,7,2,10,4), atunci după re-aranjare
devine (2,4,8,10,7,5).

Rezolvare
:
Memorăm şirul într-un vector v cu n elemente numere întregi, citite de la
tastatură. Pentru început, proiectăm un ciclu de interschimbări prin care vom aduce
elementele pare pe primele poziŃii în ordine crescătoare. În cadrul ciclului privim vectorul
ca fiind alcătuit din două părŃi: o parte aranjată (v[0],..,v[k-1]) ce conŃine elementele
pare în ordine crescătoare, şi o parte nearanjată (v[k],..,v[n-1]) ce conŃine elementele
impare (deocamdată nesortate). În variabila capat vom reŃine capătul părŃii nesortate.
Evident iniŃial partea sortată este vidă, deci k=0 şi capat=0, iar poziŃia k ce indică
”bariera” dintre cele două părŃi va evolua de la 0 la n-1. La fiecare pas al ciclului,
determinăm minimul dintre elementele pare ale părŃii nearanjate (v[k],..,v[n-1]), pe
care îl vom memora în variabila min. La un moment dat însă, partea nearanjată nu va mai
conŃine nici un element par, motiv pentru care vom utiliza o variabilă booleană ok care să
ne indice acest lucru. Astfel:

330
− dacă la finele algoritmului de minim ok este 1, înseamnă că am mai găsit un minim
valid dintre elementele pare ale părŃii nearanjate (v[k],..,v[n-1]) şi îl interschimbăm cu
v[k]; prin această operaŃie, partea aranjată va creşte cu încă un element (k++);
− în caz contrar, fixăm începutul părŃii nesortate prin atribuirea capat=k şi ieşim
forŃat din ciclu.
La finele ciclului partea nearanjată va conŃine numai elemente impare ale
vectorului, care mai trebuie ordonate descrescător, folosind unul din algoritmii cunoscuŃi
de sortare.

# include <iostream.h>
# include <values.h>

int i,j,ok,n,k,min,pmin,temp,capat,v[20];

void main ()
{
// citeste vectorul v cu n elemente
cout << endl << "n=";
cin >> n;
for (i=0; i<=n-1; i++)
{
cout << "v[" << i << "]=";
cin >> v[i];
}
// la fiecare pas al algoritmului, privind vectorul ca fiind format din doua parti:
// o parte sortata (v[0],...,v[k-1]) ce contine elementele pare in ordine crescatoare,
// si o parte nesortata (v[k],...,v[n]) in care vor ramane elementele impare
k=0; // initial partea sortata este vida
capat=0; // in variabila capat vom memora inceputul partii nearanjate
while (k<=n-1)
{
// determinam minimul min al partii nearanjate (v[k],...,v[n-1])
min=MAXINT;
ok=0; // variabila ok va indica daca partea nesortata mai contine elemente pare
for (j=k; j<=n-1; j++)
if (v[j]<min && v[j] % 2==0)
{
pmin=j; min=v[j]; ok=1;
}
if (ok) // daca in partea nesortata mai exista elemente pare
{
// interschimba minimul min al partii nearanjate cu v[k], crescand astfel
// partea sortata cu inca un element
temp=v[k]; v[k]=v[pmin]; v[pmin]=temp;
k++;
}
else
{
capat=k;
k=n; // iese fortat din ciclu
}

331
}
cout << endl;
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
// sorteaza partea nearanjata cu elementele impare
if (capat>0)
{
for (i=capat; i<=n-2; i++)
for (j=i+1; j<=n-1; j++)
if (v[j]>v[i])
{
temp=v[i]; v[i]=v[j]; v[j]=temp;
}
}
cout << endl;
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
}

Probleme propuse

Probleme suplimentare
► 1. (Bacalaureat iulie 2009, varianta 82 − enunŃ adaptat)
ScrieŃi un program care primeşte de la tastatură un tablou unidimensional
cu n elemente numere întregi, fiecare element având cel mult patru cifre, şi
afişează pe ecran produsul elementelor impare din tablou, sau valoarea 0 dacă nu
există elemente impare.
Exemplu: pentru tabloul v=(-3,8,5,1,2,4) programul va afişa numărul
-15 (-3*5*1), iar pentru tabloul v=(12,0,4,16) se va tipări valoarea 0.

► 2. (Bacalaureat iulie 2009, varianta 16)


ScrieŃi un program care citeşte de la tastatură elementele unui tablou
unidimensional cu exact 10 numere naturale, mai mici decât 1000, determină şi
afişează pe ecran, separate prin câte un spaŃiu, numărul de elemente din şir care
sunt multipli ai numărului 13 şi, în continuare, poziŃiile pe care acestea se găsesc
în şir. Elementele tabloului sunt numerotate de la 0 la 9.
Exemplu: dacă şirul citit este (2, 6, 26, 14, 130, 11, 8, 23, 52, 39), se vor
afişa numerele 4 2 4 8 9.
IndicaŃii: Dacă nu s-ar fi cerut să afişăm mai întâi numărul elementelor
divizibile cu 13 şi abia apoi poziŃiile acestora, ar fi fost suficientă o singură parcurgere a
vectorului, în care afişam poziŃiile elementelor cu pricina şi în acelaşi timp le număram
în variabila nr, apoi, după ieşirea din ciclu, afişam nr. În contextul cerinŃei privind
forma de afişare, sunt necesare două parcurgeri: cu prima parcurgere facem numărarea,
afişăm nr, iar apoi cu a doua parcurgere "vizităm" din nou toate elementele v[i] (cu
i=0,1,…,n-1) şi afişăm poziŃiile celor divizibile cu 13.

332
► 3. (Bacalaureat iulie 2009, varianta 67 − enunŃ adaptat)
ScrieŃi un program care primeşte de la tastatură un tablou unidimensional
cu n elemente numere întregi, fiecare element având cel mult nouă cifre, şi
afişează pe ecran numărul de numere prime din tablou.
Exemplu: pentru n=5 şi tabloul (12,37,43,6,72), se va tipări valoarea 2.
► 4. (Bacalaureat iulie 2009 - varianta 44)
ScrieŃi un program care citeşte de la tastatură numărul natural n
(0<n<100) şi un şir format din n numere întregi de cel mult 4 cifre fiecare,
determină şi afişează pe ecran numărul de pătrate perfecte din şir.
Exemplu: dacă n=6, iar şirul este format din elementele
(31,25,19,11,4,3), atunci pe ecran se va afişa 2.

► 5. (Bacalaureat iulie 2009 - varianta 33 - enunŃ adaptat)


ScrieŃi un program care primeşte de la tastatură un tablou unidimensional
cu n elemente numere întregi, şi afişează mesajul DA în cazul în care printre
elementele tabloului x se află cel puŃin un număr impar, sau afişează mesajul NU
în caz contrar.
Exemplu: pentru vectorul v=(2,4,4,8,6,12,12), programul va afişa mesajul NU.
► 6. ScrieŃi un program care verifică dacă cele n elemente ale unui şir dat
de numere întregi sunt în ordine strict crescătoare de la stânga la dreapta.
Exemplu: Elementele şirului (2,3,5,8) sunt în ordine strict crescătoare
iar şirul (2,3,8,5) nu îndeplineşte această cerinŃă.
IndicaŃii: Avem de-a face cu o testare logică. Presupunem mai întâi condiŃia
adevărată, iniŃializând cu 1 o variabilă ok (de tip întreg, dar cu sens logic). Apoi, într-un
ciclu dirijat de contorul i, parcurgem poziŃiile elementelor începând cu al doilea, şi
pentru fiecare element v[i] căutăm cazul contrar: dacă v[i]<=v[i-1], înseamnă că
la pasul respectiv am găsit un element v[i] care "strică" ordinea strict crescătoare, deci
ok primeşte valoarea 0 (aferentă "stării" de condiŃie falsă). În final testăm valoarea cu
care ok a ieşit din ciclu, şi în funcŃie de aceasta afişăm un mesaj sugestiv.

► 7. Fiind dat un vector v cu n elemente numere întregi, citite de la


tastatură, scrieŃi un program care afişează toate perechile de elemente consecutive
egale între ele. Fiecare astfel de pereche va fi scrisă pe un rând de ecran, între două
paranteze, cu elementele sale separate prin "virgulă".
Exemplu: Pentru vectorul v=(2,3,3,8,5,5,11,11,7,9) cu n=10
elemente, se vor afişa perechile (3,3), (5,5) şi (11,11).
► 8. Se citeşte de la tastatură un şir de n numere întregi. Să se afişeze
toate perechile de elemente consecutive cu proprietatea că al doilea element al
perechii este egal cu suma cifrelor primului.
Exemplu: Pentru şirul (124,7,12,44,8,9) se afişează perechile
(124,7), (44,4).

333
► 9. (Bacalaureat iulie 2009, varianta 10)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(n≤100) şi apoi cele n elemente, numere naturale cu cel mult patru cifre
fiecare, ale unui tablou unidimensional a. Programul determină şi afişează pe
prima linie a ecranului suma celor n elemente ale tabloului, pe a doua linie a
ecranului suma primelor n-1 elemente şi aşa mai departe, astfel încât pe linia n-1
se va afişa suma primelor 2 elemente, iar pe linia n primul element al tabloului.
PoziŃiile elementelor tabloului sunt numerotate cu 0,1,…,n-1.
Exemplu: dacă n=4, iar tabloul are elementele a=(1,2,3,4) programul
va afişa valorile: 10,6,3,1
IndicaŃii: Practic avem de calculat n sume, deci vom proiecta un ciclu în care
contorul p va lua pe rând valorile 1,2,...,n, şi la fiecare pas calculăm şi afişăm suma cu
numărul de ordine p, care este de fapt suma primelor p elemente; pentru a efectua această
sumă, într-un al doilea ciclu interior primului, parcurgem poziŃiile i ale elementelor de la 0
la p-1, şi la fiecare pas adăugăm elementul v[i] la o variabilă S (iniŃializată cu 0 la fiecare
pas al primului ciclu, înainte de declanşarea celui de-al doilea). Putem folosi aceeaşi
variabilă S la fiecare pas al primului ciclu, deoarece nu se cere salvarea acestor sume, ci
doar afişarea fiecăreia dintre ele, imediat ce a fost calculată.
► 10. (Bacalaureat iulie 2009, varianta 28)
ScrieŃi un program care citeşte de la tastatură un număr natural n din
intervalul [2,10000] şi apoi n numere reale şi afişează pe ecran câte dintre cele
n numere reale sunt egale cu media aritmetică a celorlalte n-1 numere reale.
Exemplu: pentru şirul (7,2,3,4) se va afişa valoarea 1 (pentru că un
singur element, şi anume 4, este media aritmetică a celorlalte), iar pentru şirul
(1,1,1,1,1) se va afişa valoarea 5.

► 11. (Bacalaureat iulie 2009, varianta 54)


ScrieŃi un program care citeşte de la tastatură un număr natural nenul n
(n<=100)şi apoi cele n numere naturale nenule, de maximum patru cifre,
reprezentând elementele unui tablou unidimensional v (cu indici de la 0 la n-1)
şi afişează câte dintre elementele vi (2≤i≤n-1) sunt egale cu suma celor două
elemente vecine. În cazul în care nu există niciun astfel de element în tabloul v, se
va afişa valoarea 0.
Exemplu: dacă n=7 şi tabloul unidimensional v are conŃinutul
(10,25,15,45,30,2,1), atunci se va afişa valoarea 2 (deoarece 25=10+15,
45=15+30).

► 12. Pentru un şir dat de n elemente numere reale, să se afişeze toate


tripletele de elemente consecutive cu proprietatea că al doilea element al tripletului
este media aritmetică dintre primul şi al treilea element.
Exemplu: Pentru şirul v=(2,3,5,10,15,20,9,-2) cu n=8 elemente, se
vor afişa tripletele (5,10,15), (10,15,20) şi (20,9,-2).
IndicaŃii: Dacă memorăm şirul într-un vector v=(v[0],v[1],…,v[n-1]) cu n
elemente, atunci tripletele de elemente consecutive sunt de forma

334
(v[i],v[i+1],v[i+2]), cu i=0,1,...,n-3. În cadrul unui ciclu, pentru fiecare
astfel de triplet, testăm dacă v[i+1]==(v[i]+v[i+2])/2, iar în caz afirmativ afişăm
tripletul.

► 13. Se citeşte de la tastatură un şir cu n elemente numere întregi. Să se


construiască un alt şir cu elementele şirului dat citite invers, de la dreapta la
stânga. Să se realizeze apoi aceeaşi inversare memorându-se însă noul şir în
acelaşi vector în care s-a citit şirul iniŃial (fără a folosi vreun vector suplimentar).
Exemplu: Pentru şirul (1,2,8,5) se va construi şirul (5,8,2,1).
► 14. Se citeşte de la tastatură un şir de n elemente cu numere întregi.
ScrieŃi un program care şterge elementul minim din şir, apoi afişează şirul rămas.
Exemplu: pentru şirul (7,5,2,14,8,11) cu n=6 elemente, se va şterge
minimul 2, rezultând astfel şirul (7,5,14,8,11).
IndicaŃii: Memorăm şirul într-un vector v=(v[0],v[1],…,v[n-1]). Mai întâi
determinăm elementul minim min, precum şi poziŃia p a acestuia, cu algoritmul explicat
pe larg în acest capitol. Pentru a şterge elementul de pe poziŃia p, vom muta cu o poziŃie
mai la stânga toate elementele aflate după el, adică cele de pe poziŃiile p+1,...,n-1.
Pentru aceasta, vom folosi un ciclu cu i=p+1,...,n-1, în care la fiecare pas elementul
v[i] trece pe poziŃia anterioară i-1, prin atribuirea v[i-1]=v[i].

► 15. Se citeşte de la tastatură un şir de n elemente numere întregi. Să se


insereze la mijlocul şirului media aritmetică a elementelor sale.
Exemplu: Dacă de la tastatură se citeşte şirul (8,-3,12,4) cu n=4
elemente, atunci noul şir obŃinut în urma inserării mediei 5 pe poziŃia din mijloc va
fi (8,-3,5.25,12,4).
► 16. (Bacalaureat iulie 2009 - varianta 24 - enunŃ adaptat)
Se citesc de la tastatură o valoare naturală nenulă n, (3≤n≤100), apoi cele
n elemente, distincte, ale unui tablou unidimensional x. Fiecare dintre aceste
elemente este un număr natural având cel mult patru cifre. Folosind un algoritm
eficient, realizaŃi un program care va calcula şi va afişa pe ecran media aritmetică
a elementelor care ar rămâne în tabloul x dacă s-ar elimina valoarea minimă şi
valoarea maximă din tablou. Valoarea afişată va avea cel mult 3 cifre după
virgulă.
Exemplu: dacă se citesc pentru n valoarea 5, iar pentru tabloul x valorile
(1,9,4,8,5), programul va afişa una dintre valorile 5.667 sau 5.666.
► 17. Se citesc de la tastatură cele n elemente ale unui şir dat de numere
întregi. Să se afişeze toate perechile de elemente ale şirului (nu neapărat consecutive)
cu proprietatea că ambele elemente ale perechii au aceeaşi sumă a cifrelor.
Exemplu: În şirul (14,129,221,65,409,5,32) cu n=7 elemente, avem
perechile (14,221), (14,5), (14,32), (221,5), (221,32) şi (5,32) cu
suma cifrelor 5.

335
► 18. Se dă un vector v cu n elemente numere întregi. Să se copieze într-
un alt vector u elementele strict pozitive ale vectorului iniŃial.
Exemplu: Pentru n=6 şi vectorul v=(7,-8,-15,2,0,13), vom obŃine
vectorul u=(7,2,13).
IndicaŃii: Algoritmul este foarte asemănător cu cel din problema rezolvată R.V.9.
Elementele strict pozitive din vectorul v vor fi adăugate pe rând la sfârşitul vectorului u (iniŃial
gol). Folosim un contor k, în care vom păstra în permanenŃă poziŃia (indicele "căsuŃei") la care
am ajuns cu adăugarea în vectorul u. Evident, iniŃial k=0, pentru că începem adăugarea cu
prima poziŃie. Parcurgem într-un ciclu poziŃiile i=0,1,...,n-1 ale elementelor vectorul dat v,
şi la fiecare pas, dacă elementul v[i] este strict pozitiv, atunci:
− îl adăugăm la sfârşitul vectorului u, pe poziŃia dată de valoarea curentă a lui k
(u[k]=v[i]);
− incrementăm cu 1 variabila k, pentru a pregăti "căsuŃa" din vectorul u în care se va
memora următorul numŃăr strict pozitiv din vectorul v (la un pas următor al ciclului).
În final, numărul de elemente ale vectorului u este chiar k.

► 19. Fiind dat un vector v cu n elemente numere întregi, să se


construiască alŃi doi vectori: primul va conŃine numai elementele pare, iar al doilea
numai elementele impare ale vectorului iniŃial.
Exemplu: Pentru n=7 şi v=(8,-6,11,14,10,-5,-214), vor rezulta
vectorii x=(8,-6,14,10,-214) şi y=(11,-5).
► 20. (Bacalaureat iulie 2009, varianta 93)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(1≤n≤99), impar, şi construieşte în memorie un tablou unidimensional A=(A1,
A2,…, An) cu elementele mulŃimii {1,2,...,n} astfel încât elementele de pe
poziŃii impare formează şirul crescător 1,2,...,[(n+1)/2], iar elementele de
pe poziŃii pare şirul descrescător n,n-1,..., [(n+1)/2]+1.
Exemplu: pentru n=11 se va construi tabloul
A=(1,11,2,10,3,9,4,8,5,7,6)

► 21. (Bacalaureat iulie 2008, varianta 93)


Să se introducă într-un vector, apoi să se afişeze ca atare, următorul şir de
numere: 1,1,2,1,2,3,1,2,3,4,...
Numărul de elemente câte vor fi introduse se va preciza anticipat de la
tastatură.
IndicaŃii: Putem observa următoarea grupare a elementelor şirului: (1),
(1,2), (1,2,3), (1,2,3,4), etc... Grupa 1 conŃine valorile de la 1 la 1, grupa 2
valorile de la 1 la 2, ş.a.m.d., deci o grupă oarecare i va conŃine valorile de la 1 la i, pe
care le afişăm banal într-un ciclu. Numai că, neştiindu-se numărul grupelor ci numărul
elementelor, pentru trecerea grupelor în revistă nu se poate folosi tot un ciclu for, ci un
ciclu while, în care să se numere elementele afişate, şi din care să se iese forŃat atunci
când s-au parcurs n valori. În rest, adăugarea elementelor pe rând într-un vector nou se
încadrează în algoritmul clasic.

336
► 22. Se dau două mulŃimi definite prin intermediul vectorilor u şi v, cu m
respectiv n elemente. Să se memoreze în vectorul w şi apoi să se afişeze reuniunea
celor două mulŃimi (elementele comune şi necomune luate o singură dată). La
citirea fiecăruia dintre cei doi vectori se va asigura îndeplinirea condiŃiei de
mulŃime: elementele să fie distincte şi în ordine crescătoare.
Exemplu: Pentru mulŃimile u=(2,3,8,9) şi v=(3,8,11), va rezulta
vectorul-reuniune (2,3,8,9,11).
► 23. (Bacalaureat iulie 2009, varianta 31 - enunŃ adaptat)
Se citesc de la tastatură un tablou unidimensional x cu cel mult 100 de
elemente, numere naturale cu cel mult 4 cifre fiecare, şi un număr natural n
(n≤100), ce reprezintă numărul efectiv de elemente ale tabloului x. ScrieŃi un
program care va afişa tabloul obŃinut în urma schimbarii poziŃiei doar a
elementelor impare din tablou astfel încât acestea să apară în ordinea crescătoare a
valorilor lor.
Exemplu: pentru n=6 şi x=(7,11,2,-8,-3,10) programul va afişa
tabloul (-3,7,2,-8,11,10).
IndicaŃii: Practic algoritmul de sortare prin metoda interschimbărilor directe
trebuie modificat, astfel încât la fiecare comparare să se compare între ele doar două
elemente x[i] şi x[j] care sunt ambele impare. În cazul în care vreŃi să folosiŃi
"metoda bulelor", modificările sunt mai profunde !
► 24. (Bacalaureat iulie 2009, varianta 41 - enunŃ adaptat)
Se citesc de la tastatură un număr natural n şi un tablou unidimensional a
cu n elemente numere întregi. ScrieŃi un program care afişează valoarea 1 dacă
toate elementele tabloului a sunt distincte şi dacă diferenŃa absolută a oricăror
două elemente vecine din tablou este diferită de 1, respectiv 0 în caz contrar.
Exemplu: pentru tabloul (7,2,8,11,13) se va afişa valoarea 1, iar
pentru tablourile (5,3,9,5) şi (2,-3,7,6) se va afişa valoarea 0.
► 25. (Bacalaureat iulie 2009, varianta 52)
ScrieŃi un program care citeşte de la tastatură un număr natural nenul n
(n≤100) şi apoi n numere naturale, de maximum patru cifre fiecare, reprezentând
elementele unui tablou unidimensional. Programul afişează mesajul DA în cazul în
care elementele tabloului pot fi rearanjate astfel încât să formeze o progresie
aritmetică, iar în caz contrar afişează mesajul NU.
Exemplu: dacă n=6 şi tabloul unidimensional are conŃinutul alăturat,
atunci se va afişa DA.
5 10 30 15 25 20

► 26. (Bacalaureat iulie 2008, varianta 24)


ScrieŃi un program care citeşte de la tastatură un număr natural nenul n
≤ 1000), apoi construieşte în memorie şi afişează pe ecran un tablou
(n≤
unidimensional a, având n elemente, ale cărui capete vor fi completate cu toate
numerele din mulŃimea {1,2,...,n} luate alternativ, astfel: valoarea 1 pe prima

337
poziŃie, valoarea 2 pe ultima poziŃie, valoarea 3 pe a doua poziŃie, valoarea 4 pe
penultima poziŃie, ş.a.m.d.. Elementele tabloului creat se vor afişa cu câte un
spaŃiu între ele.
Exemplu: pentru n=9, tabloul va fi (1,3,5,7,9,8,6,4,2).
► 27. Se citeşte de la tastatură un şir de n elemente numere întregi. Să se
afişeze elementele şirului în ”pagini” de câte m rânduri, fiecare rând conŃinând câte
m elemente separate prin spaŃii sau virgule (cu excepŃia ultimei pagini care poate
conŃine mai puŃin de m rânduri, respectiv a ultimului rând al ”ultimei pagini” care
poate conŃine mai puŃin de m elemente). După afişarea fiecărei ”pagini” programul
va aştepta apăsarea unei taste pentru confirmarea trecerii la ”pagina” următoare.
Exemplu: Pentru m=3, n=22 şi şirul
(8,2,4,56,87,91,12,41,62,44,65,21,87,30,2,10,35,99,70,13,18,24)
ecranul va arăta astfel: 8,2,4
56,87,91
12,41,62
----------
44,65,21
87,30,2
10,35,99
----------
70,13,18
24

► 28. (Bacalaureat iulie 2009, varianta 55)


ScrieŃi un program care citeşte de la tastatură un număr natural nenul n
(n≤100) şi 2*n numere naturale de maximum trei cifre; primele n valori
reprezintă elementele tabloului unidimensional a, iar următoarele n elementele
tabloului unidimensional b; fiecare tablou are elementele numerotate începând de
la 0. Programul construieşte în memorie şi afişează pe ecran cele n elemente ale
unui tablou unidimensional c, în care orice element ci (0≤1≤i≤n) se obŃine
conform definiŃiei următoare:
ai concatenat cu bi, dacă ai<bi
ci =
bi concatenat cu ai, altfel
Exemplu: dacă n=3 şi tablourile a şi b au conŃinutul a=(12,123,345)
şi b=(1,234,15), atunci conŃinutul tabloului c este următorul:
(112,123234,15345).

Probleme de nota 10
► 29. Fiind dat un vector v cu n elemente numere întregi, să se
construiască un alt vector u care să conŃină numai pătratele perfecte din v, în
ordine crescătoare. Aceste pătrate perfecte vor fi copiate de la început în ordine
crescătoare, fără a se aplica vectorului u nici un algoritm de sortare.
338
Exemplu: Pentru vectorul v=(34,9,45,64,18,16,39), se va crea
vectorul u=(9,16,64).
IndicaŃii: AtenŃie, algoritmul prezentat ca indicaŃii la problema 18 nu ne este de
nici un folos în acest caz. Presupunând că la un pas oarecare i al ciclului de parcurgere a
vectorului v (cu i=0,1,...,n-1) avem în u adăugate deja k elemente
u[0],u[1],...,u[k-1] ordonate crescător, adăugarea elementului v[i] nu se va face
la sfârşitul lui u ! Va trebui să găsim poziŃia pe care ar trebui să o ocupe acea valoare
v[i] în vectorul u, astfel încât, după introducerea ei, vectorul u să rămână ordonat
crescător. Pentru aceasta, căutăm în u un indice j, astfel încât u[j]<=v[i]<=u[j+1], şi,
după ce l-am găsit, inserăm pe v[i] pe poziŃia j în vectorul u.

► 30. (Bacalaureat iulie 2009, varianta 12)


Se citesc de la tastatură două valori naturale m şi n (m<=100, n<=100),
iar apoi m+n numere întregi de cel mult nouă cifre fiecare. Dintre cele m+n
numere citite, primele m sunt ordonate strict crescător, iar următoarele n sunt, de
asemenea, ordonate strict crescător. Se cere să se afişeze pe ecran câte din cele
m+n numere au fost citite o singură dată.
Exemplu: pentru m=6 şi n=9 şi valorile 1, 2, 3, 4, 7, 20, 3, 5, 7, 8, 9, 10,
12, 20, 24, se va afişa valoarea 9 (numerele care au fost citite o singură dată sunt
1 2 4 5 8 9 10 12 24).
a) DescrieŃi un algoritm de rezolvare a acestei probleme, eficient din punct
de vedere al timpului de executare şi al spaŃiului de memorie utilizat, explicând în
ce constă eficienŃa acestuia.
b) ScrieŃi programul corespunzător algoritmului descris.
► 31. (Bacalaureat iulie 2008, varianta 91)
Pentru un număr natural n citit de la tastatură (0<n<100 ), se cere să se
construiască un vector cu n componente numere naturale din mulŃimea {0,1,2},
astfel încât să nu existe două elemente alăturate egale, iar suma oricăror trei elemente
consecutive să fie egală cu 3. ScrieŃi programul care generează în memorie vectorul,
apoi scrie componentele acestuia pe ecran, în ordine, cu spaŃii între ele.
Exemplu: pentru n=4, se vor afişa valorile 1 2 0 1.
IndicaŃii: Problema pare grea, dar cu o idee genială ea devine banală. Practic,
dacă multiplicăm secvenŃa (1,2,0) de [n/3] ori, obŃinem un şir care respectă cele
două cerinŃe. Iată un exemplu: pentru n=11 avem şirul (1,2,0,1,2,0,1,2,0,1,2,0).
Obsevăm că sumele a trei elemente alăturate sunt fie 1+2+0, fie 2+0+1, fie 0+1+2, deci
întotdeauna 3.
► 32. (Bacalaureat iulie 2009, varianta 66 - enunŃ adaptat)
≤n≤
Se citesc de la tastatură un număr natural nenul n (1≤ ≤10000) precum şi
un tablou unidimensional a care conŃine n valori întregi, fiecare dintre aceste
valori având cel mult nouă cifre. RealizaŃi un program care determină şi afişează
pe ecran cel mai mare divizor comun al elementelor tabloului a.
Exemplu: în urma apelului, pentru n=5 şi tabloul unidimensional
(12,36,48,6,60), se va returna 6.

339
► 33. La ora de educaŃie fizică, în vederea apelului de prezenŃă, elevii
unei clase s-au aşezat într-un şir după înălŃime, în ordine crescătoare de la stânga
la dreapta. Profesoara doreşte să inverseze ordinea elevilor în şir, astfel încât ei să
fie aranjaŃi tot după înălŃime, dar în ordine descrescătoare de la stânga la dreapta.
SimulaŃi într-un program algoritmul pe care-l aplică profesoara. De la tastatură se
citesc numărul de elevi n, precum şi înălŃimile elevilor. Programul va trebui să
testeze dacă aşezarea iniŃială a elevilor respectă condiŃia de ordine crescătoare,
apoi să afişeze elevii după re-ordonarea dictată de profesoară.
IndicaŃii: Se interschimbă între ei primul elev din şir cu ultimul, al doilea cu
penultimul, al treilea cu antepenultimul, ş.a.m.d.. Dacă numărul elevilor este impar,
atunci elevul aflat în mijlocul şirului va rămâne pe locul iniŃial.

► 34. (Bacalaureat iulie 2009, varianta 34)


ScrieŃi programul care citeşte de la tastatură un număr natural n
(n<100), apoi n numere naturale de cel mult trei cifre fiecare şi afişează pe ecran
cel mai mare număr de valori pare (dintre cele n citite) care s-au citit consecutiv de
la tastatură.
Exemplu: pentru n=8 şi numerele 12,7,4,16,10,3,6,6 se va afişa 3.
► 35. Se citesc de la tastatură n fracŃii de forma (a1/b1,a2/b2,...,
an/bn). Să se afişeze fracŃiile simplificate ”la maximum”, precum şi fracŃia ce
reprezintă suma celor n fracŃii. Reamintim: o fracŃie se simplifică ”la maximum”
împărŃind numărătorul şi numitorul la cel mai mare divizor comun al lor.
Exemplu: Dacă cele n=3 fracŃii de intrare sunt (6/6,12/18,50/20),
atunci se vor afişa fracŃiile (1/1,2/3,5/2), iar suma acestora este (25/6).
IndicaŃii: Memorăm numărătorii respectiv numitorii celor n fracŃii în doi
vectori (a[0],a[1],..,a[n-1]) respectiv (b[0],b[1],..,b[n-1]). Într-un ciclu cu
i=0,1,..,n-1, simplificăm fiecare fracŃie a[i]/b[i] astfel: determinăm c.m.m.d.c
(a[i],b[i]), apoi împărŃim a[i] şi b[i] la acest c.m.m.d.c. Pentru a însuma
cele n fracŃii, trebuie mai întâi să determinăm cel mai mic multiplu comun al numitorilor
(b[0],b[1],..,b[n-1]), care se poate calcula după relaŃia
NC=(b[0]*b[1]*..*b[n-1])/c.m.m.d.c.(b[0],b[1],..,b[n-1]). Calculul
celui mai mare divizor comun al numitorilor (b[0],b[1],..,b[n-1]) foloseşte
proprietatea de tranzitivitate: astfel, într-un ciclu, vom determina succesiv
d1=c.m.m.d.c.(b[0],b[1]), d2=c.m.m.d.c.(d1,b[2]), ş.a.m.d. În final, într-un
alt ciclu se determină numărătorul fracŃiei sumă: a[0] se înmulŃeşte cu NC/b[0], a[1]
cu NC/b[1], etc., adunându-se aceste rezultate.
► 36. (Bacalaureat iulie 2008, varianta 45 - enunŃ adaptat)
Se citeşte de la tastatură un şir de numere naturale mai mici sau egale
decât 10000. Şirul are cel mult 100 de valori şi se termină atunci când se
introduce o valoare negativă (care nu face parte din el). ScrieŃi un program care
afişează pe ecran toate numerele impare din şir, în ordine crescătoare, separate
prin câte un spaŃiu. În cazul în care un anumit element se repetă în şir, el se va
afişa o singură dată.

340
Exemplu: dacă s-a citit şirul (7,2,1,9,4,0,7,3,22,3), se vor afişa
valorile 1 3 7 9
►37. (Bacalaureat, iulie 2000, varianta 10)
ScrieŃi un program care citeşte de la tastatură cele 10 numere reale ce
compun vectorul a şi apoi cele 8 numere reale ce constitue componentele
vectorului b şi afişează pe ecran câte dintre componentele vectorului a sunt strict
mai mici decât toate componentele vectorului b.
Exemplu: dacă a=(4,8,1,9,5,11,3,43,6,20) şi b=(9,9,6,9,9,
8,6,9), atunci numărul căutat este 4, deoarece valorile 4,1,5 şi 3 sunt mai mici
decât toate elementele lui b.
►38. Un polinom P(X)=a0+a1⋅X+a2⋅X2+...+an⋅Xn poate fi reprezentat sub
forma unui vector a=(a[0],a[1],...,a[n]) care va memora coeficienŃii săi.
a) Fiind dat un polinom P(X) şi un întreg b, să se calculeze P(b)
(valoarea lui P pentru o valoare b a argumentului);
b) Fiind date două polinoame P(X) şi Q(X), ambele de gradul n, să se
determine suma celor două polinoame, P(X)+Q(X), tipărindu-se coeficienŃii
polinomului-sumă;
c) Fiind date două polinoame P(X) şi Q(X), ambele de gradul n, să se
determine polinoamele ce reprezintă câtul şi restul împărŃirii lui P(x) la Q(x).
Rezultatul se va afişa pe ecran sub forma a două rânduri: pe primul rând coeficienŃii
polinomului ce reprezintă câtul împărŃirii, iar pe al doilea coeficienŃii restului.
► 39. (Bacalaureat iulie 2008, varianta 60)
ScrieŃi un program care citeşte un număr natural par nenul n (n<100),
precum şi n numere naturale de cel mult patru cifre fiecare, apoi determină cea
mai mare sumă care poate fi obŃinută adunând numai jumătate din numerele citite.
Rezultatul se va afişa pe ecran.
Exemplu: pentru n=6 şi numerele 728, 10, 103, 44, 1000, 94, se va afişa
valoarea 1731 (reprezentând suma 728+103+1000).
► 40. Se citeşte de la tastatură un vector cu n elemente numere întregi. Să
se afişeze toate permutările circulare ale vectorului dat. Fiecare permutare
circulară se obŃine din permutarea precedentă (respectiv din vectorul dat, pentru
prima permutare) prin aplicarea următoarelor operaŃii: primele n-1 elemente sunt
mutate fiecare cu câte o poziŃie mai la dreapta, iar ultimul element trece pe prima
poziŃie. Procedeul se repetă până când ajungem la permutarea care coincide cu
vectorul iniŃial. Fiecare dintre permutările rezultate se va afişa pe câte un rând,
elementele ce alcătuiesc o permutare urmând a fi separate prin 8 2 5 -1
câte un spaŃiu. -1 8 2 5
Exemplu: Permutările circulare ale vectorului 5 –1 8 2
v=(2,5,-1,8) sunt cele din figură. 2 5 –1 8

341
IndicaŃii: Pentru a permuta circular un vector v=(v[0],v[1],...,v[n-1])
procedăm astfel:
− salvăm ultimul element v[n-1] într-o variabilă intermediară x;
− într-un ciclu, parcurgem poziŃiile i=0,1,...,n-2 ale primelor n-1 elemente,
şi la fiecare pas mutăm elementul v[i] pe poziŃia următoare prin atribuirea
v[i+1]=v[i];
− în final, aducem ultimul element al configuraŃiei iniŃiale (salvat în x) pe poziŃia
0 (v[0]=x).
Evident tot acest algoritm trebuie cuprins într-un alt ciclu, pentru a obŃine toate
permutările posibile.

► 41. Se citesc de la tastatură n numere naturale. Fără a face înmulŃirea


celor n numere, să se determine în câte zerouri se termină produsul lor.
Exemplu: Pentru şirul (25,6,100,11,15,4000) cu n=6 elemente,
produsul elementelor este 9900000000, iar programul va afişa valoarea 8.
IndicaŃii: Orice număr se termină în 0 dacă este divizibil cu 2 şi 5. Pentru a
afla în câte zerouri se termină produsul elementelor şirului, este suficient să aflăm
puterea la care apar factorii 2 şi 5 în descompunerea elementelor, iar numărul de
zerouri este minimul dintre aceste puteri.

► 42. Se dă un vector v cu n elemente numere întregi. Fără a folosi un


vector auxiliar, să se mute la sfârşitul lui v elementele sale nule, păstrând ordinea
celorlalte elemente.
Exemplu: dacă iniŃial v=(2,3,0,9,0,0,8), în final va rezulta
v=(2,3,9,8,0,0,0).
IndicaŃii. Parcurgem vectorul dat v şi pentru fiecare element v[i] testăm dacă
este 0; în caz afirmativ, mutăm toate componentele din dreapta lui v[i] cu o poziŃie mai
la stânga, micşorăm dimensiunea lui v cu o unitate şi incrementăm un contor nr care
numără elementele nule. În final adăugăm nr elemente cu valoarea 0 la sfârşitul lui v.

► 43. Se dă un şir cu n componente naturale (1 ≤ n ≤ 100). Să se afişeze cel


mai mic număr natural care se poate alcătui luând prima cifră a fiecărui element al
şirului. Exemplu: pentru n=4 şi elementele (234,7650,19,2) numărul este 1227.
IndicaŃii. Se parcurge şirul memorat într-un vector v, şi pentru fiecare element
v[i] reŃinem prima cifră, pe care o extragem cu algoritmul clasic de împărŃiri la 10 şi o
adăugăm la sfârşitul unui "vector de cifre" c, iniŃial gol. Sortăm crescător vectorul, după
care prin parcurgerea vectorului sortat de la stânga la dreapta obŃinem numărul cerut.

► 44. Se citeşte de la tastatură un şir cu n elemente numere naturale, nu


neapărat distincte. Să se afişeze elementul care apare de cele mai multe ori în şir.
Dacă există mai multe astfel de elemente, se vor afişa toate.
Exemplu: pentru n=5 şi elementele (23,7,11,7,19,7,11,11) se vor
afişa elementele 7 şi 11 care apar fiecare de câte trei ori.
IndicaŃii. Se ordonează crescător vectorul v în care memorăm şirul. După
ordonare, elementele identice vor fi succesive în vector. Folosim alŃi doi vectori u şi f:
fiecare u[i] va fi un element distinct al vectorului v, iar f[i] va reprezenta frecvenŃa de

342
apariŃie a lui u[i] în vectorul v. Parcurgem vectorul sortat v şi la fiecare pas comparăm
elementul curent v[i] cu cel următor v[i+1]; dacă sunt diferite, am identificat un nou
element distinct al lui v, "în persoana" lui v[i+1], pe care îl adăugăm la sfârşitul lui u,
iniŃializând totodată cu 1 un element nou la sfârşitul vectorului f; în caz contrar,
incrementăm componenta din f care indică frecvenŃa elementelor egale v[i] şi v[i+1].

► 45. Se citesc de la tastatură două numere naturale foarte mari, care pot
avea până la 70 de cifre fiecare. Să se afişeze suma celor două numere.
IndicaŃii. Evident că numere atât de mari nu pot fi reprezentate în memorie nici
măcar cu ajutorul tipului long. Singura soluŃie este să memorăm cifrele lor în vectori.
Pentru adunarea celor două numere vom opera asupra vectorilor. Se parcurg "în
paralel" cei doi vectori de cifre de la dreapta la stânga. La fiecare pas, se însumează
elementele aflate pe poziŃii identice în cei doi vectori, cu memorarea rezultatului pe
aceeaşi poziŃie într-un al treilea vector. Dacă o astfel de sumă depăşeşte 10, înseamnă că
elementul corespunzător din vectorul-sumă va fi diferenŃa dintre suma obŃinută şi 10, iar
pe de altă parte vom avea un transport egal cu 1 către poziŃia următoare. Dacă suma nu
depăşeşte 10, atunci ea se va memora ca atare în vectorul sumă.

► 46. Pentru un concurs judeŃean de lupte greco-romane, din partea unui


anumit liceu s-au înscris n elevi, ale căror greutăŃi (exprimate în kg) sunt
cunoscute. Din păcate, regulamentul concursului prevede că nu pot participa
sportivi a căror greutate se află ”la graniŃa” dintre două categorii (adică este egală
cu limita superioară a unei categorii respectiv limita inferioară a categoriei
următoare), aceştia urmând a fi tăiaŃi de pe lista celor înscrişi. RealizaŃi un
program care întocmeşte lista finală a elevilor ce vor participa în concurs.
Categoriile de greutate se citesc într-un vector c alcătuit din perechi succesive de
câte două elemente, în care elementele fiecărei perechi reprezintă limita minimă şi
cea maximă de greutate a unei categorii. De la tastatură se mai citesc numărul de
elevi n precum şi greutăŃile acestora.
Exemplu: Dacă vectorul ce conŃine greutăŃile extreme ale categoriilor de
greutate este (48,54,62,66,74,82,86,92), atunci categoriile sunt: [48,54),
[54,62), [62,66), [66,74), [74,82), [82,86), [86,92). Dacă s-au înscris
n=8 elevi având greutăŃile (57,54,66,90,49,62,58,70), atunci vor fi eliminaŃi
de pe listă elevii având greutăŃile de 54 şi 66 kg.
IndicaŃii: Citirea vectorului c al categoriilor şi a vectorului g al greutăŃilor se va
face cu validare, în sensul că elementele trebuie introduse în ordine crescătoare. Ilustrăm
algoritmul cu primul concurent înscris g[0]. Pentru început depistăm în care categorie se
încadrează greutatea sa: în vectorul c al categoriilor parcurgem perechi de forma
(c[i],c[i-1]) cu i=n-1,n-2,...,1 şi pentru fiecare pereche testăm dacă greutatea se
află în intervalul respectiv; dacă greutatea este chiar egală cu c[i] sau c[i-1], atunci
concurentul g[0] trebuie şters din vectorul g. Indiferent de rezultatul acestei testări, mai
departe trebuie să trecem peste ceilalŃi elevi aflaŃi în aceeaşi categorie de greutate cu
g[0]; acest lucru se realizează printr-o simplă parcurgere a vectorului g, bazându-ne pe
faptul că dacă în g mai există elemente situate în acelaşi interval, ele vor fi cele aflate
succesiv imediat după g[0], din cauză că vectorul este sortat crescător. Ceea ce am
descris mai sus pentru elevul g[0] trebuie implementat pentru toate celelalte elemente ale

343
vectorului g. Ştergerea unui element oarecare g[k] din vectorul g se face prin mutarea cu
o poziŃie mai la stânga a tuturor elementelor aflate după el.
► 47. Fiind dat un vector v cu n elemente numere întregi, să se afişeze
cea mai lungă secvenŃă (succesiune) de elemente consecutive aflate în ordine
crescătoare. Dacă există mai multe astfel de secvenŃe, se va afişa una singură.
Exemplu: Pentru vectorul v=(7,3,5,8,4,9,-1,2,5,6,11,10) cu
n=12 elemente, programul va tipări secvenŃa (-1,2,5,6,11).
► 48. Vom spune despre un şir că are ”aspect de munte”, dacă toate
elementele aflate până la o poziŃie oarecare k inclusiv sunt în ordine crescătoare, şi
toate elementele situate după poziŃia k sunt în ordine descrescătoare. În acest caz
elementul aflat pe poziŃia k se numeşte ”vârful muntelui”. RealizaŃi un program
care citeşte de la tastatură un şir cu n elemente numere întregi şi testează dacă
acesta are sau nu ”aspect de munte”. În caz afirmativ se va tipări ”vârful
muntelui”, iar în caz contrar se va afişa un mesaj.
Exemplu: şirul memorat în vectorul (2,3,7,11,14,9,8,7,5) este un
”munte” cu vârful reprezentat de elementul 14, iar vectorul
(2,3,7,11,14,9,8,10,5) nu are ”aspect de munte”, din cauza elementului 10
care ”strică” ordinea descrescătoare.
IndicaŃii: Dacă şirul este un ”munte”, evident că ”vârful” său nu poate fi altcineva
decât elementul maxim. Se determină maximul max şi poziŃia sa k, după care se fac două
testări: dacă elementele aflate până la poziŃia k sunt în ordine strict crescătoare, şi dacă
elementele de după poziŃia k sunt în ordine strict descrescătoare. În cazul în care ambele
testări dau rezultatul ”ADEVĂRAT”, am identificat muntele şi vârful său.
► 49. Se citeşte de la tastatură un şir de numere naturale. Să se afişeze
toate grupurile de numere din şir care au aceeaşi divizori factori primi.
Exemplu: Fie şirul (12,15,2,36,32). Grupurile afişate vor fi: (12,36)
cu divizorii primi 2 şi 3, (15) cu divizorii primi 3 şi 5, (2,32) cu divizorul prim 2.
IndicaŃii. Dacă şirul are n numere, vom crea doi vectori v şi f, astfel: fiecare element
v[i] va fi un număr din şirul dat, iar f[i] va reprezenta produsul factorilor primi ai lui
v[i], cu i=1,2,...,n. Evident că dacă două elemente ale şirului au acelaşi produs de
factori primi, atunci elementele în cauză vor avea aceeaşi factori primi, deci în vectorul f se
pot evidenŃia grupurile cerute. Ordonăm crescător vectorul f, folosind oricare dintre
algoritmii de sortare studiaŃi. În final se afişează grupurile cerute prin parcurgerea vectorului
f, grupurile cerute nefiind altceva decât platourile din vector.

► 50. Se dau doi vectori a şi b, cu m respectiv n elemente numere întregi


>m). Să se verifice dacă toate componentele vectorului a sunt distincte două câte
(n>
două, iar în caz afirmativ să se testeze dacă acestea, luate în orice ordine, se găsesc în
vectorul b pe poziŃii consecutive. În cazul în care testul a reuşit, să se afişeze fiecare
poziŃie din vectorul b de unde începe secvenŃa alcătuită din elementele vectorului a.
Exemplu: dacă a=(3,5,4) şi b=(2,5,4,3,9,6,3,4,5,12), atunci
vectorul a se regăseşte de două ori în vectorul b: secvenŃa (5,4,3) care începe de
pe poziŃia a doua, respectiv secvenŃa (3,4,5) a cărei poziŃie de început este 7.
344
IndicaŃii: Dacă vectorul a are elemente identice, fireşte că în şirul sortat acestea
se vor găsi pe poziŃii consecutive. Prin urmare, cea mai simplă modalitate (dar nu
neapărat cea mai eficientă !) de a testa dacă elementele sale sunt distincte două câte
două, este următoarea: sortăm crescător vectorul, apoi parcugem perechile de elemente
de forma (v[i],v[i+1]) cu i=0,1,...,n-2, şi testăm dacă există vreo pereche cu
proprietatea v[i]=v[i+1].
În cazul în care testul anterior generează ADEVĂRAT, parcurgem elementele
vectorului b şi pentru fiecare v[k] (cu k=0,1,...,n-1), testăm dacă acesta este
începutul unei secvenŃe alcătuite cu elementele lui a în orice ordine, fiecare luat o singură
dată. Pentru aceasta:
− mai întâi testăm dacă b[k] se găseşte în vectorul a;
− în caz afirmativ, verificăm într-un ciclu dacă următoarele m elemente ale lui b
începând cu poziŃia k se găsesc la rândul lor în vectorul a; pentru aceasta parcurgem
secvenŃa alcătuită din elementele b[j] cu j=k,...,k+m-1; pentru a testa dacă
secvenŃa coincide cu vectorul a, eventual într-o altă ordine a elementelor, vom folosi un
vector sem cu rol de “semafor”.

V . 2. Ma tri c i

V . 2 .1 . N o Ńi un e a d e ma t r ic e

O matrice este un tabel cu elemente de acelaşi tip, dispuse pe linii şi


coloane. Datorită acestei aşezări a elementelor, o matrice este de fapt un tablou
bidimensional. Fiecare element al matricii se află pe o anumită linie şi pe o
anumită coloană. PoziŃia unui element pe linie se mai numeşte şi indice de linie,
iar poziŃia elementului pe coloană se mai numeşte şi indice de coloană.
Dacă notăm variabila matrice cu a, atunci elementul de pe linia i şi
coloana j în matricea a se notează a[i][j].
Ilustrăm în continuare o matrice a cu 3 linii şi 4 coloane, având ca
elemente numere întregi.
1 2 3 4 coloana

linia 1 -2 16 8 2 a[3][2]=-1
2 13 5 10 6 (elementul de pe linia 3 şi coloana 2 este -1)
3 19 -1 9 7

O variabilă-matrice se declară asemănător cu o variabilă-vector, cu


deosebirea că în loc de numărul maxim de elemente, trebuie să precizăm două
valori: numărul maxim de linii şi numărul maxim de coloane.
345
Exemplu: float a[30][25];

• identificatorul a reprezintă numele variabilei în care memorăm matricea;


• cuvântul cheie float desemnează tipul elementelor matricii (numere reale);
• numărul maxim de linii este 30, iar numărul maxim de coloane este 25; în aceste
circumstanŃe, liniile sunt numerotate cu 0,1,..,29, iar coloanele cu 0,1,..,24.

Pe caz general, sintaxa declarării unei matrici este următoarea:

Si nt axa: <tip_e> <id_mat>[<max_lin>][<max_col>]

 <id_mat> → identificatorul (numele) variabilei matrice;


 <tip_e> → tipul elementelor matricii;
 <max_lin>, <max_col> → numărul maxim de linii, respectiv coloane.

Dacă am declarat o matrice a cu maxim 30 linii * 25 coloane, asta nu


înseamnă că trebuie să folosim toate cele 750 de elemente ale sale ! Aşa cum în
cazul unui vector defineam ca variabilă un număr real de elemente (numărul
elementelor efectiv folosite), la fel, pentru o matrice a vom defini două variabile:
un număr real de linii şi un număr real de coloane, notate de obicei m respectiv n.
În aceste condiŃii, în mod implicit indicii de linie vor fi 0,1,...,m-1, iar cei de
coloană vor lua valorile 0,1,...,n-1, caz în care elementele matricii a vor fi:
a[0][0], a[0][1],...., a[0][n-1] → linia 1
a[1][0], a[1][1],...., a[1][n-1] → linia 2
.............................................
a[m-1][0], a[m-1][1],.., a[m-1][n-1] → linia m

ObservaŃie:
La fel ca în cazul unui vector, odată declarată o matrice, nu trebuie
neapărat să folosim toate elementele sale. Astfel, dacă porŃiunea efectiv folosită
din matrice are m linii şi n coloane, nu este obligatoriu ca aceasta să înceapă cu
linia 0 şi coloana 0 ! Putem numerota liniile efectiv folosite de la 1 la m şi
coloanele de la 1 la n, caz în care matricea ar arăta astfel:
a[1][1], a[1][2],..., a[1][n] → linia 1
a[2][1], a[2][2],..., a[2][n] → linia 2
.....................................
a[m][1], a[m][2],..., a[m][n] → linia m

346
IniŃializarea unei matrici la declarare
IniŃializarea unei matrici la declarare este foarte asemănătoare cu cea a
unui vector. Plecând de la faptul că o matrice poate fi privită ca un "vector de
vectori", vom proceda astfel:
− scriem liniile matricii între două acolade separate prin "virgulă";
− scriem fiecare linie a matricii ca pe un vector, adică cu elementele sale
cuprinse între alte două acolade şi separate tot prin "virgulă".
Cu alte cuvinte, iniŃializarea unei matrici se prezintă sub forma unei
înşiruiri de perechi de acolade separate prin virgule, tot acest ansamblu fiind
cuprins între două acolade exterioare.
Ex e mp l u :
int a[3][3]={{1,2,3},{4,5,6},{7,8,9}};
InstrucŃiunea declară o matrice a cu maxim trei linii şi coloane, care totodată este
şi iniŃializată cu următorul tablou de numere:

1 2 3
4 5 6
7 8 9

La fel ca şi în cazul vectorilor, valorile iniŃiale ale elementelor matricii nu


sunt "bătute în cuie", ele putând fi ulterior modificate, prin atribuiri sau citiri.

AŃi înŃeles ? Probleme cu răspuns scurt


►1. DeclaraŃi o matrice a cu maxim 15 linii * 10 coloane şi elemente numere
întregi, în care liniile şi coloanele sunt numerotate succesiv începând cu 0.

►2. Fie următoarea declaraŃie a unei matrici a:


unsigned int a[5][7];
Care dintre atribuirile de mai jos sunt corecte ?
a) a[0][0]=-1; b) a[1,2]=1; c) a[5][7]=1; d) a[1][1]=MAXINT;

►3. (Bacalaureat iulie 2000, varianta 1)


Care dintre următoarele variante reprezintă o declaraŃie corectă a unui tablou cu
elemente numere reale ?
a) float x[];
b) real x[20];
c) double x[100][20];
d) unsigned float x[100,20];

347
V . 2 . 2 . P a r c u r g e r e a , c i t i r e a ş i a f i ş a r e a u n e i m a t r i ci

Considerăm o matrice a, cu m linii şi n coloane. Presupunem că liniile şi


coloanele matricii sunt numerotate în mod natural: liniile de la 0 la m-1, iar
coloanele de la 0 la n-1. Parcurgem într-un ciclu liniile matricii, i=0,1,...,m-1.
Pentru fiecare linie i, parcurgem într-un alt ciclu coloanele acesteia,
j=0,1,...,n-1. Pentru fiecare valoare a lui i şi j, "vizităm" elementul
a[i][j], de pe linia i şi coloana j. Prezentăm în continuare algoritmul de
parcurgere, precum şi ordinea în care vor fi "vizitate" elementele matricii a:

pentru (i ← 0,1,..,m-1) execută i=0,j=0 → a[0][0]


pentru (j ← 0,1,..,n-1) execută j=1 → a[0][1]
.................
<prelucrează a[i][j]>
j=n-1 → a[0][n-1]
i=1,j=0 → a[1][0]
j=1 → a[1][1]
..................
j=n-1 → a[1][n-1]
..................
i=m-1,j=0 → a[m-1][0]
j=1 → a[m-1][1]
..................
j=n-1 → a[m-1][n-1]

A) Citirea unei matrici a cu m linii şi n coloane


Citim mai întâi numărul real de linii şi coloane, m respectiv n, apoi pentru
a citi elementele matricii a folosim algoritmul de mai sus: parcurgem în două
cicluri liniile i=0,1,...,m-1 şi coloanele j=0,1,...,n-1; pentru fiecare linie
i şi coloană j, citim elementul a[i][j].
pentru (i ← 0,1,..,m-1) SecvenŃa de program:
pentru (j ← 0,1,..,n-1) cout << "\nNr. linii si coloane: ";
cin >> m >> n;
citeşte a[i][j];
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";
cin >> a[i][j];
}

Observăm că, la fiecare pas, înainte de citirea propriu-zisă a elementului


a[i,j] (cu instrucŃiunea readln), se tipăreşte un mesaj care ne arată la ce
element am ajuns cu citirea.

348
cout << "a[" << i << "][" << j << "]=" ;

text
indicele de linie text indicele de coloană text

Astfel, de exemplu, pentru i=2 şi j=3, înainte de citirea valorii


elementului a[2][3], se va afişa textul: cursor în aşteptare
a[2][3]= _

B) Afişarea unei matrici a cu m linii şi n coloane

Folosim tot ideea algoritmului de parcurgere descris anterior. Pentru a


afişa fiecare linie a matricii pe un rând de ecran vom proceda astfel: parcurgem
într-un ciclu liniile i=0,1,...,m-1, şi pentru fiecare linie i:
 afişăm elementele liniei i pe un rând al ecranului;
 mutăm cursorul la începutul rândului următor.
pentru (i←←0,1,...,m-1) execută
început
<afişează linia i pe un rând>
<mută cursorul la începutul rândului următor>
sfârşit;
Iar pentru a afişa elementele liniei i pe un rând, vom proiecta un alt ciclu,
în care parcurgem coloanele j=0,1,...,n-1 ale liniei i, şi la fiecare pas afişăm
elementul a[i][j] (de pe linia i şi coloana j). Astfel, secvenŃa de program este:
for (i=0; i<=m-1; i++)
{
for (j=0; j<=n-1; j++)
cout << a[i][j] << " ";
cout << endl;
}

AplicaŃie R.V.16. Problemă cu răspuns scurt


(Bacalaureat iulie 2009, varianta 42 - enunŃ adaptat)
Variabila a memorează un tablou bidimensional cu 5 linii * 5 coloane,
numerotate de la 0 la 4, ale cărei elemente sunt numere întregi. Care este cea mai
mare valoare memorată în tablou în urma executării secvenŃei de program de mai
jos, şi de câte ori apare această valoare pe liniile şi coloanele tabloului ?
for (i=0; i<=4; i++)
for (j=0; j<=4; j++)
if (i && j)

349
a[i][j]=j%i+i%j;
else
a[i][j]=0;

Rezolvare
:
În primul ciclu for, se parcurg indicii liniilor matricii, cu ajutorul contorului i
care ia pe rand valorile 0,1,2,3,4. Pentru fiecare linie i, se execută un al doilea ciclu
for, în care contorul j parcurge indicii de coloană, tot cu valorile succesive 0,1,2,3,4.
La fiecare pas al celor două cicluri imbricate, se "vizitează" elementul a[i][j], a cărui
valoare este completată în urma unei testări:
− dacă atât i cât şi j sunt diferiŃi de 0 (condiŃia "i!=0 && j!=0" se poate scrie
prescurtat "i && j"), atunci a[i][j] ia valoarea i%j+j%i ;
− în caz contrar (adică unul din indici este nul), a[i][j] ia valoarea 0.
Urmărim evoluŃia ciclurilor pas cu pas. Aşadar, în primul ciclu i=0,1,2,3,4 şi
avem paşii:
Pasul 1, pentru i=0 ⇒ j=0,1,2,3,4; indiferent de valoarea lui j, condiŃia "i!=0 &&
j!=0" este falsă, deci toate elementele de pe linia 0 vor avea valoarea 0;
Pasul 2, pentru i=1 ⇒ j=0,1,2,3,4;
– Pasul 2.1., pentru j=0: din nou condiŃia din linia if este falsă, deci a[1][0]=0;
– Pasul 2.2., pentru j=1: acum condiŃia este adevărată, deci a[1][1]=1%1+1%1=0
– Pasul 2.3., pentru j=2: condiŃie adevărată ⇒ a[1][2]=1%2+2%1=1
– analog, se va constata că şi restul elementelor de pe linia 1 au valoarea 1.
În mod similar se parcurg şi ceilalŃi paşi ai primului ciclu, trecând în revistă valorile
i=2, i=3 şi i=4. În final, vom obŃine matricea:

0 0 0 0 0
0 0 1 1 1
0 1 0 3 2
0 1 3 0 4
0 1 2 4 0

În concluzie, valoarea maximă care apare în matrice este 4, şi ea se regăseşte de


două ori: pe linia 3 şi coloana 4, respectiv pe linia 4 şi coloana 3.

AplicaŃie R.V.17. Produs într-o matrice


(Bacalaureat iulie 2009, varianta 68)
ScrieŃi un program care citeşte de la tastatură două numere naturale m şi n
(0≤m≤49,0≤n≤49) precum şi m*n numere naturale de cel mult 5 cifre ce
reprezintă elementele unui tablou bidimensional, apoi afişează pe ecran produsul
elementelor pozitive aflate pe linii cu numere de ordine pare şi coloane cu numere
de ordine impare. Numerotarea liniilor, respectiv a
11 -21 31 41
coloanelor se va face începând cu valoarea 0. 5 -61 71 -81
Exemplu: pentru m=4, n=4 şi matricea 91 11 21 31
alăturată se va afişa 451 (451=11*41). -11 31 -41 0
350
Rezolvare
:
 Declarăm o matrice a cu maxim 25 de linii * 30 de coloane şi elemente
numere întregi. Notăm cu m şi n, numărul real de linii respectiv coloane efectiv folosite.
Mai definim o variabilă P care va memora produsul elementelor pozitive aflate pe linii
pare şi coloane impare, precum şi două variabile i şi j care vor fi folositre drept contoare
pentru cicluri: {int a[25][30],i,j,m,n,P;}.

 Citim mai întâi m şi n. Parcurgem într-un ciclu liniile matricii i=0,1,...,m-1, şi


pentru fiecare linie i, parcurgem într-un alt ciclu coloanele acesteia j=0,1,...,n-1. Pentru
fiecare valoare a lui i şi j, "vizităm" şi citim elementul a[i][j], de pe linia i şi coloana j.
cout << "\nDati numarul de linii si coloane: ";
cin >> m >> n;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";
cin >> a[i][j];
}

 IniŃializăm cu 1 produsul P al elementelor pozitive aflate pe linii pare şi


coloane impare.
Pentru a calcula P, parcurgem din nou liniile i şi coloanele j în două cicluri
similare cu cele de mai sus: i=0,1,..,m-1 şi j=0,1,...,n-1. Pentru fiecare element
a[i][j], testăm dacă elementul este pozitiv {a[i][j]>0}, linia i pe care se află este
pară {i%2==0, ceea ce înseamnă "not (i%2 diferit de 0)", expresie care se poate scrie pe
scurt "!(i%2)"} şi coloana j pe care se află este impară {"j%2 diferit de 0", pe scurt
"j%2"}. În caz afirmativ, înmulŃim elementul a[i][j] cu valoarea curentă a lui P şi
memorăm rezultatul tot în P {P*=a[i][j]}.
P=1;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
if (a[i][j]>0 && !(i%2) && j%2)
P*=a[i][j];

 Programul se încheie cu afişarea valorii finale a produsului P.


# include <iostream.h>
int a[25][30],i,j,m,n,P;
void main ()
{
// citeste matricea a cu m linii *n coloane
cout << "\nDati numarul de linii si coloane: "; cin >> m >> n;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";

351
cin >> a[i][j];
}
cout << endl;
// calculeaza produsul P al elementelor pozitive de pe linii pare si coloane impare
P=1;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
if (a[i][j]>0 && !(i%2) && j%2) P*=a[i][j];
cout << "\n Produsul este " << P;
}

ObservaŃie:
Algoritmul de mai sus ilustrează parcurgerea tuturor elementelor unei matrici, dar
nu este cel mai eficient pentru a calcula produsul cerut (din cele m*n treceri prin matrice,
jumătate sunt inutile). Ar trebui parcurse numai elementele de pe linii pare şi coloane
impare, folosind două cicluri while:
− plecând de la i=0 (prima linie pară), parcurgem liniile într-un ciclu while,
atâta timp cât i<=m-1 ; la fiecare pas, "vizităm" linia i, apoi trecem la următoarea linie
pară prin atribuirea i+=2;
• "vizitarea" liniei i înseamnă parcurgerea elementelor de pe coloanele
impare ale acestei linii. Plecând de la j=1 (prima coloană impară) şi
parcurgem coloanele într-un ciclu, atâta timp cât j<=n-1: la fiecare pas,
"prelucrăm" elementul a[i][j] (dacă este pozitiv îl adăugăm la suma S),
apoi trecem la următoarea coloană impară prin atribuirea j+=2.
S=0;
i=2;
while (i<=m-1) {linia i}
{
j=1;
while (j<=n-1) {linia i şi coloana j}
{
if a[i][j]>0 then
S+=a[i][j];
j+=2;
}
i+=2;
}

ÎncercaŃi singuri !

►1. Fiind dată o matrice a cu m linii şi n coloane cu elemente numere


întregi, scrieŃi câte un program care:
a) Determină media aritmetică a elementelor matricii;
b) Stabileşte de câte ori apare o valoare dată x ca element al matricii;
c) Afişează numărul elementelor pozitive, numărul elementelor negative şi
numărul elementelor nule din matrice;
d) Tipăreşte elementele pare aflate pe linii impare şi coloane divizibile cu 3.
352
►2. (Bacalaureat iulie 2009, varianta 83)
Se consideră variabilele întregi m, n şi k (1≤ ≤n≤≤10, 1≤
≤m≤
≤10, 1≤≤k≤
≤n),
precum şi variabila a, care memorează un tablou bidimensional, cu n linii
numerotate de la 0 la n-1, respectiv m coloane numerotate de la 0 la m-1. Toate
cele n*m elemente ale tabloului sunt numere întregi. ScrieŃi un 2 -5 1 7
program care să determine şi să afişeze pe ecran elementele 3 0 -1 -9
impare de pe linia k a tabloului a. 4 6 11 2
Exemplu: pentru n=4, m=4, k=1 şi matricea din figură, 0 8 4 -6
se vor afişa valorile: 3, -1 şi -9.
►3. Să se calculeze suma a două matrici date A şi B cu câte m linii şi n
coloane fiecare, citite de la tastatură. Fiecare element C[i][j] al matricii sumă C
este egal cu A[i][j]+B[i][j], pentru i=0,1,...,m-1 şi j=0,1,...,n-1.
Să se afişeze apoi matricea sumă c.

AplicaŃie R.V.18. Interschimbarea a două linii într-o matrice


(Bacalaureat iulie 2009, varianta 53)
ScrieŃi un program C/C++ care citeşte de la tastatură patru numere
naturale nenule m, n, L1 şi L2 (2 < m ≤ 1 0, 2 < n ≤ 2 0, 1 ≤ L 1 ≤ 10, 1≤ L 2 ≤ 1 0 ),
precum şi elementele unui tablou bidimensional a cu m linii numerotate de la 0
la m-1, si n coloane, numerotate de la 0 la n-1, apoi interschimbă elementele de
pe linia x a tabloului bidimensional cu cele de pe linia y. Tabloul bidimensional
astfel obŃinut se va afişa pe ecran, câte o linie a tabloului pe câte o linie a
ecranului, cu un spaŃiu între elementele fiecărei linii.
Exemplu: pentru L1=1 şi L2=2 şi dacă se citeşte matricea din figura 1,
după interschimbare vom obŃine matricea din figura 2.
2 -5 1 7 2 -5 1 7
3 0 -1 -9 4 6 11 2
4 6 11 2 3 0 -1 -9
0 8 4 -6 0 8 4 -6

Rezolvare figura 1 figura 2


:
 Citim numărul de linii şi coloane, m respectiv n, apoi citim elementele
matricii în două cicluri for: parcurgem liniile i=0,1,...,m-1 şi coloanele
j=0,1,...,n-1, citind fiecare element a[i][j].

 În continuare citim numerele de ordine L1 şi L2 ale liniilor care urmează să


fie interschimbate. Fireşte că valorile lui L1 şi L2 trebuie să fie cuprinse în intervalul
0,1,...,m-1. De aceea, la citirea acestor variabile vom valida valorile introduse.
Execută
• citeşte L1 şi L2;

353
Cât timp valorile introduse pentru L1, L2 sunt în afara intervalului [0..m-1].
do
{
cout << endl << "Dati liniile L1 si L2: ";
cin >> L1 >> L2;
} while (L1<0 || L1>m-1 || L2<0 || L2>m-1);

 Interschimbăm în această matrice liniile L1 şi L2 între ele. Într-un ciclu,


parcurgem "în paralel" coloanele celor două linii, j=0,1,..,n-1, şi, pentru fiecare
coloană j, interschimbăm între ele elementele aflate pe respectiva coloană în cele două
linii, adică a[L1][j] cu a[L2][j], folosind metoda "paharelor".
Exemplu: Dacă matricea are n=3 coloane, atunci j=0,1,2 şi facem interschimbările:
a[L1][0]↔a[L2][0], a[L1][1]↔a[L2][1], a[L1][2]↔a[L2][2]

 Interschimbarea a două elemente a[L1][j] şi a[L2][j] prin metoda paharelor:


 se salvează a[L1][j] într-o variabilă "temporară" temp;
 se memorează în a[L1][j] valoarea lui a[L2][j];
 în a[L2][j] se memorează valoarea iniŃială a lui a[L1][j], salvată în temp.
for (j=0; j<=n-1; j++)
{
temp=a[L1][j]; a[L1][j]=a[L2][j]; a[L2][j]=temp;
}

 În final tipărim matricea rezultată după interschimbare. Parcurgem într-un


ciclu liniile i=0,1,...,m-1, şi pentru fiecare linie i:
 afişăm elementele liniei i pe un rând al ecranului: parcurgem într-un alt
ciclu coloanele j=0,1,...,n-1 ale liniei i şi afişăm fiecare element
a[i][j].
 mutăm cursorul la începutul rândului următor.
for(i=0; i<=m-1; i++)
{
cout << endl;
for(j=0; j<=n-1; j++)
cout << a[i][j] << " ";
}

 Prezentăm în continuare programul complet:

#include <iostream.h>
#include <conio.h>

void main ()
{
int a[20][20],i,j,m,n;
int L1,L2,temp;
clrscr();
cout << "Dati nr de linii si coloane m si n: ";
cin >> m >> n;

354
// citim matricea a, cu m linii si n coloane
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "Elem de pe linia " << i << " si col " << j << ": ";
cin >> a[i][j];
}
// citeste numerele liniilor, L1 si L2; acestea trebuie sa fie cuprinse in intervalul [0..m-1]
do
{
cout << endl << "Dati liniile L1 si L2: ";
cin >> L1 >> L2;
} while (L1<0 || L1>m-1 || L2<0 || L2>m-1);
// interschimba intre ele liniile L1 si L2, coloana cu coloana
for (j=0; j<=n-1; j++)
{
temp=a[L1][j]; a[L1][j]=a[L2][j]; a[L2][j]=temp;
}
for(i=0; i<=m-1; i++)
{
cout << endl;
for(j=0; j<=n-1; j++)
cout << a[i][j] << " ";
}
getch();
}

ÎncercaŃi singuri !

► 1. Se citeşte de la tastatură o matrice a cu m linii * n coloane şi elemente


numere întregi. Să se interschimbe între ele două coloane date C1 şi C2, fără a folosi
altă matrice. Liniile şi coloanele matricii sunt numerotate începând cu 0.
Exemplu: pentru C1=1 şi C2=2 şi dacă se citeşte matricea din figura 1,
după interschimbare vom obŃine matricea din figura 2.
2 -5 1 7 2 1 -5 7
3 0 -1 -9 4 -1 0 2
4 6 11 2 3 11 6 -9
0 8 4 -6 0 4 8 -6

figura 1 figura 2

AplicaŃie R.V.19. Construirea unei matrice în memorie


(Bacalaureat iulie 2008, varianta 30, enunŃ adaptat)
ScrieŃi un program care citeşte de la tastatură două numere naturale m şi n
(unde 2<=m,n<=15), apoi construieşte în memorie o matrice a cu m linii * n
coloane, astfel:
355
− elementele primei linii vor fi 0,1,…,n-1, iar cele ale primei coloane
vor fi 0,1,…,m-1;
− fiecare dintre celelelalte elemente va fi egal cu suma dintre elementul
aflat în stânga sa pe aceeaşi linie şi elementul aflat deasupra sa pe aceeaşi coloană.
Liniile şi coloanele matricii vor fi numerotate începând cu 0. Matricea va fi
afişată pe ecran linie cu linie, valoriile de pe aceeaşi linie fiind separate prin câte un spaŃiu.
Exemplu: pentru m=4 linii şi n=5 coloane, matricea va arăta ca în figură.

0 1 2 3 4
1 2 4 7 11
2 4 8 15 26
3 7 15 30 56
Rezolvare
:
 Mai întîi citim de la tastatură numărul de linii m şi numărul de coloane n ale
matricii. Apoi completăm prima linie, cu indicele de linie 0, ale cărei coloane sunt
0,1,…,n-1, iar elementele de pe aceste coloane sunt aceleaşi valori 0,1,…,n-1. Cu alte
cuvinte, valoarea fiecărui element a[0][i] (de pe fiecare coloană a a liniei 0) este chiar i,
unde contorul i parcurge într-un ciclu valorile 0,1,…,n-1.
for (i=0; i<=n-1; i++)
a[0][i]=i;
 În mod similar, completăm prima coloană: observând că elementele a[i][0]
de pe liniile i=0,1,…m-1 ale primei coloane sunt chiar valorile 0,1,…,m-1, proiectăm un
ciclu for asemănător cu primul.
for (i=0; i<=m-1; i++)
a[i][0]=i;
 Fiecare dintre celelalte elemente a[i][j] este egal cu suma dintre alte două
elemente, şi anume:
− elementul situat pe aceeaşi linie în stânga lui, respectiv pe coloana j-1, în speŃă
elementul a[i][j-1] şi
− elementul situat pe aceeaşi coloană deasupra lui, respectiv pe linia i-1, în speŃă
elementul a[i-1][j].
Cu alte cuvinte, a[i][j]=a[i][j-1]+a[i-1][j]. Cum trebuie să excludem
prima linie şi prima coloană deja completate, vom avea i=1,…,m-1 şi j=1,…,n-1, în
două cicluri imbricate.
for (i=1; i<=m-1; i++)
for (j=1; j<=n-1; j++)
a[i][j]=a[i][j-1]+a[i-1][j];
 În final, afişăm matricea a cu algoritmul clasic. Într-un ciclu, parcurgem
liniile i=0,1,…,m-1 ale matricii, şi pentru fiecare linie i:
− parcurgem coloanele j=0,1,…,n-1 ale liniei i, afişând elementele a[i][j],
pe acelaşi rând, cu câte un spaŃiu între ele;
− trecem la rândul următor pe ecran.
 Iată mai jos programul complet:

356
// Bac 2009, II.5 / var 30
#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();
int a[15][15],i,j,m,n;
// citeste dimensiunile matricii a
cout << "Dati nr de linii m si nr de coloane n: ";
cin >> m >> n;
// completeaza prima linie a matricii
for (i=0; i<=n-1; i++)
a[0][i]=i;
// completeaza prima coloana
for (i=0; i<=m-1; i++)
a[i][0]=i;
// completeaza restul elementelor
for (i=1; i<=m-1; i++)
for (j=1; j<=n-1; j++)
a[i][j]=a[i][j-1]+a[i-1][j];
// afiseaza matricea construita a
cout << "Matricea este: " << endl;
for (i=0; i<=m-1; i++)
{
for (j=0; j<=n-1; j++)
cout << a[i][j] << " ";
cout << endl;
}
getch();
}

ÎncercaŃi singuri !
► 1. (Bacalaureat iulie 2009, varianta 43)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(2<n<=10) şi construieşte în memorie o matrice A cu n linii şi n coloane în care
toate elementele de pe prima linie, prima şi ultima coloană au valoarea 1 şi
oricare alt element Aij din matrice este egal cu suma a trei
1 1 1 1 1
elemente situate pe linia i-1: primul aflat pe coloana j-1, 1 3 3 3 1
al doilea pe coloana j, iar al treilea pe coloana j+1, ca în 1 7 9 7 1
exemplu. Matricea va fi afişată pe ecran, linie cu linie, 1 17 23 17 1
numerele de pe aceeaşi linie fiind separate prin câte un 1 41 57 41 1
spaŃiu.
Exemplu: pentru n=5, se afişează matricea alăturată.

► 2. (Bacalaureat iulie 2009, varianta 5)


ScrieŃi un program care citeşte de la tastatură două numere naturale n şi m
(2≤m≤10, 2≤n≤10) şi care construieşte în memorie şi apoi afişează o matrice A cu

357
n linii (numerotate de la 1 la n) şi m coloane (numerotate de la 1 la m) cu
proprietatea că fiecare element Aij memorează cea mai mare dintre valorile
indicilor i şi j (0≤i≤n-1, 0≤j≤m-1). Matricea se va afişa pe
0 1 2 3 4
ecran, câte o linie a matricei pe câte o linie a ecranului,
1 1 2 3 4
elementele fiecărei linii fiind separate prin câte un spaŃiu. 2 2 2 3 4
Exemplu: pentru n=4 şi m=5 se va afişa matricea 3 3 3 4 5
alăturată.
► 3. (Bacalaureat iulie 2009, varianta 57)
ScrieŃi un program care citeşte de la tastatură două numere naturale n şi p
(2<n<25, 0<p<n) şi construieşte în memorie o matrice cu n linii şi n coloane
numerotate de la 0 la n-1, formată numai din valori 0,1 şi 2 astfel încât:
elementele aflate pe linia p sunt egale cu 0, cele de deasupra liniei p sunt egale
cu 1, iar elementele aflate sub linia p sunt egale cu 2 ca în exemplul de mai jos.
Programul afişează pe ecran matricea construită,
fiecare linie a matricei pe o linie a ecranului şi elementele de 1 1 1 1 1
1 1 1 1 1
pe aceeaşi linie separate prin câte un singur spaŃiu.
1 1 1 1 1
Exemplu: pentru n=5, p=3 se construieşte în memorie 0 0 0 0 0
şi se afişează matricea alăturată. 2 2 2 2 2

AplicaŃie R.V.20. DiferenŃă maximă


(Bacalaureat iulie 2008, varianta 26 - enunŃ adaptat)
Se citesc de la tastatură trei numere naturale n, L1 şi L2, precum şi o
matrice pătratică a cu n linii şi coloane (numerotate 0,1,...,n-1), având
elemente numere întregi. RealizaŃi un program care determină şi afişează cea mai
mare diferenŃă care se poate calcula între două elemente, unul situat pe linia L1, iar
celălalt pe linia L2.
Exemplu: pentru L1=0, L2=1 şi matricea din figură, programul va afişa
valoarea 21, reprezentând diferenŃa în modul |a[0,0]-a[1,2]|.

2 7 11
4 6 23
1 2 9
Rezolvare
:
 Declarăm o matrice pătratică a, cu n linii şi coloane, şi elemente numere
întregi. Citim mai întâi pe n, apoi elementele matricii: parcurgem într-un ciclu liniile
matricii i=0,1,...,n-1, şi pentru fiecare linie i, parcurgem într-un alt ciclu coloanele
j=0,1,...,n-1; la fiecare pas, la "intersecŃia" celor două cicluri imbricate, citim
elementul a[i][j], situat pe linia i şi coloana j. Continuăm apoi cu citirea celor două

358
linii L1 şi L2 pentru care se cere diferenŃa maximă, cu validare, adică repetăm citirea atâta
timp cât valorile introduse pentru L1 şi L2 nu aparŃin intervalului [0,n-1].
 Pentru a calcula toate diferenŃele dintre un element de pe linia L1 şi un
element de pe linia L2, va trebui practic să stabilim toate cuplajele între o coloană j1 a
liniei L1 şi o coloana j2 a liniei L2. De ce ? Pentru că, având perechea de indici de coloană
(j1,j2), putem face imediat corespondenŃa, ajungând astfel la o pereche de forma
(a[L1][j1],a[L2][j2]), adică o pereche alcătuită cu un element de pe linia L1 şi un
element de pe linia L2 a matricii a. Mai departe, odată construite perechile de elemente
(a[L1][j1],a[L2][j2]), nu trebuie să determinăm decât cea mai mare dintre
expresiile |a[L1][j1]-a[L2][j2]|.
Dar pentru a alcătui toate perechile de indici de coloană de forma (j1,j2),
trebuie să Ńinem cont că atât j1 cât şi j2 iau valori de la 0 la n-1, deci problema se reduce
la formarea perechilor de două numere din mulŃimea {0,1,...,n-1}. Acest algoritm a
fost prezentat în problema rezolvată R.V.8. din acest capitol, care aborda perechi de
elemente într-un vector, aşa că îl vom aminti doar. Pe scurt, pentru a rezulta numai
perechile distincte şi neordonate, primul element al perechii j1 va lua pe rând valorile
0,1,...,n-2, iar al doilea element j2 va lua valorile j1+1,...,n-1. Acum putem
dezvolta algoritmul problemei noastre.
 IniŃializăm cu -MAXINT o variabilă max în care vom calcula diferenŃa maximă
cerută. Formăm toate perechile de indici de coloană de forma (j1,j2), în două cicluri
for, cu j1=0,1,...,n-2 şi j2=j1+1,...,n-1. La fiecare pas, pentru fiecare pereche
(j1,j2):
 cercetăm elementele aferente coloanelor j1 şi j2, aflate unul pe linia L1 iar
celălalt pe linia L2; dacă diferenŃa în modul dintre a[L1][j1] şi
a[L2][j2] este mai mare decât valoarea curentă a lui max {|a[L1][j1]-
a[L2][j2]|>max}, atunci respectiva diferenŃă va deveni momentan cea
maximă (max=|a[L1][j1]-a[L2][j2]|). Totodată cu actualizarea
diferenŃei maxime max, vom reŃine în variabilele C1_m şi C2_m indicii j1 şi
j2 ai coloanelor care realizează modificarea respectivului maxim (C1_m=j1
şi C2_m=j2), astfel încât după ieşirea din cicluri să putem localiza
elementele care au generat diferenŃa maximă finală.
max=-MAXINT;
for (j1=0; j1<=n-2; j1++)
for (j2=j1+1; j2<=n-1; j2++)
if (abs(a[L1][j1]-a[L2][j2])>max)
{
max=abs(a[L1][j1]-a[L2][j2]);
C1_m=j1;
C2_m=j2;
}

 În final afişăm atât diferenŃa maximă max, cât şi elementele a[L1][C1_m] şi


a[L2][C2_m] care alcătuiesc respectiva diferenŃă.

#include <iostream.h>
#include <conio.h>
#include <values.h>
#include <math.h>

359
void main ()
{
int a[20][20],i,j,n;
int max,j1,j2,L1,L2,C1_m,C2_m;
clrscr();
cout << "Dati nr de linii si coloane n: ";
cin >> n;
// citim matricea patratica a, cu n linii si coloane
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "Elem de pe linia " << i << " si coloana " << j << ":
";
cin >> a[i][j];
}
// citeste numerele liniilor, L1 si L2; acestea trebuie sa fie cuprinse in intervalul [0..n-1]
do
{
cout << endl << "Dati liniile L1 si L2: ";
cin >> L1 >> L2;
} while (L1<0 || L1>n-1 || L2<0 || L2>n-1);
// formam perechi de indicii de coloane (j1,j2)
// astfel incat sa imperechem elementele (a[L1,j1],a[l2,j2])
max=-MAXINT;
for (j1=0; j1<=n-2; j1++)
for (j2=j1+1; j2<=n-1; j2++)
// pt fiecare astfel de pereche, actualizam diferenta maxima in variabila max,
// retinand si indicii de coloana aferenti C1_m si C2_m
if (abs(a[L1][j1]-a[L2][j2])>max)
{
max=abs(a[L1][j1]-a[L2][j2]);
C1_m=j1;
C2_m=j2;
}
cout << endl << "Cea mai mare dif este " << max;
cout << endl << "pt coloana " << C1_m << " de pe linia " << L1
<< " si coloana " << C2_m << " de pe linia " << L2;
getch();
}

ÎncercaŃi singuri !

► 1. Se citesc de la tastatură trei numere naturale n, C1 şi C2, precum şi o


matrice pătratică a cu n linii * n coloane (numerotate cu 0,1,...,n-1). RealizaŃi
un program care determină şi afişează cea mai mică diferenŃă care se poate calcula
între două elemente, unul situat pe linia C1, iar celălalt pe linia C2.
Exemplu: pentru C1=1, C2=2 şi matricea din figură, 2 7 11
programul va afişa valoarea 2, reprezentând diferenŃa în modul 4 6 23
|a[0,1]-a[2,2]|. 1 2 9

360
► 2. (Bacalaureat iulie 2009, varianta 25)
Se consideră un tablou bidimensional cu m linii şi n coloane (1≤≤ m≤
≤ 100 şi
≤ n≤
1≤ ≤ 100 ), ale cărui elemente sunt numere întregi. ScrieŃi un program care citeşte
de la tastatură valorile m şi n, precum şi elementele tabloului, apoi afişează pe
ecran, numerele de ordine ale coloanelor pentru care produsul
elementelor situate pe ele este maxim. Numerele se vor afişa 2 1 1 0
separate prin câte un spaŃiu. 1 1 1 1
2 2 2 1
Exemplu: pentru m=4 şi n=4 şi tabloul din imagine, în 1 2 1 1
condiŃiile în care liniile şi coloanele sunt numerotate începând cu 0,
se va afişa, nu neapărat în această ordine: 0 1

AplicaŃie R.V.21 Eliminarea unei linii într-o matrice


(Bacalaureat iulie 2009, varianta 70)
ScrieŃi programul C/C++ care citeşte de la tastatură două numere naturale
m şi n (1 ≤ m ≤ 1 00,1 ≤ n ≤ 1 00), un număr x (1 ≤ x ≤ m ) precum şi m*n numere
naturale de cel mult cinci cifre ce reprezintă elementele unui tablou bidimensional
a, cu m linii, numerotate de la 0 la m-1, şi n coloane, numerotate de la 0 la n-1,
apoi afişează pe ecran elementele tabloului rezultat după ştergerea din memorie a
liniei x, fără a folosi un tablou bidimensional suplimentar. Afişarea matricei
obŃinută după eliminare, se va face pe m-1 linii, elementele fiecărei linii fiind
despărŃite prin câte un spaŃiu.
Exemplu: pentru m=3, n=4, x=1 şi matricea din figura 1, se va afişa
matricea din figura 2.
11 21 31 41 11 21 31 41
51 61 71 81 91 11 21 31
91 11 21 31

figura 1 figura 2
Rezolvare
:
 Citim numărul de linii şi coloane, m respectiv n, apoi citim elementele
matricii în două cicluri for. Apoi citim linia X, cu validarea valorii introduse: execută
citirea lui X, atâta timp cât valoarea introdusă nu se situează în intervalul [0,m-2) (dacă
linia ce trebuie eliminată este ultima, operaŃia de eliminare devine inutilă, fiind suficientă
afişarea liniilor 0,1,...,m-2).
Eliminarea liniei X se face prin copierea cu o linie mai sus a tuturor liniilor aflate
după linia X. Parcurgem într-un ciclu indicii i=X+1,...,m-1 ai acestor linii; La fiecare
pas al ciclului, pentru fiecare valoare a lui i, se va copia linia i cu o linie mai sus. Cu alte
cuvinte, "linia i trece în linia i-1". Astfel, într-un alt ciclu cu j=0,1,...,n-1, fiecare
element a[i][j] al liniei se va copia prin atribuire în a[i-1][j].

361
Concret, să exemplificăm cu eliminarea liniei X=1 (a doua), în matricea a cu m=4
linii şi n=3 coloane de mai jos:

0 1 2 i=X+1,...,m-1, deci i=2,3; i→i-1, deci:


− pentru i=2, linia 2 se copiază în linia 1;
0 2 5 1
− pentru i=3, linia 3 se copiază în linia 2;
1 3 12 4 Detaliem pentru i=2:
2 23 4 9 − a[2][0]→ a[1][0];
− a[2][1]→ a[1][1];
3 6 8 7
− a[2][2]→ a[1][2]

 În final tipărim matricea rezultată după eliminarea liniei X, care va avea numai
m-1 linii. Prezentăm în continuare programul complet:

# include <iostream.h>
int a[30][30],i,j,m,n,X;
void main ()
{
// citeste matricea a cu m linii * n coloane
cout << "\nDati numarul de linii si coloane: ";
cin >> m >> n;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";
cin >> a[i][j];
}
// citeste numarul X al liniei care va fi eliminata; aceasta trebuie sa fie in intervalul [0..m-1]
do
{
cout << "X="; cin >> X;
} while (X<0 || X>m-2);
// elimina linia X, prin mutarea cu o linie mai sus a tuturor liniilor aflate dupa X
for (i=X+1; i<=m-1; i++)
for (j=0; j<=n-1; j++)
a[i-1][j]=a[i][j];
// afiseaza matricea rezultata, din care ne intereseaza doar primele m-1 linii
for (i=0; i<=m-2; i++)
{
for (j=0; j<=n-1; j++)
cout << a[i][j] << " ";
cout << endl;
}
}

ÎncercaŃi singuri !
►1. Pentru o matrice dată a cu m linii * n coloane şi elemente numere
întregi, să se elimine o coloană dată C, fără a folosi altă matrice.

362
Exemplu: pentru matricea din figura 1 şi coloana C=2 (cu liniile şi
coloanele numerotate începând de la 0), va rezulta matricea din figura 2.
2 -5 1 7 2 -5 7
3 0 -1 -9 4 0 2
4 6 11 2 3 6 -9
0 8 4 -6 0 8 -6

figura 1 figura 2

► 2. (Bacalaureat iulie 2009, varianta 92)


ScrieŃi un program care citeşte de la tastatură numerele întregi m şi n
(1≤m≤50 , 1≤ ≤ n≤≤ 50 ) şi elementele unui tablou bidimensional cu m linii şi n
coloane, numere întregi distincte de cel mult 4 cifre fiecare, şi elimină din tablou,
la nivelul memoriei, linia şi coloana corespunzătoare elementului de valoare
minimă. Programul va afişa tabloul obŃinut pe ecran pe m-1 linii, elementele
fiecărei linii fiind separate prin câte un spaŃiu.
Exemplu: pentru m=3 şi n=4 şi tabloul de mai jos:
2 7 1 4
14 6 12 3
9 22 8 5

Pe ecran se va afişa:
14 6 3
9 22 5

Algoritm ►Parcurgerea unei matrici în raport cu diagonalele


Considerăm o matrice a cu n linii şi n coloane. O matrice cu proprietatea
că numărul de linii este egal cu numărul de coloane se numeşte matrice pãtratică.
Notăm: i=indicele de linie şi j=indicele de coloană; exemplificăm pentru
matricea de mai jos, în care n=4.
diagonala secundară
0 1 2 3

5 7 11 3 0 porŃiunea de deasupra diagonalei principale

8 10 4 16 1

9 6 13 2 2
diagonala principală
1 14 27 17 3 porŃiunea de sub diagonala principală

363
 elementele de pe diagonala principală sunt a[0][0], a[1][1],
a[2][2], a[3][3]; în general ele sunt de forma a[i][j] cu i=j,
sau altfel spus a[i][i] unde i=0,1,...,n-1;
 elementele de deasupra diagonalei principale sunt:
 pe linia 0: a[0][1], a[0][2], a[0][3];
 pe linia 1: a[1][2], a[1][3];
 pe linia 2: a[2][3];
 pe linia 3: nu există.
Pe caz general, elementele a[i][j] de deasupra diagonalei principale se
caracterizează prin proprietatea j>i.
Observăm că:
• liniile i care conŃin elemente deasupra diagonalei principale sunt de
la 0 la 2. Pe caz general, de la 0 la n-2;
• coloanele j care au elemente deasupra diagonalei principale sunt: de
la 1 la 3 pentru linia i=0, de la 2 la 3 pentru i=1, ş.a.m.d. Pe caz
general, j variază de la i+1 la n-1.
Pentru a "vizita" elementele de deasupra diagonalei principale, avem
două posibilităŃi:
a) parcurgem toate elementele în două cicluri (liniile i de la 0 la n-1 şi
coloanele j de la 0 la n-1) şi pentru fiecare element a[i][j] testăm dacă este
situat deasupra diagonalei principale, adică verificăm dacă j>i;
b) "vizităm" numai elementele aflate deasupra diagonalei principale:
parcurgem numai liniile i care conŃin elemente deasupra diagonalei principale:
i=0,1,...,n-2. Pentru fiecare linie i, parcurgem numai coloanele j ale liniei
i care au elemente deasupra diagonalei principale, adică j=i+1,...,n-1.
a) b)
for (i=0; i<=n-1; i++) for (i=0; i<=n-2; i++)
for (j=0; j<=n-1; j++) for (j=i+1; j<=n-1; j++)
if (j>i) <prelucrează a[i][j]>
<prelucrează a[i][j]>

Absolut analog vom proceda pentru a parcurge porŃiunea din matrice


aflată sub diagonala principală:
a) b)
for (i=0; i<=n-1; i++) for (i=1; i<=n-1; i++)
for (j=0; j<=n-1; j++) for (j=0; j<=i-1; j++)
if (j<i) <"vizitează" a[i][j]>
<prelucrează a[i][j]>

364
AplicaŃie R.V.22. Sume în raport cu diagonala secundară

(Bacalaureat iulie 2009, varianta ....)


Se consideră o matrice pătratică cu n linii şi n coloane (1≤n≤30), ce
memorează numere întregi de cel mult două cifre fiecare. ScrieŃi un program care
citeşte de la tastatură valoarea n şi elementele matricei, apoi afişează pe ecran
suma acelor elemente de pe diagonala secundară care au proprietatea că sunt valori
minime pe coloanele lor. Dacă nu există astfel de 3 4 90 10
elemente în matrice, se va afişa mesajul NU EXISTA. 25 2 7 9
Exemplu: pentru n=4 şi matricea din figură, se va 18 3 10 4
afişa pe ecran valoarea 10 (3+7). 3 7 20 3

Rezolvare
:
 Declarăm o matrice pătratică a, cu n linii şi coloane, şi elemente numere
întregi. Citim mai întâi pe n, apoi elementele matricii: parcurgem într-un ciclu liniile
matricii i=0,1,...,n-1, şi pentru fiecare linie i, parcurgem într-un alt ciclu coloanele
j=0,1,...,n-1; la fiecare pas, la "intersecŃia" celor două cicluri imbricate, citim
elementul a[i][j], situat pe linia i şi coloana j.

 IniŃializăm cu 0 variabila S în care calculăm suma cerută. IniŃiem un ciclu, în


care parcurgem coloanele j=0,1,...,n-1 ale matricii. La fiecare pas al acestui ciclu:
– suntem pe coloana j, şi trebuie să calculăm elementul minim al respectivei coloane.
Pentru aceasta, iniŃializăm cu MAXINT o variabilă min în care vom determina
minimul în cauză, apoi parcurgem într-un alt ciclu liniile i=0,1,...,n-1 ale
coloanei j; la fiecare pas, dacă elementul a[i][j] al coloanei j este mai mic decât
minimul curent, atunci a[i][j] devine noul minim;
min=MAXINT;
for (i=0; i<=n-1; i++)
if (a[i][j]<min)
min=a[i][j];
– odată determinat minimul min de pe coloana j a matricii, trebuie să
verificăm dacă el coincide cu elementul de pe coloana j aflat pe diagonala
secundară; pe matricea dată ca exemplu în enunŃ, cu n=4 linii şi coloane,
elementele de pe diagonala secundară (cele subliniate în figură) sunt
a[0][3], a[1][2], a[2][1], a[3][0]; observăm că toate aceste
elemente au o proprietate: suma indicilor de linie şi coloana este 3, adică, pe
caz general n-1; prin urmare, putem spune că dacă un element a[i][j] se
află pe diagonala principală, atunci i+j=n-1, deci i=n-1-j; în concluzie,
pentru a verifica dacă minimul min de pe coloana j se află pe diagonala
principală, este suficient să testăm dacă el coincide cu elementul
a[n-j-1][j]; în caz afirmativ, adăugăm acel minim la suma S cerută,
afişându-l totodată.

365
if (min==a[n-j-1][j])
{
cout << endl << "Un element cerut este " << min;
S+=min;
}
 În final afişăm suma S a elementelor de pe diagonala secundară cu
proprietatea că sunt minimele de pe coloana lor.

// Bac 2009, II.5 / var 38


#include <iostream.h>
#include <conio.h>
#include <values.h>

void main ()
{
int a[20][20],i,j,n,min,S;
clrscr();
cout << "Dati nr de linii si coloane n: ";
cin >> n;
// citim matricea patratica a, cu n linii si coloane
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "Elem de pe linia " << i << " si coloana " << j << ":
";
cin >> a[i][j];
}
S=0;
// parcurgem coloanele j ale matricii
for (j=0; j<=n-1; j++)
{
// pt fiecare coloana j, determinam minimul sau
min=MAXINT;
for (i=0; i<=n-1; i++)
if (a[i][j]<min)
min=a[i][j];
//verificam daca minimul min de pe coloana j este elementul de pe diagonala
secundara
// si in caz afirmativ actualizam produsul P
if (min==a[n-j-1][j])
{
cout << endl << "Un element cerut este " << min;
S+=min;
}
}
cout << endl << "Suma ceruta este: " << S;
getch();
}

366
ÎncercaŃi singuri !
►1. (Bacalaureat iulie 2009, varianta 88)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(1≤n≤20 ), elementele unei matrice cu n linii şi n coloane, numere întregi din
intervalul [-100,100] apoi afişează pe ecran media
aritmetică a elementelor strict pozitive ale matricei, care -1 2 -4 5
0 6 3 1
sunt situate deasupra diagonalei principale, ca în exemplu. 2 4 2 0
Exemplu: pentru n=4 şi matricea alăturată se 3 -5 1 -3
afişează valoarea 2.75 (sunt luate în considerare doar
elementele subliniate, deci m=(2+5+3+0)/4=2.75)
►2. O matrice pătratică cu n linii * n coloane se numeşte triunghiulară
superior dacă toate elementele aflate sub diagonala principală sunt nule.
Se citeşte de la tastatură o matrice pătratică a cu n linii * n coloane.
RealizaŃi un program care verifică dacă matricea este triunghiulară superior,
tipărind un mesaj.
►3. (Bacalaureat iulie 2009, varianta 17)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(2<n<20), apoi construieşte în memorie şi afişează pe ecran o matrice cu n linii şi
n coloane, în care fiecare element de pe diagonala secundară are valoarea n,
fiecare element aflat deasupra diagonalei secundare este mai mic cu o unitate decât
vecinul aflat pe aceeaşi linie în dreapta lui şi fiecare element
aflat sub diagonala secundară este mai mare cu o unitate decât 1 2 3 4 5
vecinul aflat pe aceeaşi linie în stânga lui. 2 3 4 5 6
Elementele matricei vor fi afişate pe ecran, câte o linie a 3 4 5 6 7
4 5 6 7 8
matricei pe câte o linie a ecranului cu câte un spaŃiu între 5 6 7 8 9
elementele fiecărei linii.
Exemplu: pentru n=5 se va afişa matricea alăturată.

AŃi înŃeles ? Probleme cu răspuns scurt


► 1. Cum scriem condiŃia ca un element a[i][j] al unei matrici a să fie pozitiv
şi să se afle pe linie pară şi coloană impară ?
► 2. (Bacalaureat iulie 2009, varianta 58)
Variabila a memorează o matrice cu 10 linii şi 10 coloane, numerotate de la 0
la 9, iar i şi j sunt variabile întregi cu valori cuprinse între 1 şi 10. ScrieŃi o expresie
care să fie nenulă dacă şi numai dacă elementul a[i][j] este nenul şi nu se află pe
diagonala principală a matricei.

367
► 3. (Bacalaureat iulie 2009, varianta 71)
În secvenŃa de program de mai jos, variabila i este de tip întreg, iar variabila a
memorează o matrice cu n linii * n coloane, numerotate de la 0 la n-1, ale cărei elemente
sunt numere întregi. ÎnlocuiŃi punctele de suspensie (reprezentate prin "..."), astfel încât,
în urma executării secvenŃei, variabila întreagă s1 să reprezinte suma elementelor de pe
diagonala principală a matricii a, iar variabila întreagă s2 să calculeze suma elementelor
de pe diagonala secundară a aceleeaşi matrici.
s1=s2=0;
for(i=0; i<=n-1; i++)
{
s1+=...; s2+=...;
}

► 4. (Bacalaureat iulie 2009, varianta 67)


Se consideră secvenŃa alăturată în care a este o matrice pătratică cu 4 linii şi 4
coloane, numerotate de la 0 la 3, iar i şi j sunt variabile de tip întreg. Ce valoare are
suma elementelor matricii a după executarea secvenŃei ?
for(i=0; i<=3; i++)
for(j=0; j<=3; j++)
if (i<=j)
a[i][j]=i;
else
a[i][j]=j;

Următoarele două probleme se referă la secvenŃa de program de mai jos:


for(i=0; i<=2; i++)
for(j=0; j<=2; j++)
a[i][j]=j-i;
i=0;
while (i<=2)
{
a[i][3-i]=a[i][0];
i+=2;
}

► 5. Câte atribuiri se execută în total pe parcursul rulării sercvenŃei ?

► 6. Câte elemente ale matricii a vor avea valoarea 0 după execuŃia secvenŃei ?

► 7. (Bacalaureat iulie 2009, varianta 60)


Fie a o matrice cu 5 linii şi 5 coloane numerotate de la 0 la 4. Fiecare element
a[i][j] (0≤i≤4,1≤j≤4 ) din matrice memorează valoarea expresiei (i-1)*5+j. Care
este valoarea sumei elementelor de pe ultima coloană a matricei?
► 8. (Bacalaureat iulie 2009, varianta 66 - enunŃ adaptat)
Se consideră secvenŃa alăturată în care a este un tablou bidimensional cu 5 linii
şi 5 coloane, numerotate de la 0 la 4, iar m, j, x, y sunt variabile de tip întreg. Ştiind că
iniŃial orice element al tabloului este egal cu suma dintre numărul de ordine al liniei şi
numărul de ordine al coloanei pe care se află, precizaŃi care sunt elementele tabloului a
după executarea secvenŃei alăturate, dacă x memorează valoarea 1 şi y memorează
valoarea 3.
368
for (j=0; j<=4; j++)
{
m=a[j][x]; a[j][x]=a[j][y]; a[j][y]=m;
}

► 9. (Bacalaureat iulie 2009, varianta 54)


Consideram următoarele declarări:
int a[50][50],i,k;
Ce valoare are variabila k după executarea secvenŃei de instrucŃiuni de mai jos,
dacă a memorează elementele unui tablou bidimensional cu zece linii (numerotate de la 0
la 9) şi zece coloane (numerotate de la 0 la 9), ce are pe fiecare linie în ordine crescătoare
numerele 0, 1, ..., 9 ?
k=0;
for (i=0; i<=9; i++)
if ((1-a[i][i]%3)*(2-a[i][i]%3)==0)
k++;

► 10. Care dintre secvenŃele de program de mai jos construieşte corect matricea
 1 2 3
 
a=  4 5 6  ?
7 8 9
 

{ SecvenŃa S2 } { SecvenŃa S1 } { SecvenŃa S3 }


for (i=3;i>=1; i--) for (i=1;i<=3; i++) for (i=3;i>=1; i--)
for (j=1; j<=3; j++) for (j=3; j>=1; j--) for (j=3; j>=1; j--)
a[i][j]=3*i+j-3; a[i][j]=3*i+j-3; a[i][j]=3*i+j-3;
a) Numai S1 b) S1 şi S2 c) Toate d) S1 şi S3

► 11. Se consideră secvenŃa de program următoare, în care a este o matrice cu n linii


* n coloane cu elemente numere întregi, iar x este o variabilă de tip ]ntreg cu sens logic.
x=1;
for (i=1; j<=n-1; j++)
for (j=0; j<=i-1; j++)
if (a[i][j]) x=0;

În urma execuŃiei secvenŃei, valoarea variabilei x va fi TRUE dacă:


a) Toate elementele de sub diagonala principală sunt zero.
b) Toate elementele de deasupra diagonalei principale sunt zero.
c) Deasupra diagonalei principale există cel puŃin un element egal cu zero.
d) Sub diagonala principală există cel puŃin un element diferit cu zero.
► 12. De câte ori va afişa caracterul '*' secvenŃa de program următoare, dacă
1 2 − 3
 
matricea a este  1 − 2 3  ?
1 0 0 

369
i=0; j=0; m=3; n=3; a) niciodată
while (i<=m-1 && a[i][j]>0) b) o dată
{ c) de două ori
j=0;
while (j<=n-1 && a[i][j]>0)
d) de trei ori
{
cout << "\n* "; j++;
}
i++;
}

► 13. Ştiind că a este o matrice pătratică cu n linii * coloane şi elemente numere


întregi, ce trebuie scris în locul simbolurilor <val>
> şi <inf> >, astfel încât valoarea afişată
de către secvenŃa următoare să reprezinte maximul dintre elementele aflate sub diagonala
principală în matrice.
<val>
max=< >; a) < val>
> → 0, <inf> > → 0;
<inf>
for (i=< > ; i<=n-1; i++) b) < val>
> → MAXINT, < inf> > → 0;
for (j=0; j<=i-1; j++) c) <val>> → a[[1,0]] , <inf>
> → 1;
if (a[i][j]>max) d) < val>
> → -MAXINT, <inf> > → 1.
max=a[i][j];
cout << max;

► 14. Fie programul următor:


void main()
{
int i,j,m,n,p,a[10][10],b[6];
m=2; n=3; p=6; i=0;
while(i<p) b[i++]=i;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
a[i][j]=b[3*i+j];
}
PrecizaŃi care dintre afirmaŃiile de mai jos nu sunt adevărate:
a) Ultimele trei elemente ale vectorului b sunt 3,4,5.
b) a[1][0] are valoarea 3.
c) a[0][2] are valoarea 2.
d) Programul nu funcŃionează corect.
► 15. Fie o matrice a cu m linii * n coloane şi elemente întregi. SecvenŃele de
program de mai jos îşi propun să memoreze în vectorul b=(b[0],b[1],...,b[m-1])
elementele maxime de pe liniile matricei (adică b[i] să fie maximul de pe linia i a
matricei, cu i=0,1,2,...,m-1). Care dintre ele nu funcŃionează corect în sensul dorit ?
a) b)
for(i=0;i<m;i++) for(i=0;i<m;i++)
{ {
x=a[i][0]; x=a[i][n-1];
for(j=1;j<n;j++) for(j=n-2;j>0;j--)
if (a[i][j]>x) if (a[i][j]>x)
x=a[i][j]; x=a[i][j];
b[i]=x; b[i]=x;
} }
370
c) d)
for(i=0;i<m;i++) for(i=0;i<m;i++)
{ {
x=a[i][n-1]; x=-MAXINT;
for(j=n-2;j>=0;j--) for(j=0;j<n;j++)
if (x<a[i][j]) if (x<a[i][j])
x=a[i][j]; x=a[i][j];
b[i]=x; b[i]=x;
} }

► 16. Fie o matrice pătratică a cu n=4 linii*coloane. Care vor fi elementele celei
de-a treia linii a matricii a după execuŃia secvenŃei de program de mai jos ?
for (i=0; i<=n-1; i++) a) (2,0,1,2);
a[n-1][i]=i-1; b) (1,2,0,1);
for (i=n; i>=1; i--)
a[i][0]=i-1; c) (1,2,3,0);
for (i=n-2; i>=0; i--) d) (0,1,2,0);
for (j=1; j<=n-1; j++)
a[i][j]=a[i+1][j-1];

Aprofundare

Probleme rezolvate

R.V.23 Sortarea unei linii într-o matrice


Se citeşte de la tastatură o matrice a cu m linii şi n coloane, având ca
elemente numere întregi. Să se ordoneze crescător elementele unei linii L, prin
interschimbări de coloane. Valoarea lui L se citeşte de la tastatură.
Rezolvare
:
Citim mai întâi matricea, apoi citim valoarea lui L. În principiu, se aplică liniei L
(cu L citit de la tastatură) algoritmul de sortare prin interschimbări directe, cu deosebirea că
în momentul în care trebuie să interschimbăm două elemente a[L][C1] şi a[L][C2] ale
liniei L, vom interschimba integral coloanele pe care se află acestea.
Pe rând, fiecare din primele n-1 elemente ale liniei L vor juca rolul unui aşa-numit
pivot. Aşadar parcurgem primii n-1 indici de coloană ai liniei L, într-un ciclu cu
C1=0,1,...,n-2. Pentru fiecare pivot a[L][C1], folosind un alt ciclu cu C2=C1+1,...,n-
1, parcurgem elementele de pe linia L aflate după pivot. La fiecare pas, comparăm a[L][C1]
cu a[L][C2]. Dacă a[L][C2]< <a[L][C1], atunci cele două elemente trebuie interschimbate,
pentru că în linia ordonată crescător, a[L][C2] trebuie să apară înaintea lui a[L][C1]. Dar
aşa cum am spus, vom interschimbă integral coloanele C1 şi C2.

371
 Parcurgem "în paralel" într-un al treilea ciclu liniile k=0,1,...,m-1 ale
celor două coloane. La fiecare pas al acestui al treilea ciclu se interschimbă
elementele aflate pe aceeaşi linie în cele două coloane, adică a[k][C1] cu
a[k][C2], folosind "metoda paharelor".
În final se afişează matricea obŃinută după sortarea liniei L.
# include <iostream.h>
int a[30][30],i,j,k,m,n,L,C1,C2,aux;
void main ()
{
// citeste matricea a cu m linii * n coloane
cout << "\nDati numarul de linii si coloane:\n ";
cin >> m >> n;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";
cin >> a[i][j];
}
cout << "Dati linia pe care o sortez: ";
cin >> L;
// pe rand, elementele a[L][C1] ale liniei L, cu C1=0,1,..,n-2 vor deveni pivoti
// intr-un alt ciclu, parcurgem elementele a[L][C2] cu C2=C1+1,..,n-1 aflate dupa pivot
for (C1=0; C1<=n-2; C1++)
for (C2=C1+1; C2<=n-1; C2++)
{
// daca elementul a[L][C2] este mai mic decat pivotul a[L][C1],
// atunci interschimbam intre ele coloanele C1 si C2
if (a[L][C2]<a[L][C1])
// pentru a interschimba coloanele C1 si C2 parcurgem in paralel liniile k=0,1,..,m-1
// pe cele doua coloane, si interschimbam elementele linie cu linie
for (k=1; k<=m-1; k++)
{
aux=a[k][C1]; a[k][C1]=a[k][C2]; a[k][C2]=aux;
}
}
// afisam matricea cu linia L sortata crescator
for (i=0; i<=m-1; i++)
{
for (j=0; j<=n-1; j++)
cout << a[i][j] << " ";
cout << endl;
}
}

R.V.24 P er e ch i d e lin i i c o m p lem e nt a r e în tr - o ma t r ice


Se dă un tablou bidimensional cu m linii şi n coloane (m,n<25),
numerotate 0,1,…,m-1 respectiv 0,1,…,n-1, având ca elemente numai cifre de
0 şi 1. Două linii se numesc complementare, dacă, pentru orice coloană, suma

372
elementelor aflate pe aceeaşi coloană este 1. Să se identifice perechile de linii
complementare şi să se determine numărul acestora. Pentru fiecare astfel de
pereche se vor afişa pe un rând al ecranului indicii liniilor ce o compun, separate
prin spaŃii, iar pe ultimul rând se va tipări numărul perechilor de linii
complementare din tablou.
1 0 1
 
1 1 1 0 2
Exemplu: pentru m=5, n=3 şi tabloul 0 1 0 , se va tipări: 1 3
 
0 0 0 2
 
Rezolvare 1 0 0
:
Citim de la tastatură matricea a cu m linii şi m coloane, în două cicluri. Identificăm
liniile matricii prin indicii lor. Astfel, pentru a evidenŃia perechile de linii, vom alcătui
toate perechile de indici de forma (i1,i2), cu i1=0,1,…,m-2 şi i2=i1+1,…,m-1. De
exemplu, pentru m=4 linii, perechile de indici ce se pot forma pe mulŃimea {0,1,2,3}
sunt: (0,1), (0,2), (0,3), (1,2), (1,3) şi (2,3). Formăm aceste perechi în două cicluri şi
pentru fiecare pereche (i1,i2) testăm dacă liniile ce o alcătuiesc sunt complementare.
Pentru aceasta, parcurgem “în paralel” coloanele liniilor perechii, printr-un alt ciclu care
străbate indicii de coloană j=0,1,..,n-1; la fiecare pas verificăm complementaritatea
elementelor a[[i1][j]] şi a[[ i2][j]] , condiŃie care observăm că se poate scrie sub forma
a[[ i1][j]] +a[[i2][j]]==1. Testarea este una logică, prin intermediul unei variabile compl.
Totodată, dacă liniile i1 şi i2 sunt complementare, incrementăm un contor nr care
numără liniile complementare.
#include <iostream.h>
int a[30][30],i,j,i1,i2,m,n,nr,compl;
void main ()
{
// citeste matricea a cu m linii * n coloane
cout << "\nDati numarul de linii si coloane: ";
cin >> m >> n;
for (i=0; i<=m-1; i++)
for (j=0; j<=n-1; j++)
{
cout << "a[" << i << "][" << j << "]=";
cin >> a[i][j];
}
nr=0; // numarul perechilor de linii complementare
// formam toate perechile de indici de linie, de forma (i1,i2)
for (i1=0; i1<=m-2; i1++)
for (i2=i1+1; i2<=m-1; i2++)
// pentru fiecare pereche de linii (i1,i2), parcurgem coloanele "in paralel"
// si testam daca liniile sunt complementare
{
compl=1;
for (j=0; j<=n-1; j++)
if (a[i1][j]+a[i2][j]!=1)
compl=0;

373
if (compl)
{
cout << endl << i1 << " " << i2;
nr++;
}
}
cout << "\n Numarul liniilor complementare este " << nr;
}

R.V.25 P a r cu rg e rea în sp ir a lă a u n ei ma t r ic i
Se citeşte de la tastatură un şir cu n*n elemente numere întregi. Să se
introducă elementele şirului într-o matrice pătratică cu n linii * n coloane prin
parcurgerea matricii în spirală, aşa cum rezultă din desenul din exemplu.
Exemplu: pentru n=4 şi şirul (1,2,3,4,8,12,16,15,14,13,9,5,6,7,
11,10), se va construi şi se va afişa matricea:

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Rezolvare
:
Deşi în toate aplicaŃiile de până acum am numerotat liniile şi coloanele matricilor
începând de la 0, aşa cum am subliniat în partea teoretică, acest lucru nu este obligatoriu.
Pe caz general, într-o matrice cu m linii * n coloane putem să numerotăm liniile de la 1 la m
şi coloanele de la 1 la n, astfel încât această numerotare să fie în ton cu exprimarea
naturală: prima linie să aibă numărul de ordine 1, a doua linie numărul de ordine 2,
ş.a.m.d. Practic, nu folosim linia şi coloana 0, deşi fizic acestea există.
Ilustrăm această variantă de numerotare în problema de faŃă. Matricea noastră
fiind pătratică, indicii de linie şi coloană sunt acum 1,2,...,n. Pentru similitudine, am
notat poziŃiile elementelor în şirul de intrare de la 1 la n*n.
Din desen se poate observa că parcurgerea în spirală a unei matrici generează
nişte “inele” concentrice care trebuie parcurse succesiv. Pentru parcurgerea fiecărui inel
avem nevoie de patru cicluri for care să străbată cele patru laturi ale inelului: sus, dreapta,
jos, stânga. Notând cu k numărul de ordine al unui nivel oarecare, constatăm că:
− elementele laturii de sus sunt de forma a[[k][i]], cu i=k,..,n-k+1;
− pe latura din dreapta întâlnim elemente de forma a[i][n-k+1], cu
i=k+1,..,n-k+1;
− elementele laturii de jos au forma a[n-k+1][i], cu i=n-k,..,k (descrescător);
− pe latura din stânga avem elementele a[i][k], cu i=n-k,..,k+1
(descrescător).
În toate cele patru situaŃii, memorăm un element x[l] al vectorului x în
elementul corespunzător al matricii a şi incrementăm poziŃia l la care am ajuns cu
parcurgerea în vectorul x.

374
Odată stabilită modalitatea de parcurgere a unui inel k, trebuie să generalizăm
formula pentru toate cele (n+1) / 2 inele, motiv pentru care ansamblul celor patru cicluri
for care parcurg un inel k, va fi inclus într-un alt ciclu for cu k de la 1 la (n+1) / 2.

#include <iostream.h>
int x[400],a[40][40],n,i,j,L,k;
void main ()
{
// citeste sirul x cu n elemente
cout << "n="; cin >> n;
cout << "Introduceti elementele sirului:\n";
for (i=1; i<=n*n; i++)
{
cout << "x[" << i << "]=";
cin >> x[i];
}
// construieste matricea a matricei
L=1; // contorul L parcurge vectorul x
for (k=1; k<=(n+1)/2; k++)
// parcurge cele [(n+1) / 2] inele concentrice in matrice, cu ajutorul a 4 cicluri for
{
for (i=k; i<=n-k+1; i++) // latura de sus a inelului k
{
a[k][i]=x[L];
L++;
}
for (i=k+1; i<=n-k+1; i++) // latura din dreapta a inelului k
{
a[i][n-k+1]=x[L];
L++;
}
for (i=n-k; i>=k; i--) // latura de jos a inelului k
{
a[n-k+1][i]=x[L];
L++;
}
for (i=n-k; i>=k+1; i--) // latura din stanga a inelului k
{
a[i][k]=x[L];
L++;
}
}
for (i=1; i<=n; i++)
{
for (j=1; j<=n; j++)
cout << a[i][j] << " ";
cout << endl;
}
}

375
R.V.26 Construirea unei matrici în memorie
(Bacalaureat iulie 2002, varianta 3)
ScrieŃi un program care construieşte în memorie un tablou t cu n linii şi n
coloane, cu elementele numere naturale, astfel încât pe diagonala principală să existe
numai elemente egale cu 1, elementele de pe cele două "semidiagonale" paralele cu
diagonala principală şi alăturate diagonalei principale să fie egale cu 2, elementele de
pe următoarele două "semidiagonale" să fie egale cu 3
1 2 3 4
etc. Valoarea lui n (n număr natural, n<20) se citeşte de 2 1 2 3
la tastatură. Tabloul se va afişa pe ecran cu formatul 3 2 1 2
sugerat în exemplul următor. Pentru n=4, se va afişa 4 3 2 1
tabloul:
1 2 3 4
2 1 2 3
3 2 1 2
4 3 2 1
Desenul ilustrează faptul că tabloul afişat respectă
cerinŃa problemei.

Rezolvare
:
Pentru o mai clară înŃelegere, prezentăm matricea
cerută şi pentru n=5, folosind numerotarea "clasică" a liniilor şi 1 2 3 4 5
coloanelor, de la 0 la n-1.
2 1 2 3 4
Într-un ciclu for, cu i de la 0 la n-1, "vizităm"
elementele a[[ i][i]] de pe diagonala principală, şi pentru fiecare 3 2 1 2 3
astfel de element realizăm următoarele operaŃii:
− Atribuim valoarea 1 elementului a[[ i][i]] de pe 4 3 2 1 2
diagonală;
− Completăm porŃiunea din linia i aflată în dreapta 5 4 3 2 1
elementului de pe diagonală. ObservaŃi că, "citind" această
porŃiune de la stânga la dreapta, elementele sale cresc cu câte o unitate, aşa cum este
ilustrat pe linia 1 din desenul de mai sus. Cu alte cuvinte, într-un ciclu, contorul k va
parcurge valorile i+1,...,n-1, reprezentând indicii coloanelor de pe linia i aflate după
elementul de pe diagonală, şi la fiecare pas elementul a[[i][k]] va lua valoarea a[[ i][k-
1]] +1 (cu 1 mai mare decât precedentul element al liniei i);
− Analog, completăm porŃiunea din linia i aflată în stânga elementului de pe
diagonala principală (vezi linia 3 din desenul anterior). Pentru aceasta, într-un ciclu cu k
descrescător de la i-1 la 0 parcurgem coloanele acestei porŃiuni, şi la fiecare pas facem
atribuirea a[i][k]=a[i][k+1]+1.
În final afişăm matricea construită, parcurgând liniile şi coloanele de la 1 la n în două
cicluri for.

376
# include <iostream.h>
int a[30][30],i,j,n,k;
void main ()
{
cout << "n="; cin >> n; // n =nr de linii si coloane
for (i=0; i<=n-1; i++)
{
// completeaza elementul de pe linia i si coloana i de pe diagonala principala
a[i][i]=1;
// completeaza elementele liniei i aflate in dreapta celui de pe diagonala principala
for (k=i+1; k<=n-1; k++) a[i][k]=a[i][k-1]+1;
// completeaza elementele liniei i aflate in stanga celui de pe diagonala principala
for (k=i-1; k>=0; k--)
a[i][k]=a[i][k+1]+1;
}
// afiseaza matricea a
for (i=0; i<=n-1; i++)
{
for (j=0; j<=n-1; j++) cout << a[i][j] << " ";
cout << endl;
}
}

Probleme propuse

Probleme suplimentare
► 1. ScrieŃi un program care afişează maximul dintre
1 8 3 9
elementele pare ale liniei L a unei matrici cu m linii şi n coloane. 2 9 5 7
Valorile lui n şi L, precum şi elementele matricii (numere întregi) 3 6 8 9
se citesc de la tastatură. 4 2 5 0
Exemplu: pentru L=2 şi matricea din figură, se va afişa
valoarea 9.
► 2. O matrice pătratică a se numeşte simetrică faŃă de diagonala
principală, dacă fiecare element de deasupra diagonalei principale este egal cu
simetricul său de sub diagonală, adică a[i][j]==a[j][i] pentru orice i≠ ≠ j.
ScrieŃi un program care verifică dacă o matrice pătratică a cu n linii şi n coloane
citită de la tastatură, este simetrică faŃă de diagonala principală. 1 2 3 4
Exemplu: matricea din figură este simetrică faŃă de 2 5 6 7
diagonala principală. 3 6 8 9
IndicaŃii: Folosim o testare logică. Presupunem iniŃial că 4 7 9 0
matricea a este simetrică, iniŃializând cu 1 o variabilă ok, de tip întreg
dar cu sens logic. Apoi, într-un ciclu, căutăm cazul contrar. Parcurgem doar elementele
de deasupra diagonalei principale, în două cicluri imbricate, cu i=0,1,...,n-2 şi

377
j=i+1,...,n-1; pentru fiecare element a[i][j], dacă el dacă este diferit de
a[j][i], atunci matricea nu mai este simetrică, deci variabila ok ia valoarea 1.
Valoarea finală a lui ok ne va da "starea" condiŃiei testate.

► 3. Se citesc de la tastatură mai întâi două numere naturale m şi n


cuprinse în intervalul [2,20], şi apoi o matrice a cu m linii * n coloane şi
elemente numere întregi, în care liniile sunt numerotate cu 0,1,...,m-1, iar
coloanele cu 0,1,...,n-1. ScrieŃi un program care verifică dacă două linii date
x şi y sunt identice (conŃin aceleaşi elemente în aceeaşi
dispunere pe coloane), şi afişează mesajul "DA" sau "NU". -1 8 -4 2
0 6 3 1
Exemplu: pentru n=4, x=1, y=2 şi matricea din
0 6 3 1
figură, programul va tipări textul "DA". 7 -5 -1 -9
► 4. (Bacalaureat iulie 2009, varianta 90)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(1≤n≤20), precum şi elementele unei matrice cu n linii şi n coloane, numere
întregi din intervalul [-100, 100], apoi afişează pe ecran diferenŃa m1-m2, unde
m1 este media aritmetică a elementelor strict pozitive ale matricei, situate
deasupra diagonalei principale, iar m2 este media aritmetică a elementelor strict
pozitive ale matricei, situate sub diagonala principală, ca în exemplu. Cele două
medii se consideră egale cu 0 dacă nu există valori strict pozitive în zonele
corespunzătoare.
Exemplu: pentru n=4 şi matricea din figură, se -1 2 -4 5
afişează valoarea 0.25 (m1=2.75, calculată din elementele 0 6 3 1
aflate deasupra diagonalei principale, subliniate cu linie 2 4 2 0
simplă, şi m2=2.5, calculată din elementele de sub diagonala 3 -5 1 3
principală, subliniate cu linie dublă).
► 5. Se citesc de la tastatură mai întâi două numere naturale m şi n, şi apoi o
matrice a cu m linii * n coloane, ale cărei elemente sunt cifre de 0 şi 1. Liniile
matricii sunt numerotate cu 0,1,...,m-1, iar coloanele cu 0,1,...,n-1.
ScrieŃi un program ce determină indicii liniilor pe care se află
cele mai multe valori de 1. Indicii respectivi vor fi afişaŃi pe un 1 0 1 0 1
1 0 1 1 1
singur rând de ecran, separaŃi prin spaŃii. 0 1 1 1 1
Exemplu: pentru matricea a din figură, programul va 0 1 0 0 0
afişa valorile 1 şi 2, pentru că a doua şi a treia linie conŃin câte
patru valori de 1.
IndicaŃii: Definim un vector nr, în care fiecare element nr[i] va reprezenta
numărul valorilor de 1 de pe linia i din matrice. Într-un ciclu, parcurgem liniile
i=0,2,...,m-1 ale matricii, şi, pentru fiecare linie i, numărăm în elementul nr[i] câte
valori de 1 conŃine, parcurgând coloanele sale j=0,1,..,n-1. În final, nu ne rămâne
altceva de făcut decât să aflăm elementul maxim al vectorului nr, şi să localizăm poziŃiile
pe care se găseşte acest maxim în vector, întrucât ele coincid cu indicii liniilor vizate în
matrice.

378
► 6. (Bacalaureat iulie 2002, varianta 2)
ScrieŃi un program care construieşte în memorie un tablou t cu n linii şi n
coloane, cu elemente numere naturale, astfel încât pe ultima coloană şi pe ultima
linie a tabloului să se afle numai elemente egale cu 1, iar oricare alt element al
tabloului să fie suma dintre elementul aflat imediat sub el şi elementul aflat
imediat în dreapta lui.
Valoarea lui n (număr natural, n< <20) se citeşte de la tastatură. Tabloul se
va afişa pe ecran în formatul ”clasic”: de la prima la ultima linie, elementele unei
linii fiind scrise de la stânga la dreapta, cu spaŃii între elementele fiecărei linii.
Exemplu: pentru n=4, se va afişa tabloul următor:

20 10 4 1
10 6 3 1
4 3 2 1
1 1 1 1

Se observă că fiecare element al tabloului (în afara elementelor cu valoarea 1)


respectă cerinŃa: 20=10+10, 10=6+4, 4=3+1, 10=4+6, 6=3+3, 3=2+1, 4=1+3, 3=1+2 şi
2=1+1.
IndicaŃii: Numerotăm indicii de linie şi coloană cu 0,1,...,n-1. Mai întâi
completăm cu 1 ultima linie şi ultima coloană:
− pentru linia n-1 facem atribuirea a[n-1][j] =1 într-un ciclu în care
parcurgem coloanele j de la 0 la n-1;
− pentru coloana n-1 facem atribuirea a[i][n-1]=1 într-un ciclu în care
parcurgem liniile i de la 0 la n-1. Pentru a completa restul matricii, trebuie să
asigurăm pentru fiecare element existenŃa vecinilor din dreapta şi de dedesupt. Pentru
aceasta, ordinea de parcurgere este următoarea: liniile de jos în sus (cu indicele de linie
i descrescător de la n-2 la 0), iar coloanele de la dreapta la stânga (cu indicele de
coloană j descrescător de la n-2 la 0); la fiecare pas, elementul a[i][j] va fi egal cu
a[i+1][j]+a[i][j+1].

► 7. (Bacalaureat iulie 2009, varianta 1)


ScrieŃi un program care citeşte de la tastatură două numere naturale nenule
n şi m (2≤m≤10,2≤n≤10 ) şi care construieşte în memorie şi apoi afişează o
matrice A cu n linii (numerotate de la 0 la n-1) şi m coloane (numerotate de la 0 la
m-1) cu proprietatea că fiecare element Aij memorează cea mai mică dintre
valorile indicilor i şi j (0≤i≤n-1,0≤j≤m-1 ). Matricea se va
1 1 1 1 1
afişa pe ecran, câte o linie a matricei pe câte o linie a ecranului, 1 2 2 2 2
elementele fiecărei linii fiind separate prin câte un spaŃiu. 1 2 3 3 3
Exemplu: pentru n=4 şi m=5 se va afişa matricea alăturată. 1 2 3 4 4
► 8. (Bacalaureat iulie 2009, varianta 12)
ScrieŃi un program care citeşte de la tastatură un număr natural n
(2<n<50) şi apoi construieşte în memorie o matrice cu n linii şi n coloane,
numerotate de la 1 la n, ale cărei elemente primesc valori după cum urmează:
− elementele aflate pe diagonala secundară sunt toate nule;
379
− elementele de pe linia i (1≤i≤n ), aflate deasupra diagonalei
secundare, au valoarea egală cu i;
− elementele de pe coloana n-i+1 (1≤i≤n ), aflate sub diagonala
secundară, au valoarea egală cu i.
Programul va afişa matricea astfel construită pe ecran, 1 1 1 0
câte o linie a matricei pe câte o linie a ecranului, elementele 2 2 0 1
fiecărei linii fiind separate prin câte un spaŃiu. 3 0 2 1
Exemplu: pentru n=4 se va afişa matricea alăturată. 0 3 2 1

► 9. (Bacalaureat iulie 2009, varianta 16)


ScrieŃi un program care citeşte de la tastatură un număr natural n
(2<n<16), construieşte în memorie şi afişează pe ecran o matrice cu n linii şi n
coloane, în care elementele de pe cele două diagonale sunt egale 4 3 3 3 4
cu 4, iar restul elementelor sunt egale cu 3. Elementele matricei 3 4 3 4 3
vor fi afişate pe ecran, câte o linie a matricei pe câte o linie a 3 3 4 3 3
ecranului cu câte un spaŃiu între elementele fiecărei linii. 3 4 3 4 3
Exemplu: pentru n=5 se va afişa matricea alăturată. 4 3 3 3 4

► 10. Se citeşte de la tastatură un număr natural n


( 1 ≤ n ≤ 6 ). Să se construiască un tablou pătratic cu n linii * n coloane având ca
elemente primii n*n termeni ai şirului lui Fibonacci. Ordinea de construire a
matricii va fi:
a[0][0],...,a[0][n-1], a[1][0],..., a[1][n-1],..., a[n-1][0],...,a[n-1][n-1].
1 1 2
 
Exemplu: pentru n=3, matricea cerută este:  3 5 8
 13 21 34
 
IndicaŃii. Se completează separat prima linie a matricii, pentru a putea memora primii
doi termeni egali cu 1 în elementele a[0][0] şi a[0][1]. Celelalte elemente de pe prima linie
se completează într-un ciclu în care parcurgem coloanele j de la 2 la n-1 şi, la fiecare pas,
memorăm un termen al şirului în elementul a[0][j]. Apoi, completăm analog restul matricii
în două cicluri cu i de la 1 la n-1 (liniile) şi j de la 0 la n-1 (coloanele).
► 11. (Bacalaureat iulie 2009, varianta 22)
ScrieŃi un program care citeşte de la tastatură numerele naturale m şi n
din intervalul [1,100], apoi construieşte în memorie şi afişează pe ecran un
tablou bidimensional cu m linii şi n coloane astfel încât prin parcurgerea acestuia
linie cu linie de sus în jos şi fiecare linie de la stânga la dreapta, se obŃin în ordine
descrescătoare toate numerele naturale de la m*n la 1, ca în exemplu.
Fiecare linie a tabloului este afişată pe câte o linie a 12 11 10
ecranului, elementele aceleiaşi linii fiind separate prin câte un 9 8 7
spaŃiu. 6 5 4
Exemplu: pentru m=4 şi n=3 se va construi şi afişa 3 2 1
tabloul alăturat.

380
► 12. (Bacalaureat iulie 2009, varianta 8)
ScrieŃi un program care citeşte de la tastatură două numere naturale n şi p
(2≤n≤20, 1≤p≤20) şi construieşte în memorie un tablou bidimensional cu n linii
şi p coloane. Tabloul va fi construit astfel încât, parcurgând tabloul linie cu linie
de sus în jos şi fiecare linie de la stânga la dreapta, să se obŃină şirul primelor n*p
pătrate perfecte impare, ordonat strict crescător, ca în exemplu. Tabloul astfel
construit va fi afişat pe ecran, fiecare linie a tabloului pe câte o linie a ecranului,
cu câte un spaŃiu între elementele fiecărei linii. 1 9 25
Exemplu: pentru n=2, p=3 programul va afişa tabloul alăturat: 49 81 121
► 13. (Bacalaureat iulie 2009, varianta 34)
ScrieŃi programul care citeşte de la tastatură un număr natural n (n<20),
construieşte în memorie şi afişează pe ecran, matricea cu n linii şi n coloane, în
care se vor memora în ordinea strict crescătoare a valorii, pe linii şi coloane,
primele n2 numere naturale nenule, pare care nu sunt divizibile cu 3.
Fiecare linie a matricei se va afişa pe câte o linie a ecranului, 2 4 8 10
cu elementele de pe aceeaşi linie separate prin câte un spaŃiu. 14 16 20 22
Exemplu: pentru n=4 se va construi şi afişa matricea 26 28 32 34
alăturată. 38 40 44 46

► 14. Se citesc de la tastatură două numere naturale


m şi n (1<m<20, 1<n<20), precum şi o matrice a cu m linii * n coloane şi
elemente numere întregi. ScrieŃi un program care construieşte un vector b având
drept componente sumele elementelor de pe fiecare linie a matricii (fiecare
element b[i] al vectorului va reprezenta suma valorilor de pe linia
12 1 16
i în matrice, cu i=0,1,...,m-1). Programul va afişa vectorul b
9 8 13
pe ecran, unul sub altul. 6 15 4
Exemplu: pentru m=4, n=3 şi matricea din figură, vectorul 2 23 1
construit va fi b=(29,30,25,26).
► 15. Se citesc de la tastatură mai întâi un număr natural n, apoi o matrice
pătratică a cu n linii * coloane şi elemente numere întregi. ScrieŃi un program care
copiază într-un vector elementele pozitive aflate deasupra diagonalei principale în
matrice, apoi tipăreşte pe ecran elementele vectorului, toate pe un rând, separate
prin câte un spaŃiu. 2 -3 1 8
Exemplu: pentru n=4 şi matricea din figură, -5 7 -4 12
programul va construi şi va afişa vectorul v=(1,8,12), care 15 -1 -8 -9
conŃine elementele subliniate din matrice. 10 1 36 22
IndicaŃii: Vom completa elementele vectorului pe rând, folosind un contor k, ce
va indica poziŃiala care am ajuns în vector. Evident, iniŃial k=0 (pe ideea că primul
număr pozitiv aflat deasupra diagonalei principale în matrice, va fi adăugat pe poziŃia 0
în vector). În două cicluri, cu i=0,1,...,n-2 şi j=i+1,..,n-1, parcurgem secŃiunea
din matrice aflată deasupra diagonalei principale; pentru fiecare element a[i][j]
astfel "vizitat", dacă a[i][j]>0, atunci:
− adăugăm a[i][j] la sfârşitul vectorului v, pe poziŃia dată de contorul k;
381
− incrementăm k, pentru a pregăti o nouă "căsuŃă" la sfârşitul vectorului v, în
vederea unei noi adăugări.
În final, numărul de elemente ale vectorului v va fi chiar k, iar afişarea lui se
va face cu ajutorul ciclului clasic de parcurgere.

► 16. Se citesc de la tastatură mai întâi un număr natural n, apoi o matrice


pătratică a cu n linii * coloane (numerotate 0,1,...,n-1), precum şi un vector v
cu n componente (cu indicii 0,1,...,n-1). Ambele tablouri sunt alcătuite din
numere întregi. ScrieŃi un program care verifică dacă vectorul v apare ca linie în
matricea a. În caz afirmativ se va afişa indicele liniei din matrice care coincide cu
vectorul, iar în caz contrar se va tipări mesajul "NU".
-1 2 -4 5
Exemplu: pentru matricea a din figură şi vectorul 0 6 3 1
v=(0,6,3,1) programul va afişa valoarea 1, iar pentru aceeaşi 2 4 2 0
matrice şi vectorul v=(0,3,6,1) se va scrie mesajul "NU". 3 -5 1 -3
► 17. Fiind dată o matrice a cu m linii * n coloane şi
elemente numere întregi, scrieŃi un program care construieşte transpusa acesteia (matricea
care se obŃine scriind liniile pe coloane şi invers). Matricea transpusă va fi afişată pe ecran,
fiecare linie a sa pe câte un rând, cu elementele liniei separate prin câte un spaŃiu.
 1 2
   1 3 5
Exemplu: transpusa matricii a =  3 4 va fi   .
 5 6  2 4 6
 

► 18. Se citesc de la tastatură mai întâi un număr natural n (1<n<10), şi


apoi o matrice pătratică a cu n linii * coloane şi elemente numere întregi. ScrieŃi un
program care realizează interschimbările de linii sau coloane necesare, astfel încât
elementele de pe diagonala principală, citite de sus în jos, să fie sortate crescător.
IndicaŃii. Aplicăm ideea algoritmului de sortare pentru elementele
a[0][0],a[1][1],...,a[n-1][n-1] de pe diagonala principală. Fiecare dintre
acestea va juca pe rând rolul unui pivot; pentru fiecare pivot a[i][i], parcurgem într-
un alt ciclu cu j=i+1,...,n-1 elementele a[j][j] de pe diagonala principală aflate
sub pivot. La fiecare pas, dacă a[j][j] < a[i][i], atunci trebuie interschimbate cele
două elemente între ele, dar vom interschimba cu totul liniile şi coloanele pe care se
află: mai întâi linia i cu linia j, apoi coloana i cu coloana j.

► 19. La examenul de Bacalaureat la Informatică, cei n absolvenŃi ai


claselor a XII-a trebuie să susŃină un test grilă alcătuit din m întrebări. Fiecare
întrebare are patru variante de răspuns, codificate prin literele 'a', 'b', 'c', 'd',
dintre care exact una este cea corectă, răspunsurile corecte ale celor m întrebări
găsindu-se într-un vector. Rezultatele concursului se vor memora într-o matrice de
dimensiune n*m, în care fiecare linie corespunde unui elev, iar fiecare coloană
unei întrebări din test. RealizaŃi un program care afişează numărul concurenŃilor ce
au răspuns corect la toate întrebările, precum şi numărul de ordine al elevilor care
au răspuns corect la o anumită întrebare indicată de la tastatură.

382
Probleme de nota 10
► 20. Pentru o matrice dată a cu m linii * n coloane şi elemente numere
întregi, să se elimine liniile şi coloanele la intersecŃia cărora se află valoarea 0,
fără a folosi altă matrice. Programul va tipări matricea rezultată după eliminări,
specificând şi noile dimensiuni ale acesteia.
Exemplu: pentru m=4 şi n=3 şi tabloul din figura 1, se va afişa tabloul
din figura 2.
2 0 5 8 3 4
3 1 2 4 5 3
7 6 0 9
5 1 4 3 figura 2
figura 1
IndicaŃii: Parcurgem în două cicluri imbricate liniile L=0,1,...,m-1 şi
coloanele C=0,1,...,n-1 ale matricii; la fiecare pas, dacă elementul a[L][C] este 0,
atunci eliminăm mai întâi linia L apoi coloana C din matrice, folosind algoritmii de
ştergere linii / coloane prezentaŃi în acest capitol. AtenŃie însă, pentru parcurgerea
matricii nu putem folosi cicluri for, deoarece după o eliminare de linie / coloană
indicele de linie sau coloană îşi va schimba valoarea (linia L devine linia L-1, respectiv
C→C-1), şi nu avem voie să modificăm contorul unui ciclu for.

► 21. (Bacalaureat iulie 2009, varianta 47)


ScrieŃi un program care citeşte de la tastatură două numere naturale nenule
m şi n (m≤10, n≤10) şi cele m*n elemente (numere naturale mai mici decât 100)
ale unui tablou bidimensional cu m linii, numerotate de la 0 la m-1, şi n coloane,
numerotate de la 0 la n-1, apoi construieşte în memorie şi afişează pe ecran
tabloul după eliminarea liniilor de rang impar.
Exemplu: pentru m=4 şi n=3 şi tabloul din figura 1, se va afişa tabloul din figura 2.
21 22 23 24 25 26
24 25 26 30 31 32
27 28 29
30 31 32

figura 1 figura 2
► 22. Se citeşte de la tastatură o matrice a cu m linii * n coloane, ale cărei
elemente sunt cifre de la 0 la 9. Să se afişeze suma numerelor care se pot forma cu
cifrele fiecărei linii (numărul aferent fiecărei linii se va obŃine prin citirea cifrelor
de pe linia respectivă de la stânga la dreapta, ignorându-se zerourile de la
începutul liniei).
Exemplu: Pentru matricea: 0 3 8 0 5
0 0 5 1 4
7 7 9 3

programul va afişa valoarea 12112, reprezentând suma 3805+514+7793.


383
IndicaŃii: Numerele alcătuite cu cifrele liniilor vor fi memorate într-un vector v,
în care fiecare element v[i] va reprezenta numărul aferent liniei i din matrice
(i=0,1,...,m-1). Pentru fiecare linie i, numărul ce rezultă prin “lipirea” cifrelor
a[i][0],...,a[i][n-1] este a[i][0]*10n-1+a[i][1]*10n-2+...+a[i][n-2]*
*101+a[i][n-1]*100. Exemplificăm acest calcul pentru linia i=3:
x=7*103+7*102+9*101+3*100. Evident că vom repeta acest rezultat într-un ciclu cu
i=0,1,...,n-1, în care avem nevoie de un alt ciclu pentru determinarea puterilor lui
10. Odată construit vectorul v mai trebuie doar să însumăm componentele sale.

► 23. (Bacalaureat iulie 2009, varianta 44)


ScrieŃi un program care citeşte de la tastatură un număr natural n
(0<n≤23) şi apoi construieşte în memorie o matrice cu n linii si n coloane,
formată din numere naturale nenule mai mici sau egale cu n, astfel încât să nu
existe două linii cu aceeaşi sumă a elementelor şi nici două coloane cu aceeaşi
sumă a elementelor. Programul va afişa matricea pe ecran, câte o
linie a matricei pe o linie a ecranului, cu un spaŃiu între elementele 1 1 1
fiecărei linii. 1 1 2
Exemplu: dacă n=3 atunci o soluŃie posibilă este matricea 1 2 3
din figură:
► 24. (Bacalaureat iulie 2009, varianta 29)
ScrieŃi un program care citeşte de la tastatură un număr natural n
≤ n≤
(1≤ ≤ 6 ) şi elementele unui tablou bidimensional A cu n linii şi n coloane, care
memorează numere naturale nenule mai mici decât 100, şi afişează pe ecran
produsul numerelor pivot pentru matricea A. Un număr natural x este "pivot"
pentru matricea A, dacă înmulŃind fiecare element de pe 2 7 4 8 4
prima coloană cu numărul x, se obŃin, în aceeaşi ordine, 1 1 2 4 2
elementele unei coloane din matrice. 3 8 6 12 13
5 4 10 20 10
Exemplu: pentru matricea din figură, se afişează 8.
► 25. Se citeşte de la tastatură o matrice a cu m linii*n coloane
(numerotate 0,1,...,m-1 respectiv 0,1,...,n-1) şi elemente numere întregi,
precum şi patru valori întregi x, y, L şi C. Să se insereze în matricea a:
− pe linia L, o linie alcătuită din valoarea x multiplicată de n ori;
− pe coloana C, o coloană alcătuită din valoarea y multiplicată de m ori.
1 2 3
Exemplu: Pentru L=1, C=0, x=11, y=10 şi matricea a= 4 5 6
10 1 2 3 7 8 9
se va obŃine matricea
10 11 11 11
10 4 5 6
IndicaŃii: 10 7 8 9
Pentru a insera o linie L în
matricea a trebuie mutate cu un rând mai jos toate liniile aflate sub L. Aceasta înseamnă
că, într-un ciclu cu j=0,1,..,n-1, fiecare element a[L][j] al liniel L se va coborâ un
rând mai jos. Mutarea efectivă a unui element a[L][j] se va face într-un alt ciclu în
care contorul i parcurge în ordine inversă indicii liniilor aflate sub linia L inclusiv:
384
i=m-1,m-2,..,L. La fiecare pas al acestui al doilea ciclu, elementul a[i][j] va trece
pe poziŃia (i+1,j), mutare care se face prin atribuirea inversă, a[i+1][j]=a[i][j].
Odată “eliberată” linia L (prin cele două cicluri anterioare, conŃinutul liniei L a fost
reprodus şi pe linia L+1), nu ne rămâne decât să memorăm valoarea x pe fiecare poziŃie
a liniei L: într-un ciclu cu j=0,1,..,n-1, facem la fiecare pas atribuirea a[L][j]:=x.
Absolut analog se mută întreaga coloană C cu o coloană mai la dreapta şi se inserează o
coloană cu valoarea y multiplicată de m ori.
► 26 (Bacalaureat iulie 2009, varianta 45)
ScrieŃi un program care citeşte de la tastatură două numere naturale m şi n
(0<m<11, 0<n<11), precum şi elementele unei matrici cu m linii * n coloane
(numere naturale mai mici decât 100), apoi roteşte matricea cu 900 în sens
trigonometric. Programul va afişa pe ecran matricea rezultată după rotire, ca în
exemplu.
Exemplu: Dacă matricea citită este cea din figura 1, atunci după rotire va
rezulta matricea din figura 2.

21 22 23 24 25 25 30 35 40
26 27 28 29 30 24 29 34 39
31 32 33 34 35 23 28 33 38
36 37 38 39 40 22 27 32 37
21 26 31 36
figura 1
figura
► 27 (Bacalaureat iulie 2008, varianta 32, enunŃ 2
adaptat)
De la terminalul standard de intrare se introduc două numere naturale m şi
n, cuprinse în intervalul [1,10], apoi se citesc elementele unei matrici a cu m linii
* n coloane, toate numere întregi. Liniile matricii sunt numerotate cu
0,1,...,m-1, iar coloanele cu 0,1,...,n-1. ScrieŃi un program care afişează
pe ecran numărul de coloane ale matricii care sunt alcătuite numai din valori
distincte.
Exemplu: m=4, n=5 şi matricea din figură, programul 1 2 1 5 9
va afişa valoarea 3, întrucât trei coloane ale matricii, şi anume 7 3 3 2 8
cele cu indicii 1, 4 şi 5, conŃin numai valori distincte (nici un 6 3 4 9 5
element nu se repetă ca valoare pe respectivele coloane). 4 7 1 6 0

► 28. Se consideră o matrice pătratică cu n linii * coloane ale cărei


elemente sunt numere întregi, o parte dintre acestea având valoarea 0. Fără a folosi
altă matrice, să se mute la sfârşitul matricii a toate coloanele care conŃin cel puŃin
k elemente nule, unde valoarea lui k se citeşte de la tastatură.
Exemplu: Pentru n=5, k=3 şi matricea a 2 0 4 0 0 0 4 0 2 0
din figură, se vor muta la sfârşit coloanele 0 şi 3 0 3 0 0 1 ⇒ 3 0 1 0 0
0 1 0 0 7 1 0 7 0 0
deoarece conŃin cel puŃin 3 elemente nule, 0 1 6 0 4 1 6 4 0 0
rezultând astfel matricea alăturată. 9 5 7 0 0 5 7 0 9 0

385
IndicaŃii: În secŃiunea “Aprofundare” a capitolului “Vectori” (“Probleme de
nota 10”) am propus o problemă asemănătoare care cerea să se mute la sfârşitul unui
vector toate elementele sale nule. Algoritmul este similar, doar că el trebuie extins: în
loc să testăm un element v[i] al vectorului v vom testa o coloană j a matricii a, iar în
loc să mutăm pe v[i] la sfârşitul vectorului vom muta coloana j la sfârşitul matricii,
prin aducerea cu o coloană mai la stânga a tuturor coloanelor aflate după j.

► 29. Fie o matrice a cu m linii * n coloane şi elemente numere întregi.


Numim "oglinda matricii a", matricea obŃinută din a prin aplicarea următoarelor
operaŃii:
− se inversează liniile între ele (se scriu de sus în jos liniile citite de jos în
sus);
− se inversează elementele fiecărei linii între ele (se scriu de la stânga la
dreapta elementele liniei citite de la dreapta la stânga);
− fiecărui element i se inversează cifrele (elementele sunt înlocuite cu
oglinditele lor);
Numim ”matrice perfect oglindită” o matrice a cărei ”oglindă” este
identică cu matricea. RealizaŃi un program care, pentru o matrice dată a, verifică
dacă este ”perfect oglindită”, afişând un mesaj corespunzător. Se va implementa
un algoritm eficient de rezolvare.
Exemplu: matricea din figură este perfect oglindită.

131 77 4 77 131
2 252 55 252 2
131 77 4 77 131

► 30. Se citeşte de la tastatură o matrice a cu m linii * n coloane,


numerotate 0,1,...,m-1, respectiv 0,1,...,n-1. Să se elimine atâtea linii
câte sunt necesare, aşa încât elementele coloanei C parcurse de sus în jos să fie în
ordine crescătoare (unde C este cunoscut).
2 6 3
 
7 4 2
Exemplu: Pentru matricea a=  5 8 9  şi coloana C=2, după eliminări se
 
1 5 3
6 9 4 

 2 6 3
 
va obŃine matricea:  5 8 9 
6 9 4
 
IndicaŃii. Se parcurg într-un ciclu liniile i ale coloanei C, cu i de la 1 la m-1.
Pentru fiecare element a[i][C], dacă este mai mic decât elementul a[i-1][C] aflat pe
aceeaşi coloană şi în linia anterioară, înseamnă că a[i][C] "strică" ordinea
crescătoare a coloanei C. În această situaŃie, trebuie eliminată integral linia i pe care
se află acest element, folosind algoritmul dat în capitolul de faŃă.
386

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