Documente Academic
Documente Profesional
Documente Cultură
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
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.
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.
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]
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];
}
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.
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)
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.
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
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ă.
text text
salt la rând nou valoarea poziŃiei i
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];
}
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];
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
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)
Rezolvare I:
Î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;
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 !
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 !
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 !
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.
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;
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
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.
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];
}
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] << " ";
299
for (i=0; i<=n-1; i++)
cout << v[i] << " ";
}
getch();
}
ÎncercaŃi singuri !
Algoritmi de căutare
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];
}
# 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 !
303
Algoritmi de formare a perechilor de elemente într-un vector
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).
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:
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).
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 !
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
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:
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).
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:
• 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
• 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
314
Exemplu: 0 1 2 3
3 -4 8 -5
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
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();
}
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();
}
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
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).
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++;
}
►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
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];
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);
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.
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
Aprofundare
Probleme rezolvate
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] << " ";
}
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;}.
# 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.
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.
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.
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.
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.
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
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
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.
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.
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.
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ă.
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.
V . 2. Ma tri c i
V . 2 .1 . N o Ńi un e a d e ma t r ic e
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
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
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
348
cout << "a[" << i << "][" << j << "]=" ;
text
indicele de linie text indicele de coloană text
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
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 !
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);
#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 !
figura 1 figura 2
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ă.
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
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;
}
#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 !
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
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:
Î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
Pe ecran se va afişa:
14 6 3
9 22 5
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]>
364
AplicaŃie R.V.22. Sume în raport cu diagonala secundară
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.
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.
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ă.
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+=...;
}
► 6. Câte elemente ale matricii a vor avea valoarea 0 după execuŃia secvenŃei ?
► 10. Care dintre secvenŃele de program de mai jos construieşte corect matricea
1 2 3
a= 4 5 6 ?
7 8 9
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++;
}
► 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
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;
}
}
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.
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
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
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.
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
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
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.
131 77 4 77 131
2 252 55 252 2
131 77 4 77 131