Matrici (tablouri bidimensionale) la atestatul de informatică
Citirea unei matrici din fișier, parcurgerea pe linii și pe coloane, diagonalele, maximul cu poziții și verificarea unei proprietăți pe toată linia — cu problemele de atestat în care apar.
La atestat, matricile vin aproape întotdeauna dintr-un fișier, nu de la tastatură. Toate cele 9
probleme din sesiunea Dolj 2026 folosesc același fişier mat.in și același format. Odată ce
memorezi scheletul de citire, rămâne doar logica fiecărei probleme.
Scheletul de citire din fișier
Se repetă identic la toate problemele:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream f("mat.in");
int n;
f >> n;
int a[20][20];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
f >> a[i][j];
f.close();
// ...
}
ifstream e „ruda" lui cin pentru fișiere — se folosește la fel, cu >>. Trebuie doar deschis cu
numele fişierului și închis la final.
Formatul lui mat.in e mereu același: pe prima linie n, apoi n linii cu câte n valori.
Atenție la sursa datelor. Unele enunțuri citesc matricea din fişier, dar parametrii (de exemplu liniile de interschimbat) de la tastatură. Sunt fluxuri separate:
f >>pentru fişier,cin >>pentru tastatură.
Tipul urmează enunțul: „numere întregi" → int, „numere reale" → double.
Linii și coloane: ce decide parcurgerea
Acesta e conceptul cel mai important din toată categoria, și cel mai des greșit.
// pe LINII: fixezi linia i, plimbi coloana j
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) ... a[i][j]
// pe COLOANE: fixezi coloana j, plimbi linia i
for (int j = 0; j < n; j++)
for (int i = 0; i < n; i++) ... a[i][j]
Observă că a[i][j] rămâne neschimbat în ambele cazuri. Primul indice e întotdeauna linia,
al doilea întotdeauna coloana. Ce se schimbă e doar ordinea buclelor.
Greșeala clasică e să scrii a[j][i] în loc să inversezi buclele. Pe o matrice pătratică programul
rulează fără eroare, dar lucrezi pe transpusă — obții liniile când ai cerut coloanele.
Poziții vs. indici. Enunțurile numără liniile și coloanele de la 1, C++ de la 0. Elementul
a[0][1]se raportează cal=1 c=2.
Diagonalele
Merită memorate — apar la multe subiecte:
| Diagonala | Formulă | Direcție | Pentru n = 3 |
|---|---|---|---|
| principală | a[i][i] |
stânga-sus → dreapta-jos | a[0][0], a[1][1], a[2][2] |
| secundară | a[i][n - 1 - i] |
dreapta-sus → stânga-jos | a[0][2], a[1][1], a[2][0] |
Pentru diagonala secundară, pe măsură ce linia crește, coloana scade — de aici n - 1 - i. Scrierea
greșită a[i][n - i] iese din matrice chiar la primul pas.
O singură buclă e suficientă pentru o diagonală: are exact n elemente, câte unul pe fiecare
linie. Nu ai nevoie de parcurgere completă cu if.
Probleme: media pe diagonala secundară
Tehnica 1 — Valoare extremă și pozițiile ei
Când enunțul cere și valoarea maximă, și unde apare, ai nevoie de două parcurgeri:
double maxim = a[0][0]; // primul element, NU 0
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (a[i][j] > maxim) maxim = a[i][j];
for (int i = 0; i < n; i++) // abia acum stim ce cautam
for (int j = 0; j < n; j++)
if (a[i][j] == maxim)
cout << "l=" << i + 1 << " c=" << j + 1 << endl;
Motivul: ca să știi dacă o poziție conține maximul, trebuie să-l cunoști deja — dar el poate apărea abia la ultimul element.
Inițializarea cu a[0][0], nu cu 0, e obligatorie: 0 e greșit pentru matrici cu toate valorile
negative (la maxim) sau toate pozitive (la minim).
Pentru minim se schimbă doar semnul comparației.
Probleme: elementul maxim și pozițiile · elementul minim și pozițiile · maximele de pe fiecare linie
Când enunțul cere un rezultat per linie, calculul stă în bucla exterioară, iar acumulatorul se redeclară la fiecare linie — altfel se „târăște" de pe o linie pe alta.
Tehnica 2 — „Toate elementele respectă o proprietate"
Aici logica se inversează față de problemele obișnuite.
Ca să demonstrezi că toate elementele unei linii sunt pare, trebuie să le verifici pe toate. Dar ca să demonstrezi că nu sunt, e suficient un singur contraexemplu:
bool toatePare = true; // pornesti OPTIMIST
for (int j = 0; j < n; j++)
if (a[i][j] % 2 != 0) {
toatePare = false; // un contraexemplu strica tot
break;
}
Compară cu tiparul obișnuit „există un element care...", unde pornești cu false și cauți o
confirmare. Confuzia dintre cele două e cea mai frecventă greșeală de logică la matrici.
Flagul trebuie declarat în interiorul buclei de linii, ca să se reseteze pentru fiecare linie.
Probleme: liniile cu toate elementele pare · coloanele cu toate elementele impare · matrice simetrică
Matrice simetrică
O matrice e simetrică față de diagonala principală dacă a[i][j] == a[j][i] pentru orice pereche.
Se verifică doar deasupra diagonalei:
for (int i = 0; i < n && simetrica; i++)
for (int j = i + 1; j < n; j++) // j porneste de la i + 1
if (a[i][j] != a[j][i]) { simetrica = false; break; }
Perechile de sub diagonală sunt aceleași verificate a doua oară, iar elementele de pe diagonală se compară cu ele însele. Jumătate din muncă, niciun test inutil.
Tehnica 3 — Medie condiționată
Ai nevoie de doi acumulatori: suma și numărătoarea.
double suma = 0;
int cate = 0;
for (...)
if (a[i][j] > 0) { suma += a[i][j]; cate++; }
if (cate > 0) cout << suma / cate;
else cout << "NU EXISTA";
Media e suma / cate, nu suma / (n * n) — împarți la câte elemente ai selectat, nu la totalul
din matrice. Iar verificarea cate > 0 previne împărțirea la zero.
„Strict pozitiv" înseamnă > 0; zeroul nu intră.
Probleme: media elementelor strict pozitive
Tehnica 4 — Interschimbarea a două linii
O linie nu e o valoare, ci n valori. Nu poți scrie a[l1] = a[l2] — muți element cu element:
for (int j = 0; j < n; j++) {
double aux = a[l1 - 1][j];
a[l1 - 1][j] = a[l2 - 1][j];
a[l2 - 1][j] = aux;
}
Indicii de linie rămân fixați, bucla plimbă coloana. Pentru coloane e exact invers: bucla merge
pe i, iar indicii de coloană rămân constanți.
Probleme: interschimbarea a două linii
Afișarea unei matrici
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
cout << a[i][j] << " ";
cout << endl; // in bucla EXTERIOARA
}
cout << endl stă după ce s-a terminat o linie întreagă. În bucla interioară, fiecare element ar
apărea pe rândul lui.
Greșeli care se repetă
a[j][i]în loc de inversarea buclelor — lucrezi pe transpusămaxim = 0în loc dea[0][0]— greșit la valori negative- Flag declarat în afara buclei de linii — nu se resetează
a[i][n - i]pentru diagonala secundară — iese din matrice- Împărțirea la
n * nla media condiționată - Afișarea pozițiilor în prima parcurgere — apar maxime temporare
cout << endlîn bucla interioară — matricea iese pe o coloană- Indici afișați fără
+ 1
Toate problemele din această categorie
Fiecare are rezolvare completă în C++, explicată pas cu pas.
- Să se afişeze cel mai mare element din matrice şi poziţiile pe care apareProgramare
- Să se afişeze cel mai mic element din matrice şi poziţiile pe care apareProgramare
- Să se afişeze indicii coloanelor care au toate elementele impareProgramare
- Să se afişeze indicii liniilor care au toate elementele pareProgramare
- Să se afişeze maximele de pe fiecare linieProgramare
- Să se afişeze media aritmetică a elementelor strict pozitiveProgramare
- Să se calculeze şi să se afişeze media aritmetică a elementelor situate pe diagonala secundarăProgramare
- Să se schimbe între ele două linii l1 şi l2, date de la tastaturăProgramare
- Verificarea dacă o matrice este simetrică față de diagonala principalăProgramare