Sari la conținut

Bac informatică 2021 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 2021

Modelul din 2021 trece prin expresii, structuri, recursivitate, arbori, grafuri, backtracking, șiruri de caractere, matrice ș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 cu împărțire întreagă, afișarea câmpurilor unei structuri data, un subprogram recursiv cu doi parametri, numărul maxim de frunze ale unui arbore în funcție de rădăcina aleasă și câte muchii pot fi eliminate dintr-un graf complet cu 21 de noduri ca să rămână un graf conex fără cicluri.

Subiectul al II-lea (40p): Un algoritm în pseudocod care construiește un număr din cifrele lui n, după paritatea valorilor prin care trece n, o problemă de backtracking cu numere de cinci cifre în ordine strict crescătoare și o secvență cu șiruri de caractere care transformă vocalele în litere mari, parcurgând textul de la coadă.

Subiectul al III-lea (30p): Un subprogram cu numere prime (prime, care furnizează cele mai mari două numere prime mai mici decât n), o problemă cu o matrice completată cu primele m*n pătrate perfecte pare, în ordine descrescătoare, și o problemă de eficiență cu cheltuielile pe tipuri de produse, citite din fișierul cheltuieli.in.

⚠️ La ce să fii atent

  • La I.1: Ambii operanzi sunt întregi, deci 21/2 dă 10, nu 10.5. Expresia valorează 10*2-5, adică 15, nu 16.
  • La I.3: Fiecare apel crește x înainte să-l scadă din rezultat, deci se scad valorile 2, 3 și 4. Rezultatul este -9.
  • La II.1.a: Fii atent la prima instrucțiune din buclă! c←n%2 ia paritatea lui n, nu ultima lui cifră. Abia după ce n pierde ultima cifră, se adaugă la nr noua cifră a unităților. Rezultatul este 46.
  • La II.3: Parcurgerea merge de la ultimul caracter spre primul, iar strchr("aeiou",s[i]) găsește doar vocalele mici. A-ul de la început nu se afișează, deci rezultatul este OAIAE.
  • La III.2: Cel mai mic pătrat perfect par este 0, iar în exemplu tabloul se termină chiar cu 0. Primele m*n pătrate perfecte pare sunt deci pătratele numerelor 0, 2, 4, ..., 2*(m*n-1).

Subiectul I

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

    Indicați valoarea expresiei C/C++ alăturate.

    21/2*2-5
    • a)0
    • b)0.25
    • c)15
    • d)16
    Vezi rezolvarea

    Răspuns corect: c) 15

    Amândoi operanzii sunt întregi, deci 21/2 este împărțire întreagă: dă 10, nu 10,5.

    Operatorii / și * au aceeași prioritate și se evaluează de la stânga la dreapta:

    21/2 → 10, apoi 10*2 → 20, apoi 20-5 → 15, varianta c).

    Dacă împărțirea ar fi fost reală, ar fi ieșit 21/2*2 = 21 și apoi 16 — de aceea varianta d) e pusă acolo, ca să prindă exact această confuzie.

  2. Exercițiul 2 4p Tipul înregistrare (struct)

    Variabila x este declarată alăturat.

    Indicați secvența care, în urma executării, afișează pe ecran ziua, luna și anul corespunzătoare unei date calendaristice memorate în variabila x.

    struct data
          {
            int zi, luna, an;
          }x;
    • a)cout<<x.zi<<" "<<x.luna<<" "<<x.an; | printf("%d %d %d",x.zi,x.luna,x.an);
    • b)cout<<zi.x<<" "<<luna.x<<" "<<an.x; | printf("%d %d %d",zi.x,luna.x,an.x);
    • c)cout<<x(zi," ",luna," ",an); | printf("%d %d %d",x(zi,luna,an));
    • d)cout<<data.x.zi<<" "<<data.x.luna<<" "<<data.x.an; | printf("%d %d %d",data.x.zi,data.x.luna,data.x.an);
    Vezi rezolvarea

    Răspuns corect: a) cout<<x.zi<<" "<<x.luna<<" "<<x.an; | printf("%d %d %d",x.zi,x.luna,x.an);

    Accesul la un câmp al unei structuri se scrie variabila.camp, deci x.zi, x.luna, x.an — varianta a).

    Celelalte trei inversează sau inventează sintaxa: b) pune câmpul înaintea variabilei, c) folosește parantezele de apel de funcție, iar d) pune numele tipului (data) înaintea variabilei. data e numele structurii, nu un obiect din care să poți citi ceva.

  3. Exercițiul 3 4p Recursivitate

    Subprogramul f este definit alăturat.

    Indicați valoarea f(3,1).

    int f(int n,int x)
    { if(n!=0)
      { x=x+1;
        return f(n-1,x)-x;
      }
      return 0;
    }
    • a)0
    • b)-3
    • c)-6
    • d)-9
    Vezi rezolvarea

    Răspuns corect: d) -9

    Fiecare apel crește x cu 1, apoi scade această valoare din ce returnează apelul de mai jos:

    apelx devinece returnează
    f(3,1)2f(2,2) - 2
    f(2,2)3f(1,3) - 3
    f(1,3)4f(0,4) - 4
    f(0,4)—0

    Se calculează de jos în sus: f(1,3) = 0-4 = -4, apoi f(2,2) = -4-3 = -7, apoi `f(3,1) = -7-2 = -9`, varianta d).

    Cu alte cuvinte, rezultatul e -(2+3+4): se scad valorile pe care le ia x la fiecare nivel.

  4. Exercițiul 4 4p Arbori

    Un arbore cu rădăcină are 8 noduri, numerotate de la 1 la 8, și muchiile:

    1. [1,3]
    2. [1,7]
    3. [1,8]
    4. [2,4]
    5. [3,5]
    6. [3,6]
    7. [4,5]

    Indicați numărul maxim de frunze ale arborelui, în funcție de rădăcina aleasă.

    • a)5
    • b)4
    • c)3
    • d)2
    Vezi rezolvarea

    Răspuns corect: b) 4

    Într-un arbore cu rădăcină, un nod diferit de rădăcină e frunză dacă are gradul 1 în graf, adică n-are decât legătura cu tatăl lui.

    Gradele nodurilor sunt: 1 → 3, 2 → 1, 3 → 3, 4 → 2, 5 → 2, 6 → 1, 7 → 1, 8 → 1.

    Nodurile de grad 1 sunt 2, 6, 7 și 8. Dacă alegi drept rădăcină un nod cu gradul cel puțin 2 — adică 1, 3, 4 sau 5 — toate patru rămân frunze, deci arborele are 4 frunze, varianta b).

    Dacă ai alege drept rădăcină chiar unul dintre nodurile de grad 1, acela n-ar mai fi frunză (rădăcina nu e frunză când are fii) și ar rămâne doar 3. Cum se cere numărul maxim, răspunsul e 4.

  5. Exercițiul 5 4p Grafuri neorientate

    Un graf neorientat complet are 21 de noduri.

    Indicați numărul de muchii ce pot fi eliminate, astfel încât graful parțial obținut să fie conex și fără cicluri.

    • a)211
    • b)209
    • c)190
    • d)188
    Vezi rezolvarea

    Răspuns corect: c) 190

    Un graf complet cu 21 de noduri are toate perechile legate: `21·20/2 = 210` muchii.

    Un graf conex și fără cicluri este un arbore, iar un arbore cu 21 de noduri are exact 21-1 = 20 muchii.

    Se elimină deci `210 - 20 = 190` muchii, varianta c).

Subiectul al II-lea

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

    Algoritmul alăturat este reprezentat în pseudocod.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Scrieți numărul afișat în urma executării algoritmului dacă se citesc, în această ordine, numerele 3845267 și 3.

     citește n,k
      (numere naturale)
     p←1
    ┌dacă k=0 atunci
    │ nr←-1
    │altfel
    │ nr←0
    │┌repetă
    ││ c←n%2; n←[n/10]
    ││┌dacă c≠0 atunci
    │││ nr←nr+(n%10)*p; p←p*10
    │││altfel
    │││ k←k-1
    ││└■
    │└până când n=0 sau k=0
    └■
     scrie nr
    Vezi rezolvarea

    Răspunsul din barem: 46

    Atenție la prima instrucțiune din buclă: c←n%2 ia paritatea lui n, nu ultima lui cifră. Abia după aceea n pierde o cifră, iar dacă n era impar se adună la nr cifra rămasă la coadă.

    n la intrarec (paritate)n devinece se întâmplănr
    38452671384526se adaugă cifra 66
    384526038452k scade la 26
    3845203845k scade la 16
    38451384se adaugă cifra 4, în față46
    384038k scade la 0 → stop46

    Se afișează 46. Cifrele adunate se așază de la dreapta spre stânga, fiindcă p se înmulțește cu 10 după fiecare.

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

    Același algoritm ca la 1.a.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Dacă pentru variabila k se citește 2, scrieți trei numere din intervalul [10^3,10^4) care pot fi citite pentru n astfel încât, pentru fiecare dintre acestea, în urma executării algoritmului, să se afișeze 20.

    Vezi rezolvarea

    2101, 2103, 2105

    Cu k=2, algoritmul se oprește după ce întâlnește a doua valoare pară a lui n, iar pe parcurs adună cifrele rămase la coadă după fiecare valoare impară.

    Urmărește 2101:

    nparitaten devinenr
    2101impar210se adaugă 0 → 0
    210par21k devine 1
    21impar2se adaugă 2, în față → 20
    2par0k devine 0 → stop

    La fel se întâmplă cu 2103 și 2105: contează doar paritățile pe parcurs și cele două cifre culese, 0 și apoi 2. În total există 25 de numere de patru cifre care dau 20; oricare trei dintre ele sunt un răspuns bun.

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

    Același algoritm ca la 1.a.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

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

    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, k, p = 1, nr, c;
        cin >> n >> k;
        if (k == 0)
            nr = -1;
        else
        {
            nr = 0;
            do
            {
                c = n % 2;
                n = n / 10;
                if (c != 0)
                {
                    nr = nr + (n % 10) * p;
                    p = p * 10;
                }
                else
                    k = k - 1;
            } while (n != 0 && k != 0);
        }
        cout << nr;
        return 0;
    }
  4. Exercițiul 1.d 6p Algoritmi în pseudocod

    Același algoritm ca la 1.a.

    S-a notat cu a%b restul împărțirii numărului natural a la numărul natural nenul b și cu [c] partea întreagă a numărului real c.

    Scrieți în pseudocod un algoritm, echivalent cu cel dat, înlocuind adecvat structura repetă...până când cu o structură repetitivă cu test inițial.

    Vezi rezolvarea

    `` citește n,k (numere naturale) p←1 ┌dacă k=0 atunci │ nr←-1 │altfel │ nr←0 │ c←n%2; n←[n/10] │┌dacă c≠0 atunci ││ nr←nr+(n%10)*p; p←p*10 ││altfel ││ k←k-1 │└■ │┌cât timp n≠0 și k≠0 execută ││ c←n%2; n←[n/10] ││┌dacă c≠0 atunci │││ nr←nr+(n%10)*p; p←p*10 │││altfel │││ k←k-1 ││└■ │└■ └■ scrie nr ``

    Condiția de oprire n=0 sau k=0 se neagă și devine condiția de continuare: n≠0 și k≠0.

    Prima prelucrare se scoate înaintea buclei, fiindcă repetă execută corpul cel puțin o dată, pe când o structură cu test inițial poate să nu-l execute deloc. Aici chiar contează: pentru n=0 și k nenul, algoritmul dat intră o dată în corp și afișează 0, iar unul care ar începe direct cu cât timp n≠0 ar sări peste tot și ar afișa tot 0, dar fără să fi prelucrat nimic — la alte valori diferența s-ar vedea.

  5. Exercițiul 2 6p Backtracking

    Utilizând metoda backtracking se generează toate numerele din intervalul [10^4,10^5), cu cifrele în ordine strict crescătoare. Primele trei numere generate sunt:

    1. 12345
    2. 12346
    3. 12347

    Scrieți, în ordinea obținerii, ultimele trei numere generate care au prima cifră 4.

    Vezi rezolvarea

    Răspunsul din barem: 45689, 45789, 46789

    Numerele au cinci cifre strict crescătoare și încep cu 4, deci celelalte patru cifre se aleg, tot crescător, dintre 5, 6, 7, 8, 9. Sunt cinci astfel de alegeri, generate în ordine crescătoare:

    45678, 45679, 45689, 45789, 46789

    Ultimele trei sunt 45689, 45789, 46789.

    Backtracking-ul le produce exact în această ordine fiindcă încearcă mereu întâi cifra cea mai mică posibilă pe poziția curentă și abia apoi o crește.

  6. Exercițiul 3 6p Șiruri de caractere

    Variabila s memorează un șir cu cel mult 20 de caractere, iar celelalte variabile sunt de tip întreg.

    Scrieți ce se afișează pe ecran în urma executării secvenței alăturate.

    k='a'-'A';
    strcpy(s,"A realizat tot");
    for(i=strlen(s)-1;i>=0;i--)
      if(strchr("aeiou",s[i])!=NULL)
      {  s[i]=s[i]-k;
         cout<<s[i];  |  printf("%c",s[i]);
      }
    Vezi rezolvarea

    Răspunsul din barem: OAIAE

    k primește 'a'-'A', adică 32 — distanța dintre o literă mică și corespondenta ei mare în codul ASCII. Deci s[i]-k transformă o literă mică în literă mare.

    Parcurgerea merge de la coadă spre început, iar strchr("aeiou",s[i]) e nenul doar pentru vocalele mici. Textul e A realizat tot:

    pozițieliterăce se afișează
    12oO
    8aA
    6iI
    4aA
    3eE

    Se afișează deci OAIAE. A-ul de la început nu intră în calcul: e literă mare, iar strchr caută printre cele mici.

Subiectul al III-lea

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

    Subprogramul prime are trei parametri:

    • n, prin care primește un număr natural (n∈[4,10^9]);

    • x și y, prin care furnizează cele mai mari două numere prime din intervalul [1,n), x<y.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă n=49, în urma apelului x=43, y=47.

    Vezi rezolvarea
    int estePrim(int v)
    {
        if (v < 2)
            return 0;
        for (int d = 2; d * d <= v; d++)
            if (v % d == 0)
                return 0;
        return 1;
    }
    
    void prime(int n, int &x, int &y)
    {
        int v = n - 1;
        while (estePrim(v) == 0)
            v--;
        y = v;
        v--;
        while (estePrim(v) == 0)
            v--;
        x = v;
    }
  2. Exercițiul 2 10p Tablouri bidimensionale

    Scrieți un program C/C++ care citește de la tastatură două numere naturale din intervalul [2,10^2], m și n, și construiește în memorie un tablou bidimensional cu m linii și n coloane, cu proprietatea că parcurgându-l linie cu linie de sus în jos și fiecare linie de la stânga la dreapta, se obține șirul primelor m*n pătrate perfecte pare, ordonat strict descrescător, ca în exemplu.

    Elementele tabloului obținut se afișează pe ecran, fiecare linie a tabloului pe câte o linie a ecranului, valorile de pe aceeași linie fiind separate prin câte un spațiu.

    Exemplu: pentru m=2, n=3 se obține tabloul alăturat.

    1006436
    1640
    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m, n;
        cin >> m >> n;
        long long v = 2LL * (m * n - 1);
        for (int i = 0; i < m; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cout << v * v;
                if (j < n - 1)
                    cout << ' ';
                v = v - 2;
            }
            cout << '\n';
        }
        return 0;
    }
  3. Exercițiul 3.a 2p Algoritmi eficienți

    Fișierul cheltuieli.in are cel mult 10^6 linii, fiecare linie conținând câte trei numere naturale din intervalul [1,10^2], reprezentând, în această ordine, date despre câte o achiziție: tipul produsului cumpărat, numărul de produse de acest tip cumpărate, respectiv prețul unui astfel de produs la acel moment. Numerele aflate pe aceeași linie sunt separate prin câte un spațiu.

    Se cere să se afișeze pe ecran cea mai mare sumă cheltuită pentru toate produsele de același tip, precum și numărul de tipuri de produse pentru care s-a obținut această sumă.

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

    Exemplu: dacă fișierul cheltuieli.in are conținutul alăturat, se afișează pe ecran: 26 2 (s-a cheltuit suma maximă 26 pentru produsele de tipul 1 și 4: 26=16·1+5·2=1·10+2·8)

    4110
    1161
    428
    215
    152

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

    Vezi rezolvarea

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

    Fișierul se citește o singură dată, linie cu linie, fără să fie păstrat.

    Tipurile de produse sunt cel mult 100, așa că folosesc un vector suma cu 100 de poziții, câte una pentru fiecare tip. La fiecare achiziție citită — tip, număr, preț — adun număr·preț la poziția tipului respectiv.

    După ce s-a terminat fișierul, parcurg vectorul o dată: rețin cea mai mare sumă și număr de câte ori apare. Afișez cele două valori.

    Pe exemplul din enunț, tipul 1 adună 16·1 + 5·2 = 26, tipul 4 adună 1·10 + 2·8 = 26, iar tipul 2 doar 1·5 = 5. Maximul e 26 și se obține la două tipuri, deci se afișează 26 2.

    De ce e eficient: fiecare linie se citește și se prelucrează o singură dată, deci timpul e O(n) pentru cele cel mult 10⁶ linii, plus o trecere fixă prin cele 100 de poziții. Memoria nu depinde de mărimea fișierului: vectorul are mereu 100 de poziții, iar achizițiile nu se păstrează.

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

    Fișierul cheltuieli.in are cel mult 10^6 linii, fiecare linie conținând câte trei numere naturale din intervalul [1,10^2], reprezentând, în această ordine, date despre câte o achiziție: tipul produsului cumpărat, numărul de produse de acest tip cumpărate, respectiv prețul unui astfel de produs la acel moment. Numerele aflate pe aceeași linie sunt separate prin câte un spațiu.

    Se cere să se afișeze pe ecran cea mai mare sumă cheltuită pentru toate produsele de același tip, precum și numărul de tipuri de produse pentru care s-a obținut această sumă.

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

    Exemplu: dacă fișierul cheltuieli.in are conținutul alăturat, se afișează pe ecran: 26 2 (s-a cheltuit suma maximă 26 pentru produsele de tipul 1 și 4: 26=16·1+5·2=1·10+2·8)

    4110
    1161
    428
    215
    152

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream f("cheltuieli.in");
        long long suma[101] = {0};
        int tip, numar, pret;
        while (f >> tip >> numar >> pret)
            suma[tip] = suma[tip] + (long long) numar * pret;
        f.close();
        long long maxim = 0;
        int cate = 0;
        for (int t = 1; t <= 100; t++)
            if (suma[t] > maxim)
            {
                maxim = suma[t];
                cate = 1;
            }
            else if (suma[t] == maxim && maxim > 0)
                cate++;
        cout << maxim << " " << cate;
        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?