Sari la conținut

Bac informatică 2021 Varianta 7, rezolvată

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

Varianta 7 din 2021 trece prin expresii cu / și %, backtracking, structuri, arbori și grafuri, recursivitate, șiruri de caractere, matrice și fișiere. Este o variantă echilibrată, bună pentru exersat atenția la detalii.

Subiectul I (20p): 5 grile: o expresie care are valoarea 1 dacă 2021 îl divide pe x, o problemă de backtracking cu numere formate din cifrele lui 2021, o atribuire corectă între structuri masina, numărul de fii ai unui nod într-un arbore dat prin vectorul de „tați” și numărul de noduri ale unui graf complet cu 210 muchii.

Subiectul al II-lea (40p): Un algoritm în pseudocod cu o interschimbare care afișează câte o steluță pentru fiecare număr impar dintr-un interval, un subprogram recursiv f calculat pentru 2 și 21 și o secvență cu șiruri de caractere care afișează x+3 și apoi literele din bac2021.

Subiectul al III-lea (30p): Un subprogram cu cifre (imog, care verifică dacă două numere sunt „impar-oglindite”), o problemă cu matrice în care se interschimbă o parte de linie cu o parte de coloană și o problemă de eficiență care scrie invers termenii unui șir în fișierul bac.out.

⚠️ La ce să fii atent

  • La I.1: În variantele b) și d), x%2021 este exact 0 când 2021 îl divide pe x, deci s-ar face o împărțire la zero. Varianta corectă este x%(x/2021)==0.
  • La I.2: Numerele trebuie să fie strict mai mici decât 2021, deci după 2020 nu se generează 2021. Algoritmul se întoarce la a doua cifră, iar următorul număr este 21.
  • La II.1.b: Nu uita interschimbarea de la început! Pentru n=79, merge și un m mai mare decât n: 157 și 158 devin capătul de sus al intervalului și dau tot 40 de steluțe, ca și m=1.
  • La II.3: x+3 înseamnă șirul care începe de la al patrulea caracter, deci prima linie afișată este 2021. Apoi strchr returnează 0 pentru caracterele care nu sunt cifre, deci se afișează b!a!c!.
  • La III.3: Diferența dintre doi termeni vecini îți dă poziția: y-x este 2·n, unde n este poziția lui y. Pornind de la y, scazi pe rând 2·n, 2·(n-1) și așa mai departe, scriind direct în fișier, fără să salvezi termenii.

Subiectul I

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

    Variabila x este de tip întreg și memorează un număr nenul.

    Indicați expresia C/C++ cu valoarea 1 dacă 2021 este divizor al lui x.

    • a)x/(x/2021)==0
    • b)x/(x%2021)==0
    • c)x%(x/2021)==0
    • d)x%(x%2021)==0
    Vezi rezolvarea

    Răspuns corect: c) x%(x/2021)==0

    Citește cu atenție cerința: se cere o expresie cu valoarea 1 dacă 2021 îl divide pe x — nu „dacă și numai dacă”. E de ajuns să funcționeze în acest caz.

    Presupune deci că x = 2021·k. Atunci x/2021 e chiar k, iar x%k = 2021·k % k = 0, deci varianta c) dă 1.

    Celelalte pică:

    • a) x/(x/2021) devine x/k, adică 2021, care nu e 0;
    • b) și d) împart, respectiv iau restul, la x%2021 — care e exact 0 când 2021 îl divide pe x. Împărțirea la zero nu dă „fals”, ci oprește programul.

    Varianta corectă e c).

  2. Exercițiul 2 4p Backtracking

    Utilizând metoda backtracking se generează toate valorile naturale formate cu cifre ale numărului 2021 și care sunt strict mai mici decât acesta. Primele 12 soluții generate sunt, în această ordine:

    1. 0
    2. 1
    3. 10
    4. 100
    5. 1000
    6. 1001
    7. 1002
    8. 101
    9. 1010
    10. 1011
    11. 1012
    12. 102

    Indicați două soluții care se generează pe poziții consecutive, în această ordine.

    • a)2002, 2020
    • b)2020, 21
    • c)122, 1221
    • d)21, 22
    Vezi rezolvarea

    Răspuns corect: b) 2020, 21

    Backtracking-ul construiește numere din cifrele 0, 1 și 2, încercându-le mereu în această ordine, și le prelungește cât timp rămân strict sub 2021.

    Urmărește ce se întâmplă pe ramura care începe cu 2: 2 → 20 → 200 → 2000, 2001, 2002 → 201 → 2010, 2011, 2012 → 202 → 2020.

    După 2020, prelungirile s-au terminat: 2021 nu e strict mai mic decât 2021, iar 2022 e mai mare. Algoritmul se întoarce până la prima cifră și trece de la 20… la 21.

    Deci 2020 și 21 se generează una după alta — varianta b).

    Celelalte perechi nu sunt consecutive: după 2002 urmează 201, după 122 urmează 1220, iar după 21 urmează 210.

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

    Variabilele x și y sunt declarate alăturat.

    Indicați o instrucțiune de atribuire corectă din punctul de vedere sintactic.

    struct masina
    {  char model[51];
       int an;
    }x[10],y;
    • a)x[1]=y;
    • b)x.an[1]=y.an;
    • c)x[1].an.masina=y.an.masina;
    • d)model.x[1]=model.y;
    Vezi rezolvarea

    Răspuns corect: a) x[1]=y;

    x e un tablou de 10 structuri, iar y o singură structură de același tip. În C/C++ o structură se poate atribui întreagă altei structuri de același tip, deci x[1]=y; e corectă — varianta a). Se copiază deodată și model, și an.

    Celelalte greșesc ordinea sau inventează sintaxă: b) pune indicele după câmp (x.an[1]), c) adaugă numele tipului la capătul accesului, iar d) scrie câmpul înaintea variabilei.

  4. Exercițiul 4 4p Arbori

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

    Indicați numărul de descendenți direcți (“fii”) ai nodului 4.

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

    Răspuns corect: c) 5

    În vectorul de „tați”, poziția i spune cine e tatăl nodului i:

    nod1234567891011
    tată93464860444

    Fiii nodului 4 sunt nodurile care au valoarea 4 în tabel: 3, 5, 9, 10 și 11 — cinci noduri, varianta c).

    Nodul 8 e rădăcina, fiindcă are tatăl 0. Nodul 1 nu e fiu al lui 4, ci al lui 9 — deci e nepot, descendent, dar nu direct.

  5. Exercițiul 5 4p Grafuri neorientate

    Indicați numărul de noduri ale unui graf neorientat, complet, cu 210 muchii.

    • a)14
    • b)15
    • c)20
    • d)21
    Vezi rezolvarea

    Răspuns corect: d) 21

    Într-un graf complet cu n noduri, fiecare pereche de noduri e legată, deci numărul de muchii este n·(n-1)/2.

    Din n·(n-1)/2 = 210 rezultă n·(n-1) = 420. Căutăm două numere consecutive cu produsul 420: 20·21 = 420, deci `n = 21` — varianta d).

    Verificare rapidă pentru celelalte: 14 ar da 91 de muchii, 15 ar da 105, iar 20 ar da 190.

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 a←→b operația de interschimbare a valorilor variabilelor a și b.

    Scrieți succesiunea de caractere afișate în urma executării algoritmului dacă se citesc, în această ordine, numerele 2 și 9.

     citește m,n
                 (numere naturale)
    ┌dacă m>n atunci
    │ n←→m
    └■
    ┌dacă m%2=0 atunci
    │ m←m+1
    └■
    ┌cât timp m≤n execută
    │ m←m+2
    │ scrie '*'
    └■
    Vezi rezolvarea

    Răspunsul din barem: ****

    Se citesc m=2 și n=9. Cum m nu e mai mare decât n, nu se interschimbă nimic. m e par, deci devine 3.

    Bucla crește m cu 2 înainte de a scrie steluța:

    m la intrarem devinese scrie
    35*
    57*
    79*
    911*

    La pasul următor m=11 depășește pe n=9 și bucla se oprește. Se afișează patru steluțe: ****.

    Atenție la ultimul pas: m=9 e încă ≤9, deci intră în buclă și scrie a patra steluță.

  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 a←→b operația de interschimbare a valorilor variabilelor a și b.

    Dacă pentru n se citește numărul 79, scrieți două numere nenule care pot fi citite pentru m astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea, să se afișeze de 40 de ori caracterul *.

    Vezi rezolvarea

    1 157

    Steluțele numără câte numere impare sunt de la m (crescut la impar, dacă era par) până la n, inclusiv.

    m=1: rămâne 1, iar bucla merge până la 79. Numerele impare de la 1 la 79 sunt (79-1)/2 + 1 = 40 — exact 40 de steluțe.

    m=157: aici m>n, deci se interschimbă și devin m=79, n=157. Numerele impare de la 79 la 157 sunt (157-79)/2 + 1 = 40 — tot 40.

    Interschimbarea de la început e cheia: un m mai mare decât n nu strică algoritmul, ci doar schimbă capetele intervalului. Merge și m=158, care după interschimbare dă același interval.

  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 a←→b operația de interschimbare a valorilor variabilelor a și b.

    Scrieți programul C/C++ corespunzător algoritmului dat, fără a utiliza eventuale funcții predefinite pentru operația de interschimbare.

    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int m, n, aux;
        cin >> m >> n;
        if (m > n)
        {
            aux = n;
            n = m;
            m = aux;
        }
        if (m % 2 == 0)
            m = m + 1;
        while (m <= n)
        {
            m = m + 2;
            cout << '*';
        }
        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 a←→b operația de interschimbare a valorilor variabilelor a și b.

    Scrieți în pseudocod un algoritm echivalent cu cel dat, înlocuind structura cât timp...execută cu o structură repetitivă cu test final.

    Vezi rezolvarea

    `` citește m,n (numere naturale) ┌dacă m>n atunci │ n←→m └■ ┌dacă m%2=0 atunci │ m←m+1 └■ ┌dacă m≤n atunci │┌repetă ││ m←m+2 ││ scrie '*' │└până când m>n └■ ``

    cât timp verifică înainte, deci poate să nu execute corpul deloc; repetă…până când îl execută întotdeauna cel puțin o dată. De aceea bucla nouă se pune sub un dacă care verifică aceeași condiție: dacă m e deja mai mare decât n, nu se scrie nicio steluță.

    Fără acel dacă, pentru m=10, n=10 algoritmul dat n-ar scrie nimic — m devine 11, mai mare decât 10 — pe când repetă ar scrie o steluță.

    Condiția de oprire e negata celei de continuare: se repetă cât timp m≤n, deci se iese când m>n.

  5. Exercițiul 2 6p Recursivitate

    Subprogramul f este definit alăturat.

    Scrieți ce valori au f(2), respectiv f(21).

    int f(int x)
    { if (x<=4) return x;
      else return x-f(x-2);
    }
    Vezi rezolvarea

    Răspunsul din barem: 2 10

    f(2) iese direct pe prima ramură: 2≤4, deci se returnează chiar 2.

    f(21) coboară din doi în doi până la un număr mai mic sau egal cu 4, apoi se întoarce scăzând:

    xf(x)
    33
    55−3 = 2
    77−2 = 5
    99−5 = 4
    1111−4 = 7
    1313−7 = 6
    1515−6 = 9
    1717−9 = 8
    1919−8 = 11
    2121−11 = 10

    Deci f(2)=2 și f(21)=10.

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

    Variabila i este de tip întreg, iar variabila x permite memorarea unui șir cu cel mult 100 de caractere.

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

    strcpy(x,"bac2021");
    cout<<x+3<<endl;  |  printf("%s\n",x+3);
    for(i=0;i<strlen(x);i++)
      if(strchr("0123456789",x[i])==0)
        cout<<x[i]<<'!'; | printf("%c! ",x[i]);
    Vezi rezolvarea

    Răspunsul din barem: 2021 b!a!c!

    2021 b!a!c!

    Prima instrucțiune afișează x+3: un șir de caractere afișat de la a patra poziție încolo, fiindcă x e adresa primului caracter, iar x+3 sare peste trei. Din bac2021 rămâne 2021, urmat de trecerea pe rândul următor.

    Bucla parcurge tot șirul și scrie caracterul urmat de ! doar pentru cele care nu sunt cifre — strchr întoarce 0 când caracterul nu e găsit printre cifre. Literele sunt b, a, c, deci se afișează b!a!c!

Subiectul al III-lea

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

    Două numere se numesc oglindite dacă fiecare se obține din celălalt, prin parcurgerea cifrelor acestuia de la dreapta la stânga. Două numere se numesc impar-oglindite dacă numerele obținute din acestea, prin îndepărtarea tuturor cifrelor lor pare, sunt oglindite.

    Subprogramul imog are trei parametri:

    • x și y, prin care primește câte un număr natural din intervalul [0,10^9];

    • rez, prin care furnizează valoarea 1 dacă x și y sunt impar-oglindite sau valoarea 0 în caz contrar.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă x=523 și y=84356, după apel rez=1, iar dacă x=523 și y=84536 sau x=523 și y=84576 sau x=40 și y=86, după apel rez=0.

    Vezi rezolvarea
    void imog(int x, int y, int &rez)
    {
        long long a = 0, p = 1, b = 0;
        int areX = 0, areY = 0;
        while (x != 0)
        {
            int c = x % 10;
            if (c % 2 == 1)
            {
                a = a + c * p;
                p = p * 10;
                areX = 1;
            }
            x = x / 10;
        }
        while (y != 0)
        {
            int c = y % 10;
            if (c % 2 == 1)
            {
                b = b * 10 + c;
                areY = 1;
            }
            y = y / 10;
        }
        if (areX == 1 && areY == 1 && a == b)
            rez = 1;
        else
            rez = 0;
    }
  2. Exercițiul 2 10p Tablouri bidimensionale

    Scrieți un program C/C++ care citește de la tastatură numere naturale: n (n∈[2,20]), k (k∈[2,n]) și n∙n numere din intervalul [0,10^9], elemente ale unui tablou bidimensional cu n linii și n coloane. Programul transformă tabloul în memorie, interschimbând șirul elementelor situate pe linia a k-a, în stânga diagonalei principale, parcurse de la stânga la dreapta, cu șirul elementelor situate pe coloana a k-a, deasupra diagonalei principale, parcurse de sus în jos, ca în exemplu. Elementele tabloului obținut sunt afișate pe ecran, fiecare linie pe câte o linie a ecranului, cu elementele fiecărei linii separate prin câte un spațiu.

    Exemplu: pentru n=5, k=4 și tabloul

    Figura din enunț
    Vezi rezolvarea
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int n, k;
        cin >> n >> k;
        long long a[21][21], aux;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                cin >> a[i][j];
        for (int i = 0; i < k - 1; i++)
        {
            aux = a[k - 1][i];
            a[k - 1][i] = a[i][k - 1];
            a[i][k - 1] = aux;
        }
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cout << a[i][j];
                if (j < n - 1)
                    cout << ' ';
            }
            cout << '\n';
        }
        return 0;
    }
  3. Exercițiul 3.a 2p Algoritmi eficienți

    Se consideră șirul 1, 3, 7, 13, 21, 31, 43 ... definit astfel: f^0=1, iar f^n=f^n-1+2·n, dacă n≥1 (unde n este un număr natural).

    Se citesc de la tastatură două numere naturale din intervalul [1,10^9], x și y (x<y), reprezentând doi termeni aflați pe poziții consecutive în șirul dat, și se cere să se scrie în fișierul text bac.out, separați prin câte un spațiu, toți termenii șirului mai mici sau egali cu y, în ordine inversă a apariției lor în șir. Proiectați un algoritm eficient din punctul de vedere al spațiului de memorie și al timpului de executare.

    Exemplu: dacă x=21 și y=31, fișierul conține valorile

    31 21 13 7 3 1

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

    Vezi rezolvarea

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

    Termenii cresc după regula fₙ = fₙ₋₁ + 2·n, deci diferența dintre doi termeni vecini îmi spune pe ce poziție mă aflu: dacă x și y sunt vecini, atunci y - x = 2·n, unde n e poziția lui y.

    De aici cobor înapoi prin șir fără să-l construiesc: pornesc de la y, cu n = (y-x)/2, scriu termenul în fișier, apoi trec la cel dinainte scăzând 2·n și micșorând n cu 1. Când n ajunge 0, am ajuns la primul termen, 1, pe care îl scriu la final.

    Pe exemplul din enunț, x=21 și y=31 dau n = 5: se scriu 31, apoi 31-10=21, 21-8=13, 13-6=7, 7-4=3 și, în sfârșit, 1.

    De ce e eficient: termenii se scriu direct, în ordinea cerută — de la cel mare la cel mic — deci nu trebuie păstrați nicăieri ca să fie întorși la final; memoria e O(1). Numărul de pași e chiar n, iar cum fₙ = n²+n+1, pentru un y de ordinul 10⁹ înseamnă în jur de 31.000 de pași, adică O(√y) — mult sub numărul de termeni pe care i-ar cere o căutare pas cu pas de la început.

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

    Același algoritm ca la 3.a.

    Se citesc de la tastatură două numere naturale din intervalul [1,10^9], x și y (x<y), reprezentând doi termeni aflați pe poziții consecutive în șirul dat, și se cere să se scrie în fișierul text bac.out, separați prin câte un spațiu, toți termenii șirului mai mici sau egali cu y, în ordine inversă a apariției lor în șir. Proiectați un algoritm eficient din punctul de vedere al spațiului de memorie și al timpului de executare.

    Exemplu: dacă x=21 și y=31, fișierul conține valorile

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        long long x, y;
        cin >> x >> y;
        ofstream g("bac.out");
        long long n = (y - x) / 2, t = y;
        while (n > 0)
        {
            g << t << " ";
            t = t - 2 * n;
            n--;
        }
        g << t;
        g.close();
        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?