Sari la conținut

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

Modelul din 2023 trece prin expresii cu % și /, recursivitate, backtracking, grafuri orientate și neorientate, structuri, ș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: valorile pentru care x%20==x/23, un subprogram recursiv care afișează mijlocul a două numere care se apropie, o problemă de backtracking cu torturi din trei straturi de cremă, componenta tare conexă a unui vârf într-un graf orientat și câte muchii trebuie eliminate dintr-un graf cu un ciclu eulerian și unul hamiltonian ca să rămână un arbore.

Subiectul al II-lea (40p): Un algoritm în pseudocod care adună numerele dintr-un interval divizibile cu exact unul dintre m și n, o secvență care afișează numele a trei echipe în ordinea descrescătoare a rezultatelor, memorate într-un tablou de structuri echipa, și o secvență cu strchr și strcpy care obține un cuvânt nou din plantau fistic.

Subiectul al III-lea (30p): Un subprogram cu cifre (DoiTrei, care verifică dacă toate cifrele sunt 2 sau 3), o problemă cu matrice despre caruselele care nu au nicio latură comună cu un tobogan și o problemă de eficiență care verifică dacă un șir citit din fișierul bac.txt este „p-ordonat”.

⚠️ La ce să fii atent

  • La I.2: Afișarea se face înainte de verificarea m<=n, deci și ultimul apel, cel în care m>n, afișează o valoare. La f(21,27) se afișează 24, 23, 23 și 22.
  • La I.5: Lungimea ciclului eulerian este numărul de muchii (11), iar a celui hamiltonian este numărul de noduri (7). Un arbore cu 7 noduri are 6 muchii, deci elimini 11 - 6 = 5 muchii.
  • La II.1.a: Numerele care se împart și la m, și la n se adună, apoi se scad imediat, deci nu contează. Pentru 4, 3, 11 și 25 rămân 15, 16, 18, 20 și 21, cu suma 90.
  • La II.3: p este poziția spațiului, 7, iar cout<<p<<s2 afișează cele două valori lipite, fără spațiu între ele: 7fantastic.
  • La III.3: Nu compara fiecare x din prima jumătate cu fiecare y din a doua. E de ajuns ca cel mai mic număr par din prima jumătate să fie mai mare decât cel mai mare impar din a doua, iar cel mai mic impar din prima jumătate să fie mai mare decât cel mai mare par din a doua.

Subiectul I

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

    Indicați două valori pe care le poate avea variabila întreagă x, astfel încât, pentru fiecare dintre acestea, expresia C/C++ alăturată să aibă valoarea 1.

    x%20==x/23
    • a){20, 40}
    • b){20,41}
    • c){40, 62}
    • d){60, 83}
    Vezi rezolvarea

    Răspuns corect: b) {20,41}

    Pentru 20: 20%20 este 0, iar 20/23 este 0, deci egalitatea este adevărată. Pentru 41: 41%20 este 1, iar 41/23 este tot 1, deci și ea este adevărată.

    În a) și c), pentru 40 se obțin 0 și 1, iar în d), pentru 60 se obțin 0 și 2.

  2. Exercițiul 2 4p Recursivitate

    Subprogramul f este definit alăturat.

    Indicați un apel în urma căruia în șirul afișat există două valori egale cu 23.

    void f(int m, int n)
    { cout<<(m+n)/2<<' '; | printf("%d ",(m+n)/2);
      if(m<=n) f(m+1,n-2);
    }
    • a)f(20,23);
    • b)f(20,26);
    • c)f(21,25);
    • d)f(21,27);
    Vezi rezolvarea

    Răspuns corect: d) f(21,27);

    Fiecare apel afișează (m+n)/2 și continuă cu m mai mare cu 1 și n mai mic cu 2, cât timp m≤n.

    f(21,27) afișează 24, apoi f(22,25) afișează 23, f(23,23) afișează tot 23, iar f(24,21) afișează 22 și se oprește: două valori egale cu 23. Celelalte apeluri afișează valoarea 23 cel mult o dată.

  3. Exercițiul 3 4p Backtracking

    Utilizând metoda backtracking, se generează toate torturile formate din trei straturi de tipuri distincte de cremă din mulțimea {castane, mousse, frișcă, șerbet, ganache}. Ultimul strat este de frișcă sau de ganache, iar aceste tipuri de cremă nu pot apărea pe primele două straturi. Două torturi cu straturi din aceleași tipuri de cremă sunt diferite dacă acestea sunt dispuse în altă ordine. Primele patru soluții generate sunt, în această ordine:

    1. (castane, mousse, frișcă)
    2. (castane, mousse, ganache)
    3. (castane, șerbet, frișcă)
    4. (castane, șerbet, ganache)

    Indicați a șasea soluție generată.

    • a)(mousse, castane, ganache)
    • b)(mousse, șerbet, frișcă)
    • c)(șerbet, castane, frișcă)
    • d)(șerbet, mousse, ganache)
    Vezi rezolvarea

    Răspuns corect: a) (mousse, castane, ganache)

    Pe primele două straturi pot fi doar castane, mousse sau șerbet, iar ultimul strat este frișcă sau ganache; tipurile se încearcă în ordinea din mulțime.

    Primele patru torturi încep cu castane. După (castane, șerbet, ganache) nu mai există alt al doilea strat pentru castane, deci primul strat devine mousse, iar al doilea, cel mai mic posibil, castane: al cincilea tort este (mousse, castane, frișcă), iar al șaselea (mousse, castane, ganache).

  4. Exercițiul 4 4p Grafuri orientate

    Un graf orientat cu 8 vârfuri, numerotate de la 1 la 8, are arcele:

    1. (1,2)
    2. (1,3)
    3. (2,3)
    4. (2,6)
    5. (3,2)
    6. (3,4)
    7. (3,6)
    8. (4,5)
    9. (4,7)
    10. (6,1)
    11. (7,4)

    Indicați numărul total de vârfuri ale componentei tare conexe din care face parte vârful 3.

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

    Răspuns corect: c) 4

    Vârfurile 1, 2, 3 și 6 sunt în aceeași componentă tare conexă: 1→3→2→6→1 este un circuit care le cuprinde pe toate.

    Din 3 se ajunge și în 4, 5 și 7, dar din acestea nu se mai poate reveni în 3: 4 și 7 formează o componentă separată, iar din 5 nu pleacă niciun arc. Componenta lui 3 are 4 vârfuri.

  5. Exercițiul 5 4p Grafuri neorientate

    Un graf neorientat admite un ciclu eulerian, de lungime 11, precum și un ciclu hamiltonian, de lungime 7.

    Indicați numărul de muchii care pot fi eliminate din graf, astfel încât graful parțial obținut să fie arbore.

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

    Răspuns corect: d) 5

    Ciclul eulerian trece o singură dată prin fiecare muchie, deci graful are 11 muchii. Ciclul hamiltonian trece o singură dată prin fiecare nod, deci graful are 7 noduri.

    Un arbore cu 7 noduri are 6 muchii, iar un ciclu hamiltonian arată că graful e conex, deci se poate păstra un astfel de arbore. Se elimină 11 − 6 = 5 muchii.

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.

    Scrieți valoarea afișată dacă se citesc, în această ordine, numerele 4, 3, 11 și 25.

     citește m,n,p,q
        (numere naturale nenule, p≤q)
     s←0
    ┌pentru x←p,q execută
    │┌dacă x%m=0 sau x%n=0 atunci
    ││ s←s+x
    │└■
    │┌dacă x%m=0 și x%n=0 atunci
    ││ s←s-x
    │└■
    └■
     scrie s
    Vezi rezolvarea

    Răspunsul din barem: 90

    Numerele care se împart la m sau la n se adună, iar cele care se împart la amândouă se scad imediat înapoi: se adună, de fapt, numerele dintre p și q care se împart la exact unul dintre m și n. Pentru m=4, n=3, între 11 și 25: multiplii lui 3 sunt 12, 15, 18, 21, 24, ai lui 4 sunt 12, 16, 20, 24, iar 12 și 24 se împart la amândouă. Rămân 15 + 18 + 21 + 16 + 20 = 90.

  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.

    Dacă pentru m, n și p se citesc numerele 10, 15, respectiv 2, scrieți două numere care pot fi citite pentru q astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea, valoarea afișată să fie 250.

    Vezi rezolvarea

    Exemplu: 70 74

    Pentru m=10, n=15 și p=2 se adună numerele care se împart la exact unul dintre 10 și 15, de la 2 la q. Numerele adunate sunt 10, 15, 20, 40, 45, 50, 70, 75, … (30 și 60 se împart la amândouă și nu se adună), iar sumele parțiale sunt 10, 25, 45, 85, 130, 180 și 250 după 70. Următorul număr adunat este 75, deci suma este 250 pentru orice q de la 70 la 74.

  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.

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

    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m, n, p, q, s = 0, x;
        cin >> m >> n >> p >> q;
        for (x = p; x <= q; x++)
        {
            if (x % m == 0 || x % n == 0) s = s + x;
            if (x % m == 0 && x % n == 0) s = s - x;
        }
        cout << s;
        return 0;
    }

    pentru x←p,q execută devine for (x = p; x <= q; x++), sau devine ||, iar și devine &&.

  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.

    Scrieți în pseudocod un algoritm, echivalent cu cel dat, înlocuind structura pentru...execută cu o structură repetitivă cu test inițial.

    Vezi rezolvarea
    citește m,n,p,q (numere naturale nenule, p≤q)
    s←0
    x←p
    ┌cât timp x≤q execută
    │┌dacă x%m=0 sau x%n=0 atunci
    ││ s←s+x
    │└■
    │┌dacă x%m=0 și x%n=0 atunci
    ││ s←s-x
    │└■
    │ x←x+1
    └■
    scrie s

    Cu cât timp, contorul se gestionează explicit: x primește valoarea inițială p înainte de buclă, se continuă cât timp x≤q, iar x←x+1 se face la sfârșitul corpului.

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

    Variabila c, declarată alăturat, permite accesul la datele fiecăreia dintre cele trei echipe participante la ultima etapă a unui concurs: numele și rezultatul (număr natural din intervalul [0,100]); cele trei echipe au rezultate distincte.

    Scrieți o secvență de instrucțiuni în urma executării căreia să se afișeze pe ecran, separate prin câte un spațiu, numele celor trei echipe, în ordinea descrescătoare a rezultatelor obținute.

    struct echipa
    {  char nume[50];
       int rezultat;
    };
    struct echipa c[3];
    Vezi rezolvarea
    int i, j, ord[3] = {0, 1, 2}, aux;
    for (i = 0; i < 2; i++)
        for (j = i + 1; j < 3; j++)
            if (c[ord[i]].rezultat < c[ord[j]].rezultat)
            {
                aux = ord[i];
                ord[i] = ord[j];
                ord[j] = aux;
            }
    cout << c[ord[0]].nume << ' ' << c[ord[1]].nume << ' ' << c[ord[2]].nume;

    Tabloul ord ține pozițiile echipelor și se ordonează după rezultate, descrescător, fără să se mute înregistrările propriu-zise. La final se afișează numele echipelor în această ordine. Se poate la fel de bine interschimba direct elementele tabloului c.

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

    Variabila p este de tip întreg, iar variabilele s1 și s2 permit memorarea câte unui șir de cel mult 30 de caractere.

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

    strcpy(s1, "plantau fistic");
    p=strchr(s1,' ')-s1;
    strcpy(s2,s1+p+1); strcpy(s1+p-1,s2+2);
    strcpy(s2+1,s1+2);
    cout<<p<<s2; | printf("%d%s",p,s2);
    Vezi rezolvarea

    Răspunsul din barem: 7fantastic

    strchr(s1,' ') indică spațiul, aflat pe poziția 7, deci p = 7, iar s2 devine "fistic", tot ce urmează după spațiu. strcpy(s1+p-1, s2+2) scrie de la poziția 6 a lui s1 șirul "stic": s1 devine "plantastic". strcpy(s2+1, s1+2) scrie de la poziția 1 a lui s2 șirul "antastic": s2 devine "fantastic". Se afișează 7 urmat imediat de fantastic.

Subiectul al III-lea

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

    Subprogramul DoiTrei are un parametru, n, prin care primește un număr natural (n∈[0,10^9]). Subprogramul returnează valoarea 1 dacă toate cifrele lui n sunt din mulțimea {2,3} sau valoarea 0 în caz contrar.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă n=22323 sau n=3, atunci subprogramul returnează 1, iar dacă n=2023 atunci subprogramul returnează 0.

    Vezi rezolvarea
    int DoiTrei(int n)
    {
        do
        {
            if (n % 10 != 2 && n % 10 != 3) return 0;
            n = n / 10;
        } while (n != 0);
        return 1;
    }

    Cifrele se iau pe rând, de la dreapta. La prima cifră diferită de 2 și de 3 se returnează 0; dacă toate trec verificarea, se returnează 1. Structura do…while verifică și cifra lui n=0, care nu este din mulțime.

  2. Exercițiul 2 10p Tablouri bidimensionale

    Suprafața unui loc de joacă pentru copii este împărțită în n∙n zone de formă pătrată dispuse pe n rânduri și n coloane, numerotate de la 1 la n, în fiecare zonă fiind plasat un tobogan, un leagăn, un balansoar sau un carusel. Zonelor li se atribuie câte un cod, în funcție de destinație: codul 0 pentru tobogan, codul 1 pentru leagăn, codul 2 pentru balansoar și codul 3 pentru carusel.

    Scrieți un program C/C++ care citește de la tastatură un număr natural, n (n∈[1,10^2]), și cele n∙n elemente ale unui tablou bidimensional, reprezentând codurile corespunzătoare zonelor din locul de joacă, în ordinea parcurgerii lor rând după rând, și a fiecărui rând de la stânga la dreapta.

    Programul determină zonele destinate plasării câte unui carusel, care NU au nicio latură comună cu o zonă cu tobogan și, pentru fiecare dintre acestea, afișează pe ecran numărul de ordine al rândului pe care se află. Numerele afișate sunt separate prin câte un spațiu, iar dacă nu există nicio astfel de zonă, se afișează pe ecran mesajul nu exista.

    Exemplu: pentru n=6 și tabloul alăturat se afișează pe ecran, nu neapărat în această ordine, numerele: 2 3 3 6.

    Tablou cu 6 linii și 6 coloane. Pe linii: 2 0 0 2 1 3; 3 1 3 1 2 0; 2 1 3 3 2 0; 0 2 1 3 1 1; 3 1 2 0 0 2; 0 0 0 2 1 3. Unele zone sunt colorate cu gri, iar patru zone cu valoarea 3 au chenar îngroșat: linia 2 coloana 1, linia 3 coloanele 3 și 4, linia 6 coloana 6.
    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, a[102][102], i, j, gasit = 0;
        cin >> n;
        for (i = 0; i <= n + 1; i++)
            for (j = 0; j <= n + 1; j++)
                a[i][j] = 1;
        for (i = 1; i <= n; i++)
            for (j = 1; j <= n; j++)
                cin >> a[i][j];
        for (i = 1; i <= n; i++)
            for (j = 1; j <= n; j++)
                if (a[i][j] == 3 && a[i - 1][j] != 0 && a[i + 1][j] != 0 && a[i][j - 1] != 0 && a[i][j + 1] != 0)
                {
                    cout << i << ' ';
                    gasit = 1;
                }
        if (gasit == 0) cout << "nu exista";
        return 0;
    }

    Tabloul are o bordură de zone fictive, cu codul 1 (nu tobogan), în jurul suprafeței: așa, și zonele de pe margini sau din colțuri au patru vecini de verificat, fără cazuri separate. Un carusel se afișează dacă niciunul dintre cei patru vecini nu este tobogan. Rândurile se parcurg de sus în jos, deci numerele ies în ordine crescătoare, iar enunțul acceptă orice ordine.

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

    O pereche de numere naturale (x,y) se numește p-ordonată dacă x și y au paritate diferită, cu x>y, sau dacă x și y au aceeași paritate.

    Exemplu: (7,4), (8,7), (7,9) sunt perechi p-ordonate, dar (7,8), (8,9) nu sunt perechi p-ordonate. Un șir, format din 2∙n numere naturale, se numește p-ordonat dacă perechile de forma (x,y) sunt p-ordonate, pentru orice x, dintre primii n termeni ai șirului, și orice y, dintre ultimii n termeni ai șirului.

    Fișierul bac.txt conține numere naturale din intervalul [0,10^6]: pe prima linie un număr nenul, n, iar pe a doua linie un șir de 2∙n numere, separate prin câte un spațiu. Se cere să se afișeze pe ecran mesajul DA, în cazul în care șirul aflat în fișier este p-ordonat, sau mesajul NU, în caz contrar. Proiectați un algoritm eficient din punctul de vedere al timpului de executare și al memoriei utilizate.

    Exemplu: dacă fișierul are unul dintre conținuturile de mai jos, se afișează pe ecran mesajul DA.

    5
    22 37 21 8 15 2 3 14 4 5
    
    sau
    
    5
    22 36 20 8 14 44 42 4 2 5

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

    Vezi rezolvarea

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

    O pereche (x, y) nu este p-ordonată doar dacă x și y au parități diferite și x < y. Șirul este p-ordonat exact când nu există o astfel de pereche între un x din prima jumătate și un y din a doua.

    Pentru un x par, cel mai „periculos” y este cel mai mare impar din a doua jumătate; pentru un x impar, cel mai mare par. Deci șirul este p-ordonat exact când cel mai mic par din prima jumătate este mai mare decât cel mai mare impar din a doua și cel mai mic impar din prima jumătate este mai mare decât cel mai mare par din a doua.

    Se citesc primii n termeni, reținând minimul par și minimul impar (pornite de la 1000001), apoi ultimii n termeni, reținând maximul par și maximul impar (pornite de la -1). La final se fac cele două comparații și se afișează DA sau NU.

    Eficiență: fiecare număr se prelucrează o singură dată, în timp constant, fără să fie memorat, deci timpul este liniar, iar memoria constantă.

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

    Același algoritm ca la 3.a.

    Exemplu: (7,4), (8,7), (7,9) sunt perechi p-ordonate, dar (7,8), (8,9) nu sunt perechi p-ordonate. Un șir, format din 2∙n numere naturale, se numește p-ordonat dacă perechile de forma (x,y) sunt p-ordonate, pentru orice x, dintre primii n termeni ai șirului, și orice y, dintre ultimii n termeni ai șirului.

    Fișierul bac.txt conține numere naturale din intervalul [0,10^6]: pe prima linie un număr nenul, n, iar pe a doua linie un șir de 2∙n numere, separate prin câte un spațiu. Se cere să se afișeze pe ecran mesajul DA, în cazul în care șirul aflat în fișier este p-ordonat, sau mesajul NU, în caz contrar. Proiectați un algoritm eficient din punctul de vedere al timpului de executare și al memoriei utilizate.

    Exemplu: dacă fișierul are unul dintre conținuturile de mai jos, se afișează pe ecran mesajul DA.

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream fin("bac.txt");
        int n, i, x, p1 = 1000001, i1 = 1000001, p2 = -1, i2 = -1;
        fin >> n;
        for (i = 0; i < n; i++)
        {
            fin >> x;
            if (x % 2 == 0)
            {
                if (x < p1) p1 = x;
            }
            else if (x < i1) i1 = x;
        }
        for (i = 0; i < n; i++)
        {
            fin >> x;
            if (x % 2 == 0)
            {
                if (x > p2) p2 = x;
            }
            else if (x > i2) i2 = x;
        }
        fin.close();
        if (p1 > i2 && i1 > p2) cout << "DA";
        else cout << "NU";
        return 0;
    }

    Programul face pașii de la 3.a. Dacă o jumătate nu are numere pare (sau impare), minimul rămâne 1000001 și maximul -1, iar comparațiile corespunzătoare sunt adevărate de la sine, cum trebuie: nu există perechi de acel tip.

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?