Sari la conținut

Bac informatică 2022 Model, rezolvat

Modelul de la Bacalaureatul la Informatică (Mate-Info, C/C++): conține 3 subiecte (90 de puncte) și are un timp de lucru de 3 ore. Sub fiecare exercițiu găsești răspunsul corect și rezolvarea.

Subiecte oficiale publicate de Ministerul Educației. Rezolvări realizate de subac. Actualizat la .

📌 Despre Modelul din 2022

Modelul din 2022 trece prin expresii logice, recursivitate, backtracking, grafuri și arbori, matrice, structuri imbricate, divizibilitate, șiruri de caractere și fișiere. Este un test complet, bun ca să vezi cum arată un subiect de Bac de la cap la coadă.

Subiectul I (20p): 5 grile: o expresie logică echivalentă cu x<=20 || x>22, un subprogram recursiv cu un parametru transmis prin referință, o problemă de backtracking cu cutii de dulciuri, numărul de noduri ale unui graf fără cicluri cu 22 de muchii și două componente conexe și dimensiunea unei matrice pătratice din poziția unui element de pe diagonala secundară.

Subiectul al II-lea (40p): Un algoritm în pseudocod care adună pătratele numerelor de la 1 la [√k] și afișează sumele când se schimbă, fiii unui nod într-un arbore dat prin vectorul de „tați” și o structură zbor cu un câmp aterizare care este tot o structură.

Subiectul al III-lea (30p): Un subprogram (mozaic) care calculează lungimea minimă a unui mozaic din trei benzi de plăcuțe, o problemă cu șiruri de caractere care verifică dacă toate numerele dintr-un text au același număr de cifre și o problemă de eficiență cu „secvențe par-încadrate” dintr-un șir de cifre citit din fișierul bac.txt.

⚠️ La ce să fii atent

  • La I.1: Verifică variantele pe valorile de la margine, 20, 21 și 22. Varianta d) se reduce la x>=20, care este 1 pentru x=21, deși expresia dată este 0.
  • La I.5: Pe diagonala secundară a unei matrice cu n linii, numerotate de la 0, suma indicilor este n-1. Din 2021+2022=n-1 rezultă n=4044.
  • La II.1.a: Suma se schimbă doar când [√k] crește, adică la pătratele perfecte. Pentru 2 și 7 se afișează doar 1*1 5*2, pentru că de la 5 la 7 suma rămâne 5.
  • La III.1: Cele trei benzi au aceeași lungime, deci lungimea trebuie să fie multiplu comun al lui x, y și z. Cea mai mică lungime este cel mai mic multiplu comun, nu produsul: pentru 30, 40 și 20 răspunsul este 120.
  • La III.3: Pentru fiecare valoare pară, cea mai lungă secvență pornește de la prima ei apariție și se termină la ultima. Pot fi mai multe valori cu aceeași lungime maximă: în exemplu, 4 și 8 dau amândouă lungimea 9 și se afișează amândouă, în ordine crescătoare.

Subiectul I

20 de puncte
  1. Exercițiul 1 4p Expresii și operatori

    Variabila x este de tip întreg.

    Indicați o expresie care are valoarea 1 dacă și numai dacă expresia C/C++ alăturată are valoarea 1.

    x<=20 || x>22
    • a)!(x>20) || !(x<=22)
    • b)!(x>=20) && !(x>=22)
    • c)!(x<20 || x<=22)
    • d)!(x<20 && x<22)
    Vezi rezolvarea

    Răspuns corect: a) !(x>20) || !(x<=22)

    !(x>20) înseamnă x<=20, iar !(x<=22) înseamnă x>22, deci a) este chiar expresia dată. În b) rămâne x<20 && x<22, adică x<20, care este 0 pentru x=20; în c) rămâne x>22, tot 0 pentru x=20; în d) rămâne x>=20, care este 1 pentru x=21, deși expresia dată este 0.

  2. Exercițiul 2 4p Recursivitate

    Subprogramul f este definit alăturat, iar variabila întreagă r are valoarea 0 înainte de apel.

    Indicați apelul în urma căruia variabila r are valoarea 2.

    void f(int x, int y, int&z)
    { if((x%2)*(y%2)!=0) z=1;
      else { f(x/2,y/2,z); z=z+1; }
    }
    • a)f(21,22,r);
    • b)f(20,21,r);
    • c)f(19,20,r);
    • d)f(18,19,r);
    Vezi rezolvarea

    Răspuns corect: d) f(18,19,r);

    Subprogramul înjumătățește ambele numere până când sunt amândouă impare; abia atunci z devine 1 și, la fiecare revenire din apel, crește cu 1. Așadar r este 1 plus numărul de apeluri recursive. La f(18,19,r) se coboară o singură dată — 18 este par, iar 9 și 9 sunt amândouă impare — deci r ajunge 2. La a) și b) se coboară de două ori (r=3), iar la c) de patru ori (r=5).

  3. Exercițiul 3 4p Backtracking

    Utilizând metoda backtracking, se generează toate posibilitățile de a forma cutii cu dulciuri de tipuri distincte din mulțimea {bomboane, drajeuri, jeleuri, praline}. Într-o cutie sunt cel puțin două tipuri de dulciuri, dar nu pot fi și jeleuri și praline simultan. Două cutii sunt distincte dacă ele conțin cel puțin un tip diferit de dulciuri. Primele patru soluții generate sunt, în această ordine:

    1. (bomboane, drajeuri)
    2. (bomboane, drajeuri, jeleuri)
    3. (bomboane, drajeuri, praline)
    4. (bomboane, jeleuri)

    Indicați a șasea soluție, în ordinea generării acestora.

    • a)(bomboane, praline)
    • b)(drajeuri, jeleuri)
    • c)(drajeuri, praline)
    • d)(jeleuri, praline)
    Vezi rezolvarea

    Răspuns corect: b) (drajeuri, jeleuri)

    Soluțiile se generează în ordinea tipurilor din mulțime, iar jeleurile și pralinele nu pot apărea împreună: (bomboane, drajeuri), (bomboane, drajeuri, jeleuri), (bomboane, drajeuri, praline), (bomboane, jeleuri), (bomboane, praline), (drajeuri, jeleuri). A șasea este (drajeuri, jeleuri). Combinațiile (bomboane, jeleuri, praline) și (jeleuri, praline) sunt sărite, pentru că au și jeleuri, și praline.

  4. Exercițiul 4 4p Grafuri neorientate

    Indicați numărul de noduri ale unui graf neorientat fără cicluri, cu 22 de muchii și două componente conexe.

    • a)11
    • b)23
    • c)24
    • d)44
    Vezi rezolvarea

    Răspuns corect: c) 24

    Un graf neorientat fără cicluri cu n noduri și c componente conexe are exact n-c muchii: fiecare componentă este un arbore, iar un arbore cu k noduri are k-1 muchii. Din 22 = n-2 rezultă n = 24.

  5. Exercițiul 5 4p Tablouri bidimensionale

    Variabila a memorează un tablou bidimensional cu cu n linii și n coloane, numerotate începând de la 0.

    Știind că elementul a[2021][2022] se află pe diagonala secundară a tabloului, indicați valoarea lui n.

    • a)4040
    • b)4042
    • c)4044
    • d)4046
    Vezi rezolvarea

    Răspuns corect: c) 4044

    Pe diagonala secundară a unui tablou cu n linii și n coloane, numerotate începând de la 0, suma indicilor unui element este n-1. Din 2021 + 2022 = n-1 rezultă n = 4044.

Subiectul al II-lea

40 de puncte
  1. Exercițiul 1.a 6p Algoritmi în pseudocod

    Algoritmul alăturat este reprezentat în pseudocod.

    Scrieți ce se afișează în urma executării algoritmului dacă se citesc, în această ordine, numerele 2 și 7.

    citește x,y (numere naturale, x<y)
     u←0; nr←0
    ┌pentru k←x,y execută
    │ s←0; nr←nr+1
    │┌pentru t←1,[√k] execută
    ││ s←s+t*t
    │└■
    │┌dacă s≠u atunci
    ││ scrie s,'*',nr,' '
    ││ u←s; nr←0
    │└■
    └■
    Vezi rezolvarea

    Răspunsul din barem: 1*1 5*2

    Pentru k=2: [√2] este 1, deci s=1; fiind primul afișaj (u=0), se scrie 1*1, apoi u=1 și nr=0. Pentru k=3: [√3] este tot 1, deci s=1=u și nu se afișează nimic. Pentru k=4: [√4] este 2, deci s=1+4=5; cum 5≠1, se scrie 5*2 (nr numărase 3 și 4), apoi u=5. Pentru k=5, 6 și 7: [√k] rămâne 2, deci s=5=u și nu se mai afișează nimic.

  2. Exercițiul 1.b 6p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    Dacă pentru y se citește numărul 22, scrieți două numere care pot fi citite pentru x, astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea, să se afișeze doar 30*1.

    Vezi rezolvarea

    Exemplu: 16 și 20

    Se afișează o singură dată, la primul k, iar valoarea scrisă trebuie să fie 30: suma 1²+2²+3²+4² se obține când [√k] este 4, adică pentru k între 16 și 24. Primul k este chiar x, iar nr este atunci 1, deci se scrie 30*1. Pentru ca după aceea să nu se mai afișeze nimic, s trebuie să rămână 30 până la y=22, ceea ce se întâmplă pentru orice k≤24. Cum enunțul cere x<y, x poate fi orice număr din mulțimea {16, 17, 18, 19, 20, 21}.

  3. Exercițiul 1.c 10p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    Scrieți programul C/C++ corespunzător algoritmului dat.

    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int x, y, u = 0, nr = 0;
        cin >> x >> y;
        for (int k = x; k <= y; k++)
        {
            int s = 0;
            nr = nr + 1;
            // t ≤ [√k], scris fără sqrt: la un pătrat perfect virgula mobilă poate
            // întoarce 6,999… în loc de 7, iar suma ar pierde ultimul termen.
            for (int t = 1; t * t <= k; t++)
                s = s + t * t;
            if (s != u)
            {
                cout << s << '*' << nr << ' ';
                u = s;
                nr = 0;
            }
        }
        return 0;
    }
  4. Exercițiul 1.d 6p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    Scrieți în pseudocod un algoritm, echivalent cu cel dat, înlocuind adecvat una dintre structurile pentru...execută cu o structură de tip cât timp...execută.

    Vezi rezolvarea
    citește x,y (numere naturale, x<y)
     u←0; nr←0
    ┌pentru k←x,y execută
    │ s←0; nr←nr+1
    │ t←1
    │┌cât timp t≤[√k] execută
    ││ s←s+t*t
    ││ t←t+1
    │└■
    │┌dacă s≠u atunci
    ││ scrie s,'*',nr,' '
    ││ u←s; nr←0
    │└■
    └■

    Structura pentru ținea singură contorul: îl pornea de la 1, îl compara cu [√k] și îl creștea. Înlocuită cu cât timp, cele trei lucruri se scriu separat — t←1 înaintea buclei, condiția t≤[√k] în antet și t←t+1 la sfârșitul corpului. Inițializarea stă în interiorul buclei după k, pentru că t trebuie să pornească din nou de la 1 la fiecare k.

  5. Exercițiul 2 6p Arbori

    Un arbore cu 9 noduri, numerotate de la 1 la 9, este reprezentat prin vectorul de „tați” (3, 5, 2, 2, 0, 5, 3, 3, 8).

    Scrieți numerele asociate nodurilor care sunt descendenți direcți („fii”) ai nodului cu eticheta 3.

    Vezi rezolvarea

    Răspunsul din barem: 1,7,8

    Vectorul de „tați" ține pe poziția i eticheta părintelui nodului i. Fiii nodului 3 sunt nodurile care au valoarea 3 pe poziția lor: poziția 1 (3), poziția 7 (3) și poziția 8 (3).

  6. Exercițiul 3 6p Tipul înregistrare (struct)

    Variabila z memorează date referitoare la un zbor al unui avion, derulat în totalitate în aceeași zi, pe teritoriul României: codul zborului, momentul de timp corespunzător aterizării (ora și minutul) și durata zborului, exprimată în minute. Toate valorile precizate sunt numere naturale: codul are maximum trei cifre, ora este un număr din intervalul [0,23], iar minutul este un număr din intervalul [0,59].

    Știind că expresiile C/C++ de mai jos au ca valori codul zborului, respectiv ora la care a decolat avionul, scrieți definiția unei structuri cu eticheta zbor, care să permită memorarea datelor referitoare la un zbor de tipul precizat, și declarați corespunzător variabila z.

    z.cod       (60*z.aterizare.ora+z.aterizare.minut-z.durata)/60
    Vezi rezolvarea
    struct zbor
    {
        int cod;
        struct
        {
            int ora, minut;
        } aterizare;
        int durata;
    } z;

    Structura are câte un câmp pentru fiecare dată din enunț: codul, momentul aterizării și durata. Momentul aterizării e format din două numere, ora și minutul, iar expresia din enunț le folosește ca z.aterizare.ora și z.aterizare.minut — deci aterizare e la rândul ei o structură. Variabila z se declară odată cu definirea structurii.

Subiectul al III-lea

30 de puncte
  1. Exercițiul 1 10p Subprograme

    Pentru grădina publică a orașului se dorește proiectarea unui mozaic de formă dreptunghiulară, format din plăcuțe dreptunghiulare de ceramică. Furnizorul dispune de trei tipuri de plăcuțe și de suficient de multe plăcuțe din fiecare tip, astfel încât să fie posibilă realizarea oricărui model. Modelul proiectat este constituit din trei benzi suprapuse, fiecare bandă fiind formată din plăcuțe întregi, de același tip, montate unele după altele; oricare două benzi diferite sunt formate din plăcuțe de tipuri diferite.

    Subprogramul mozaic are trei parametri, x, y și z, prin care primește trei numere naturale din intervalul [10,200], reprezentând lungimea, exprimată în milimetri, a unei plăcuțe de primul tip, de al doilea tip, respectiv de al treilea tip. Subprogramul returnează un număr natural, reprezentând lungimea minimă, exprimată în milimetri, a unui mozaic care să respecte modelul proiectat.

    Scrieți definiția completă a subprogramului.

    Exemplu: pentru x=30, y=40, z=20, subprogramul returnează valoarea 120 (mozaicul are trei benzi, fiecare de lungime 120 mm: prima formată din 4 plăcuțe de câte 30 mm, a doua formată din 3 plăcuțe de câte 40 mm, iar a treia formată din 6 plăcuțe de câte 20 mm).

    Figura din enunț
    Vezi rezolvarea
    int cmmdc(int a, int b)
    {
        while (b != 0)
        {
            int r = a % b;
            a = b;
            b = r;
        }
        return a;
    }
    
    int mozaic(int x, int y, int z)
    {
        int m = x / cmmdc(x, y) * y;
        return m / cmmdc(m, z) * z;
    }

    Cele trei benzi au aceeași lungime, iar fiecare e formată din plăcuțe întregi de un singur tip: lungimea mozaicului trebuie să fie multiplu și al lui x, și al lui y, și al lui z. Cea mai mică lungime posibilă este deci cel mai mic multiplu comun al celor trei numere. Se calculează din doi în doi, cu algoritmul lui Euclid: x*y/cmmdc(x,y), iar rezultatul cu z. Împărțirea se face înaintea înmulțirii, ca produsul să nu depășească domeniul lui int.

  2. Exercițiul 2 10p Șiruri de caractere

    Un text are cel mult 100 de caractere și este format din cuvinte, numere naturale și spații. Textul conține cel puțin un număr, iar cuvintele sunt formate numai din litere mici ale alfabetului englez. Cuvintele și numerele sunt separate prin câte un spațiu, ca în exemplu.

    Scrieți un program C/C++ care citește de la tastatură un text de tipul precizat și afișează pe ecran un număr natural k, dacă toate numerele care intră în componența sa au câte k cifre, sau mesajul NU, în caz contrar.

    Exemplu: pentru textul la zoo sunt 100 de cocori si 120 de pasari flamingo sau pentru textul la zoo sunt 100 de cocori se afișează 3 iar pentru textul la zoo sunt 100 de cocori si 10 pasari flamingo se afișează NU

    Vezi rezolvarea
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main()
    {
        char s[101];
        cin.getline(s, 101);
        int k = 0, toate = 1;
        for (char *p = strtok(s, " "); p != NULL; p = strtok(NULL, " "))
            if (p[0] >= '0' && p[0] <= '9')
            {
                int cifre = strlen(p);
                if (k == 0) k = cifre;
                else if (cifre != k) toate = 0;
            }
        if (toate) cout << k;
        else cout << "NU";
        return 0;
    }

    Textul se citește întreg, cu spații, deci cin.getline. strtok îl taie în cuvinte după spații, iar un cuvânt care începe cu o cifră este un număr — cuvintele propriu-zise au numai litere mici. Numărul de cifre este chiar lungimea acelui cuvânt. Primul număr întâlnit dă k; dacă vreunul de după are altă lungime, răspunsul devine NU.

  3. Exercițiul 3.a 2p Algoritmi eficienți

    Numim secvență par-încadrată a unui șir de numere naturale un subșir al acestuia, format din termeni aflați pe poziții consecutive în șirul dat, subșir care începe și se termină cu aceeași valoare, pară. Lungimea secvenței este egală cu numărul de termeni ai acesteia.

    Fișierul bac.txt conține un șir de cel puțin două și cel mult 10^6 numere naturale din intervalul [0,9]. Numerele sunt separate prin câte un spațiu, iar în șir există cel puțin doi termeni pari egali.

    Se cere să se determine secvențele par-încadrate din acest șir care au lungime maximă și să se afișeze pe prima linie a ecranului lungimea maximă determinată, iar pe următoarea linie, pentru fiecare astfel de secvență, valoarea primului său termen. Numerele de pe a doua linie sunt afișate în ordine strict crescătoare, separate prin câte un spațiu.

    Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul bac.txt conține numerele atunci pe ecran se afișează valorile:

    5 1 3 2 4 3 3 2 8 9 7 3 4 6 6 0 8

    9

    4 8

    Descrieți în limbaj natural algoritmul proiectat, justificând eficiența acestuia.

    Vezi rezolvarea

    Timp de executare: O(n) · Memorie: O(1)

    Se citește șirul o singură dată. Pentru fiecare dintre cele zece valori posibile se ține minte poziția pe care a apărut prima oară (prim[v]). Când se citește un termen par x aflat pe poziția i, secvența par-încadrată cea mai lungă care se termină aici începe la prim[x], deci are lungimea i-prim[x]+1. Se păstrează lungimea maximă și valorile care o dau: la o lungime mai mare lista se golește și rămâne doar x, la una egală x se adaugă.

    Algoritmul parcurge șirul o singură dată și nu îl memorează: face un număr de operații proporțional cu numărul de termeni și folosește doar zece poziții suplimentare, oricât de lung ar fi șirul.

  4. Exercițiul 3.b 8p Algoritmi eficienți

    Același algoritm ca la 3.a.

    Fișierul bac.txt conține un șir de cel puțin două și cel mult 10^6 numere naturale din intervalul [0,9]. Numerele sunt separate prin câte un spațiu, iar în șir există cel puțin doi termeni pari egali.

    Se cere să se determine secvențele par-încadrate din acest șir care au lungime maximă și să se afișeze pe prima linie a ecranului lungimea maximă determinată, iar pe următoarea linie, pentru fiecare astfel de secvență, valoarea primului său termen. Numerele de pe a doua linie sunt afișate în ordine strict crescătoare, separate prin câte un spațiu.

    Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul bac.txt conține numerele atunci pe ecran se afișează valorile:

    9

    4 8

    Scrieți programul C/C++ corespunzător algoritmului proiectat.

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream f("bac.txt");
        int prim[10], da[10] = {0}, x, i = 0, maxim = 0;
        for (int v = 0; v < 10; v++) prim[v] = -1;
        while (f >> x)
        {
            if (x % 2 == 0)
            {
                if (prim[x] == -1) prim[x] = i;
                int lung = i - prim[x] + 1;
                if (lung > maxim)
                {
                    maxim = lung;
                    for (int v = 0; v < 10; v++) da[v] = 0;
                    da[x] = 1;
                }
                else if (lung == maxim) da[x] = 1;
            }
            i++;
        }
        f.close();
        cout << maxim << "\n";
        for (int v = 0; v < 10; v++)
            if (da[v]) cout << v << " ";
        return 0;
    }

Vrei să vezi ce notă ai lua la examen?

Intră în modul simulare: ai cronometru de 3 ore, codul ți se compilează pe loc, iar la final primești nota conform baremului.

Începe simularea3 ore

Ai găsit o problemă sau ai o idee?

Despre ce este vorba?