Ideea Divide et Impera — împarte, rezolvă, combină

Mediu~16 min5 pași

De ce contează?

Cauți un nume într-o carte de telefon groasă cât o cărămidă. Nu o iei pagină cu pagină — o deschizi fix la mijloc. Numele căutat e înainte? Arunci toată jumătatea din dreapta. E după? Arunci jumătatea din stânga. Dintr-o singură mișcare, problema ta s-a făcut de două ori mai mică. Repeți pe ce a rămas. Asta e ideea din spatele metodei Divide et Impera: nu ataci problema mare direct, ci o tot rupi în bucăți mai mici de aceeași formă, până devin banale.

Cei trei pași: împarte, rezolvă, combină

Divide et Impera („împarte și stăpânește”) este o metodă de rezolvare care construiește răspunsul în trei pași, mereu aceiași:

  1. ÎMPARTE — rupi problema în două (sau mai multe) subprobleme mai mici de același tip. Nu probleme diferite — aceeași problemă, doar pe o porțiune mai mică din date.
  2. REZOLVĂ — rezolvi fiecare subproblemă recursiv, cu exact aceeași metodă. Pentru că au aceeași formă, se aplică din nou cei trei pași. Coborârea se oprește la cazul de bază: o instanță atât de mică (de obicei un singur element) încât răspunsul e direct, fără alt apel.
  3. COMBINĂ — lipești răspunsurile subproblemelor într-un răspuns pentru problema mare.

De ce funcționează? Pentru că fiecare subproblemă e o versiune mai mică a aceleiași probleme. Dacă știi să rezolvi problema în general, știi automat să rezolvi și subproblema — e doar aceeași sarcină, cu mai puține date. Iar cum la fiecare pas datele se micșorează, ajungi garantat la cazul de bază, unde recursia se oprește.

Fiecare dintre cei trei pași are propria lui lecție în acest capitol (împărțirea problemei, rezolvarea subproblemelor, combinarea rezultatelor). Aici prinzi doar imaginea de ansamblu. Recursivitatea este motorul întregii metode — dacă nu o ai solidă, recapituleaz-o întâi din capitolul de recursivitate.

Exemplu pas cu pas: maximul din [3, 7, 2, 9]

Vrem cel mai mare element dintr-un șir. Cu Divide et Impera gândim așa:

  • ÎMPARTE șirul la mijloc în două jumătăți: [3, 7] și [2, 9].
  • REZOLVĂ maximul fiecărei jumătăți (recursiv, prin aceeași înjumătățire): max([3, 7]) = 7 și max([2, 9]) = 9.
  • COMBINĂ: maximul întregului șir e cel mai mare dintre cele două rezultate: max(7, 9) = 9.

Desfășurat, jumătatea [3, 7] se rupe mai departe în [3] și [7] — fiecare cu un singur element, deci cazuri de bază: răspunsul e chiar elementul. Apoi rezultatele urcă înapoi și se combină: max(3, 7) = 7, max(2, 9) = 9, iar la final max(7, 9) = 9.

v
3
7
2
9
0
1
2
3
max
Împarți la mijloc: max(stânga 3,7)=7, max(dreapta 2,9)=9, combini → max(7,9)=9.

Implementare C++

Maximul prin Divide et Impera. Funcția primește capetele intervalului st și dr și se apelează pe jumătăți.

#include <iostream>
using namespace std;

int maximDI(int v[], int st, int dr) {
    if (st == dr) return v[st];          // caz de baza: un singur element
    int mid = st + (dr - st) / 2;        // mijloc fara overflow
    int maxStanga = maximDI(v, st, mid); // REZOLVA jumatatea stanga
    int maxDreapta = maximDI(v, mid + 1, dr); // REZOLVA jumatatea dreapta
    // COMBINA: cel mai mare dintre cele doua
    return maxStanga > maxDreapta ? maxStanga : maxDreapta;
}

int main() {
    int v[] = {3, 7, 2, 9};
    int n = 4;
    cout << maximDI(v, 0, n - 1) << "\n"; // 9
    return 0;
}

Observă cele trei părți în cod: împărțirea (mid), rezolvarea (cele două apeluri recursive) și combinarea (alegerea celui mai mare). Cazul de bază (st == dr) oprește coborârea.

Complexitate

Pentru maxim, fiecare element e atins exact o dată în drumul recursiei, deci munca totală e liniară.

MărimeTimpDe ce
maximDI(n)O(n)fiecare element e privit o singură dată la combinare
memorieO(log n)adâncimea recursiei (înjumătățiri succesive)

Aici Divide et Impera nu bate o simplă buclă for (tot O(n)) — exemplul e ales ca să vezi clar tiparul. Forța metodei apare când combinarea e isteață: la căutarea binară pe șir sortat arunci o jumătate întreagă la fiecare pas și ajungi la O(log n), iar la sortările prin interclasare la O(n log n). Aceste cazuri clasice le studiezi separat.

Observația-cheie

Subproblemele unei probleme Divide et Impera sunt de exact același tip ca problema mare — doar pe mai puține date. Tocmai de asta le poți rezolva cu același algoritm, adică recursiv. Dacă subproblema ar fi o problemă diferită, nu ai mai putea reapela aceeași funcție și metoda s-ar prăbuși.

Greșeli frecvente
  • mid = (st + dr) / 2: la valori mari st + dr depășește int (overflow) și mid iese aiurea. Scrie mereu mid = st + (dr - st) / 2.
  • Uiți cazul de bază: fără if (st == dr) return ..., recursia coboară la intervale goale sau invalide la nesfârșit — stack overflow.
  • Nu combini corect: rezolvi ambele jumătăți, dar returnezi doar una (de ex. doar maxStanga). Rezultatele subproblemelor trebuie îmbinate, altfel pierzi jumătate din răspuns.
  • Subprobleme care nu se micșorează: apelezi recursiv pe [st, dr] în loc de jumătăți (sau pui mid + 1 greșit), așa că datele nu scad și nu atingi niciodată cazul de bază.

Vizualizare

Urmărește cum se rupe șirul în jumătăți până la elemente singulare, apoi cum urcă înapoi rezultatele și se combină.

Indiciu

Folosește săgețile și ca să mergi pas cu pas: coboară în câte o subproblemă (împărțirea), iar te întoarce ca să vezi cum se combină rezultatele.

Recapitulare

  • Divide et Impera rezolvă o problemă în trei pași: ÎMPARTE în subprobleme mai mici de același tip, REZOLVĂ-le recursiv, COMBINĂ rezultatele.
  • Funcționează pentru că subproblemele sunt versiuni mai mici ale aceleiași probleme, deci se opresc sigur la cazul de bază; împarte mereu cu mid = st + (dr - st) / 2.
  • Recursivitatea e motorul metodei; puterea reală apare când combinarea e isteață (căutare binară O(log n), interclasare O(n log n)) — cazuri studiate separat.

Întrebarea 1 / 3

Care sunt, în ordine, cei trei pași ai metodei Divide et Impera?