Sari la conținut

Bac informatică 2021 Varianta 4, rezolvată

Varianta 4 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 Varianta 4 din 2021

Varianta 4 din 2021 trece prin expresii aritmetice, recursivitate, backtracking, arbori și grafuri, șiruri de caractere, structuri imbricate, matrice și fișiere. Este o variantă echilibrată, bună pentru exersat calculul atent și lucrul cu cifrele.

Subiectul I (20p): 5 grile: scrierea în C/C++ a unei fracții cu numărător și numitor compuși, un subprogram recursiv care adună cifrele impare ale unui număr, o problemă de backtracking cu numere din cifre distincte cu suma 6, numărul de cicluri elementare după ce adaugi o muchie unui arbore și numărul de zerouri din matricea de adiacență a unui graf cu 21 de noduri.

Subiectul al II-lea (40p): Un algoritm în pseudocod care afișează numerele divizibile cu exact unul dintre x și y, o secvență care face interschimbări în șirul ROMANIA și o secvență care inițializează câmpurile primului angajat dintr-un tablou de structuri angajat, cu un câmp dp care este tot o structură.

Subiectul al III-lea (30p): Un subprogram (cuburi) care afișează descrescător primele n cuburi perfecte nenule, o problemă cu o matrice care are pe diagonala principală multiplii lui k și pe fiecare linie numere consecutive, și o problemă de eficiență cu „perechi asemenea” din două șiruri citite din fișierul numere.in.

⚠️ La ce să fii atent

  • La I.1: Bara de fracție ține loc de paranteze, deci în C/C++ trebuie să le scrii pe toate. a/b+2 nu este același lucru cu a/(b+2): răspunsul este ((x+y)/5+(x-y)/2)/(x+2).
  • La I.3: După ce găsește o soluție, algoritmul încearcă să o prelungească cu cifra 0, care nu schimbă suma. De aceea, după 123 urmează 1230, a șasea soluție.
  • La I.5: Ultima cifră 1 apare la trei noduri (1, 11 și 21), iar fiecare altă ultimă cifră la câte două. Pe diagonală sunt doar zerouri, pentru că muchiile leagă noduri distincte. Sunt 24 de valori de 1, deci 21² - 24 de zerouri.
  • La II.1.a: Condiția cere ca i să se împartă la exact unul dintre x și y. Pentru 15, 3 și 4, numărul 12 se împarte la amândouă, deci nu se afișează: 3 4 6 8 9 15.
  • La III.3: Ultimele două cifre pot fi în orice ordine, deci 20 și 402 formează o pereche asemenea. Nu compara fiecare număr din A cu fiecare din B: numără într-un vector cu 100 de poziții câte numere au fiecare pereche de ultime cifre.

Subiectul I

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

    Variabilele x și y sunt de tip real (x≠-2).

    Indicați o expresie C/C++ corespunzătoare expresiei aritmetice alăturate.

    Figura din enunț
    • a)(x+y/5+x-y/2)/x+2
    • b)(x+y)/5+(x-y)/2/(x+2)
    • c)((x+y)/5+(x-y)/2)/x+2
    • d)((x+y)/5+(x-y)/2)/(x+2)
    Vezi rezolvarea

    Răspuns corect: d) ((x+y)/5+(x-y)/2)/(x+2)

    Fracția din enunț are la numărător suma (x+y)/5 + (x-y)/2, iar la numitor x+2. Bara mare de fracție ține loc de paranteze în amândouă părțile, deci în C/C++ ele trebuie scrise explicit:

    ((x+y)/5+(x-y)/2)/(x+2) — varianta d).

    Ce greșesc celelalte:

    • a) pierde parantezele de la x+y și x-y, deci împarte doar pe y la 5;
    • b) leagă /(x+2) doar de al doilea termen, nu de toată suma;
    • c) împarte suma doar la x, iar +2 rămâne pe dinafară — a/b+2 nu e același lucru cu a/(b+2).
  2. Exercițiul 2 4p Recursivitate

    Subprogramul f este definit alăturat.

    Indicați valoarea lui f(1234).

    int f(int n)
    { if (n!=0)
       return (n%2)*(n%10)+f(n/10);
      return 0;
    }
    • a)0
    • b)4
    • c)6
    • d)10
    Vezi rezolvarea

    Răspuns corect: b) 4

    La fiecare apel se adună (n%2)·(n%10): paritatea numărului curent înmulțită cu ultima lui cifră. Când numărul e par, n%2 e 0 și termenul se pierde.

    nn%2n%10se adună
    1234040
    123133
    12020
    1111

    Suma este `0+3+0+1 = 4`, varianta b).

    Cu alte cuvinte, se adună ultima cifră doar atunci când numărul rămas e impar — adică exact când acea ultimă cifră e ea însăși impară.

  3. Exercițiul 3 4p Backtracking

    Utilizând metoda backtracking se generează toate numerele formate din cifre distincte, cifre a căror sumă să fie 6. Primele patru soluții generate sunt, în această ordine: 1023, 1032, 105 și 1203.

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

    • a)1230
    • b)132
    • c)123
    • d)15
    Vezi rezolvarea

    Răspuns corect: a) 1230

    Numerele se construiesc cifră cu cifră, cu cifre distincte, iar o valoare e raportată de îndată ce suma cifrelor ajunge la 6. Important: după ce a găsit o soluție, algoritmul încearcă să o prelungească — mai poate adăuga cifra 0, care nu schimbă suma.

    nr.număr
    11023
    21032
    31051050 nu se poate: 0 e deja folosit
    41203
    5123suma e deja 6
    61230prelungirea lui 123 cu un 0

    Primele patru coincid cu cele din enunț, iar a șasea este 1230 — varianta a).

    Variantele c) și b) ar veni mai devreme, respectiv mai târziu, în ordinea generării, iar 15 are suma cifrelor 6, dar ar apărea abia după toate numerele care încep cu 12 și 13.

  4. Exercițiul 4 4p Arbori

    Unui arbore cu 10 noduri i se adaugă o muchie, cu extremitățile în două dintre nodurile sale.

    Indicați numărul ciclurilor elementare pe care le conține graful obținut.

    • a)0
    • b)1
    • c)9
    • d)10
    Vezi rezolvarea

    Răspuns corect: b) 1

    Un arbore este conex și fără cicluri, iar între oricare două noduri ale lui există exact un singur lanț elementar.

    Adăugând o muchie între două noduri, ea se închide cu lanțul care exista deja între ele și formează un singur ciclu elementar — varianta b).

    Nu pot apărea mai multe: orice ciclu ar trebui să folosească muchia nouă (fără ea graful e arbore, deci fără cicluri), iar drumul care o completează e unic.

  5. Exercițiul 5 4p Grafuri neorientate

    Un graf neorientat are 21 de noduri, numerotate de la 1 la 21; pentru oricare două noduri distincte ale sale, numerotate cu i, respectiv cu j, există muchia [i,j] dacă și numai dacă ultima cifră a lui i este egală cu ultima cifră a lui j.

    Indicați numărul valorilor nule din matricea de adiacență a grafului.

    • a)2·21-10^2
    • b)21^2-11
    • c)21^2-2·12
    • d)2·21^2-13
    Vezi rezolvarea

    Răspuns corect: c) 21^2-2·12

    Două noduri sunt legate dacă au aceeași ultimă cifră, deci nodurile se grupează după ultima cifră:

    • ultima cifră 1: 1, 11, 21 — trei noduri
    • ultima cifră 0: 10, 20 — două noduri
    • ultimele cifre 2, 3, …, 9: câte două noduri (de exemplu 2 și 12)

    Matricea de adiacență are 21² = 441 de poziții. Valorile de 1 apar doar între noduri din aceeași grupă și distincte:

    • grupa de trei dă 3·2 = 6 valori de 1
    • fiecare dintre cele nouă grupe de câte două dă 2·1 = 2, deci 18 cu totul

    În total 24 de valori de 1, iar restul sunt nule: `21² - 24 = 21² - 2·12 = 417` — varianta c).

    Diagonala e formată din zerouri: enunțul cere noduri distincte, deci un nod nu e legat de el însuși.

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 ce se afișează în urma executării algoritmului dacă se citesc, în această ordine, numerele 15, 3, 4.

    citește n,x,y
      (numere naturale nenule, x≤n, y≤n)
     ok←0
    ┌pentru i←1,n execută
    │┌dacă (i%x=0 și i%y≠0) sau
    ││     (i%x≠0 și i%y=0) atunci
    ││ scrie i, ' '
    ││ ok←1
    │└■
    └■
    ┌dacă ok=0 atunci scrie 0
    └■
    Vezi rezolvarea

    Răspunsul din barem: 3 4 6 8 9 15

    Condiția e adevărată când i se împarte exact la exact unul dintre x și y — la 3 sau la 4, dar nu la amândouă.

    ise împarte la 3se împarte la 4se scrie
    3, 6, 9, 15danuda
    4, 8nudada
    12dadanu

    Restul numerelor până la 15 nu se împart la niciunul, deci nu intră.

    Se afișează 3 4 6 8 9 15. Numărul 12 e singurul care cade pentru că îndeplinește amândouă condițiile — exact ce exclude „sau” din enunț, care e de fapt un *sau exclusiv*, scris cu două condiții negate.

  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.

    Scrieți două seturi distincte de date de intrare, astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea să se afișeze valoarea 0.

    Vezi rezolvarea

    5 2 2 și 1 1 1

    Se afișează 0 doar când niciun i din 1 până la n nu se împarte exact la unul singur dintre x și y.

    Cel mai simplu e să iei x egal cu y: atunci cele două condiții sunt tot timpul la fel — ori se împart amândouă, ori niciuna — deci sau-ul exclusiv e mereu fals, iar ok rămâne 0.

    • n=5, x=2, y=2: multiplii lui 2 se împart la amândouă, restul la niciuna.
    • n=1, x=1, y=1: singurul i e 1, care se împarte la amândouă.

    Amândouă respectă și condiția din enunț, x≤n și y≤n.

  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 n, x, y, ok = 0;
        cin >> n >> x >> y;
        for (int i = 1; i <= n; i++)
            if ((i % x == 0 && i % y != 0) || (i % x != 0 && i % y == 0))
            {
                cout << i << ' ';
                ok = 1;
            }
        if (ok == 0)
            cout << 0;
        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.

    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 n,x,y (numere naturale nenule, x≤n, y≤n) ok←0 i←1 ┌cât timp i≤n execută │┌dacă (i%x=0 și i%y≠0) sau ││ (i%x≠0 și i%y=0) atunci ││ scrie i, ' ' ││ ok←1 │└■ │ i←i+1 └■ ┌dacă ok=0 atunci scrie 0 └■ ``

    pentru i←1,n ascunde trei lucruri: pornirea contorului de la 1, verificarea i≤n și creșterea cu 1 la fiecare pas. Cu cât timp toate trei se scriu pe față — inițializarea înainte, condiția în cap, i←i+1 la sfârșitul corpului.

    Creșterea trebuie să fie ultima instrucțiune din corp, nu prima: altfel primul i prelucrat ar fi 2, nu 1.

  5. Exercițiul 2 6p Șiruri de caractere

    Variabila s poate memora un șir de cel mult 20 de caractere, variabila aux este de tip char, iar celelalte variabile sunt de tip întreg.

    Scrieți șirul memorat prin intermediul variabilei s în urma executării secvenței alăturate.

    strcpy(s,"ROMANIA");
    i=strlen(s)-1;
    for(j=3;j>=0;j--)
    { aux=s[i]; s[i]=s[i-j]; s[i-j]=aux;
      i=i-j;
    }
    Vezi rezolvarea

    Răspunsul din barem: ARMONIA

    i pornește de la ultima poziție, 6, iar bucla interschimbă s[i] cu s[i-j], apoi mută i pe poziția i-j.

    jse schimbășirul devinei
    3poziția 6 cu 3 (A cu A)ROMANIA3
    2poziția 3 cu 1 (A cu O)RAMONIA1
    1poziția 1 cu 0 (A cu R)ARMONIA0
    0poziția 0 cu ea însășiARMONIA0

    Primul pas nu schimbă nimic vizibil, fiindcă amândouă literele sunt A, iar ultimul pas interschimbă o poziție cu ea însăși. Rezultatul este ARMONIA.

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

    Variabila a memorează datele personale ale fiecăruia dintre cei 30 de angajați (codul numeric personal – CNP, anul nașterii) și venitul lunar al acestuia.

    Scrieți o secvență de instrucțiuni în urma executării căreia pentru primul angajat să se inițializeze anul nașterii cu valoarea 2000, iar venitul cu valoarea 4000.

    struct date
           { char CNP[14];
             int anNastere;
           };
    struct angajat
           { struct date dp;
             int venit;
           }a[30];
    Vezi rezolvarea

    ``cpp a[0].dp.anNastere = 2000; a[0].venit = 4000; ``

    Structura e pe două niveluri: fiecare angajat are un câmp dp, care e la rândul lui o structură cu CNP-ul și anul nașterii, plus un câmp venit scris direct în angajat.

    De aceea anul se scrie cu două puncte — a[0].dp.anNastere — iar venitul cu unul singur: a[0].venit. Primul angajat e a[0], fiindcă indicii tabloului încep de la 0.

Subiectul al III-lea

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

    Un număr natural n se numește cub perfect dacă există un număr natural b, astfel încât n=b^3.

    Subprogramul cuburi are un singur parametru, n, prin care primește un număr natural (n∈[1,10^3]). Subprogramul afișează pe ecran, separate prin câte un spațiu, în ordine descrescătoare, primele n cuburi perfecte nenule.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă n=5 atunci, după apel, se afișează pe ecran numerele

    125 64 27 8 1
    Vezi rezolvarea
    void cuburi(int n)
    {
        for (int b = n; b >= 1; b--)
        {
            cout << b * b * b;
            if (b > 1)
                cout << ' ';
        }
    }
  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], k și n, și construiește în memorie un tablou bidimensional cu n linii și n coloane, astfel încât parcurgând diagonala principală, de sus în jos, să se obțină un șir strict crescător format din primii n multipli naturali nenuli ai lui k și parcurgând fiecare linie a sa, de la stânga la dreapta, să se obțină câte un șir strict crescător de numere naturale consecutive. Programul afișează pe ecran tabloul obținut, fiecare linie a tabloului pe câte o linie a ecranului, elementele de pe aceeași linie fiind separate prin câte un spațiu.

    Exemplu: pentru k=3 și n=4 se obține tabloul de mai jos

    3
    4
    5
    6
    5
    6
    7
    8
    7
    8
    9
    10
    9
    10
    11
    12
    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int k, n;
        cin >> k >> n;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cout << k * (i + 1) - i + j;
                if (j < n - 1)
                    cout << ' ';
            }
            cout << '\n';
        }
        return 0;
    }
  3. Exercițiul 3.a 2p Algoritmi eficienți

    Numim pereche asemenea (x,y) două numere naturale cu cel puțin două cifre, x și y, cu proprietatea că ultimele două cifre ale lui x sunt egale cu ultimele două cifre ale lui y, dispuse eventual în altă ordine. Fișierul numere.in conține numere naturale din intervalul [10,10^5]: pe prima linie două numere na și nb, pe a doua linie un șir A de na numere, iar pe a treia linie un șir B de nb numere. Numerele aflate pe aceeași linie a fișierului sunt separate prin câte un spațiu.

    Se cere să se afișeze pe ecran numărul de perechi asemenea (x,y), cu proprietatea că x este un termen al șirului A, iar y este un termen al șirului B. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele se afișează pe ecran numărul 13 deoarece sunt 13 perechi asemenea: (112,321), (112,521), (20,402), (42,1024), (42,6542), (112,321), (112,521), (824,1024), (824,6542), (10012,321), (10012,521), (55,255), (155,255).

    9 7
    112 20 42 112 5013 824 10012 55 155
    402 1024 321 521 57 6542 255

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

    Vezi rezolvarea

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

    Din fiecare număr contează doar ultimele două cifre, iar ordinea lor nu contează. Le pun deci în ordine crescătoare și obțin o „cheie” între 0 și 99: 112 și 321 dau amândouă cheia 12, deci formează o pereche asemenea.

    Algoritmul are două treceri:

    1. Citesc șirul A și, pentru fiecare termen, cresc contorul cheii lui într-un vector cate cu 100 de poziții. 2. Citesc șirul B și, pentru fiecare termen, adun la rezultat cate[cheia lui] — adică toate numerele din A cu care formează pereche.

    Pe exemplul din enunț, cheia 12 apare de trei ori în A (112, 112, 10012), iar în B apar 321 și 521, tot cu cheia 12: doar acestea dau 3·2 = 6 perechi din cele 13.

    De ce e eficient: fiecare număr e citit o singură dată și îi calculez cheia din două împărțiri, deci timpul e O(na+nb) — nu se compară fiecare număr din A cu fiecare din B, ceea ce ar fi însemnat na·nb comparații. Memoria e constantă: 100 de contoare, oricât de lungi ar fi șirurile.

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

    Același algoritm ca la 3.a.

    Se cere să se afișeze pe ecran numărul de perechi asemenea (x,y), cu proprietatea că x este un termen al șirului A, iar y este un termen al șirului B. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele se afișează pe ecran numărul 13 deoarece sunt 13 perechi asemenea: (112,321), (112,521), (20,402), (42,1024), (42,6542), (112,321), (112,521), (824,1024), (824,6542), (10012,321), (10012,521), (55,255), (155,255).

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int cheie(long long v)
    {
        int u = v % 10, p = v / 10 % 10;
        if (p > u)
        {
            int aux = p;
            p = u;
            u = aux;
        }
        return p * 10 + u;
    }
    
    int main()
    {
        ifstream f("numere.in");
        long long na, nb, v;
        long long cate[100] = {0};
        f >> na >> nb;
        for (long long i = 0; i < na; i++)
        {
            f >> v;
            cate[cheie(v)]++;
        }
        long long total = 0;
        for (long long i = 0; i < nb; i++)
        {
            f >> v;
            total = total + cate[cheie(v)];
        }
        f.close();
        cout << total;
        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?