Sari la conținut
Înapoi la teorie

Teorie

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.

7

minute de citit

11

secțiuni

61

probleme rezolvate legate

Actualizat pe .

Pe această pagină
  1. Scheletul de citire din fișier
  2. Linii și coloane: ce decide parcurgerea
  3. Diagonalele
  4. Tehnica 1 — Valoare extremă și pozițiile ei
  5. Tehnica 2 — „Toate elementele respectă o proprietate”
  6. Tehnica 3 — Medie condiționată
  7. Tehnica 4 — Interschimbarea a două linii
  8. Afișarea unei matrici
  9. Greșeli care se repetă
  10. Unde exersezi mai departe
  11. Toate problemele din această categorie

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.

La Galați 2026, în schimb, matricea se construiește după o formulă, fără fișier deloc: se citește doar n, iar fiecare element se calculează din poziția lui. Sunt două tipuri diferite de subiect, și pagina le acoperă pe amândouă — lista completă e la finalul paginii.

Scheletul de citire din fișier

Se repetă identic la toate problemele:

C++
#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.

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.

C++
// 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.

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.

Exersează pe subiecte reale

Tehnica 1

Valoare extremă și pozițiile ei

Când enunțul cere și valoarea maximă, și unde apare, ai nevoie de două parcurgeri:

C++
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.

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:

C++
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.

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:

C++
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.

C++
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ă.

Exersează pe subiecte reale

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:

C++
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.

Exersează pe subiecte reale

Afișarea unei matrici

C++
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 de a[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 * n la 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

Mai departe

Unde exersezi mai departe

Parcurgerile pe linii, coloane și diagonale se învață prin repetiție — sunt prea multe variante ca să le reții din citit.

Pentru asta, pbinfo.ro e cea mai bună resursă românească: peste 2500 de probleme de informatică cu evaluator automat, și o trimiți la testat direct din browser. E construită pentru olimpiadă și bacalaureat, deci se completează cu ce găsești aici — noi acoperim subiectele de atestat, cu rezolvări scrise.

Dacă dai și bacalaureatul la informatică, subiectebac.ro adună variantele oficiale de BAC la informatică din 2009 încoace, cu bareme, separate pe specializare și pe limbaj. Baremul îți arată cum se punctează o rezolvare, nu doar dacă e corectă.

Toate problemele din această categorie

Fiecare are rezolvare completă în C++, explicată pas cu pas.

61Arată toate problemele rezolvate61 programare