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 ș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++.
Notele elevilor, organizate pe linii (elevi) și coloane (discipline)
Ordonarea elementelor unei zone (de exemplu, diagonala) crescător
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.
#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)).
#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:
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:
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:
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.
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:
- Citim matricea pătrată
- Copiem elementele
a[i][i]în vectorulv - Sortăm vectorul prin selecție, crescător
- Afișăm vectorul sortat
Scrie soluția în C++:
Soluție corectă:
#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:
- Citim matricea cu liniile sortate
- Interclasăm linia 1 și linia 2, cu indicii
i,jșik - Copiem restul din linia neepuizată
- Afișăm vectorul rezultat
Scrie soluția în C++:
Soluție corectă:
#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ț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]cui + j == n + 1. - Interclasarea a două linii cu
nelemente 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 cheie - cod 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++; }
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, nui + 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.
#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 minimula[1][1]- verificări rapide la barem. - Verifică dimensiunile înainte de a interclasa: matricea trebuie să aibă cel puțin două linii.