Ce vei învăța astăzi?
După această lecție vei recapitula întreg modulul: toți algoritmii Divide et impera și Greedy, complexitățile lor și tabelul rezumativ care te ajută să alegi metoda potrivită la orice problemă de bacalaureat.
Recapitulare: Divide et impera
Ideea: problema se descompune în subprobleme de același tip (probleme mai mici, de aceeași natură cu cea inițială), se rezolvă recursiv (cazul de bază rezolvat direct), apoi rezultatele se combină. Toate funcțiile au aceeași schemă: caz de bază, mij = (st + dr) / 2, apeluri recursive, combinare.
| Problemă | Caz de bază | Combinare | Complexitate |
|---|---|---|---|
| Suma intervalului | st == dr → st |
adunare | O(n) |
| Maximul / minimul | st == dr → v[st] |
comparație | O(n) |
| Merge sort | un element, deja sortat | interclasare | O(n log n) |
| Căutarea binară | st > dr → nu există |
restrângere la o jumătate | O(log n) |
| Inversiunile | un element, fără inversiuni | interclasare + contor | O(n log n) |
| Căutare în tablou rotit | st > dr → 0 |
jumătate sortată + restrângere | O(log n) |
Reține: două convenții de caz de bază: st == dr pentru sumă, maxim, numărare; st > dr pentru căutări. Amestecarea lor este cea mai frecventă greșeală.
Recapitulare: metoda Greedy
Ideea: la fiecare pas alegem optimul local, fără a reconsidera deciziile. Corectitudinea se bazează pe substructura optimală; fiecare problemă are criteriul ei local, pe care trebuie să-l recunoști din enunț.
| Problemă | Criteriul greedy | Etapele |
|---|---|---|
| Restul cu monede | cea mai mare monedă care încape | buclă + while pe rest |
| Spectacolele | sortare după ora de sfârșit | sortare + parcurgere |
| Rucsacul fracționar | eficiență valoare / greutate | sortare + umplere |
| Problema platoului | cât mai multe pătrate pe fiecare direcție | formula (L/l) * (W/l) |
| Platoul extins | pătrat cu latura dimensiunii mai mici | divizări cu rest repetate |
Reține: sortarea este aproape întotdeauna pasul de pregătire al Greedy. Pentru n mare, alege merge sort; pentru n mic, sortarea prin selecție este suficientă și mai simplă.
Tabel rezumativ: D&I vs Greedy
| Criteriu | Divide et impera | Greedy |
|---|---|---|
| Mod de lucru | descompune în subprobleme, apoi combină | construiește soluția pas cu pas |
| Decizii | toate subproblemele sunt rezolvate | alege optimul local, fără reconsiderare |
| Recursivitate | esențială (caz de bază + divizare) | de obicei iterativ |
| Exemple | sumă, maxim, merge sort, căutare binară, inversiuni | monede, spectacole, rucsac fracționar, platou |
| Garantarea optimului | da, metoda este corectă prin construcție | doar dacă substructura optimală există |
| Complexitate tipică | O(log n), O(n), O(n log n) |
O(n), O(n log n) cu sortare |
Program recapitulativ: maximul prin D&I
#include <iostream>
using namespace std;
int v[1001];
int maxim(int st, int dr) {
if (st == dr) {
return v[st];
}
int mij = (st + dr) / 2;
int a = maxim(st, mij);
int b = maxim(mij + 1, dr);
if (a > b) {
return a;
}
return b;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
cout << maxim(1, n) << endl;
return 0;
}
Ce învățăm: acest program reunește toate elementele D&I: tablou global, funcție înainte de main(), caz de bază, divizare, apeluri recursive reținute în variabile, combinare prin comparație.
Aprofundare
Cum alegi metoda la examen: citește enunțul și caută indicii. „Funcție recursivă", „interval", „înjumătățire", „căutare într-un tablou sortat" indică D&I. „Număr minim de monede", „număr maxim de activități", „valoare maximă, fracționar", „alege cât mai multe" indică Greedy. Dacă ambele apar, problema este combinată, ca la ora 12.
Complexități care se cer la oral: suma și maximul prin D&I fac n - 1 operații (stiva are adâncimea log₂(n)); merge sort compară pe fiecare nivel n elemente, deci n log₂(n); căutarea binară elimină o jumătate la fiecare pas, deci log₂(n); monedele parcurg 6 valori fixe, deci O(1) față de n; spectacolele și rucsacul cu sortare prin selecție sunt O(n), cu merge sort O(n log n).
Legătura dintre lecțiile modulului: ora 1-4 au construit reflecția D&I (sumă, maxim, merge sort, căutare), ora 5-8 au construit reflecția Greedy (monede, spectacole, rucsac, platou), ora 9 a comparat metodele, iar ora 10-12 au adăugat aplicațiile avansate: inversiuni, tablou rotit, rucsac eficient, platou extins și probleme combinate. Toate împreună formează „arsenalul" de subiecte de bacalaureat pe acest modul.
Greseli de recapitulare, sistematizate: (1) cazuri de bază amestecate; (2) comparații cu < în loc de <= la inversiuni; (3) criterii greedy greșite (sortare după început, nu după sfârșit); (4) tipuri prea mici (int în loc de long long); (5) uitarea condițiilor de oprire din buclele greedy.
Exemplu din viața reală: un magazin online care gestionează livrările folosește căutarea binară pentru a găsi rapid o comandă într-o listă sortată (D&I), sortarea prin interclasare pentru listele de livrare (D&I) și algoritmul greedy pentru încărcarea mașinilor de curierat. În spatele fiecărui buton de „plasare a comenzii" stau exact metodele recapitulate astăzi.
Exercițiu de completare
Completează comparația celor două metode:
D&I ______ problema în subprobleme, pe când Greedy alege ______ local. D&I ______ rezultatele subproblemelor; Greedy nu ______ asupra deciziilor.
Bancă de cuvinte:
Exercițiu de completare: complexitățile modulului
Completează cu complexitățile potrivite:
Merge sort are complexitatea ______. Căutarea binară are complexitatea ______. Maximul prin D&I are complexitatea ______. Restul cu monede parcurge un număr ______ de valori, deci timpul nu depinde de n.
Bancă de cuvinte:
Test de înțelegere
Test final - recapitulare generală:
1. Care dintre următorii algoritmi este o aplicație Divide et impera?
2. Care dintre următoarele este o aplicație Greedy?
3. Complexitatea căutării într-un tablou sortat și rotit este:
PbInfo - Maximul prin D&I (recapitulare)
Enunț:
Cerință: Se citește n și apoi n numere întregi. Să se afișeze valoarea maximă, determinată cu o funcție recursivă de tip Divide et impera.
Date de intrare:
Programul citește n, apoi cele n numere.
Date de ieșire:
Programul va afișa valoarea maximă.
Restricții și precizări:
1 ≤ n ≤ 1000; elementele sunt numere întregi.
Exemplu:
Intrare:
6 4 9 2 7 5 8
Ieșire:
9
Cum gândim soluția:
- Definim
maxim(st, dr): caz de bazăst == dr - Împărțim la mijloc și returnăm maximul celor două jumătăți
- Afișăm
maxim(1, n)
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
using namespace std;
int v[1001];
int maxim(int st, int dr) {
if (st == dr) {
return v[st];
}
int mij = (st + dr) / 2;
int a = maxim(st, mij);
int b = maxim(mij + 1, dr);
if (a > b) {
return a;
}
return b;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
cout << maxim(1, n) << endl;
return 0;
}
Ce învățăm: maximul prin D&I rezolvă problema în O(n) comparații, cu aceeași schemă: divizare, apeluri recursive, comparație la combinare.
PbInfo - Restul cu monede (recapitulare)
Enunț:
Cerință: Se dă suma S. Să se afișeze numărul minim de monede cu care poate fi plătită suma S, folosind monede de valori 100, 50, 10, 5, 2, 1 (metoda Greedy).
Date de intrare:
Programul citește de la tastatură numărul natural S.
Date de ieșire:
Programul va afișa numărul minim de monede.
Restricții și precizări:
1 ≤ S ≤ 100000; se folosește metoda Greedy.
Exemplu:
Intrare:
88
Ieșire:
7
Cum gândim soluția:
- Definim tabloul
monededescrescător - Pentru fiecare monedă, cât timp încape, o scădem și numărăm
- Afișăm numărul total
Scrie soluția în C++:
Soluție corectă:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int monede[] = {100, 50, 10, 5, 2, 1};
int nr = 0;
for (int i = 0; i < 6; i++) {
while (n >= monede[i]) {
n -= monede[i];
nr++;
}
}
cout << nr << endl;
return 0;
}
Ce învățăm: 88 = 50 + 10 + 10 + 10 + 5 + 2 + 1, deci 7 monede. Alegerea greedy a monedei celei mai mari dă numărul minim pentru sistemul canonic.
Exercițiul Practic: recapitulare generală a modulului
Sarcini de lucru
Rezolvă sarcinile de mai jos pentru a încheia recapitularea modulului 4
Sarcina 1: Merge sort (recapitulare)
Cerință: Scrie programul complet de sortare prin interclasare (merge sort), crescător, pentru un vector cu n elemente.
Soluție pentru Sarcina 1:
#include <iostream>
using namespace std;
int v[1001], temp[1001];
void interclaseaza(int st, int mij, int dr) {
int i = st, j = mij + 1, k = st;
while (i <= mij && j <= dr) {
if (v[i] < v[j]) {
temp[k++] = v[i++];
} else {
temp[k++] = v[j++];
}
}
while (i <= mij) {
temp[k++] = v[i++];
}
while (j <= dr) {
temp[k++] = v[j++];
}
for (int p = st; p <= dr; p++) {
v[p] = temp[p];
}
}
void mergeSort(int st, int dr) {
if (st < dr) {
int mij = (st + dr) / 2;
mergeSort(st, mij);
mergeSort(mij + 1, dr);
interclaseaza(st, mij, dr);
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
mergeSort(1, n);
for (int i = 1; i <= n; i++) {
cout << v[i] << " ";
}
return 0;
}
Verifică: pentru v = 5 2 8 1 9 3, rezultatul este 1 2 3 5 8 9. Funcțiile sunt definite înainte de main(), iar temp este vector auxiliar.
Sarcina 2: Spectacolele (recapitulare)
Cerință: Scrie programul complet pentru problema Spectacole: citește n spectacole (început, sfârșit) și afișează numărul maxim de spectacole compatibile, folosind metoda Greedy.
Soluție pentru Sarcina 2:
#include <iostream>
using namespace std;
int inceput[101], sfarsit[101];
void sorteaza(int n) {
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (sfarsit[i] > sfarsit[j]) {
int aux = sfarsit[i];
sfarsit[i] = sfarsit[j];
sfarsit[j] = aux;
aux = inceput[i];
inceput[i] = inceput[j];
inceput[j] = aux;
}
}
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> inceput[i] >> sfarsit[i];
}
sorteaza(n);
int nr = 1;
int ultimul = sfarsit[1];
for (int i = 2; i <= n; i++) {
if (inceput[i] >= ultimul) {
nr++;
ultimul = sfarsit[i];
}
}
cout << nr << endl;
return 0;
}
Verifică: pentru spectacolele (1,3), (2,5), (4,6), (6,8), rezultatul este 3. Sortarea după sfârșit este criteriul greedy care maximizează numărul de spectacole.
Scrie pe caiet - Recapitulare generală a modulului 4
Titlul lecției
- Ora 13: Recapitulare generală
Definiția lecției
Lecția recapitulă întregul modul 4 înaintea evaluării finale. Toți algoritmii Divide et impera (sumă, maxim, minim, merge sort, căutare binară, inversiuni, tablou rotit) respectă aceeași schemă: caz de bază, mijloc, apeluri recursive, combinare. Toate problemele Greedy (monede, spectacole, rucsac fracționar, platou clasic și extins) aleg pas cu pas optimul local, fără reconsiderare. Tabelul rezumativ D&I vs Greedy reunește fiecare algoritm cu cazul său de bază, criteriul de combinare sau de alegere și complexitatea. La recapitulare se exersează și recunoașterea metodei potrivite pentru o problemă dată, exact decizia cerută la Bacalaureat. Materialul de studiu este întreg modulul: schemele, programele și greșelile comune din lecțiile 1-12.
Definiții esențiale
- Divide et impera: descompunere, rezolvare recursivă, combinare; exemple: sumă, maxim, merge sort, căutare binară, inversiuni, tablou rotit.
- Greedy: alegerea optimului local, fără reconsiderare; exemple: monede, spectacole, rucsac fracționar, platou (clasic și extins).
- Substructură optimală: proprietatea care garantează corectitudinea Greedy.
- Problemă combinată: D&I pregătește sau verifică datele, Greedy ia deciziile.
Algoritmul cheie - pseudocod
- Schema D&I:
dacă st == dr → caz de bază; altfelmij, apeluri recursive, combinare (adunare, comparație, interclasare). - Schema Greedy: sortare după criteriul local, apoi buclă de alegeri cu condiții de oprire.
Algoritmul cheie - cod C++
maxim(st, dr): caz de bazăv[st], divizare, compararea luiașib.mergeSort+interclaseazacutemp.- Monede:
while (n >= monede[i])pe tablou descrescător. - Spectacole: sortare după
sfarsit, numărare cuinceput[i] >= ultimul.
Greșeli comune de evitat
- Cazurile de bază amestecate:
st == drla sumă/maxim,st > drla căutări. - Greedy fără substructură optimală verificată (exemplu: monede 1, 3, 4).
- Tipuri prea mici:
long longpentru inversiuni și sume mari. - Uitarea condițiilor de oprire (
g == 0, rest 0) în buclele greedy.
Sfaturi practice și trucuri
- Ține un tabel de sinteză cu toți algoritmii modulului, criteriile și complexitățile lor.
- Pentru fiecare problemă de antrenament, numește întâi metoda și justificarea, apoi scrie codul.
- Testează cazurile limită: vector cu un element, n = 1, rest 0, capacitate mai mare decât suma greutăților.
- Înainte de evaluare, reia de la ora 1 și scrie din memorie fiecare program principal.
Exemplu practic
Un elev se pregătește pentru test repetând fiecare program din memorie: pentru maximul prin D&I scrie funcția de mai jos, apoi o rulează mental pe un vector mic, de exemplu v = [4, 9, 2, 7], unde rezultatul este 9:
int maxim(int st, int dr) {
if (st == dr) {
return v[st];
}
int mij = (st + dr) / 2;
int a = maxim(st, mij);
int b = maxim(mij + 1, dr);
if (a > b) {
return a;
}
return b;
}