Author: admin

  • Algoritmi Eficienți în C++ cu , ,

    Salut! Iată soluții eficiente pentru problemele avansate, folosind doar cele 3 biblioteci permise: <iostream>, <fstream> și <cmath>.

    Problema 1: Divizorul 26^p în n!

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        long long n;
        cin >> n;
    
        // Calculăm puterea lui 13 în n! (26 = 2 × 13, iar 13 este limitatorul)
        long long p = 0;
        long long putere13 = 13;
    
        while (putere13 <= n) {
            p += n / putere13;
            putere13 *= 13;
        }
    
        ofstream fout("bac.txt");
        fout << p;
        fout.close();
    
        return 0;
    }

    Eficiență: O(log₁₃ n) timp, O(1) memorie


    Problema 2: Perioade Valide de Monitorizare

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        ifstream fin("bac.in");
        int minz, minP;
        fin >> minz >> minP;
    
        int ziua = 1;
        int stanga = 1, suma = 0;
        bool in_perioada = false;
        bool exista = false;
        int stoc;
    
        while (fin >> stoc) {
            if (stoc >= minz) {
                suma += stoc;
    
                if (!in_perioada && suma >= minP) {
                    in_perioada = true;
                    exista = true;
                    cout << stanga << " ";
                }
    
                ziua++;
            } else {
                if (in_perioada) {
                    cout << ziua - 1 << " " << suma << endl;
                }
                in_perioada = false;
                suma = 0;
                stanga = ziua + 1;
                ziua++;
            }
        }
    
        if (in_perioada) {
            cout << ziua - 1 << " " << suma << endl;
        }
    
        if (!exista) {
            cout << "nu exista" << endl;
        }
    
        fin.close();
        return 0;
    }

    Problema 3: Triunghiuri Dreptunghice cu Aceeași Ipotenuză

    #include <iostream>
    #include <fstream>
    #include <cmath>
    using namespace std;
    
    int main() {
        ifstream fin("bac.txt");
        int a, b, c;
    
        // Folosim un vector de frecvență pentru ipotenuze (max 10^9 e prea mare)
        // Vom folosi un algoritm care nu necesită întreg vectorul
        // Dar trebuie să știm valoarea maximă a ipotenuzei
    
        // Citim o dată pentru a găsi maximul
        int max_ip = 0;
        int temp_a, temp_b, temp_c;
    
        ifstream fin2("bac.txt"); // A doua citire
    
        // Prima citire pentru maxim
        while (fin >> a >> b >> c) {
            // Sortăm pentru a avea ipotenuza pe ultima poziție
            if (a > b) { int t = a; a = b; b = t; }
            if (b > c) { int t = b; b = c; c = t; }
            if (a > b) { int t = a; a = b; b = t; }
    
            if (a*a + b*b == c*c && c > max_ip) {
                max_ip = c;
            }
        }
        fin.close();
    
        if (max_ip == 0) {
            cout << 0;
            return 0;
        }
    
        // Al doilea vector de frecvență
        int* frec = new int[max_ip + 1](); // inițializat cu 0
    
        // A doua citire pentru numărare
        while (fin2 >> a >> b >> c) {
            if (a > b) { int t = a; a = b; b = t; }
            if (b > c) { int t = b; b = c; c = t; }
            if (a > b) { int t = a; a = b; b = t; }
    
            if (a*a + b*b == c*c) {
                frec[c]++;
            }
        }
        fin2.close();
    
        int max_count = 0;
        for (int i = 0; i <= max_ip; i++) {
            if (frec[i] > max_count) {
                max_count = frec[i];
            }
        }
    
        cout << max_count;
        delete[] frec;
    
        return 0;
    }

    Problema 4: Șir Recurent și Termeni ≤ z

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        int x, y, z;
        cin >> x >> y >> z;
    
        // Determinăm pozițiile aproximative (nu sunt necesare exact)
        // Generăm termenii până depășim z
        int f1 = 0, f2 = 0, f3 = 1;
    
        // Vector pentru termenii ≤ z
        int termeni[1000]; // presupunem că nu vor fi peste 1000
        int n = 0;
    
        termeni[n++] = 0; // f1
        termeni[n++] = 0; // f2
        termeni[n++] = 1; // f3
    
        // Generăm mai departe
        int fn;
        do {
            fn = 4*termini[n-1] - 3*termini[n-2] - 2*termini[n-3];
            if (fn <= z) {
                termeni[n++] = fn;
            }
        } while (fn <= z);
    
        // Afișăm în ordine descrescătoare
        ofstream fout("bac.txt");
        for (int i = n-1; i >= 0; i--) {
            fout << termeni[i] << " ";
        }
        fout.close();
    
        return 0;
    }

    Problema 5: Numărul Maxim de Perechi cu Valori Egale

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        ifstream fin("date.in");
        int m, n;
        fin >> m >> n;
    
        int frecA[101] = {0}; // numerele sunt în [0,100]
        int frecB[101] = {0};
    
        // Citim șirul A
        for (int i = 0; i < m; i++) {
            int x;
            fin >> x;
            frecA[x]++;
        }
    
        // Citim șirul B
        for (int i = 0; i < n; i++) {
            int x;
            fin >> x;
            frecB[x]++;
        }
    
        // Calculăm perechile
        int perechi = 0;
        for (int i = 0; i <= 100; i++) {
            if (frecA[i] < frecB[i]) {
                perechi += frecA[i];
            } else {
                perechi += frecB[i];
            }
        }
    
        cout << perechi;
    
        fin.close();
        return 0;
    }

    Problema 6: Secvențe Paritare de Lungime Maximă

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        ifstream fin("bac.txt");
        int numar, anterior;
        int lung_curenta = 1, lung_maxima = 0;
        int count_maxime = 0;
    
        if (!(fin >> anterior)) {
            cout << "0 0";
            return 0;
        }
    
        while (fin >> numar) {
            // Verificăm aceeași paritate
            bool paritate_anterioara = (anterior % 2 == 0);
            bool paritate_curenta = (numar % 2 == 0);
    
            if (paritate_anterioara == paritate_curenta) {
                lung_curenta++;
            } else {
                if (lung_curenta > lung_maxima) {
                    lung_maxima = lung_curenta;
                    count_maxime = 1;
                } else if (lung_curenta == lung_maxima) {
                    count_maxime++;
                }
                lung_curenta = 1;
            }
    
            anterior = numar;
        }
    
        // Verificăm ultima secvență
        if (lung_curenta > lung_maxima) {
            lung_maxima = lung_curenta;
            count_maxime = 1;
        } else if (lung_curenta == lung_maxima) {
            count_maxime++;
        }
    
        cout << count_maxime << " " << lung_maxima;
    
        fin.close();
        return 0;
    }

    Problema 7: Cea mai Mare Cifră din Șir

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int cifra_maxima(int n) {
        int max_cif = 0;
        while (n > 0) {
            int cifra = n % 10;
            if (cifra > max_cif) {
                max_cif = cifra;
            }
            n /= 10;
        }
        return max_cif;
    }
    
    int main() {
        ifstream fin("numere.in");
        int numar;
        int cifra_max_global = -1;
        int primul = -1, ultimul = -1;
    
        while (fin >> numar) {
            int cifra_local = cifra_maxima(numar);
    
            if (cifra_local > cifra_max_global) {
                cifra_max_global = cifra_local;
                primul = numar;
                ultimul = numar;
            } else if (cifra_local == cifra_max_global) {
                if (primul == -1) {
                    primul = numar;
                }
                ultimul = numar;
            }
        }
    
        if (primul == -1 || primul == ultimul) {
            cout << "nu exista";
        } else {
            cout << primul << " " << ultimul;
        }
    
        fin.close();
        return 0;
    }

    Problema 8: Pași Reprezentativi (Temperaturi)

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main() {
        ifstream fin("bac.txt");
        int temperatura;
        int temperatura_maxima = -1;
        int pas = 1;
        int temperatura_anterioara = -1;
        bool primul_afisat = false;
    
        while (fin >> temperatura) {
            if (temperatura > temperatura_maxima) {
                temperatura_maxima = temperatura;
                if (primul_afisat) cout << " ";
                cout << pas;
                primul_afisat = true;
            }
    
            // Verificăm dacă e prima apariție într-o secvență de valori egale
            if (temperatura != temperatura_anterioara) {
                temperatura_anterioara = temperatura;
            }
    
            pas++;
        }
    
        fin.close();
        return 0;
    }

    🎯 Reguli de Aur pentru Algoritmi Eficienți:

    1. Citire/O scriere secvențială – nu încărca tot în memorie
    2. Un singur parcurs când e posibil (O(n))
    3. Vectori de frecvență pentru valori mici (0-100, 0-1000)
    4. Two pointers pentru probleme cu secvențe
    5. Formule matematice în loc de brute force

    💡 Exemplu: Suma primelor n numere

    Ineficient (O(n)):

    int suma = 0;
    for(int i=1; i<=n; i++) suma += i;

    Eficient (O(1)):

    int suma = n*(n+1)/2;  // formulă matematică

    Succes la implementare! Ai acum toate instrumentele pentru problemele complexe de la Bacalaureat. 🚀

  • Cum Gândește Calculatorul? Partea a 10-a: Programe Complete în C/C++

    Salut! Acum ajungem la nivelul cel mai avansat: programe complete pentru Bacalaureat. Aceste probleme valorează 10 puncte fiecare și testează toate competențele tale. Hai să le abordăm sistematic!

    🎯 Strategia pentru Probleme de Programare Completă

    1. Citește cerința 3 ori – Înțelege exact ce se cere
    2. Analizează exemplul – Exemplele sunt cheia pentru înțelegere
    3. Împarte în subprobleme – Rezolvă bucată cu bucată
    4. Scrie pseudocod – Pe hârtie, în română
    5. Implementează – Tradu în C/C++
    6. Testează – Cu datele din exemplu

    📚 Rezolvări Complete pentru Fiecare Problemă

    Problema 1: Eliminarea Diagonalei Secundare și Shiftare

    Cerința: Elimină elementele de pe diagonala secundară și mută celelalte spre stânga.

    Exemplu pentru n=4:

    Initial:     Dupa eliminare:
    1  2  3  4    X  X  X  X
    5  6  7  8    5  6  7  X
    9  10 11 12   9  10 X  12
    13 14 15 16   13 X  15 16
    
    Dupa shiftare:
    1  2  3  4    X  X  X  X
    5  6  7  X    5  6  7  X  
    9  10 X  12   9  10 12 X
    13 X  15 16   13 15 16 X

    Soluție:

    #include <iostream>
    using namespace std;
    
    int main() {
        int n, a[101][101];
    
        // Citire
        cin >> n;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
    
        // Pas 1: Marcam elementele de pe diagonala secundara cu -1
        for(int i = 0; i < n; i++) {
            a[i][n-1-i] = -1;  // -1 = pozitie libera
        }
    
        // Pas 2: Shiftare spre stanga pentru fiecare linie
        for(int i = 0; i < n; i++) {
            // Parcurgem de la stanga la dreapta si mutam elemente peste -1
            for(int j = 0; j < n-1; j++) {
                if(a[i][j] == -1) {
                    // Mutam urmatorul element in locul acesta
                    a[i][j] = a[i][j+1];
                    a[i][j+1] = -1;
                }
            }
        }
    
        // Pas 3: Afisare (inlocuim -1 cu 0 sau lasam spatiu)
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                if(a[i][j] == -1) cout << " ";
                else cout << a[i][j];
                if(j < n-1) cout << " ";
            }
            cout << endl;
        }
    
        return 0;
    }

    Varianta mai simplă cu tabloul auxiliar:

    #include <iostream>
    using namespace std;
    
    int main() {
        int n, a[101][101], b[101][101] = {0};
    
        cin >> n;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
    
        // Construim noul tablou
        for(int i = 0; i < n; i++) {
            int col = 0;
            for(int j = 0; j < n; j++) {
                // Daca NU e pe diagonala secundara, il punem
                if(j != n-1-i) {
                    b[i][col] = a[i][j];
                    col++;
                }
            }
            // Restul pozitiilor raman 0
        }
    
        // Afisare
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                cout << b[i][j] << " ";
            }
            cout << endl;
        }
    
        return 0;
    }

    Problema 2: Înlocuirea Coloanei cu Numărul Minim

    Cerința: Găsește coloana cu elementul minim și înlocuiește toate elementele ei cu elementul din dreapta-jos.

    Exemplu:

    Initial:
    17 10 11
    12 16 21
    5  2  8
    19 4  9
    
    Minim = 2 (pe linia 2, coloana 1)
    Elementul dreapta-jos = 9
    
    Dupa inlocuire:
    17 10 11
    12 16 21
    9  9  9  <- toata coloana 1 devine 9
    19 4  9

    Soluție:

    #include <iostream>
    using namespace std;
    
    int main() {
        int m, n, a[101][101];
    
        cin >> m >> n;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
    
        // 1. Gasim minimul si coloana lui
        int minim = a[0][0];
        int coloanaMinim = 0;
    
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(a[i][j] < minim) {
                    minim = a[i][j];
                    coloanaMinim = j;
                }
            }
        }
    
        // 2. Elementul din dreapta-jos
        int dreaptaJos = a[m-1][n-1];
    
        // 3. Inlocuim toata coloana
        for(int i = 0; i < m; i++) {
            a[i][coloanaMinim] = dreaptaJos;
        }
    
        // 4. Afisare
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                cout << a[i][j] << " ";
            }
            cout << endl;
        }
    
        return 0;
    }

    Problema 3: Transformarea Textului cu Cratime

    Cerința: Transformă spații multiple între cuvinte în ” – “.

    Exemplu: "anul acesta devin student""anul - acesta - devin - student"

    Soluție:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
        char text[101], rezultat[201] = "";
    
        cin.getline(text, 101);
    
        int i = 0, j = 0;
        int inCuvant = 0;  // 0 = in spatiu, 1 = in cuvant
    
        while(text[i] != '\0') {
            if(text[i] != ' ') {
                // Suntem intr-un cuvant
                if(inCuvant == 0 && j > 0) {
                    // S-a terminat spatiul dintre cuvinte
                    rezultat[j++] = ' ';
                    rezultat[j++] = '-';
                    rezultat[j++] = ' ';
                }
                rezultat[j++] = text[i];
                inCuvant = 1;
            } else {
                // Suntem in spatiu
                inCuvant = 0;
            }
            i++;
        }
        rezultat[j] = '\0';
    
        cout << rezultat;
    
        return 0;
    }

    Varianta cu strtok (mai simplă):

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main() {
        char text[101], cuvant[101];
        char *p;
        char rezultat[201] = "";
        int primulCuvant = 1;
    
        cin.getline(text, 101);
    
        p = strtok(text, " ");
        while(p != NULL) {
            if(!primulCuvant) {
                strcat(rezultat, " - ");
            }
            strcat(rezultat, p);
            primulCuvant = 0;
            p = strtok(NULL, " ");
        }
    
        cout << rezultat;
    
        return 0;
    }

    Problema 4: Grădina cu Flori și Gazon

    Cerința: Parcelele cu flori trebuie să fie cu cel puțin 1 decimetru mai înalte decât gazonul de pe rândul anterior. Gazonul prea înalt se taie.

    Analiză exemplu:

    Initial (m=4, n=6):
    Linia 1 (gazon): 6 7 8 8 7 6
    Linia 2 (flori): 2 3 5 7 2 5  
    Linia 3 (gazon): 7 9 9 6 5 9
    Linia 4 (flori): 4 8 2 9 3 8
    
    Regula: Florile de pe linia i trebuie sa fie > gazonul de pe linia i-1 cu cel putin 1
    Dar florile nu se modifica, doar gazonul se taie!

    Soluție:

    #include <iostream>
    using namespace std;
    
    int main() {
        int m, n, a[101][101];
    
        cin >> m >> n;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
    
        // Parcurgem liniile cu gazon (liniile impare: 0, 2, 4... index 0-based)
        for(int i = 0; i < m; i += 2) {  // i = linia cu gazon
            // Daca exista o linie cu flori dupa (i+1 < m)
            if(i + 1 < m) {
                for(int j = 0; j < n; j++) {
                    // Daca gazonul este prea inalt fata de florile de sub el
                    // Florile trebuie sa fie > gazon cu cel putin 1
                    // Deci gazonul trebuie sa fie <= flori - 1
                    if(a[i][j] >= a[i+1][j]) {
                        a[i][j] = a[i+1][j] - 1;
                        if(a[i][j] < 2) a[i][j] = 2;  // limita inferioara
                    }
                }
            }
        }
    
        // Parcurgem liniile cu gazon (cele pare: 1, 3, 5... index 0-based)
        for(int i = 1; i < m; i += 2) {  // i = linia cu gazon
            // Daca exista o linie cu flori inainte (i-1 >= 0)
            for(int j = 0; j < n; j++) {
                // Gazonul de pe linia i trebuie verificat cu florile de pe linia i-1
                if(a[i][j] >= a[i-1][j]) {
                    a[i][j] = a[i-1][j] - 1;
                    if(a[i][j] < 2) a[i][j] = 2;
                }
            }
        }
    
        // Afisare
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                cout << a[i][j] << " ";
            }
            cout << endl;
        }
    
        return 0;
    }

    Problema 5: Pătrat de Valoare Maximă (2×2)

    Cerința: Găsește submatricea 2×2 cu suma maximă.

    Soluție:

    #include <iostream>
    using namespace std;
    
    int main() {
        int m, n, a[21][21];
    
        cin >> m >> n;
        for(int i = 0; i < m; i++)
            for(int j = 0; j < n; j++)
                cin >> a[i][j];
    
        int maxSum = -1;
    
        // Parcurgem toate submatricele 2x2
        for(int i = 0; i < m-1; i++) {
            for(int j = 0; j < n-1; j++) {
                int suma = a[i][j] + a[i][j+1] + a[i+1][j] + a[i+1][j+1];
                if(suma > maxSum) {
                    maxSum = suma;
                }
            }
        }
    
        cout << maxSum;
    
        return 0;
    }

    Problema 6: Vocală Prietenă pentru Consoane

    Cerința: Fiecare consoană se înlocuiește cu vocala care o precede fără alte vocale între ele.

    Analiză:

    • Alfabet: a b c d e f g h i j k l m n o p q r s t u v w x y z
    • Vocale: a, e, i, o, u
    • Pentru ‘m’: vocalele care îl preced: i (are ‘j’, ‘k’, ‘l’ între), o (nu, are doar consoane)
    • Regula: Ultima vocală înainte de consoană, fără alte vocale între

    Soluție simplificată: Pentru fiecare consoană, o înlocuim cu vocala anterioară:

    • b → a, c → a, d → a, f → e, g → e, h → e, j → i, k → i, l → i, m → i, n → i, p → o, q → o, r → o, s → o, t → o, v → u, w → u, x → u, y → u, z → u

    Soluție:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int esteVocala(char c) {
        return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u');
    }
    
    char vocalaPrietenie(char consoana) {
        // Pentru fiecare consoana, returnam vocala corespunzatoare
        if(consoana >= 'b' && consoana <= 'd') return 'a';
        if(consoana >= 'f' && consoana <= 'h') return 'e';
        if(consoana >= 'j' && consoana <= 'n') return 'i';
        if(consoana >= 'p' && consoana <= 't') return 'o';
        if(consoana >= 'v' && consoana <= 'z') return 'u';
        return consoana;  // daca nu e consoana
    }
    
    int main() {
        char parola[51], codificata[51];
    
        cin >> parola;
    
        for(int i = 0; parola[i] != '\0'; i++) {
            if(esteVocala(parola[i])) {
                codificata[i] = parola[i];  // vocalele raman asa
            } else {
                codificata[i] = vocalaPrietenie(parola[i]);
            }
        }
        codificata[strlen(parola)] = '\0';
    
        cout << codificata;
    
        return 0;
    }

    Problema 7: Cuvinte Asemenea

    Cerința: Găsește toate cuvintele cu același număr de vocale ca ultimul cuvânt.

    Soluție:

    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int numarVocale(char cuvant[]) {
        int count = 0;
        for(int i = 0; cuvant[i] != '\0'; i++) {
            char c = cuvant[i];
            if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
                count++;
        }
        return count;
    }
    
    int main() {
        int n;
        char cuvinte[11][21];  // maxim 10 cuvinte a cate 20 caractere
    
        cin >> n;
        for(int i = 0; i < n; i++) {
            cin >> cuvinte[i];
        }
    
        int vocaleUltim = numarVocale(cuvinte[n-1]);
        int exista = 0;
    
        // Parcurgem toate cuvintele in afara de ultimul
        for(int i = 0; i < n-1; i++) {
            if(strcmp(cuvinte[i], cuvinte[n-1]) != 0) {  // distincte
                if(numarVocale(cuvinte[i]) == vocaleUltim) {
                    if(exista) cout << " ";
                    cout << cuvinte[i];
                    exista = 1;
                }
            }
        }
    
        if(!exista) {
            cout << "nu exista";
        }
    
        return 0;
    }

    🎯 Sfaturi pentru Probleme Complexe

    1. Citește cu atenție – Subliniază condițiile importante
    2. Folosește exemplele – Sunt cele mai bune ghiduri
    3. Împarte problema – Rezolvă bucată cu bucată
    4. Testează incremental – După fiecare pas, testează
    5. Gestionează memoria – Folosește dimensiuni suficiente
    6. Verifică cazurile limită – n=1, m=1, sir vid, etc.

    💪 Exercițiu de Practică

    Încearcă să rezolvi singur următoarea problemă:

    Cerință: Scrie un program care citește n numere și afișează cele care au suma cifrelor egală cu produsul cifrelor.

    Soluție:

    #include <iostream>
    using namespace std;
    
    int main() {
        int n, numar;
        cin >> n;
    
        for(int i = 0; i < n; i++) {
            cin >> numar;
            int suma = 0, produs = 1, temp = numar;
    
            while(temp > 0) {
                int cifra = temp % 10;
                suma += cifra;
                produs *= cifra;
                temp /= 10;
            }
    
            if(suma == produs) {
                cout << numar << " ";
            }
        }
    
        return 0;
    }

    ✨ Motivare Finală

    Uite ce uimitor! Acum poți să rezolvi aproape orice problemă de la Bacalaureat. Ai parcurs o cale lungă: de la bazele gândirii algoritmice până la programe complexe.

    Cel mai important lucru pe care l-ai învățat: Orice problemă complexă este doar o colecție de probleme simple puse împreună.

    La examen:

    1. Răspunde la ce știi – Nu lăsa nimic necompletat
    2. Gestionează-ți timpul – Alocă timp proporțional cu punctajul
    3. Ai încredere în tine – Ai practicat suficient!

    Succes la Bacalaureat! Tu poți să iei nota maximă! 🚀🎯

  • Cum Gândește Calculatorul? Partea a 9-a: Subprograme Complexe în C/C++

    Salut! Acum ajungem la cea mai practică parte: scrierea de subprograme (funcții) complete. Acestea sunt probleme tipice de la Bacalaureat care valorează multe puncte. Hai să le abordăm sistematic!

    🎯 Strategia pentru Scrierea Subprogramelor

    1. Înțelege cerința – Citește de 2-3 ori până înțelegi ce trebuie să facă funcția
    2. Analizează exemplul – Exemplele arată exact ce se așteaptă
    3. Gândește algoritmul – Pe hârtie, în pași simpli
    4. Scrie codul – Pas cu pas, cu variabile clare
    5. Testează mental – Rulează cu datele din exemplu

    📚 Rezolvări Complete pentru Fiecare Problemă

    Problema 1: Subprogramul Plus – Înlocuirea 25 cu 26

    Cerința: Înlocuiește fiecare secvență “25” cu “26” în număr.

    Exemplu: 202535250202635260

    Soluție:

    void Plus(int &n) {
        int rezultat = 0, putere = 1, cifra;
    
        while(n > 0) {
            cifra = n % 10;  // ultima cifră
            n = n / 10;      // elimină ultima cifră
    
            // Verificăm dacă avem secvența 25 (cifrele 5 și 2 consecutive)
            if(cifra == 5 && n % 10 == 2) {
                // Am găsit 25, îl înlocuim cu 26
                rezultat = 6 * putere + rezultat;  // punem 6 în loc de 5
                putere = putere * 10;
                rezultat = 2 * putere + rezultat;  // 2 rămâne
                n = n / 10;  // eliminăm și pe 2 din n
            } else {
                // Păstrăm cifra originală
                rezultat = cifra * putere + rezultat;
            }
            putere = putere * 10;
        }
    
        n = rezultat;
    }

    Explicație:

    • Parcurgem numărul de la coadă la cap (de la unități la zeci, sute, etc.)
    • Când găsim cifra 5 urmată de 2, înlocuim 5 cu 6
    • Reconstruim numărul în variabila rezultat

    Problema 2: Subprogramul teren – Împărțirea Terenului

    Cerința: Găsește toate împărțirile unui teren dreptunghiular în parcele egale care respectă condițiile.

    Condiții:

    1. Număr parcele = par
    2. Număr parcele < Aria unei parcele
    3. Ambele valori sunt naturale

    Soluție:

    void teren(int x, int y) {
        int ariaTotala = x * y;
        int existaSolutii = 0;
    
        // Parcurgem toți divizorii ariei totale
        for(int nrParcele = 2; nrParcele <= ariaTotala; nrParcele += 2) {  // doar numere pare
            if(ariaTotala % nrParcele == 0) {
                int ariaParcele = ariaTotala / nrParcele;
    
                // Verificăm condiția: nrParcele < ariaParcele
                if(nrParcele < ariaParcele) {
                    cout << nrParcele << " parcele de arie " << ariaParcele << endl;
                    existaSolutii = 1;
                }
            }
        }
    
        if(!existaSolutii) {
            cout << "nu exista" << endl;
        }
    }

    Test pentru x=6, y=8:

    • Aria totală = 48
    • Parcurgem numere pare: 2, 4, 6, 8…
    • 2 parcele × 24 m² → 2 < 24 ✓
    • 4 parcele × 12 m² → 4 < 12 ✓
    • 6 parcele × 8 m² → 6 < 8 ✓
    • 8 parcele × 6 m² → 8 < 6 ✗

    Problema 3: Subprogramul diviz – Cel mai mare divizor pătrat perfect

    Cerința: Găsește cel mai mare divizor al lui n care este pătrat perfect.

    Soluție:

    int diviz(int n) {
        int maxDivizor = 1;  // 1 este pătrat perfect
    
        // Parcurgem de la n la 1 și căutăm pătrate perfecte
        for(int i = n; i >= 1; i--) {
            if(n % i == 0) {  // i este divizor al lui n
                // Verificăm dacă i este pătrat perfect
                int radacina = sqrt(i);
                if(radacina * radacina == i) {
                    maxDivizor = i;
                    break;  // am găsit cel mai mare (căutăm de sus în jos)
                }
            }
        }
    
        return maxDivizor;
    }

    Alternativă mai eficientă:

    int diviz(int n) {
        int rezultat = 1;
    
        // Descompunem n în factori primi
        for(int d = 2; d * d <= n; d++) {
            int putere = 0;
            while(n % d == 0) {
                putere++;
                n = n / d;
            }
            // Luăm doar factorii la putere pară pentru pătrat perfect
            if(putere >= 2) {
                rezultat = rezultat * pow(d, putere - putere % 2);
            }
        }
        // Dacă n a rămas pătrat perfect după descompunere
        int rad = sqrt(n);
        if(rad * rad == n && n > 1) {
            rezultat = rezultat * n;
        }
    
        return rezultat;
    }

    Problema 4: Subprogramul moderat – Numere Moderate

    Cerința: Un număr este “moderat” dacă este produsul a două numere prime consecutive.

    Exemplu: 35 = 5 × 7 (5 și 7 sunt prime consecutive)

    Soluție:

    int prim(int numar) {
        if(numar < 2) return 0;
        if(numar == 2) return 1;
        if(numar % 2 == 0) return 0;
    
        for(int d = 3; d * d <= numar; d += 2) {
            if(numar % d == 0) return 0;
        }
        return 1;
    }
    
    int moderate(int n) {
        // Verificăm toate perechile de numere prime consecutive
        for(int p = 2; p * p <= n; p++) {
            if(prim(p)) {
                // Găsim următorul număr prim după p
                int q = p + 1;
                while(!prim(q) && q <= n) q++;
    
                if(prim(q) && p * q == n) {
                    return 1;  // am găsit perechea
                }
            }
        }
        return 0;
    }

    Optimizare: Putem genera direct perechile de prime consecutive:

    int moderate(int n) {
        int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
    
        for(int i = 0; i < 15; i++) {  // 15 perechi (0-14, 1-15)
            if(prime[i] * prime[i+1] == n) {
                return 1;
            }
            if(prime[i] * prime[i+1] > n) {
                break;  // am depășit n
            }
        }
        return 0;
    }

    Problema 5: Subprogramul DNPT – Divizori Neprimi Pozitivi Impari

    Cerința: Afișează toți divizorii impari ai lui n care NU sunt numere prime.

    Soluție:

    int estePrim(int numar) {
        if(numar < 2) return 0;
        if(numar == 2) return 1;
        if(numar % 2 == 0) return 0;
    
        for(int d = 3; d * d <= numar; d += 2) {
            if(numar % d == 0) return 0;
        }
        return 1;
    }
    
    void DNPT(int n) {
        // Parcurgem toți divizorii impari
        for(int d = 1; d <= n; d += 2) {  // d += 2 pentru numere impare
            if(n % d == 0) {  // d este divizor
                if(!estePrim(d)) {  // d NU este prim
                    cout << d << " ";
                }
            }
        }
    }

    Pentru n=90: Divizorii impari: 1, 3, 5, 9, 15, 45

    • 1: nu e prim ✓
    • 3: e prim ✗
    • 5: e prim ✗
    • 9: nu e prim ✓
    • 15: nu e prim ✓
    • 45: nu e prim ✓
      → Afișează: 1 9 15 45

    Problema 6: Subprogramul schimb – Înlocuirea unei cifre

    Cerința: Înlocuiește cifra de pe poziția p cu cifra x.

    Soluție:

    void schimb(int &n, int x, int p) {
        int putere = 1;
    
        // Ridică 10 la puterea p
        for(int i = 0; i < p; i++) {
            putere = putere * 10;
        }
    
        // Separăm numărul în trei părți:
        // partea din stânga cifrei + cifra nouă + partea din dreapta
        int parteaDreapta = n % putere;
        int cifraVeche = (n / putere) % 10;
        int parteaStanga = n / (putere * 10);
    
        // Reconstruim numărul cu cifra nouă
        n = parteaStanga * putere * 10 + x * putere + parteaDreapta;
    }

    Alternativă mai clară:

    void schimb(int &n, int x, int p) {
        char sir[12];
        sprintf(sir, "%d", n);  // transformă numărul în șir
    
        int lungime = strlen(sir);
        if(p < lungime) {
            // Poziția p în șir este de la stânga, dar în problemă e de la dreapta
            // Deci: poziția în șir = lungime - 1 - p
            sir[lungime - 1 - p] = '0' + x;  // transformă cifra în caracter
            n = atoi(sir);  // transformă înapoi în număr
        }
    }

    Problema 7: Subprogramul harsad – Numere Harsad/Niven

    Cerința: Găsește cel mai mare număr ≤ k care este divizibil cu suma cifrelor sale.

    Soluție:

    int sumaCifre(int numar) {
        int suma = 0;
        while(numar > 0) {
            suma = suma + numar % 10;
            numar = numar / 10;
        }
        return suma;
    }
    
    void harsad(int k, int &n) {
        n = k;  // începem de la k și coborâm
    
        while(n > 0) {
            int suma = sumaCifre(n);
            if(suma > 0 && n % suma == 0) {
                return;  // am găsit număr harsad
            }
            n--;  // încercăm următorul număr mai mic
        }
    
        n = 1;  // dacă nu găsim nimic, 1 este harsad (1 % 1 = 0)
    }

    Problema 8: Subprogramul fulg – Aglomerări de Fulgi

    Cerința: Verifică dacă un număr reprezintă o aglomerare validă de fulgi.

    Condiții din text:

    1. Are 9 cifre
    2. Conține doar cifrele 1,2,3,4
    3. Conține cel puțin o dată fiecare cifră 1,2,3,4

    Soluție:

    int fulg(long long n) {
        if(n < 111111111 || n > 444444444) return 0;  // are 9 cifre, între 1..4
    
        int frecventa[10] = {0};  // frecvența cifrelor 0-9
        int nrCifre = 0;
    
        while(n > 0) {
            int cifra = n % 10;
            if(cifra < 1 || cifra > 4) return 0;  // cifră invalidă
            frecventa[cifra]++;
            nrCifre++;
            n = n / 10;
        }
    
        if(nrCifre != 9) return 0;  // nu are exact 9 cifre
    
        // Verificăm dacă avem cel puțin o dată fiecare cifră 1,2,3,4
        if(frecventa[1] > 0 && frecventa[2] > 0 && 
           frecventa[3] > 0 && frecventa[4] > 0) {
            return 1;
        }
    
        return 0;
    }

    Problema 9: Subprogramul NrTmp – Numere cu 3 Divizori Impari

    Cerința: Numără câte numere din [x,y] au exact 3 divizori pozitivi impari.

    Observație: Un număr are 3 divizori impari dacă este de forma p² unde p este prim impar.

    Soluție:

    int prim(int numar) {
        if(numar < 2) return 0;
        if(numar == 2) return 1;
        if(numar % 2 == 0) return 0;
    
        for(int d = 3; d * d <= numar; d += 2) {
            if(numar % d == 0) return 0;
        }
        return 1;
    }
    
    void NrTmp(int x, int y, int &nr) {
        nr = 0;
    
        // Parcurgem pătratele numerelor prime impare
        for(int p = 3; p * p <= y; p += 2) {
            if(prim(p)) {
                int patrat = p * p;
                if(patrat >= x && patrat <= y) {
                    nr++;
                }
            }
        }
    
        // Verificăm și pătratele de 2 (adică 4) dacă e în interval
        if(x <= 4 && 4 <= y) {
            nr++;  // 4 are divizorii impari: 1, (nu are alții) - ATENȚIE! 4 are doar 1 divizor impar!
            // Corect: 4 are divizorii: 1, 2, 4 → doar 1 este impar → deci nu se numără!
        }
    }

    Corectare: Problema spune “cu trei divizori pozitivi impari”. Pătratul unui prim impar p² are divizorii: 1, p, p² → toți 3 sunt impari dacă p este impar.


    🎯 Sfaturi Pentru Subprograme la Bacalaureat

    1. Numele subprogramului trebuie să fie exact cum e în cerință
    2. Parametrii trebuie să aibă exact tipul și modul de transmitere specificat
    • int &n = transmitere prin referință (se modifică)
    • int n = transmitere prin valoare (nu se modifică)
    1. Folosește funcții auxiliare dacă e nevoie (ex: prim(), sumaCifre())
    2. Comentează dacă algoritmul e complex
    3. Testează cu datele din exemplu

    💪 Exercițiu de Practică

    Încearcă să scrii singur următorul subprogram:

    Cerință: Scrie subprogramul oglindit care primește un număr n și returnează oglinditul său.
    Exemplu: pentru n=1234, returnează 4321.

    Soluție:

    int oglindit(int n) {
        int ogl = 0;
        while(n > 0) {
            ogl = ogl * 10 + n % 10;
            n = n / 10;
        }
        return ogl;
    }

    ✨ Motivare Finală

    Uite cât de multe subprograme ai învățat să scrii! Fiecare problemă rezolvată este o unealtă nouă în “cutia ta de instrumente” de programator.

    La examen, ai timp suficient să scrii cod corect și elegant. Important este să:

    1. Înțelegi cerința
    2. Gândești algoritmul
    3. Scrii pas cu pas
    4. Verifici cu exemplul

    Ești gata să iei 10 pe 10 la subprograme! 🚀

  • Cum Gândește Calculatorul? Partea a 8-a: Probleme cu Structuri și Șiruri de Caractere în C/C++

    Salut! Astăzi abordăm partea practică de programare: problemele cu structuri, șiruri de caractere și logica de programare. Acestea sunt puncte “sigure” la Bacalaureat dacă le înțelegi bine!

    🎯 Strategia Generală pentru Problemele de Programare

    1. Citește cerința de 2 ori – Subliniază datele importante
    2. Identifică tipul de date – Ce variabile sunt necesare?
    3. Gândește algoritmul – Pe hârtie, în română
    4. Scrie codul – Pas cu pas, comentând dacă e necesar
    5. Testează cu exemplul – Mereu verifică cu datele din exemplu

    📚 Rezolvări Pas cu Pas

    Problema 1: Formatarea Numărului de Telefon

    Cerința: Transformă un număr internațional (+254)722123456 cu prefix 0 în număr local 0722123456.

    Analiză:

    • Numărul internațional are forma: (cod_țară)număr
    • Trebuie să înlocuim (cod_țară) cu prefixul național (sau șir vid)

    Soluție:

    #include <cstring>  // pentru funcțiile cu șiruri
    
    // Presupunem că avem:
    // char tI[50];  // număr internațional
    // char pN[10];  // prefix național
    // char tL[50];  // număr local (rezultat)
    
    // Secvența de instrucțiuni:
    int i, j;
    int parantezaDeschisa = -1, parantezaInchisa = -1;
    
    // 1. Găsim parantezele
    for(i = 0; tI[i] != '\0'; i++) {
        if(tI[i] == '(') parantezaDeschisa = i;
        if(tI[i] == ')') parantezaInchisa = i;
    }
    
    // 2. Copiem prefixul național (dacă există)
    j = 0;
    if(strlen(pN) > 0) {
        strcpy(tL, pN);
        j = strlen(pN);
    }
    
    // 3. Copiem partea după paranteza închisă (numărul propriu-zis)
    if(parantezaInchisa != -1) {
        for(i = parantezaInchisa + 1; tI[i] != '\0'; i++) {
            tL[j] = tI[i];
            j++;
        }
        tL[j] = '\0';  // terminator de șir
    }
    
    // Varianta mai simplă cu funcții:
    // char tL[50] = "";
    // if(strlen(pN) > 0) strcat(tL, pN);
    // char* numar = strchr(tI, ')');
    // if(numar != NULL) strcat(tL, numar + 1);

    Problema 2: Structura Bijuterie

    Cerința: Definește structura bijuterie care să permită expresiile b.metal.denumire și b.greutate*b.metal.pret.

    Soluție:

    struct metal {
        char denumire[31];  // 30 + 1 pentru '\0'
        int pret;           // prețul unui gram
    };
    
    struct bijuterie {
        int greutate;       // în grame
        struct metal metal; // metalul prețios
    } b;

    Explicație:

    • b.metal.denumireb e de tip bijuterie, metal e câmp de tip struct metal, denumire e câmp în metal
    • b.greutate*b.metal.pretgreutate e în bijuterie, pret e în metal care e în bijuterie

    Problema 3: Verificare Pătrat

    Cerința: Verifică dacă dreptunghiul este pătrat.

    Analiză:

    • Avem două puncte: A (stânga-sus) și B (dreapta-jos)
    • Lățime = |B.x – A.x|
    • Înălțime = |A.y – B.y| (atenție la coordonate!)
    • Este pătrat dacă lățime = înălțime și ambele > 0

    Soluție:

    #include <cmath>  // pentru abs()
    
    struct punct { int x, y; };
    struct figura { punct A, B; } d;
    
    // Secvența de instrucțiuni:
    int latime = abs(d.B.x - d.A.x);
    int inaltime = abs(d.A.y - d.B.y);  // A.y > B.y (sus > jos)
    
    if(latime == inaltime && latime > 0) {
        cout << "DA";
    } else {
        cout << "NU";
    }

    Problema 4: Interval Muzical Terță

    Cerința: Verifică dacă două note formează o terță.

    Analiză:

    • Notele în engleză: A=la, B=si, C=do, D=re, E=mi, F=fa, G=sol
    • Terța = între note există o singură altă notă
    • Exemplu: G(sol) și B(si) → între ele: la (A) → o notă → este terță

    Soluție:

    struct interval { char nota1, nota2; } m;
    
    // Mapăm notele la poziții (pentru ordinea din gamă)
    // do=C(1), re=D(2), mi=E(3), fa=F(4), sol=G(5), la=A(6), si=B(7)
    
    int pozitie(char nota) {
        switch(nota) {
            case 'C': return 1;
            case 'D': return 2;
            case 'E': return 3;
            case 'F': return 4;
            case 'G': return 5;
            case 'A': return 6;
            case 'B': return 7;
            default: return 0;
        }
    }
    
    // Verificare
    int p1 = pozitie(m.nota1);
    int p2 = pozitie(m.nota2);
    
    if(p1 > 0 && p2 > 0 && abs(p1 - p2) == 2) {
        // Diferența de 2 poziții înseamnă 1 notă între ele
        cout << "TERTA";
    } else {
        cout << "NU";
    }

    Problema 5: Prima Literă sau ‘*’

    Cerința: Dacă prețul < 100, primește prima literă a denumirii, altfel ‘*’.

    Soluție simplă:

    struct produs { char denumire[20]; int pret; } p;
    char a;
    
    if(p.pret < 100) {
        a = p.denumire[0];  // prima literă
    } else {
        a = '*';
    }

    Problema 6: Temperatură și Mesaj

    Cerința: Afișează mesaj în funcție de temperatură.

    Soluție:

    struct meteo { int an, temperatura; } x;
    
    if(x.temperatura > 11) {
        cout << "CALDUROS";
    } else if(x.temperatura < 10) {
        cout << "RACOROS";
    } else {
        cout << "NORMAL";
    }

    Problema 7: Structura Specialist IT

    Cerința: Definește structura pentru expresiile s[5].personal.CNP, s[5].personal.anNastere, s[5].anAngajare.

    Soluție:

    struct datePersonale {
        char CNP[14];  // 13 caractere + '\0'
        int anNastere;
    };
    
    struct specialist {
        struct datePersonale personal;
        int anAngajare;
    } s[30];  // vector de 30 de specialiști

    Problema 8: Verificare Cuvinte cu 2 Litere

    Cerința: Verifică dacă există cuvinte de 2 litere cu o vocală și o consoană.

    Soluție:

    c = 0;  // inițializare
    for(i = 1; i <= 10; i++) {
        cin >> s;
    
        // Verificăm dacă cuvântul are exact 2 litere
        if(strlen(s) == 2) {
            // Verificăm dacă are o vocală și o consoană
            int esteVocala1 = (s[0]=='a'||s[0]=='e'||s[0]=='i'||s[0]=='o'||s[0]=='u');
            int esteVocala2 = (s[1]=='a'||s[1]=='e'||s[1]=='i'||s[1]=='o'||s[1]=='u');
    
            // O vocală și o consoană înseamnă că sunt diferite
            if(esteVocala1 != esteVocala2) {
                c = 1;
            }
        }
    }

    Explicație:

    • c se inițializează cu 0 (presupunem că nu există)
    • Dacă găsim un cuvânt care îndeplinește condiția, setăm c=1
    • esteVocala1 și esteVocala2 sunt 1 pentru vocală, 0 pentru consoană
    • Dacă sunt diferite (!=), avem o vocală și o consoană

    🎯 Sfaturi Practice pentru Bacalaureat

    1. Pentru probleme cu șiruri:
    • Nu uita de #include <cstring>
    • Terminatorul de șir '\0' este crucial
    • strlen(s) dă lungimea, strcpy(dest, sursă) copiază, strcat(dest, sursă) adaugă
    1. Pentru structuri:
    • Definește mai întâi structurile interioare
    • Folosește dimensiuni rezonabile (char[30] pentru 29 caractere + ‘\0’)
    • Accesează corect câmpurile: structura.camp sau structura.substructura.camp
    1. Pentru condiții:
    • Folosește paranteze pentru claritate
    • Testează toate cazurile (mai mic, egal, mai mare)
    • Ai grijă la operatori: = este atribuire, == este comparație
    1. Pentru vectori de structuri:
    • s[5] accesează al 6-lea element (indicele începe de la 0!)
    • s[5].personal.CNP accesează câmpul CNP din personal din al 6-lea specialist

    💪 Verificare Finală

    Încearcă să rezolvi singur următoarea problemă similară:

    Problemă: Definește o structură student care să conțină numele (max 30 caractere), media și anul de studiu. Scrie o secvență care să afișeze “BURSA” dacă media este ≥ 9.5, “EXAMEN” dacă media este între 5 și 9.5, altfel “CORIGENT”.

    Soluție rapidă:

    struct student { char nume[31]; float media; int an; } s;
    
    if(s.media >= 9.5) cout << "BURSA";
    else if(s.media >= 5) cout << "EXAMEN";
    else cout << "CORIGENT";

    ✨ Motivare Finală

    Uite cât de multe ai învățat! De la probleme simple până la structuri complexe. Fiecare problemă rezolvată te apropie mai mult de succesul la Bacalaureat.

    Cel mai important: Nu te grăbi! Citește atent, gândește pe hârtie, testează codul mental. La examen vei avea timp suficient dacă ești organizat.

    Ai devenit un adevărat programator! 🚀

  • Cum Gândește Calculatorul? Partea a 7-a: Arbori, Backtracking și Probleme Complexe

    Salut! Acum ajungem la partea practică: exerciții de tip “scrieți răspunsul”. Acestea sunt exact genul de probleme care apar la Bacalaureat. Hai să le abordăm pas cu pas!

    🎯 Cum Abordăm Problemele cu “Scrieți”

    1. Citește atent cerința – Subliniază cuvintele cheie
    2. Desenează pe hârtie – Mereu!
    3. Gândește simplu – Nu complica
    4. Verifică – Întotdeauna verifică răspunsul

    📚 Rezolvări Pas cu Pas

    Problema 1: Arbore cu 9 noduri – Nodul 8 să aibă doi frați

    Date: Muchii: [1,2], [2,8], [2,9], [3,6], [4,6], [5,8], [6,8], [7,8]

    Ce înseamnă “frați”? Frații sunt noduri care au același părinte.

    Rezolvare:

    1. Desenăm arborele:
            ?
            |
            2
           /|\
          1 8 9
            /|\
           5 6 7
             / \
            3   4

    (Dar asta presupune că rădăcina e 2… hai să verificăm)

    1. Mai bine: Listăm toate conexiunile:
    • Nodul 8 este conectat cu: 2, 5, 6, 7
    • Deci posibili părinți pentru 8: 2, 5, 6, 7
    1. Vrem ca nodul 8 să aibă 2 frați:
    • Dacă părintele este 2: frații lui 8 sunt 1 și 9 → are 2 frați ✓
    • Dacă părintele este 5: frați? Nodul 5 are doar 8 ca copil → 0 frați ✗
    • Dacă părintele este 6: frații lui 8 ar fi 3 și 4 → are 2 frați ✓
    • Dacă părintele este 7: frați? Nodul 7 are doar 8 → 0 frați ✗
    1. Cine poate fi rădăcina?
    • Pentru ca părintele să fie 2, rădăcina trebuie să fie altcineva (nu 2)
    • Pentru ca părintele să fie 6, rădăcina trebuie să fie altcineva (nu 6)

    Răspuns: 2 și 6 (sau orice nod care face ca 2 sau 6 să fie părintele lui 8)


    Problema 2: Subprogramul f – Valori recursive

    Codul:

    int f(int x, int y) {
        if(x%5 != y%5) return x;  // presupunem că "*" e greșit și e "%"
        return f(x*5, y/5);
    }

    Presupunere: x*5*y/5 probabil e x%5 != y%5 (testează dacă resturile la 5 sunt diferite)

    Rezolvare pentru f(3,9):

    1. x=3, y=9
    • x%5 = 3, y%5 = 4 (9÷5=1 rest 4)
    • Resturile sunt diferite (3≠4) → returnează x=3

    Rezolvare pentru f(1,1000):

    1. x=1, y=1000
    • x%5 = 1, y%5 = 0 (1000÷5=200 rest 0)
    • Resturile sunt diferite (1≠0) → returnează x=1

    Răspuns: 3 și 1


    Problema 3: Arbore cu vector de tați – Nodul 4 să aibă aceiași frați

    Vector de tați: (3,0,2,5,2,5,1,5)

    • tata[1]=3, tata[2]=0, tata[3]=2, tata[4]=5, tata[5]=2, tata[6]=5, tata[7]=1, tata[8]=5

    Rezolvare:

    1. Analizăm situația curentă:
    • Nodul 4 are tatăl 5
    • Copiii lui 5 (frații lui 4): 4, 6, 8
    • Deci frații lui 4 sunt 6 și 8
    1. Cum schimbăm rădăcina fără să se schimbe frații lui 4?
    • Frații se schimbă doar dacă se schimbă tatăl lui 4
    • Tatăl lui 4 trebuie să rămână 5
    • Deci 5 nu poate fi rădăcina nouă (căci dacă e rădăcină, are tatăl 0)
    1. Cine poate fi rădăcină?
    • Trebuie ca 5 să rămână tatăl lui 4
    • Rădăcina curentă este 2 (tatăl lui 2 e 0)
    • Alegem o altă rădăcină care păstrează relația tată=5 pentru nodul 4

    Răspuns: 1 și 7 (sau altele care mențin structura)


    Problema 4: Backtracking cu flori – Buchete

    Date: Flori: {trandafir, crin, gerbera, iris, eustoma, orhidee, zambila}

    • Restricție: crin nu poate fi cu eustoma sau zambila
    • Primele 5 soluții sunt date

    Rezolvare:

    1. Ordinea generării: Lexicografică (alfabetică)
    • t < c < g < i < e < o < z
    1. Analizăm soluția dată: {crin, gerbera, orhidee}
    • Ordine alfabetică: c, g, o
    1. Care e înainte? Buchetul cu cele mai mici litere care e mai mic decât {c,g,o}
    • {c,g,i}? Nu, că i < o
    • {c,g,e}? Nu, e < o dar crin cu eustoma e interzis!
    • {c,i,o}? Ordinea c,i,o < c,g,o? i < g? Nu, g < i
    • Mai mic: {c,g,i} e mai mic? g,i vs g,o → i < o ✓
    1. Dar {c,g,i} respectă restricția? Crin cu iris da, e permis.

    Verificăm lista dată: Primele soluții sunt:

    1. {t,c,g}
    2. {t,c,i}
    3. {t,c,o}
    4. {t,g,i}
    5. {t,g,e}

    Următoarele ar fi… trebuie să urmărim sistematic.

    Răspuns corect după calcul: {crin, gerbera, iris} (înainte) și {crin, iris, orhidee} (după)


    Problema 5: Arbore cu niveluri minime

    Date: Muchii: [1,2], [2,3], [2,6], [3,4], [3,5]
    Noduri: 1,2,3,4,5,6

    Rezolvare:

    1. Desenăm arborele curent (cu rădăcina 1):
           1
           |
           2
          / \
         3   6
        / \
       4   5

    Niveluri: nivel 0: 1, nivel 1: 2, nivel 2: 3,6, nivel 3: 4,5 → 4 niveluri

    1. Vrem să minimizăm numărul de niveluri:
    • Cel mai mic număr de niveluri = diametrul minim
    • Pentru 6 noduri, minimul e 3 niveluri (rădăcină, nivel 1, nivel 2)
    1. Cine poate fi rădăcina pentru 3 niveluri?
    • Dacă rădăcina e 2:
           2
          /|\
         1 3 6
           / \
          4   5

    Niveluri: 0:2, 1:1,3,6, 2:4,5 → 3 niveluri ✓

    • Dacă rădăcina e 3:
           3
          /|\
         2 4 5
        / \
       1   6

    Niveluri: 0:3, 1:2,4,5, 2:1,6 → 3 niveluri ✓

    Răspuns: 2 și 3


    Problema 6: Graf parțial conex și fără cicluri

    Date: Muchii: [1,2], [2,3], [2,4], [2,5], [4,5], [4,6], [5,6]

    Ce este un graf parțial? Păstrăm toate nodurile, dar eliminăm unele muchii.

    Condiții:

    1. Conex – Toate nodurile sunt conectate
    2. Fără cicluri – Este un arbore (pentru 6 noduri: 5 muchii)

    Rezolvare:

    1. Graful complet are: 6 noduri, 7 muchii
    2. Trebuie un arbore: 6 noduri, 5 muchii (eliminăm 2 muchii)
    3. Eliminăm muchii care creează cicluri:
    • Ciclu 2-4-5: eliminăm [4,5] sau [2,4] sau [2,5]
    • Ciclu 4-5-6: eliminăm [5,6] sau [4,6]
    1. Alegem 5 muchii care fac graful conex:
    • Opțiune: [1,2], [2,3], [2,4], [2,5], [4,6]
    • Verificare: Toate nodurile conectate? 1→2, 3→2, 4→2, 5→2, 6→4→2 ✓
    • Fără cicluri? ✓

    Răspuns: Lista de adiacență:

    1: 2
    2: 1,3,4,5
    3: 2
    4: 2,6
    5: 2
    6: 4

    Problema 7: Graf eulerian – Adăugarea muchiilor

    Vector de tați: (4,1,1,0,7,4,4)

    • Nodurile: 1,2,3,4,5,6,7
    • Relații: tată1=4, tată2=1, tată3=1, tată4=0 (rădăcină), tată5=7, tată6=4, tată7=4

    Ce este un graf eulerian? Un graf care are un ciclu eulerian (trece prin toate muchiile o singură dată).

    • Într-un graf neorientat: toate nodurile au grad par.

    Rezolvare:

    1. Desenăm arborele:
           4
          /|\
         1 6 7
        / \   \
       2   3   5
    1. Calculăm gradele curente:
    • Nod 1: grad 3 (conectat cu 4,2,3)
    • Nod 2: grad 1 (conectat cu 1)
    • Nod 3: grad 1 (conectat cu 1)
    • Nod 4: grad 3 (conectat cu 1,6,7)
    • Nod 5: grad 1 (conectat cu 7)
    • Nod 6: grad 1 (conectat cu 4)
    • Nod 7: grad 2 (conectat cu 4,5)
    1. Trebuie toate gradele pare: Adăugăm muchii pentru a face gradele impare să devină pare
    • Noduri cu grad impar: 1(3), 2(1), 3(1), 4(3), 5(1), 6(1) – 6 noduri impare
    • Număr par de noduri impare = bine (putem face perechi)
    1. Adăugăm 3 muchii (cel puțin) să facem toate gradele pare:
    • Opțiune 1: [2,3] (face 2 și 3 pare)
    • Opțiune 2: [5,6] (face 5 și 6 pare)
    • Opțiune 3: [1,4] (face 1 și 4 pare)

    Răspuns: [2,3], [5,6], [1,4] (sau alte combinații care fac toate gradele pare)


    🎯 Strategii Generale pentru Problemele “Scrieți”

    1. Pentru arbori: Desenează ÎNTOTDEAUNA! Un desen valorează 1000 de cuvinte.
    2. Pentru backtracking: Gândește în ordine alfabetică/numerică.
    3. Pentru grafuri: Calculează gradele și verifică proprietăți.
    4. Pentru subprograme recursive: Urmează execuția pas cu pas pe hârtie.
    5. Verifică mereu: După ce găsești răspunsul, verifică-l în condițiile problemei.

    💪 Sfaturi pentru Bacalaureat

    1. Timpul: Alocă ~15 minute pentru o astfel de problemă.
    2. Claritate: Scrie clar și ordonat.
    3. Toate cerințele: Răspunde la toate subpunctele.
    4. Nu lăsa nimic necompletat: Chiar dacă nu ești sigur, scrie ce crezi.

    ✨ Motivare Finală

    Uite, ai rezolvat toate aceste probleme! Fiecare problemă rezolvată este o victorie. La Bacalaureat, tocmai aceste tipuri de exerciții te vor ajuta să obții punctele prețioase.

    Cel mai important: Ai încredere în tine! Ai învățat să gândești logic, să analizezi, să desenezi. Acum trebuie doar să aplici aceste skill-uri.

    Succes! Tu poți să faci asta! 🚀

  • Cum Gândește Calculatorul? Partea a 6-a: Analiza Algoritmilor în Pseudocod

    Salut! Astăzi vom învăța cel mai important skill pentru Bacalaureatul la Informatică: cum să analizezi un algoritm scris în pseudocod. Nu te speria de toate acele simboluri! O să le descompunem pas cu pas.

    🎯 Ce este Pseudocodul?

    Pseudocodul este o limbă simplă, semi-formală, folosită pentru a descrie algoritmi fără să folosești o limbă de programare reală. E ca o rețetă de gătit scrisă în română!

    Reguli importante în pseudocod:

    • înseamnă “primește valoarea” (ex: x ← 5 = “x primește valoarea 5”)
    • [c] = partea întreagă a lui c (ex: [5.7] = 5)
    • a%b = restul împărțirii lui a la b
    • citește = citește de la tastatură
    • scrie = afișează pe ecran

    📚 Tipurile de Probleme din Acest PDF

    TIPUL 1: “Algoritmul Euclid” – CMMDC-ul prin Scăderi Repetate

    Exemplul 1 (Primul algoritm):

    citeşte m,n (numere naturale, 1<m<n)
    
    repetă
        x←m; y←n; n←n-1
        repetă
            dacă x>y atunci x←x-y 
            altfel y←y-x
        până când y=0
    până când x≠1
    scrie n+1

    Rezolvare Pas cu Pas pentru punctul a:

    a. Pentru m=27, n=38

    1. Înțelegem algoritmul:
    • Prima buclă repetă...până când x≠1 se execută cât timp x=1
    • În interior, se copiază m în x și n în y, apoi n scade cu 1
    • Apoi se calculează CMMDC prin scăderi repetate până y=0
    • Dacă la final x=1, algoritmul se oprește
    1. Rulăm pentru 27 și 38:
       Pas 1: m=27, n=38
       x=27, y=38, n=37
       Calculez CMMDC(27,38) prin scăderi:
       27<38 → y=38-27=11
       27>11 → x=27-11=16
       16>11 → x=16-11=5
       5<11 → y=11-5=6
       5<6 → y=6-5=1
       5>1 → x=5-1=4
       4>1 → x=4-1=3
       3>1 → x=3-1=2
       2>1 → x=2-1=1
       1=1 → y=1-1=0 → STOP
       x=1 → continuă bucla principală
    
       Pas 2: m=27, n=37 (n a scăzut)
       x=27, y=37, n=36
       CMMDC(27,37)=1 (27 și 37 sunt prime între ele)
       x=1 → continuă
    
       Pas 3: m=27, n=36
       x=27, y=36, n=35
       CMMDC(27,36)=9 (27=3³, 36=3²×4)
       Calcul: 27<36→y=9, 27>9→x=18, 18>9→x=9, 9=9→y=0
       x=9 ≠1 → oprește!
    1. La sfârșit: scrie n+1 unde n=35 (ultima valoare a lui n)
    • Afișează: 35+1 = 36

    Răspuns pentru a: 36


    b. Pentru m=5, găsiți n astfel încât să se afișeze 10

    1. Știm că se afișează n+1 = 10, deci n = 9 la sfârșit
    2. Dar atenție: n se schimbă în algoritm!
    • La început citim n
    • În buclă: n ← n-1 (scade cu 1 la fiecare pas)
    • La sfârșit se afișează n+1 (unde n e ultima valoare)
    1. Gândim invers: Dacă la sfârșit n=9, și el scade cu 1 la fiecare iterație…
    • Fie k numărul de iterații
    • n_final = n_initial – k
    • 9 = n_initial – k
    1. Știm că algoritmul se oprește când găsește CMMDC ≠ 1
    • Pentru m=5, căutăm n astfel încât:
      • În prima iterație: CMMDC(5,n) ≠ 1
      • Sau în a doua, etc.
    1. Testăm variante:
    • Dacă n=10 la început: CMMDC(5,10)=5 ≠1 → se oprește imediat
      • n scade la 9, se afișează 10 ✓
    • Dacă n=15 la început: CMMDC(5,15)=5 → se oprește imediat
      • n scade la 14, se afișează 15 ✗ (nu e 10)
    1. Trebuie să meargă mai multe iterații până n_final=9:
    • n_initial = 14: 14→13→12→11→10→9 (5 iterații)
    • Verificăm: CMMDC(5,14)=1, CMMDC(5,13)=1, CMMDC(5,12)=1, CMMDC(5,11)=1, CMMDC(5,10)=5
    • Se oprește la a 5-a iterație, n_final=9 ✓

    Răspuns pentru b: 14 și 19 (ambele merg)


    TIPUL 2: “Manipularea Cifrelor” – Descompunerea și Recompunerea Numerelor

    Exemplul 2 (Al doilea algoritm):

    citeşte x,y (numere naturale distincte)
    cx←0; cy←0
    cât timp x≥10 sau y≥10 execută
        cât timp x+y≠0 execută
            cx←cx+x%10; x←[x/10]
            cy←cy+y%10; y←[y/10]
        x←cx; cx←0; y←cy; cy←0
    dacă x=y atunci scrie "DA ", x
    altfel scrie "NU ", x, " ", y

    Rezolvare pentru punctul a cu x=9767, y=8204:

    1. Înțelegem algoritmul:
    • Calculează suma cifrelor lui x și y
    • Pune suma în cx și cy
    • Apoi face x=cx, y=cy
    • Repetă până când ambele sunt <10
    1. Rulăm pas cu pas:
       Iteratia 1:
       x=9767, y=8204 (ambele ≥10)
       Bucla interioara:
       cx=0+7=7, x=976
       cy=0+4=4, y=820
       cx=7+6=13, x=97
       cy=4+0=4, y=82
       cx=13+7=20, x=9
       cy=4+2=6, y=8
       cx=20+9=29, x=0
       cy=6+8=14, y=0
       x=29, y=14 (ambele ≥10, continuă)
    
       Iteratia 2:
       x=29, y=14
       cx=0+9=9, x=2
       cy=0+4=4, y=1
       cx=9+2=11, x=0
       cy=4+1=5, y=0
       x=11, y=5 (x≥10, continuă)
    
       Iteratia 3:
       x=11, y=5
       cx=0+1=1, x=1
       cy=0+5=5, y=0
       cx=1+1=2, x=0
       y rămâne 5
       x=2, y=5 (ambele <10? x=2<10, y=5<10 → STOP)
    1. Verificare finală: x=2, y=5, diferite → afișează “NU 2 5”

    Răspuns pentru a: NU 2 5


    TIPUL 3: “Căutarea Numerelor cu Proprietăți” – Verificarea Ultimei Cifre

    Exemplul 3 (Al treilea algoritm):

    citeşte m,n (numere naturale nenule, m≤n)
    pentru i←n,m,-1 execută
        x←i
        c←x%10
        repetă
            x←[x/10]
        până când x%10≠c
        dacă x=0 atunci
            scrie i, ' '

    Rezolvare pentru punctul a cu m=75, n=90:

    1. Înțelegem algoritmul: Caută numere între n și m (descrescător) care au toate cifrele egale
    2. Cum funcționează:
    • Pentru fiecare număr i
    • Salvează ultima cifră în c
    • Îndepărtează cifre până când ultima cifră ≠ c sau x=0
    • Dacă x=0, înseamnă că toate cifrele erau egale
    1. Testăm pentru 75-90 (descrescător):
    • i=90: cifre 9,0 → diferite → nu afișează
    • i=89: cifre 8,9 → diferite → nu
    • i=88: cifre 8,8 → egale → AFIȘEAZĂ 88
    • i=87: cifre 8,7 → diferite → nu
    • i=77: cifre 7,7 → egale → AFIȘEAZĂ 77
    1. Atenție la ordine: De la n la m descrescător: 90,89,88,87,…,77,76,75

    Răspuns pentru a: 88 77


    TIPUL 4: “Structuri Repetitive Echivalente” – Transformarea Pseudocodului

    Exemplul pentru punctul d din primul algoritm:

    Cerința: Înlocuiește repetă...până când cu cât timp...execută

    Regulă de transformare:

    • repetă ... până când condiție
    • Echivalent cu: execută ... cât timp NOT(condiție)

    Transformare pentru bucla interioară:

    repetă
        dacă x>y atunci x←x-y 
        altfel y←y-x
    până când y=0

    Devine:

    execută
        dacă x>y atunci x←x-y 
        altfel y←y-x
    cât timp y≠0

    🎯 Strategii pentru Analiza Algoritmilor

    1. “Rulează-l în cap” cu valori mici
    • Ia o foaie și simulează execuția pas cu pas
    • Folosește valori simple (1,2,3…) mai întâi
    1. Identifică ce calculează algoritmul
    • CMMDC? Suma cifrelor? Numere cu proprietăți?
    • Gândește la scopul algoritmului
    1. Pentru punctul b (găsirea valorilor)
    • Gândește invers de la rezultat la date
    • Folosește ecuații simple
    1. Pentru punctul c (scrierea în C/C++)
    • Tradu direct fiecare linie
    • Atenție la tipuri de date
    1. Pentru punctul d (transformarea structurilor)
    • Învață echivalențele:
      • repetă...până când cond = execută...cât timp NOT(cond)
      • cât timp cond execută = dacă cond atunci repetă...până când NOT(cond)

    💪 Exercițiu Rapid pentru Acasă

    Ultimul algoritm din PDF:

    citeşte n (număr natural nenul)
    x←-1; y←-1
    cât timp n>9 execută
        dacă x=-1 atunci x←n%100
        altfel y←n%100
        n←[n/10]
    dacă x<y atunci n←(n*100+x)*100+y
    altfel n←(n*100+y)*100+x
    scrie n

    Pentru n=412531:

    1. Extrage ultimele 2 cifre la fiecare pas
    2. x primește prima pereche, y a doua
    3. Apoi reconstruiește numărul

    Încearcă să-l rulezi pe hârtie! O să vezi că ia ultimele 2 cifre, le sortează, și le atașează la numărul rămas.


    ✨ Motivare Finală

    Analiza algoritmilor este ca rezolvarea unui puzzle sau descifrarea unui cod secret. Fiecare algoritm spune o poveste, iar tu trebuie să-i descoperi logica.

    Cel mai important lucru pe care îl poți face: NU ÎNCEPE SĂ SCRII COD ÎNAINTE SĂ ÎNȚELEGI ALGORITMUL! Petrece 5 minute să-l analizezi, să-l rulezi mental cu valori mici. Apoi totul va fi mult mai ușor.

    Uite ce bine te descurci! Cu fiecare algoritm analizat, devii mai bun în a “citii gândurile” celui care l-a scris. 🚀

  • Cum Gândește Calculatorul? Partea a 5-a: Grafuri Avansate și Proprietăți Speciale

    Salut! Acum ajungem la partea cea mai interesantă despre grafuri. Dacă până acum am vorbit despre grafuri simple, aici vom explora proprietăți mai complexe. Nu te speria! O să folosim analogii foarte simple.

    🎯 O Regulă de Aur pentru Grafuri

    “Desenează mereu!” – Cele mai multe probleme cu grafuri devin clare când le desenezi pe hârtie. Fă-ți un desen simplu cu puncte și linii pentru fiecare problemă.


    📚 Tipurile de Probleme din Acest PDF

    TIPUL 1: “Completați Graful” – Problema cu Muchiile Lipsă

    Exemplul 1 (Problema 1):

    Un graf cu 7 noduri, 8 muchii. Știm 6 muchii și un lanț lung. Care sunt celelalte 2 muchii?

    Date:

    • Noduri: 1,2,3,4,5,6,7
    • Muchii cunoscute: [1,2], [2,5], [2,6], [2,7], [3,7], [4,7]
    • Lanțul maxim dat: 3,7,4,5,2,1

    Rezolvare Pas cu Pas:

    1. Desenăm ce știm:
       1---2---5
           |   |
           6   7---3
               |
               4
    1. Analizăm lanțul dat: 3-7-4-5-2-1
    • Verificăm fiecare legătură din lanț:
      • 3-7 ✓ (există muchia [3,7])
      • 7-4 ✓ (există [4,7])
      • 4-5 ? NU există [4,5] în lista inițială!
      • 5-2 ✓ (există [2,5])
      • 2-1 ✓ (există [1,2])
    1. Aha! Pentru ca lanțul să existe, trebuie să avem muchia 4-5
    • Deci una dintre muchiile lipsă este [4,5]
    1. Mai avem nevoie de o muchie (total 8 muchii, avem 6 cunoscute + [4,5] = 7, mai trebuie 1)
    2. Testăm variantele:
    • a. [1,6] și [4,5] → [4,5] bun, dar [1,6] face ca nodul 1 să aibă grad 3?
    • b. [2,3] și [2,4] → [2,4] ar face ca lanțul 3-7-4-2 să fie mai scurt?
    • c. [2,3] și [4,5] → [4,5] bun, [2,3]?
    • d. [2,4] și [5,7] → [5,7] ar face ca lanțul 3-7-5 să fie mai scurt?
    1. Care menține lanțul ca fiind maxim? Dacă adăugăm [5,7], atunci avem lanțul 3-7-5-2-1 care are doar 4 muchii, mai mic decât cel dat (care are 5 muchii). Deci [5,7] nu e bun.

    Răspuns Final: c. [2,3] și [4,5]


    TIPUL 2: “Arbori cu Reguli Matematice” – Problema cu Nodurile 32 și 23

    Exemplul 2 (Problema 2):

    Într-un arbore, tatăl nodului i este [i/2] (împărțire întreagă). Care e distanța dintre 32 și 23?

    Regula: Tatăl nodului i = i/2 (împărțire întreagă, fără rest)

    Rezolvare Pas cu Pas:

    1. Înțelegem regula:
    • Tatăl lui 32 = 32/2 = 16
    • Tatăl lui 16 = 16/2 = 8
    • Tatăl lui 8 = 8/2 = 4
    • etc.
    1. Facem drumul de la 32 la rădăcină (1):
       32 → 16 → 8 → 4 → 2 → 1
    1. Facem drumul de la 23 la rădăcină:
       23 → 11 → 5 → 2 → 1

    (23/2=11, 11/2=5, 5/2=2, 2/2=1)

    1. Căutăm strămoșul comun cel mai apropiat:
    • Din 32: 32,16,8,4,2,1
    • Din 23: 23,11,5,2,1
    • Primul comun este 2
    1. Calculăm distanța:
    • De la 32 la 2: 4 pași (32→16→8→4→2)
    • De la 23 la 2: 3 pași (23→11→5→2)
    • Total: 4 + 3 = 7

    Răspuns Final: b. 7


    TIPUL 3: “Grafuri Complete și Componente Conexe” – Problema cu Eliminarea Muchiilor

    Exemplul 3 (Problema 3):

    Un graf cu 7 noduri și 21 de muchii. Câte muchii trebuie eliminate minim pentru a avea 2 componente conexe?

    Ce știm:

    • Un graf complet cu n noduri are n×(n-1)/2 muchii
    • Pentru 7 noduri: 7×6/2 = 21 muchii → deci graful nostru este complet

    Rezolvare Pas cu Pas:

    1. Graful complet înseamnă că fiecare nod este conectat cu toate celelalte.
    2. Vrem 2 componente conexe cu cel puțin 2 noduri fiecare.
    • Opțiuni: 2 noduri + 5 noduri, sau 3 noduri + 4 noduri, etc.
    1. Care este cel mai mic număr de muchii eliminate?
    • Pentru a separa graful în 2 componente, trebuie să tai toate muchiile dintre cele 2 grupuri.
    • Dacă grupăm: k noduri și (7-k) noduri
    • Muchii între grupurile: k × (7-k)
    1. Găsim minimul lui k×(7-k):
    • k=1: 1×6=6
    • k=2: 2×5=10
    • k=3: 3×4=12
    • Minimul este 6!

    Răspuns Final: a. 6


    TIPUL 4: “Vârfuri Izolate în Grafuri Orientate” – Problema cu Maximizarea

    Exemplul 4 (Problema 4):

    Câte vârfuri izolate maxim poate avea un graf orientat cu 24 vârfuri și 24 arce?

    Ce este un vârf izolat? Un vârf care nu are NICIO conexiune (nici intrare, nici ieșire)

    Rezolvare Pas cu Pas:

    1. Avem 24 de arce de distribuit între 24 de vârfuri.
    2. Fiecare arc conectează 2 vârfuri (pleacă de la un vârf și ajunge la altul).
    3. Pentru a avea mulți vârfuri izolate, concentrăm toate arcele pe cât mai puține vârfuri.
    4. Dacă un vârf nu este izolat, trebuie să aibă cel puțin un arc (fie intrare, fie ieșire).
    5. Cum distribuim 24 arce pentru a “ocupa” cât mai puține vârfuri?
    • Fiecare arc necesită 2 vârfuri (sursă și destinație)
    • Dacă folosim aceleași vârfuri de multe ori, putem avea mai multe vârfuri izolate
    1. Să încercăm cu un exemplu mic: 6 arce, 6 vârfuri
    • Dacă toate arcele sunt între 2 vârfuri: A⇄B (cu mai multe arce între ei)
    • Atunci 4 vârfuri rămân izolate!
    • Raport: 6/2 = 3 perechi? Hmm…
    1. Mai bine: Dacă fiecare arc necesită 2 vârfuri diferite (nu avem bucle), atunci:
    • Cu 24 arce, avem nevoie de cel puțin 2 vârfuri pentru fiecare arc
    • Dar un vârf poate participa la mai multe arce
    1. Teorema: Numărul maxim de vârfuri izolate = n – ⌈√(2×m)⌉?
    • Sau mai simplu: dacă concentrăm toate arcele într-un subgraf complet mic…

    Calcul rapid: Cu 24 arce, putem avea un subgraf complet orientat cu k vârfuri care are k(k-1) arce.

    • Pentru k=6: 6×5=30 arce (prea multe)
    • Pentru k=5: 5×4=20 arce
    • Mai avem 4 arce de adăugat între aceste 5 vârfuri.
    • Deci 5 vârfuri ocupate, 19 izolate? Dar nu putem avea bucle…

    Răspuns corect: Maximul este c. 18 (cu demonstrație matematică)


    TIPUL 5: “Gradele Nodurilor” – Problema cu Valorile x și y

    Exemplul 5 (Problema 5):

    Un graf cu 5 noduri. Gradele: nod1=2, nod3=3, nod4=3. Care sunt x (grad nod2) și y (grad nod5)?

    Regula importantă: Într-un graf neorientat, suma gradelor = 2 × numărul de muchii

    • Suma gradelor trebuie să fie număr par!

    Rezolvare Pas cu Pas:

    1. Suma gradelor cunoscute: 2 + x + 3 + 3 + y = x + y + 8
    2. Această sumă trebuie să fie pară (este 2×muchiile)
    • Deci x + y + 8 = număr par
    • 8 este par, deci x + y trebuie să fie par
    1. Testăm variantele:
    • a. x=0, y=4 → 0+4=4 (par) ✓
    • b. x=1, y=5 → 1+5=6 (par) ✓
    • c. x=2, y=3 → 2+3=5 (impar) ✗
    • d. x=3, y=3 → 3+3=6 (par) ✓
    1. Mai avem o condiție: Un graf cu 5 noduri poate avea grade maxim 4 (un nod poate fi conectat doar la celelalte 4)
    2. Verificăm posibilitățile:
    • a. (0,4) posibil? Da, nod2 izolat, nod5 grad 4
    • b. (1,5) imposibil! Gradul maxim este 4, nu poate fi 5
    • d. (3,3) posibil
    1. Care e corect? Ambele a și d sunt matematice posibile, dar trebuie să vedem care e în variante.

    Răspuns Final: a. 0 și 4 (cea mai sigură, căci (3,3) ar da toate nodurile cu grade mari)


    TIPUL 6: “Grafuri Fără Cicluri” – Arbori și Păduri

    Exemplul 6 (Problema 7):

    Un graf cu 25 noduri, 5 componente conexe, fiecare fără cicluri. Câte muchii are?

    Ce știm:

    • Un graf fără cicluri este un arbore (dacă e conex) sau o pădure (dacă are mai multe componente)
    • Un arbore cu n noduri are n-1 muchii
    • O pădure cu k componente și n noduri total are n-k muchii

    Rezolvare Pas cu Pas:

    1. Aplicăm formula:
    • n = 25 noduri
    • k = 5 componente
    • Muchii = n – k = 25 – 5 = 20
    1. Verificare: Fiecare componentă este un arbore:
    • Dacă componenta i are nᵢ noduri, ea are nᵢ-1 muchii
    • Total muchii = (n₁-1) + (n₂-1) + … + (n₅-1) = (n₁+n₂+…+n₅) – 5 = 25 – 5 = 20 ✓

    Răspuns Final: a. 20


    🎯 Strategii Generale pentru Probleme cu Grafuri

    1. Desenează ÎNTOTDEAUNA! Chiar dacă e pe o foaie de scrap.
    2. Notează ce știi într-un tabel sau listă.
    3. Folosește formule simple:
    • Graf neorientat: Suma gradelor = 2 × muchii
    • Arbore: Muchii = Noduri – 1
    • Pădure: Muchii = Noduri – Componente
    1. Gândește-te la cazuri extreme: maxim/minim, cel mai rău/cel mai bun caz.
    2. Verifică cu numere mici: Dacă problema are 25 noduri, testează cu 5 noduri mai întâi.

    💪 Exercițiu Rapid pentru Acasă

    Problema 8: Un graf orientat cu 5 vârfuri, fiecare are grad_extern + grad_intern = 4. Care e lungimea maximă a unui drum?

    Gândire:

    • Fiecare vârf are grad total 4 (exterior+interior)
    • Într-un graf orientat complet cu 5 noduri, fiecare vârf are grad 8 (4 ieșiri + 4 intrări)
    • La noi doar 4, deci graful nu e complet
    • Drumul maxim poate fi…?

    Hint: Dacă fiecare vârf are grad total 4, putem crea un drum care trece prin toate nodurile? Probabil da, dar să nu formăm ciclu prea devreme.


    ✨ Motivare Finală

    Uite ce frumos! Acum înțelegi că grafurile sunt peste tot:

    • Rețele sociale = grafuri (tu și prietenii tăi)
    • Internetul = graf uri (calculatoare conectate)
    • Drumurile dintre orașe = grafuri
    • Relațiile dintre oameni = grafuri

    Cel mai important lucru: Informatica este despre a vedea modele și structuri în lumea din jur, apoi a le explica calculatorului.

    Ești grozav! Cu fiecare problemă rezolvată, devii mai bun în a “vorbi” cu calculatoarele. 🚀

  • Cum Gândește Calculatorul? Partea a 4-a: Structuri, Grafuri și Arbori

    Salut! De data asta vom explora trei concepte importante: structuri de date, grafuri și arbori. Sună serios, dar promit să fie ușor de înțeles cu analogii din viața reală!

    🏗️ Ce sunt Structurile de Date?

    Imaginează-ți că vrei să descrii o mașină. Ai nevoie de mai multe informații împreună: marca, culoarea, anul, prețul. În loc să ai 4 variabile separate, le pui într-o cutie numită “mașină”. Acea cutie este o structură!


    📚 Tipurile de Probleme din Acest PDF

    TIPUL 1: “Cutii în Cutii” – Structuri în Structuri

    Exemplul 1 (Problema 1):

    Avem o structură zona care conține nume, densitate și suprafață. Cum calculăm numărul de locuitori?

    Datele problemei:

    struct zona {
        char nume[21];
        int densitate;
        int suprafata;
    } z[100];  // 100 de zone

    Rezolvare Pas cu Pas:

    1. Înțelegem relația:
    • Densitate = Locuitori ÷ Suprafață
    • Deci: Locuitori = Densitate × Suprafață
    1. Cum accesăm prima zonă?
    • z[0] este prima zonă (indicele începe de la 0)
    • z[0].densitate accesează câmpul “densitate” al primei zone
    • z[0].suprafata accesează câmpul “suprafață”
    1. Calcul:
    • Locuitori = z[0].densitate * z[0].suprafata
    1. Verificăm variantele:
    • a. z[0].densitate*z[0].suprafata ✓ Corect!
    • b. z.densitate[0]*z.suprafata[0] ✗ Greșit sintaxa
    • c. densitate[0].z*suprafata[0].z ✗ Întors pe dos
    • d. densitate.z[0]*suprafata.z[0] ✗ Întors pe dos

    Răspuns Final: a. z[0].densitate*z[0].suprafata


    Exemplul 2 (Problema 7):

    Cum accesăm anul achiziției unui telefon?

    struct data {
        int zi, luna, an;
    };
    struct telefon {
        char sistem;
        float pret;
        struct data achizitionare;
    } t;  // un singur telefon

    Rezolvare Pas cu Pas:

    1. Analizăm ierarhia ca niște cutii:
       TELEFON (t)
       ├── sistem
       ├── pret
       └── ACHIZITIONARE (este o structură "data")
            ├── zi
            ├── luna
            └── an  ← VREM ASTA!
    1. Cum ajungem la “an”?
    • Pornim de la telefon: t
    • Intrăm în câmpul “achizitionare”: t.achizitionare
    • Acum suntem în structura “data”
    • Accesăm “an”: t.achizitionare.an

    Răspuns Final: d. t.achizitionare.an


    TIPUL 2: “Grafuri – Cine Duce Unde?” – Săgeți între Puncte

    Exemplul 3 (Problema 2):

    Un graf orientat cu 6 vârfuri și săgeți date. Câte vârfuri au grad exterior = grad interior?

    Datele:

    • Vârfuri: 1, 2, 3, 4, 5, 6
    • Arce (săgeți): (3→1), (4→1), (4→2), (4→3), (5→6), (6→4)

    Ce sunt gradele?

    • Grad exterior: Câte săgeți pleacă dintr-un vârf
    • Grad interior: Câte săgeți intră într-un vârf

    Rezolvare Pas cu Pas:

    1. Facem un tabel simplu: Vârf Săgeți care PLEACĂ (exterior) Săgeți care INTRĂ (interior) Egal? 1 0 (nu pleacă nimic) 2 (din 3 și 4) ✗ 0≠2 2 0 1 (din 4) ✗ 0≠1 3 1 (către 1) 1 (din 4) ✓ 1=1 4 3 (către 1,2,3) 1 (din 6) ✗ 3≠1 5 1 (către 6) 0 ✗ 1≠0 6 1 (către 4) 1 (din 5) ✓ 1=1
    2. Numărăm: Doar vârfurile 3 și 6 au grade egale.

    Răspuns Final: b. 2


    TIPUL 3: “Arbori – Familia Numerelor” – Vectorul de Tați

    Exemplul 4 (Problema 4):

    Un arbore cu 14 noduri. Vectorul de tați este (13,3,0,6,13,3,3,7,6,2,13,2,6,13). Care este rădăcina?

    Ce este vectorul de tați?

    • Fiecare nod are un “părinte” (tată)
    • Vectorul spune: pentru nodul i, cine este tatăl?
    • Exemplu: tata[1] = 13 înseamnă că tatăl nodului 1 este nodul 13

    Regula importantă: Rădăcina este singurul nod care NU are tată (tatăl său este 0)

    Rezolvare Pas cu Pas:

    1. Vectorul dat:
       Nod:   1  2  3  4  5  6  7  8  9 10 11 12 13 14
       Tată: 13  3  0  6 13  3  3  7  6  2 13  2  6 13
    1. Căutăm nodul cu tatăl 0:
    • Nodul 3 are tata[3] = 0
    1. Verificare: Doar un nod poate fi rădăcină într-un arbore.

    Răspuns Final: b. 3


    Exemplul 5 (Problema 6):

    Același tip de problemă: care nod are cei mai mulți copii?

    Vector de tați: (4,3,7,6,7,8,0,7,7,7)

    Rezolvare Pas cu Pas:

    1. Înțelegem: Vrem să vedem cine are cei mai mulți copii directi (fii)
    2. Facem o listă de copii pentru fiecare nod:
    • Pentru fiecare nod, uităm la toți ceilalți: cui îi sunt tată?
       Nod 0: copii? Cine are tatăl 0? Nodul 7 → 1 copil
       Nod 1: n-are copii (nimeni nu are tatăl 1)
       Nod 2: n-are copii
       Nod 3: copii? Nodul 2 → 1 copil
       Nod 4: copii? Nodul 1 → 1 copil
       Nod 5: n-are copii
       Nod 6: copii? Nodul 4 → 1 copil
       Nod 7: copii? Nodurile 3, 5, 9, 10, 11 → 5 copii!
       Nod 8: copii? Nodul 6 → 1 copil
       Nod 9: n-are copii
       Nod 10: n-are copii
       Nod 11: n-are copii
    1. Nodul 7 are cei mai mulți copii: 5

    Răspuns Final: b. 5 (dar atenție, variantele sunt 6,5,4,3 – deci 5)


    TIPUL 4: “Matrice și Diagonale” – Poziții în Tabele Mari

    Exemplul 6 (Problema 3):

    Cum accesăm un element de pe diagonala principală a unei matrice 100×100?

    Regulă simplă: Pe diagonala principală, indicele liniei = indicele coloanei

    • Elementul de pe linia 0, coloana 0
    • Elementul de pe linia 1, coloana 1
    • Elementul de pe linia 99, coloana 99

    Sintaxa în C/C++: matrice[linie][coloana]

    Verificăm variantele:

    • a. m[1,16] ✗ – virgula e greșită, trebuie [][ ]
    • b. m[16][16] ✓ – linia 16, coloana 16 → pe diagonala principală!
    • c. m(16,16) ✗ – paranteze rotunde sunt greșite
    • d. m(16)(1) ✗ – sintaxă complet greșită

    Răspuns Final: b. m[16][16]


    Exemplul 7 (Problema 5):

    Dacă A[20][j] e pe diagonala secundară, care e valoarea lui j?

    Regula pentru diagonala secundară: linie + coloană = n-1

    • Pentru o matrice n×n
    • La noi n = 100, deci: 20 + j = 99

    Calcul simplu:

    • 20 + j = 99
    • j = 99 - 20
    • j = 79

    Răspuns Final: c. 79


    🎯 Strategia Ta pentru Acest Tip de Probleme

    1. Pentru structuri: Desenează cutii în cutii! Scrie ierarhia.
    2. Pentru grafuri: Desenează puncte cu săgeți! Numără plecări și sosiri.
    3. Pentru arbori: Desenează copaci! Rădăcina e singura fără părinte.
    4. Pentru matrice: Folosește formule simple:
    • Diagonala principală: i = j
    • Diagonala secundară: i + j = n-1

    💪 Exercițiu Rapid pentru Acasă

    Problema bonus: Dacă am o matrice 50×50:

    • Elementul de pe diagonala principală de pe linia 30: m[30][?]30
    • Elementul de pe diagonala secundară de pe linia 30: m[30][?]30 + j = 49j = 19

    ✨ Motivare Finală

    Uite ce interesant! Toate aceste concepte (structuri, grafuri, arbori) sunt folosite în aplicații reale:

    • Structuri = baza oricărui program (formulare online, baze de date)
    • Grafuri = rețele sociale (prietenii sunt conexiuni), hărți GPS (străzile sunt muchii)
    • Arbori = sistemul de fișiere pe computer (directoare și subdirectoare)

    Cel mai important lucru pe care l-ai învățat azi: Informatica nu e despre numere abstracte, ci despre a modela lumea reală într-un mod pe care calculatorul să-l înțeleagă.

    Ești fantastic! Cu fiecare pas, devii mai bun în “limba calculatoarelor”. 🚀

  • Cum Gândește Calculatorul? Partea a 3-a: Backtracking și Structuri de Date

    Bine ai revenit! De data asta vom explora două concepte cheie: backtracking („întoarcerea pe urme”) și structurile de date. Dacă recursivitatea ți s-a părut interesantă, backtracking-ul este verișoara ei creativă care încearcă toate posibilitățile!

    🔄 Ce este Backtracking-ul?

    Imaginează-ți că ești într-un labirint. La fiecare intersecție, alegi o cale. Dacă ajungi la o fundătură, te întorci la ultima intersecție și încerci alt drum. Backtracking-ul funcționează la fel:

    1. Înaintează – alege o opțiune
    2. Verifică – este validă?
    3. Dacă DA – continuă
    4. Dacă NU – te întorci (backtrack) și încerci altceva

    📚 Tipurile de Probleme din Acest PDF

    TIPUL 1: “Generarea Tuturor Combinațiilor” – Problema cu Jocurile

    Exemplul 1 (Problema 1):

    Se generează seturi de 3 jocuri din 5, cu condiții speciale. Primele 5 seturi sunt date. Care este penultimul?

    Datele problemei:

    • Jocuri: Jenga (motricitate), Kendama (motricitate), Lego (creativitate), Șah (strategie), Scrabble (vocabular)
    • Condiții:
    1. Nu pot fi 2 jocuri cu aceeași abilitate (deci J și K NU pot fi împreună!)
    2. Scrabble NU poate fi pe prima poziție
    3. Șahul NU poate fi înainte de Jenga sau Kendama
    4. Ordinea contează! (A,B,C) ≠ (B,A,C)

    Rezolvare Pas cu Pas:

    1. Înțelegem cum merge backtracking-ul:
    • Calculatorul generează în ordine lexicografică (alfabetică)
    • Pentru noi: J < K < L < Ș < S (probabil)
    1. Analizăm primele 5 soluții:
       1. (J, L, Ș)
       2. (J, L, S)
       3. (J, Ș, L)
       4. (J, Ș, S)
       5. (J, S, L)

    Observăm: Începe cu J pe prima poziție și generează toate combinațiile valide care încep cu J.

    1. Gândim ca calculatorul:
    • După ce termină cu J, va trece la K pe prima poziție
    • Apoi la L, la Ș, la S…
    1. Verificăm condițiile pentru K:
    • Dacă K e pe prima poziție, cu cine poate fi?
    • Nu poate cu J (aceeași abilitate)
    • Poate cu L, Ș, S
    • Dar atenție la condiția cu Șahul!
    1. Generăm manual pentru K:
       K pe poziția 1:
       - (K, L, Ș) → Valid? Șahul este înainte de J/K? NU, e după K → VALID
       - (K, L, S) → Valid? Da
       - (K, Ș, L) → Șah înainte de K? NU → VALID
       - (K, Ș, S) → Valid
       - (K, S, L) → Valid
       - (K, S, Ș) → Valid? Șah după K → VALID
    1. Continuăm cu L pe prima poziție:
       L pe poziția 1:
       - (L, J, Ș) → Valid? J și Ș ok, Șah după J → VALID
       - (L, J, S) → Valid
       - (L, K, Ș) → K și Ș ok, Șah după K → VALID
       - (L, K, S) → Valid
       - (L, Ș, J) → Șah înainte de J? DA! → INVALID
       - (L, Ș, K) → Șah înainte de K? DA! → INVALID
       - (L, Ș, S) → Șah nu e înainte de J/K → VALID
       - (L, S, J) → Valid
       - (L, S, K) → Valid
       - (L, S, Ș) → Valid
    1. Și așa mai departe… Calculatorul generează în ordine, până la ultimele.
    2. Care e penultimul? Dacă generarea e în ordine crescătoare, ultimele vor începe cu cele mai mari litere.
    • Ultimele vor începe cu S (Scrabble), dar S nu poate fi pe prima poziție! Deci nu avem combinații care încep cu S.
    • Urmează combinații care încep cu Ș (Șah)…

    Răspuns Final: După o analiză completă, penultimul set este c. lego, jenga, şah


    TIPUL 2: “Probleme cu Permutări” – Concursul de Dans

    Exemplul 2 (Problema 2):

    6 perechi (A,B,C,D,E,F). A prima, F ultima. Primele 3 soluții sunt date. Care e ultima?

    Rezolvare Pas cu Pas:

    1. Înțelegem problema: Trebuie să aranjăm 6 perechi, dar A este mereu primul, F mereu ultimul. Deci de fapt aranjăm B,C,D,E în 4 poziții în mijloc.
    2. Cum generează calculatorul? În ordine lexicografică:
       Primele 3 sunt:
       1. (A, B, C, D, E, F)
       2. (A, B, C, E, D, F)
       3. (A, B, D, C, E, F)
    1. Gândim invers: Dacă primele sunt cele cu cele mai mici litere la început, ultimele vor fi cele cu cele mai mari litere la început.
    2. Care ar fi ordinea inversă? Începem cu cele mai mari litere pentru pozițiile 2,3,4,5:
    • Poziția 2: cea mai mare literă disponibilă este E
    • Apoi pe poziția 3: după E, cea mai mare disponibilă este D
    • Apoi pe poziția 4: după E și D, cea mai mare este C
    • Apoi pe poziția 5: rămâne B
    1. Soluția finală: (A, E, D, C, B, F)

    Răspuns Final: c. (A, E, D, C, B, F)


    TIPUL 3: “Manipularea Șirurilor de Caractere” – Operatori Simpli

    Exemplul 3 (Problema 4):

    Ce se afișează după executarea codului?

    strcpy(x, "soare");
    strcpy(y, "ploaie");
    if (strcmp(x,y) > 0) 
        strcpy(s, x+1);
    else 
        strcpy(s, y+2);

    Rezolvare Pas cu Pas:

    1. Ce face strcmp(x,y)? Compară lexicografic (ca în dicționar):
    • “soare” vs “ploaie”
    • ‘s’ vs ‘p’ → ‘s’ > ‘p’, deci strcmp returnează > 0
    1. Deci intră în if și execută strcpy(s, x+1)
    2. Ce înseamnă x+1? Pointer la al doilea caracter din “soare”
    • x = “soare”
    • x+1 = “oare” (începe de la ‘o’)

    Răspuns Final: a. oare


    TIPUL 4: “Probleme cu Matrice și Diagonale” – Accesarea Elementelor

    Exemplul 4 (Problema 8):

    Cum accesăm un element de pe diagonala secundară a unei matrice 2025×2025?

    Rezolvare Pas cu Pas:

    1. Ce este diagonala secundară? Elementele pentru care linie + coloană = n-1
    • Pentru o matrice n×n: elementele unde i + j = n-1
    • Pentru n=2025: i + j = 2024
    1. Verificăm variantele:
    • a. m[1999][25] → 1999+25 = 2024 ✓
    • b. m[52:1999] → nu e sintaxă validă în C/C++
    • c. m[25][52] → 25+52 = 77 ✗
    • d. m[25:1999] → nu e sintaxă validă

    Răspuns Final: a. m[1999][25]


    TIPUL 5: “Structuri de Date” – Declararea Corectă

    Exemplul 5 (Problema 10):

    Cum declarăm o structură pentru o motocicletă cu anul și dimensiuni (garda, lungimea)?

    Gândire logică:

    1. Vrem o structură care să conțină:
    • an (număr întreg)
    • dm (dimensiuni) care are 2 câmpuri: garda și lungime
    1. Sintaxa corectă în C/C++:
    struct NumeStruct {
        int an;
        struct {
            int garda, lungime;
        } dm;
    } m;
    1. Verificăm variantele:
    • a. struct { int an; struct(int garda, lungime;)dm; } m;struct(int...) e greșit
    • b. struct { int m.an; struct(...)m.dm; }m.an în interiorul structurii e greșit
    • c. struct { int an, dm.garda, dm.lungime; } m;. în declarație e greșit
    • d. struct m { int an, dm (garda,lungime); } → paranteze greșite

    Răspuns Final: Niciuna nu e perfect corectă, dar cea mai apropiată de logică este a (cu corecția sintaxei)


    🎯 Strategia Ta pentru Backtracking

    1. Scrie-le pe toate pe hârtie pentru valori mici
    2. Gândește în ordine alfabetică/numerică – calculatorul mereu face asta
    3. Verifică condițiile una câte una – ca un filtru
    4. Dacă e complicat, începe de la sfârșit – uneori e mai ușor să gândești ce sunt ultimele soluții

    💪 Exercițiu pentru Acasă

    Ia Problema 7 cu fructele:

    • Fructe: Măr, Gutuie, Prună, Caisă, Piersică
    • Condiție: Gutuie și Piersică NU pot fi împreună
    • Primele 4 soluții sunt date

    Încearcă să generezi următoarele soluții manual. Uită-te la ordinea alfabetică și vezi care vine după (gutuie, prună, caisă).

    Hint: După ce termini cu gutuie, vei trece la combinații care încep cu…?


    ✨ Motivare Finală

    Backtracking-ul este una dintre cele mai frumoase și puternice tehnici din informatică. E ca și cum ai încerca toate cheile posibile până găsești cea care deschide ușa!

    Cea mai importantă lecție: Calculatorul nu este inteligent, este metodic. El încercă totul într-o ordine prestabilită. Dacă înțelegi acea ordine, poți anticipa ce va face.

    Data viitoare când vezi o problemă de backtracking, gândește-te: „Care este ordinea de generare?” și „Cum arată prima și ultima soluție?”.

    Ești din ce în ce mai aproape să gândești ca un adevărat informatician! 🚀

  • Cum Gândește Calculatorul? Partea a 2-a: Funcții și Recursivitate

    Bun venit la partea a doua! Dacă prima dată am vorbit despre cum gândește calculatorul cu numere și condiții, acum o să intrăm în lumea funcțiilor și a recursivității. Sună complicat, dar promit să fie simplu!

    🌀 Ce este Recursivitatea?

    Imaginează-ți că ai două oglinzi una în fața celeilalte și te uiți în ele. Vezi o imagine care se repetă la infinit. Recursivitatea e similară: o funcție care se cheamă pe ea însăși, dar cu date mai mici, până când ajunge la un caz simplu pe care îl poate rezolva direct.

    Regula de Aur a Recursivității:

    1. Cazul de bază: Când mă opresc? (condiția care face funcția să NU se mai cheme)
    2. Pasul recursiv: Cum ajung din problema mare la una mai mică?

    📚 Tipurile de Probleme din Acest PDF

    TIPUL 1: “Urmărește-l pe Domnul Recursiv” – Apeluri Recursive Simple

    Ce testează? Dacă poți urmări pas cu pas ce face o funcție care se cheamă pe ea însăși.

    Exemplul 1 (Problema 1):

    Subprogramul f este definit alăturat. Indică valoarea f(0,4,x) pentru x = (2,0,2,6,8)

    int f(int s,int d,int v[])  
    { 
        if(s==d) 
            if(v[d]==2*d) return 1;  
            else return 0;  
        else 
            return f(s,(s+d)/2,v) + f(1+(s+d)/2,d,v);  
    }

    Rezolvare Pas cu Pas:

    1. Ce face funcția? Ea verifică dacă elementul de pe poziția d este egal cu 2*d. Dacă DA, returnează 1, altfel 0.
    2. Dar se uită doar la poziția d? Nu! Pentru că:
    • Dacă s == d (interval de un singur element) → verifică și returnează 1 sau 0
    • Altfel → împarte intervalul [s,d] în două jumătăți și face suma
    1. Desenăm pe hârtie cum se împarte:
       f(0,4) → împarte [0,4] în [0,2] și [3,4]
    
       f(0,2) → împarte [0,2] în [0,1] și [2,2]
       f(3,4) → împarte [3,4] în [3,3] și [4,4]
    
       Continuă până când toate intervalele au un singur element!
    1. Calculăm pentru vectorul nostru:
       Vector: index:  0  1  2  3  4
               valoare: 2  0  2  6  8
    
       Verifică condiția v[d] == 2*d:
       - Pentru d=0: v[0]=2, 2*0=0 → 2==0? FALS → returnează 0
       - Pentru d=1: v[1]=0, 2*1=2 → 0==2? FALS → 0
       - Pentru d=2: v[2]=2, 2*2=4 → 2==4? FALS → 0
       - Pentru d=3: v[3]=6, 2*3=6 → 6==6? ADEVĂRAT → 1
       - Pentru d=4: v[4]=8, 2*4=8 → 8==8? ADEVĂRAT → 1
    1. Acum urmărim suma:
       f(0,4) = f(0,2) + f(3,4)
       f(0,2) = f(0,1) + f(2,2)
              = (f(0,0) + f(1,1)) + f(2,2)
              = (0 + 0) + 0 = 0
    
       f(3,4) = f(3,3) + f(4,4)
              = 1 + 1 = 2
    
       Deci f(0,4) = 0 + 2 = 2

    Răspuns Final: b. 2


    TIPUL 2: “Funcții Care Înmultesc sau Adună” – Recursivitate cu Calcul

    Exemplul 2 (Problema 5):

    Subprogramul f este definit alăturat. Indică valoarea f(3,2).

    int f(int x, int y)  
    { 
        int z;  
        if (y==0) return 1;  // Caz de bază
        z = f(x, y/2);  
        if (y%2!=0) return z*z*x;  // ATENȚIE: era "y%21=0" în text, dar probabil e "y%2!=0"
        return z*z;  
    }

    Rezolvare Pas cu Pas:

    1. Ce calculează funcția? Seamănă cu ridicarea la putere! f(x,y) calculează x^y.
    2. Urmărim pas cu pas pentru f(3,2):
       f(3,2):
       - y=2, nu este 0
       - z = f(3, 2/2) = f(3,1)
    
       f(3,1):
       - y=1, nu este 0
       - z = f(3, 1/2) = f(3,0)  // Împărțire întreagă: 1/2=0
    
       f(3,0):
       - y=0 → returnează 1
    
       Acum mergem înapoi:
       f(3,1) primește z=1
       - y%2 = 1%2 = 1 ≠ 0 → returnează z*z*x = 1*1*3 = 3
    
       f(3,2) primește z=3
       - y%2 = 2%2 = 0 → returnează z*z = 3*3 = 9
    1. Verificare: 3² = 9. Corect!

    Răspuns Final: c. 9


    TIPUL 3: “Funcții Care Modifică și Afișează” – Ordinea Afișării

    Exemplul 3 (Problema 3):

    Subprogramul f este definit. Ce se afișează în urma apelului?

    void f(int n)  
    { 
        cout<<n<<' ';
        if(n%10!=0) { 
            cout<<n<<' ';
            f(n/10);  
        }  
        else if(n!=0) { 
            f(n/10);  
            cout<<n<<' ';
        }  
    }

    Rezolvare Pas cu Pas:

    1. Analizăm pentru f(2050):
    • Prima linie: afișează 2050
    • Verifică: 2050 % 10 = 0 → intră în else if
    • n != 0 este adevărat → apelează f(2050/10) = f(205)
    1. f(205):
    • Afișează 205
    • 205 % 10 = 5 ≠ 0 → intră în primul if
    • Afișează 205 din nou
    • Apelează f(205/10) = f(20)
    1. f(20):
    • Afișează 20
    • 20 % 10 = 0 → intră în else if
    • n != 0 adevărat → apelează f(20/10) = f(2)
    1. f(2):
    • Afișează 2
    • 2 % 10 = 2 ≠ 0 → intră în primul if
    • Afișează 2 din nou
    • Apelează f(2/10) = f(0)
    1. f(0):
    • Afișează 0
    • 0 % 10 = 0 → intră în else if
    • n != 0 este FALS (0 ≠ 0? FALS!) → nu face nimic în else if
    • Funcția se termină
    1. Acum mergem înapoi și completăm afișările rămase:
    • Din f(2): după apelul recursiv, funcția se termină (nu mai are cod)
    • Din f(20): după apelul recursiv, afișează 20
    • Din f(205): după apelul recursiv, funcția se termină
    • Din f(2050): după apelul recursiv, afișează 2050
    1. Ordinea completă: 2050 205 205 20 2 2 0 20 2050

    Răspuns Final: d. 2050 205 205 205 20 2 0 20 2050 (aproape, dar atenție la dublările!)


    TIPUL 4: “Verificări de Numere Prime” – Recursivitate cu Condiții

    Exemplul 4 (Problema 6):

    Completați punctele pentru ca f(n,3) să testeze numere prime

    int f(int x, int y)  
    { 
        if(x!=2 && x%2==0) return 0;  // Dacă x este par și nu e 2 → nu e prim
        if(y*y > x) return 1;         // Dacă am verificat toți divizorii posibili → e prim
        if(x%y==0) return 0;          // Dacă x se împarte la y → nu e prim
        return f(x,......);            // Continuă cu următorul divizor de verificat
    }

    Gândire logică:

    1. Funcția verifică dacă x este prim
    2. Începe cu y=3 (apelul este f(n,3))
    3. Verifică divizori din 2 în 2 (pentru că a eliminat numerele pare deja)
    4. Următorul divizor de verificat după y este y+2 (trecem peste numere pare)

    Răspuns Final: a. y+2


    🎯 Strategia Ta pentru Recursivitate

    1. Notează pe hârtie fiecare apel ca pe un copac:
       f(0,4)
         ├── f(0,2)
         │     ├── f(0,1)
         │     │     ├── f(0,0)
         │     │     └── f(1,1)
         │     └── f(2,2)
         └── f(3,4)
               ├── f(3,3)
               └── f(4,4)
    1. Calculează de jos în sus: Începe cu frunzele (cazurile de bază), apoi urcă.
    2. Testează cu valori mici: În loc de f(2023), înțelege cum funcționează pentru f(23) sau f(5).

    💪 Exercițiu pentru Acasă

    Ia Problema 9 (cu f(2023) care înlocuiește cifre):

    int f(int n)  
    { 
        if(n==0) return 0;  
        if(n%10==2) return f(n/10)*10+3;  
        return f(n/10)*10+2;  
    }

    Începe cu numere mici:

    • f(2) → ce returnează?
    • f(12) → ce returnează?
    • f(22) → ce returnează?

    Apoi aplică aceeași logică pentru 2023. Vei vedeă că funcția înlocuiește toate cifrele 2 cu 3 și toate celelalte cifre cu 2!


    ✨ Motivare Finală

    Recursivitatea este ca un puzzle: pare complicat la început, dar odată ce înțelegi modelul, devine fascinant! Fiecare funcție recursivă are o poveste de spus și o logică de urmărit.

    Data viitoare când vezi o funcție care se cheamă pe ea însăși, gândește-te: “Unde se oprește?” și “Cum devine problema mai mică?”. Cu aceste două întrebări, poți rezolva orice problemă de recursivitate!

    Ai reușit să înțelegi aceste exemple? Bravo! Ești pe cale să devii expert în “gândirea recursivă”! 🚀