Școala Româno-Britanică
Modulul 3 Clasa a X-a | C++

Ora 10: Aplicații integrate: matrice și liste sortate

Ce vei învăța astăzi: Să combini matricea cu listele sortate în probleme integrate: elementele de pe diagonală sortate și interclasarea liniilor matricei

Rezultat practic: Rezolvi programe C++ complete care folosesc simultan matricea, sortarea și interclasarea, aplicând corect complexitățile algoritmilor (Competența 6.4).

Competența 6.4 Săptămâna 16

Înainte de a începe

De ce contează? Sortarea diagonalei sau interclasarea liniilor sunt subiecte tipice de evaluare: testează înțelegerea combinațiilor, nu doar memorarea unui singur algoritm - exact genul de problemă pe care o vei întâlni la test.

Ce știi deja?

Știi formulele diagonalelor (ora 3) și sortarea, căutarea binară și interclasarea (orele 4-6). Azi le combini pe aceeași matrice, exact ca la evaluare. Cum ai extrage elementele diagonalei principale într-un vector (un tablou unidimensional)?

Ideea-cheie: Orice zonă a matricei (diagonală, linie) poate fi extrasă într-un vector de lucru, prelucrată cu algoritmii pe liste sortate, apoi întoarsă la loc - așa descompui problema în pași simpli și testabili.
SINTEZĂ TEORETICĂ ȘI EXEMPLE GHIDATE

Ce vei învăța astăzi?

După această lecție vei putea combina cunoștințele despre matrice cu cele despre liste sortate: vei sorta elementele de pe diagonala principală, vei interclasa liniile unei matrice și vei verifica eficiența soluțiilor.

Probleme combinate: matrice + liste sortate
Elementele de pe diagonală, sortate
Interclasarea liniilor matricei
Căutarea binară în rezultatul interclasării

Probleme combinate: matrice și liste sortate

Definiție: O problemă integrată (problemă care combină mai multe structuri de date și algoritmi) folosește simultan structuri și algoritmi diferiți: matricea pentru organizarea datelor în tabel și algoritmii pe liste sortate (sortare, căutare binară, interclasare) pentru prelucrarea rapidă a liniilor sau a zonelor matricei.

Cheia rezolvării este decompoziția (împărțirea problemei în pași mai mici și independenți): împărțim problema în pași independenți (extragere, sortare, interclasare, căutare), pe care îi rezolvăm unul câte unul, cu algoritmi deja cunoscuți.

Analogia: organizarea unei excursii

Un profesor organizează o excursie: întâi strânge notele elevilor pe clase (matricea), apoi face clasamentele pe clase (liste sortate) și în final combină clasamentele în unul singur (interclasarea). Fiecare pas folosește structura potrivită, iar pașii se leagă unul de altul exact ca într-un program C++.

Matricea

Notele elevilor, organizate pe linii (elevi) și coloane (discipline)

Sortarea

Ordonarea elementelor unei zone (de exemplu, diagonala) crescător

Interclasarea

Combinarea a două linii sortate într-un singur vector sortat

Elementele de pe diagonala principală, sortate

Diagonala principală este o listă ascunsă în matrice: elementele a[1][1], a[2][2], ..., a[n][n]. Pentru a le sorta, le copiem într-un vector v, sortăm vectorul (de exemplu, prin selecție) și afișăm rezultatul. Matricea rămâne neschimbată - lucrăm pe copie.

Program complet: elementele diagonalei principale, sortate crescător
#include <iostream>
using namespace std;

int main() {
    int n, a[101][101], v[101], i, j, k, aux, poz;
    cin >> n;

    // pasul 1: citim matricea pătrată
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    // pasul 2: copiem elementele diagonalei principale în vectorul v
    k = 0;
    for (i = 1; i <= n; i++) {
        k++;
        v[k] = a[i][i];
    }

    // pasul 3: sortăm vectorul prin selecție, crescător
    for (i = 1; i < k; i++) {
        poz = i;
        for (j = i + 1; j <= k; j++)
            if (v[j] < v[poz])
                poz = j;
        aux = v[i];
        v[i] = v[poz];
        v[poz] = aux;
    }

    // pasul 4: afișăm vectorul sortat
    for (i = 1; i <= k; i++)
        cout << v[i] << " ";
    return 0;
}

Observă: pasul de extracție folosește condiția de pe diagonală (a[i][i]), iar pasul de sortare lucrează exclusiv pe vectorul v - matricea nu se modifică.

Interclasarea liniilor matricei și căutarea binară

Dacă liniile matricei sunt sortate crescător, le putem trata ca pe niște liste independente. Interclasarea a două linii produce un vector sortat, iar pe acest vector putem aplica imediat căutarea binară pentru o valoare x.

Complexitatea totală: interclasarea a două linii cu n elemente costă O(n), iar căutarea binară în rezultat, O(log2(2n)).

Algoritmul InterclasareLiniiȘiCăutare(a, m, n, x): // pasul 1: citim matricea cu liniile sortate citește m, n și matricea a // pasul 2: interclasăm liniile 1 și 2 în vectorul c i <- 1, j <- 1, k <- 0 cât timp i <= n și j <= n execută dacă a[1][i] <= a[2][j] atunci k <- k + 1 c[k] <- a[1][i] i <- i + 1 altfel k <- k + 1 c[k] <- a[2][j] j <- j + 1 sfârșit dacă sfârșit cât timp cât timp i <= n execută k <- k + 1 c[k] <- a[1][i] i <- i + 1 sfârșit cât timp cât timp j <= n execută k <- k + 1 c[k] <- a[2][j] j <- j + 1 sfârșit cât timp // pasul 3: căutăm binar valoarea x în vectorul c (sortat) citește x st <- 1, dr <- k, gasit <- fals cât timp st <= dr execută mij <- (st + dr) / 2 dacă c[mij] = x atunci gasit <- adevărat oprește bucla altfel dacă c[mij] < x atunci st <- mij + 1 altfel dr <- mij - 1 sfârșit dacă sfârșit cât timp // pasul 4: afișăm vectorul c și rezultatul căutării pentru i = 1, k execută scrie c[i], spațiu sfârșit pentru dacă gasit atunci scrie "DA" altfel scrie "NU" sfârșit dacă
Program complet: interclasarea liniilor 1 și 2, cu căutare binară a lui x
#include <iostream>
using namespace std;

int main() {
    int m, n, a[101][101], c[201], x, i, j, k, st, dr, mij;
    bool gasit = false;
    cin >> m >> n;

    // pasul 1: citim matricea (liniile sunt sortate crescător)
    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    // pasul 2: interclasăm liniile 1 și 2 în vectorul c
    i = 1;
    j = 1;
    k = 0;
    while (i <= n && j <= n) {
        k++;
        if (a[1][i] <= a[2][j]) {
            c[k] = a[1][i];
            i++;
        } else {
            c[k] = a[2][j];
            j++;
        }
    }
    while (i <= n) {
        k++;
        c[k] = a[1][i];
        i++;
    }
    while (j <= n) {
        k++;
        c[k] = a[2][j];
        j++;
    }

    // pasul 3: căutăm binar x în vectorul c, care este sortat
    cin >> x;
    st = 1;
    dr = k;
    while (st <= dr) {
        mij = (st + dr) / 2;
        if (c[mij] == x) {
            gasit = true;
            break;
        } else if (c[mij] < x) {
            st = mij + 1;
        } else {
            dr = mij - 1;
        }
    }

    // pasul 4: afișăm vectorul interclasat și verdictul căutării
    for (i = 1; i <= k; i++)
        cout << c[i] << " ";
    cout << endl;
    if (gasit)
        cout << "DA";
    else
        cout << "NU";
    return 0;
}

Observă: liniile matricei se accesează cu a[1][i] și a[2][j], exact ca două liste sortate independente. Rezultatul interclasării are 2 * n elemente și rămâne sortat, deci căutarea binară este validă.

Exercițiu de completare

Completează enunțul cu cuvintele potrivite:

Elementele de pe diagonala principală se copiază într-un ______ înainte de sortare. După sortare, matricea rămâne ______. Interclasarea liniilor produce un vector ______.

Bancă de cuvinte:
vector neschimbată sortat ștearsă

Exercițiu de completare 2

Completează afirmațiile despre problemele integrate:

La interclasarea liniilor 1 și 2, bucla principală rulează cât timp ______. Vectorul rezultat are ______ elemente. Pe acest vector putem aplica ______.

Bancă de cuvinte:
i <= n și j <= n 2 * n căutarea binară i <= n sau j <= n

Test de înțelegere

Test rapid - aplicații integrate:

1. Elementele de pe diagonala principală a unei matrice n x n formează:

2. Interclasarea liniilor 1 și 2, fiecare cu n elemente, produce un vector cu:

3. Pentru a aplica căutarea binară pe rezultatul interclasării liniilor:

Ai grijă la: sortarea „în loc" a matricei când enunțul cere doar afișarea unei zone sortate: lucrează pe un vector auxiliar, ca să nu alterezi datele inițiale cerute de pașii următori ai problemei.

Aprofundare

Eficiența unei probleme combinate se calculează pas cu pas: extracția diagonalei costă O(n), sortarea prin selecție O(n^2), interclasarea a două linii O(n), iar căutarea binară O(log2 n). La barem se punctează identificarea corectă a fiecărei complexități și alegerea algoritmului potrivit pentru fiecare pas. Dacă diagonala trebuie doar afișată sortată, iar n este mare, se poate folosi orice metodă de sortare cunoscută - la BAC, sortarea prin selecție este suficientă pentru restricțiile obișnuite.

Matrice cu toate liniile sortate - întrebări rapide: dacă liniile sunt sortate crescător, atunci maximul matricei se află la intersecția ultimei linii cu ultima coloană (a[m][n]), iar minimul la a[1][1]. Această proprietate permite răspunsuri instant la probleme de tip „cel mai mare element" și apare frecvent în testele integrate.

Decompoziția - strategia generală pentru problemele combinate:

  • Extrage zona cerută (diagonală, linie, coloană) într-un vector de lucru.
  • Prelucrează vectorul cu algoritmul potrivit (sortare, căutare, interclasare).
  • Raportează rezultatul, având grijă să nu modifici datele de intrare dacă nu se cere.

Cazuri particulare: dacă matricea are o singură linie (m = 1), interclasarea liniilor 1 și 2 nu are sens - verifică întotdeauna dimensiunile înainte de prelucrare. Dacă n = 1, interclasarea a două linii produce un vector cu 2 elemente, iar căutarea binară rămâne validă. Sortarea unui vector cu 0 sau 1 element se termină imediat, fără erori.

APLICARE ȘI REZOLVARE DE PROBLEME

PbInfo - Diagonala sortată

Enunț:

Cerință: Se citește o matrice pătrată cu n linii și n coloane. Să se afișeze, în ordine crescătoare, elementele de pe diagonala principală.

Date de intrare:

Programul citește de la tastatură numărul n, apoi cele n * n elemente ale matricei, linie cu linie.

Date de ieșire:

Programul va afișa cele n valori ale diagonalei principale, sortate crescător, separate prin spații.

Restricții și precizări:

1 <= n <= 100, elementele matricei sunt numere întregi.

Exemplu:

Intrare:

3
5 1 3
2 4 6
7 8 9

Ieșire:

4 5 9
Cum gândim soluția:
  1. Citim matricea pătrată
  2. Copiem elementele a[i][i] în vectorul v
  3. Sortăm vectorul prin selecție, crescător
  4. Afișăm vectorul sortat
Scrie soluția în C++:
Soluție corectă:
Soluția completă
#include <iostream>
using namespace std;

int main() {
    int n, a[101][101], v[101], i, j, k, aux, poz;
    cin >> n;

    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    k = 0;
    for (i = 1; i <= n; i++) {
        k++;
        v[k] = a[i][i];
    }

    for (i = 1; i < k; i++) {
        poz = i;
        for (j = i + 1; j <= k; j++)
            if (v[j] < v[poz])
                poz = j;
        aux = v[i];
        v[i] = v[poz];
        v[poz] = aux;
    }

    for (i = 1; i <= k; i++)
        cout << v[i] << " ";
    return 0;
}

Ce învățăm: combinăm extragerea diagonalei (un singur indice i, elementul a[i][i]) cu sortarea prin selecție a vectorului rezultat.

PbInfo - Interclasare pe linii

Enunț:

Cerință: Se citește o matrice cu m linii și n coloane, ale cărei linii sunt sortate crescător. Să se afișeze, în ordine crescătoare, elementele obținute prin interclasarea primelor două linii.

Date de intrare:

Programul citește de la tastatură numerele m și n, apoi cele m * n elemente ale matricei, linie cu linie.

Date de ieșire:

Programul va afișa cele 2 * n valori rezultate din interclasarea liniilor 1 și 2, în ordine crescătoare, separate prin spații.

Restricții și precizări:

2 <= m <= 100, 1 <= n <= 100, liniile matricei sunt sortate crescător.

Exemplu:

Intrare:

3 3
1 4 7
2 5 8
3 6 9

Ieșire:

1 2 4 5 7 8
Cum gândim soluția:
  1. Citim matricea cu liniile sortate
  2. Interclasăm linia 1 și linia 2, cu indicii i, j și k
  3. Copiem restul din linia neepuizată
  4. Afișăm vectorul rezultat
Scrie soluția în C++:
Soluție corectă:
Soluția completă
#include <iostream>
using namespace std;

int main() {
    int m, n, a[101][101], c[201], i, j, k;
    cin >> m >> n;

    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    i = 1;
    j = 1;
    k = 0;
    while (i <= n && j <= n) {
        k++;
        if (a[1][i] <= a[2][j]) {
            c[k] = a[1][i];
            i++;
        } else {
            c[k] = a[2][j];
            j++;
        }
    }
    while (i <= n) {
        k++;
        c[k] = a[1][i];
        i++;
    }
    while (j <= n) {
        k++;
        c[k] = a[2][j];
        j++;
    }

    for (i = 1; i <= k; i++)
        cout << c[i] << " ";
    return 0;
}

Ce învățăm: liniile matricei se tratează ca liste sortate independente; interclasarea lor folosește exact algoritmul cu trei indici, cu elementele a[1][i] și a[2][j].

EXERCIȚII PRACTICE

Exercițiul Practic: Probleme integrate cu matrice și liste sortate

Sarcini de lucru

Rezolvă cele două sarcini integrate pentru a combina matricea cu listele sortate

Sarcina 1: Diagonala secundară, sortată descrescător

Cerință: Scrie un program C++ care citește o matrice pătrată cu n linii și coloane, copiază elementele de pe diagonala secundară (i + j == n + 1) într-un vector și le afișează sortate descrescător.

Soluție pentru Sarcina 1:
#include <iostream>
using namespace std;

int main() {
    int n, a[101][101], v[101], i, j, k, aux, poz;
    cin >> n;

    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    k = 0;
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (i + j == n + 1) {
                k++;
                v[k] = a[i][j];
            }

    for (i = 1; i < k; i++) {
        poz = i;
        for (j = i + 1; j <= k; j++)
            if (v[j] > v[poz])
                poz = j;
        aux = v[i];
        v[i] = v[poz];
        v[poz] = aux;
    }

    for (i = 1; i <= k; i++)
        cout << v[i] << " ";
    return 0;
}

Verifică: condiția diagonalei secundare este i + j == n + 1, iar pentru sortare descrescătoare alegem în selecție elementul cel mai mare din rest.

Sarcina 2: Liniile sortate și interclasarea

Cerință: Scrie un program C++ care citește o matrice cu m linii și n coloane, verifică dacă toate liniile sunt sortate crescător și, dacă da, interclasează primele două linii într-un vector c, pe care îl afișează.

Soluție pentru Sarcina 2:
#include <iostream>
using namespace std;

int main() {
    int m, n, a[101][101], c[201], i, j, k;
    bool sortat = true;
    cin >> m >> n;

    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    for (i = 1; i <= m && sortat; i++)
        for (j = 1; j < n; j++)
            if (a[i][j] > a[i][j + 1])
                sortat = false;

    if (!sortat) {
        cout << "NU";
        return 0;
    }

    i = 1;
    j = 1;
    k = 0;
    while (i <= n && j <= n) {
        k++;
        if (a[1][i] <= a[2][j]) {
            c[k] = a[1][i];
            i++;
        } else {
            c[k] = a[2][j];
            j++;
        }
    }
    while (i <= n) {
        k++;
        c[k] = a[1][i];
        i++;
    }
    while (j <= n) {
        k++;
        c[k] = a[2][j];
        j++;
    }

    for (i = 1; i <= k; i++)
        cout << c[i] << " ";
    return 0;
}

Verifică: mai întâi validăm ipoteza (toate liniile sortate), apoi interclasăm; dacă o linie nu este sortată, afișăm NU și oprim programul.

Scrie pe caiet - De reținut

Titlul lecției

Ora 10: Aplicații integrate: matrice și liste sortate

Definiția lecției

O problemă integrată folosește simultan matricea și algoritmii pe liste sortate: matricea organizează datele în tabel, iar sortarea, căutarea binară și interclasarea prelucrează rapid liniile sau zonele ei. Diagonala principală este o listă ascunsă în matrice: elementele a[1][1], a[2][2], ..., a[n][n] se copiază într-un vector de lucru, se sortează prin selecție, iar matricea rămâne neschimbată. Interclasarea a două linii sortate tratează fiecare linie ca pe o listă independentă: indicii i și j parcurg liniile 1 și 2, iar k construiește vectorul rezultat, sortat, cu 2 * n elemente. Pe acest vector se poate aplica imediat căutarea binară, fără o sortare suplimentară. Cheia rezolvării este decompoziția: extragem zona cerută, o prelucrăm cu algoritmul potrivit, apoi raportăm rezultatul, fără a modifica datele de intrare.

Definiții esențiale

  • Problema integrată combină matricea cu algoritmii pe liste sortate: extragem zona cerută într-un vector, apoi aplicăm sortare, căutare binară sau interclasare.
  • Elementele diagonalei principale: a[i][i]; ale diagonalei secundare: a[i][j] cu i + j == n + 1.
  • Interclasarea a două linii cu n elemente produce un vector cu 2 * n elemente, sortat.
  • Pe rezultatul interclasării se poate aplica direct căutarea binară, fără sortare suplimentară.

Algoritmul cheie - pseudocod

Algoritmul InterclasareLiniiȘiCăutare(a, m, n, x): citește m, n și matricea a i <- 1, j <- 1, k <- 0 cât timp i <= n și j <= n execută dacă a[1][i] <= a[2][j] atunci c[k + 1] <- a[1][i], k <- k + 1, i <- i + 1 altfel c[k + 1] <- a[2][j], k <- k + 1, j <- j + 1 sfârșit dacă sfârșit cât timp cât timp i <= n execută c[k + 1] <- a[1][i], k <- k + 1, i <- i + 1 sfârșit cât timp cât timp j <= n execută c[k + 1] <- a[2][j], k <- k + 1, j <- j + 1 sfârșit cât timp citește x st <- 1, dr <- k, gasit <- fals cât timp st <= dr execută mij <- (st + dr) / 2 dacă c[mij] = x atunci gasit <- adevărat altfel dacă c[mij] < x atunci st <- mij + 1 altfel dr <- mij - 1 sfârșit dacă sfârșit cât timp scrie c[1..k] și verdictul căutării

Algoritmul cheie - cod C++

Interclasarea liniilor 1 și 2
i = 1;
j = 1;
k = 0;
while (i <= n && j <= n) {
    k++;
    if (a[1][i] <= a[2][j]) {
        c[k] = a[1][i];
        i++;
    } else {
        c[k] = a[2][j];
        j++;
    }
}
while (i <= n) { k++; c[k] = a[1][i]; i++; }
while (j <= n) { k++; c[k] = a[2][j]; j++; }

Greșeli comune de evitare

  • Sortarea elementelor direct în matrice: modifică datele de intrare; lucrează mereu pe un vector de lucru.
  • Confundarea diagonalei secundare: condiția este i + j == n + 1, nu i + j == n.
  • Interclasarea liniilor fără a verifica dacă acestea sunt sortate: rezultatul nu va mai fi ordonat.

Exemplu practic

Un profesor are notele elevilor pe două discipline, fiecare linie a matricei fiind sortată crescător. El vrea lista completă a notelor elevilor la cele două discipline, în ordine, și verifică apoi dacă nota x apare în această listă. Programul interclasează liniile 1 și 2 ale matricei, apoi caută binar valoarea x în vectorul rezultat.

Interclasarea liniilor 1 și 2, cu căutare binară
#include <iostream>
using namespace std;

int main() {
    int m, n, a[101][101], c[201], x, i, j, k, st, dr, mij;
    bool gasit = false;
    cin >> m >> n;

    for (i = 1; i <= m; i++)
        for (j = 1; j <= n; j++)
            cin >> a[i][j];

    i = 1; j = 1; k = 0;
    while (i <= n && j <= n) {
        k++;
        if (a[1][i] <= a[2][j]) { c[k] = a[1][i]; i++; }
        else { c[k] = a[2][j]; j++; }
    }
    while (i <= n) { k++; c[k] = a[1][i]; i++; }
    while (j <= n) { k++; c[k] = a[2][j]; j++; }

    cin >> x;
    st = 1; dr = k;
    while (st <= dr) {
        mij = (st + dr) / 2;
        if (c[mij] == x) { gasit = true; break; }
        else if (c[mij] < x) st = mij + 1;
        else dr = mij - 1;
    }

    for (i = 1; i <= k; i++)
        cout << c[i] << " ";
    cout << endl;
    if (gasit)
        cout << "DA";
    else
        cout << "NU";
    return 0;
}

Pentru matricea cu liniile 1 3 5 și 2 4 6, programul afișează 1 2 3 4 5 6 și verdictul căutării, totul fără o sortare suplimentară.

Sfaturi practice și trucuri

  • Decompune problema în pași: extragere, prelucrare, raportare - și rezolvă fiecare pas separat.
  • Dacă liniile sunt sortate, maximul matricei este a[m][n], iar minimul a[1][1] - verificări rapide la barem.
  • Verifică dimensiunile înainte de a interclasa: matricea trebuie să aibă cel puțin două linii.