Sari la conținut

Bac informatică 2020 Varianta 6, rezolvată

Varianta 6 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 6 din 2020

Varianta 6 din 2020 acoperă tipurile de date, recursivitatea cu tablouri, backtracking-ul, arborii, grafurile parțiale, structurile imbricate, matricele, șirurile de caractere și fișierele. Este o variantă bună pentru exersat urmărirea atentă a codului.

Subiectul I (20p): 5 grile: o expresie cu împărțire reală, un subprogram recursiv care modifică și afișează elementele unui tablou, o problemă de backtracking cu patru persoane care plătesc 200 de lei, numărul de frunze ale unui arbore dat prin vectorul de „tați” și numărul grafurilor parțiale conexe ale unui graf dat prin matricea de adiacență.

Subiectul al II-lea (40p): Un algoritm în pseudocod care verifică, pentru fiecare cifră pară, dacă apare într-un număr, o structură calculator cu un câmp memorie care este tot o structură și o secvență care completează o matrice 9×9 cu < și >, după un model desenat.

Subiectul al III-lea (30p): Un subprogram cu divizori (suma, care adună divizorii comuni a două numere), o problemă cu șiruri de caractere în care fiecare cuvânt de cel puțin trei litere se rotește spre stânga și o problemă de eficiență care verifică dacă numerele din fișierul bac.in pot fi rearanjate într-un șir palindromic.

⚠️ La ce să fii atent

  • La I.1: Uită-te la punctul zecimal! 5.0/2 are un operand real, deci dă 2.5, nu 2, iar expresia valorează 7.5.
  • La I.2: Afișarea se face la întoarcerea din recursivitate, deci elementele apar în ordine inversă, de la v[3] la v[0]. În plus, v[3] crește cu 1 înainte să fie afișat, deci în tablou trebuie să fie 1, nu 2.
  • La I.5: Un graf parțial păstrează toate nodurile. Muchia [1,5] trebuie păstrată, altfel nodul 5 rămâne izolat, iar din ciclul 1-2-3-4-1 poți scoate cel mult o muchie. Nu număra și graful dat: răspunsul este 4.
  • La II.1.b: Ca toate valorile afișate să fie nenule, numărul trebuie să conțină toate cifrele pare, inclusiv 0. Cel mai mic număr nu poate începe cu 0, deci este 102468, iar cel mai mare este 986420.
  • La III.3: Nu trebuie să construiești șirul palindromic. Numără aparițiile fiecărei valori într-un vector de frecvență: răspunsul este DA dacă cel mult o valoare apare de un număr impar de ori.

Subiectul I

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

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

    3+5.0/2+2
    • a)2
    • b)5
    • c)6
    • d)7.5
    Vezi rezolvarea

    Răspuns corect: d) 7.5

    Împărțirea 5.0/2 are un operand real, deci se face împărțire reală: rezultatul e 2.5, nu 2. De aici, 3+2.5+2 = 7.5, varianta d).

    Dacă în locul lui 5.0 ar fi fost 5, amândoi operanzii ar fi fost întregi, 5/2 ar fi dat 2, iar expresia ar fi valorat 7. Punctul zecimal e singura diferență, și schimbă tot.

  2. Exercițiul 2 4p Recursivitate

    Variabila v memorează un tablou unidimensional cu 4 elemente, numerotate începând de la 0.

    Subprogramul f este definit alăturat.

    Indicați setul de elemente pe care le poate avea tabloul memorat în v, în ordinea în care apar în acesta, astfel încât, în urma apelului de mai jos, să se afișeze pe ecran 2020.

    void f(int i, int v[4])
    { if(i>=3) v[i]=v[i]+1;
      else f(i+1,v);
      cout<<v[i];  |  printf("%d",v[i]);
    }
    f(0,v);
    • a)-1,1,0,2
    • b)0,2,0,1
    • c)1,-1,0,1
    • d)2,0,1,0
    Vezi rezolvarea

    Răspuns corect: b) 0,2,0,1

    Subprogramul coboară până la i=3 fără să afișeze nimic, iar afișările se fac la întoarcere:

    apelce facece afișează
    f(0,v)cheamă f(1,v)v[0], ultimul
    f(1,v)cheamă f(2,v)v[1]
    f(2,v)cheamă f(3,v)v[2]
    f(3,v)v[3] crește cu 1v[3], primul

    Se afișează deci, în ordine: v[3]+1, v[2], v[1], v[0]. Ca să iasă 2020, trebuie ca v[3]+1=2, v[2]=0, v[1]=2, v[0]=0, adică tabloul 0, 2, 0, 1 — varianta b).

    Atenție la v[3]: el e 1 în tablou, nu 2; abia după creșterea din subprogram devine 2.

  3. Exercițiul 3 4p Backtracking

    Utilizând metoda backtracking se generează toate variantele prin care patru persoane pot plăti o consumație totală de 200 de lei în următoarele condiții:

    • fiecare plătește o sumă nenulă, divizibilă cu 10;

    • primul plătește mai mult decât al doilea, al doilea mai mult decât al treilea, iar acesta mai mult decât al patrulea.

    O soluție constă în patru valori, reprezentând, în ordine, sumele plătite de fiecare dintre cele patru persoane. Primele patru soluții generate sunt, în această ordine:

    1. (70, 60, 40, 30)
    2. (70, 60, 50, 20)
    3. (80, 50, 40, 30)
    4. (80, 60, 40, 20)

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

    • a)(80,60,45,15)
    • b)(80,60,50,10)
    • c)(80,70,30,20)
    • d)(80,70,40,10)
    Vezi rezolvarea

    Răspuns corect: c) (80,70,30,20)

    Backtracking-ul încearcă sumele în ordine crescătoare pentru fiecare poziție, păstrând condiția ca fiecare să plătească strict mai puțin decât cel dinaintea lui, iar totalul să fie 200.

    nr.soluție
    170, 60, 40, 30
    270, 60, 50, 20
    380, 50, 40, 30
    480, 60, 40, 20
    580, 60, 50, 10
    680, 70, 30, 20

    Primele patru coincid cu cele din enunț. După ele, cu primii doi 80, 60, mai există o singură împărțire a celor 60 de lei rămași: 50, 10. Apoi crește al doilea la 70, rămân 50 de lei pentru ultimii doi, iar prima împărțire validă, în ordine crescătoare pe poziția a treia, e 30, 20 — varianta c).

    Varianta a) n-ar fi validă deloc: 45 și 15 nu se împart la 10.

  4. Exercițiul 4 4p Arbori

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

    Indicați numărul de noduri „frunză” ale acestui arbore.

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

    Răspuns corect: c) 5

    În vectorul de „tați”, un nod e frunză dacă nu apare ca tată al nimănui.

    nod12345678910
    tată7565706338

    Nodurile care apar ca tați sunt 7, 5, 6, 3 și 8 — ele au cel puțin un fiu. Rămân 1, 2, 4, 9 și 10, care nu apar nicăieri în listă: sunt cele 5 frunze, varianta c).

    Nodul 6 e rădăcina, fiindcă are tatăl 0, dar asta nu-l face frunză: are fiii 3 și 7.

  5. Exercițiul 5 4p Grafuri neorientate

    Un graf neorientat cu 5 noduri este reprezentat prin matricea de adiacență alăturată.

    Indicați numărul grafurilor parțiale conexe ale acestuia care sunt diferite de graful dat.

    01011
    10100
    01010
    10100
    10000
    • a)4
    • b)6
    • c)8
    • d)30
    Vezi rezolvarea

    Răspuns corect: a) 4

    Din matricea de adiacență, muchiile sunt [1,2], [1,4], [1,5], [2,3], [3,4]: un pătrat 1-2-3-4-1 de care atârnă nodul 5, legat doar de 1.

    Un graf parțial păstrează toate nodurile și alege o parte dintre muchii. Ca să rămână conex:

    • muchia [1,5] trebuie păstrată, altfel nodul 5 rămâne izolat;
    • din pătrat se poate scoate cel mult o muchie: scoțând una, rămâne un lanț care ține nodurile legate; scoțând două, pătratul se rupe.

    Deci avem graful întreg, plus patru grafuri obținute scoțând pe rând câte una dintre cele patru muchii ale pătratului: 5 grafuri parțiale conexe cu totul. Cum se cer cele diferite de graful dat, rămân 4 — varianta a).

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 valorile afișate dacă se citește numărul 240107.

    citește a (număr natural)
     c←0
    ┌repetă
    │ b←a; x←0
    │┌repetă
    ││┌dacă b%10=c atunci
    │││ x←1
    ││└■
    ││ b←[b/10]
    │└până când b=0 sau x=1
    │ scrie x,' '
    │ c←c+2
    └până când c>9
    Vezi rezolvarea

    Răspunsul din barem: 1 1 1 0 0

    Variabila c ia pe rând valorile 0, 2, 4, 6, 8 — crește din doi în doi și se oprește când trece de 9. Pentru fiecare dintre ele, bucla dinăuntru caută cifra c printre cifrele lui a, oprindu-se fie când s-au terminat cifrele, fie de îndată ce a găsit-o (x=1).

    Numărul citit e 240107, cu cifrele 2, 4, 0, 1, 0, 7:

    ce printre cifre?se afișează
    0da1
    2da1
    4da1
    6nu0
    8nu0

    Deci 1 1 1 0 0. Cu alte cuvinte, algoritmul spune, pentru fiecare cifră pară, dacă apare sau nu în număr.

  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.

    Scrieți cel mai mic și cel mai mare număr din intervalul [10^5,10^6), cu cifre distincte, care pot fi citite astfel încât, pentru fiecare dintre acestea, în urma executării algoritmului, toate valorile afișate să fie nenule.

    Vezi rezolvarea

    Răspunsul din barem: 102468 986420

    Ca toate cele cinci valori afișate să fie nenule, numărul trebuie să conțină toate cifrele pare: 0, 2, 4, 6 și 8. Cum are șase cifre, toate distincte, mai rămâne loc pentru exact o cifră, care poate fi oricare dintre cele impare.

    Cel mai mic: alegem cifra suplimentară cât mai mică, deci 1, și așezăm cifrele crescător. Numărul nu poate începe cu 0, așa că pe prima poziție vine 1, iar 0 imediat după: 102468.

    Cel mai mare: alegem cifra suplimentară cât mai mare, deci 9, și așezăm cifrele descrescător: 986420.

  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 a, b, c = 0, x;
        cin >> a;
        do
        {
            b = a;
            x = 0;
            do
            {
                if (b % 10 == c)
                    x = 1;
                b = b / 10;
            } while (b != 0 && x == 0);
            cout << x << ' ';
            c = c + 2;
        } while (c <= 9);
        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 a doua structură repetă...până când cu o structură repetitivă de alt tip.

    Vezi rezolvarea

    `` citește a (număr natural) c←0 ┌repetă │ b←a; x←0 │┌dacă b%10=c atunci ││ x←1 │└■ │ b←[b/10] │┌cât timp b≠0 și x=0 execută ││┌dacă b%10=c atunci │││ x←1 ││└■ ││ b←[b/10] │└■ │ scrie x,' ' │ c←c+2 └până când c>9 ``

    A doua structură repetă are condiția de oprire b=0 sau x=1, deci se repetă cât timp b≠0 și x=0 — condiția negată.

    Dar repetă execută corpul cel puțin o dată, iar cât timp poate să nu-l execute deloc. De aceea prima verificare a fost scoasă înaintea buclei. Fără ea, algoritmul n-ar mai fi echivalent pentru a=0: cel dat verifică o dată cifra 0 și afișează 1 pentru c=0, pe când un simplu cât timp b≠0 n-ar intra niciodată în corp și ar afișa 0.

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

    Variabila c memorează, pentru un calculator, capacitatea memoriei (interne și externe), măsurată în GB, și o literă, corespunzătoare tipului monitorului acestuia.

    Știind că expresiile C/C++ de mai jos au ca valori litera corespunzătoare tipul monitorului și două numere naturale din intervalul [1,10^6], reprezentând capacitatea memoriei interne, respectiv capacitatea memoriei externe a calculatorului, scrieți definiția unei structuri cu eticheta calculator, care permite memorarea datelor despre un calculator, și declarați corespunzător variabila c.

    c.monitor   c.memorie.interna   c.memorie.externa
    Vezi rezolvarea

    ```cpp struct capacitate { int interna; int externa; };

    struct calculator
    {
        char monitor;
        capacitate memorie;
    };

    calculator c; ```

    Expresia c.memorie.interna are două puncte, deci cere o structură în altă structură: c are un câmp memorie, iar acela are câmpurile interna și externa.

    Tipurile vin din enunț: monitorul e o literă, deci char; capacitățile sunt numere naturale până la 10⁶, deci int. Eticheta structurii mari trebuie să fie calculator, cum cere cerința; structura dinăuntru poate purta orice nume, important e ca membrul din calculator să se cheme memorie.

  6. Exercițiul 3 6p Tablouri bidimensionale

    Variabilele i și j sunt de tip întreg, iar variabila a memorează un tablou bidimensional cu 9 linii și 9 coloane, numerotate de la 0 la 8, având inițial toate elementele egale cu simbolul egal (=).

    Scrieți secvența de mai jos, înlocuind punctele de suspensie, astfel încât, în urma executării secvenței obținute, variabila a să memoreze tabloul alăturat.

    for(i=0;i<9;i++)
      for(j=0;j<9;j++)
        ..................
    Figura din enunț
    Vezi rezolvarea

    ``cpp for (i = 0; i < 9; i++) for (j = 0; j < 9; j++) if (j >= 9 - i && j <= i - 1) a[i][j] = '<'; else a[i][j] = '>'; ``

    Semnele < formează un triunghi care pornește dintr-un singur element, pe linia 5, coloana 4, și se lărgește cu câte o poziție în fiecare parte pe fiecare linie de mai jos.

    Pe linia i, triunghiul se întinde de la coloana 9-i până la coloana i-1:

    liniade lapână la
    544
    635
    726
    817

    Pentru liniile de sus intervalul iese gol de la sine — pe linia 4, de pildă, ar merge „de la 5 până la 3”, ceea ce nu cuprinde nimic — deci nu mai e nevoie de nicio verificare în plus pentru ele. În rest se pune >.

Subiectul al III-lea

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

    Subprogramul suma are doi parametri, a și b, prin care primește câte un număr natural din intervalul [1,10^4]. Subprogramul returnează suma divizorilor naturali comuni lui a și b.

    Scrieți definiția completă a subprogramului.

    Exemplu: dacă a=20 și b=12, atunci subprogramul returnează valoarea 7 (1+2+4=7).

    Vezi rezolvarea
    int suma(int a, int b)
    {
        int s = 0;
        for (int d = 1; d <= a && d <= b; d++)
            if (a % d == 0 && b % d == 0)
                s = s + d;
        return s;
    }
  2. Exercițiul 2 10p Șiruri de caractere

    Numim rotire spre stânga a unui cuvânt format din cel puțin trei litere operația prin care prima sa literă se mută la final, iar toate celelalte litere se mută cu o poziție spre stânga.

    Exemplu: în urma rotirii spre stânga a cuvântului ilumina se obține cuvântul luminai.

    Un text are cel mult 100 de caractere, iar cuvintele sale sunt formate din litere mici ale alfabetului englez și sunt separate prin câte un spațiu.

    Scrieți un program C/C++ care citește de la tastatură un text de tipul menționat mai sus și îl transformă în memorie prin rotirea spre stânga a fiecărui cuvânt al său format din cel puțin trei litere, ca în exemplu. Programul afișează pe ecran textul obținut sau mesajul nu exista, dacă în text nu există niciun cuvânt de cel puțin trei litere.

    Exemplu: pentru textul un palc mic de scolarite ilumina sala se afișează pe ecran un alcp icm de colarites luminai alas

    Vezi rezolvarea
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    int main()
    {
        char s[101], cuv[51][101];
        cin.getline(s, 101);
        int k = 0;
        for (char *p = strtok(s, " "); p != NULL; p = strtok(NULL, " "))
        {
            strcpy(cuv[k], p);
            k++;
        }
        int rotite = 0;
        for (int i = 0; i < k; i++)
        {
            int n = strlen(cuv[i]);
            if (n >= 3)
            {
                char prima = cuv[i][0];
                for (int j = 0; j < n - 1; j++)
                    cuv[i][j] = cuv[i][j + 1];
                cuv[i][n - 1] = prima;
                rotite++;
            }
        }
        if (rotite == 0)
        {
            cout << "nu exista";
            return 0;
        }
        for (int i = 0; i < k; i++)
        {
            cout << cuv[i];
            if (i < k - 1)
                cout << ' ';
        }
        return 0;
    }
  3. Exercițiul 3.a 2p Algoritmi eficienți

    Un șir finit se numește palindromic dacă parcurgându-l termen cu termen, de la stânga la dreapta sau de la dreapta la stânga se obține același șir de valori.

    Exemplu: șirul 12, 13, 16, 13, 12 este palindromic.

    Fișierul bac.in conține un șir de cel mult 10^6 numere naturale din intervalul [1,10^3], separate prin câte un spațiu. Se cere să se afișeze pe ecran mesajul DA, dacă numerele din șir pot fi rearanjate, astfel încât să formeze un șir palindromic, sau mesajul NU în caz contrar. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele 100 30 100 30 500 30 30 se afișează pe ecran DA

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

    Vezi rezolvarea

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

    Într-un șir palindromic, fiecare termen are perechea lui la aceeași distanță de celălalt capăt. Deci fiecare valoare trebuie să apară de un număr par de ori — cu o singură excepție: dacă șirul are lungime impară, valoarea din mijloc n-are pereche.

    Algoritmul: citesc șirul o singură dată și țin un vector frecv cu 1000 de poziții, în care număr de câte ori apare fiecare valoare. La final număr câte valori au apărut de un număr impar de ori: dacă sunt cel mult una, răspunsul e DA, altfel NU.

    Pe exemplul din enunț — 100 30 100 30 500 30 30 — valoarea 100 apare de două ori, 30 de patru ori, iar 500 o singură dată: o singură frecvență impară, deci DA (de pildă 30 100 30 500 30 100 30).

    De ce e eficient: fiecare număr e citit și numărat o singură dată, deci timpul e O(n), iar la final se mai face o trecere prin cele 1000 de poziții, care nu depinde de lungimea șirului. Memoria e constantă: vectorul de frecvențe are mereu 1000 de poziții, fiindcă atâtea valori se pot afla în șir, oricât de lung ar fi el — șirul însuși nu se păstrează niciodată.

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

    Un șir finit se numește palindromic dacă parcurgându-l termen cu termen, de la stânga la dreapta sau de la dreapta la stânga se obține același șir de valori.

    Exemplu: șirul 12, 13, 16, 13, 12 este palindromic.

    Fișierul bac.in conține un șir de cel mult 10^6 numere naturale din intervalul [1,10^3], separate prin câte un spațiu. Se cere să se afișeze pe ecran mesajul DA, dacă numerele din șir pot fi rearanjate, astfel încât să formeze un șir palindromic, sau mesajul NU în caz contrar. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

    Exemplu: dacă fișierul conține numerele 100 30 100 30 500 30 30 se afișează pe ecran DA

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

    Vezi rezolvarea
    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        ifstream f("bac.in");
        int frecv[1001] = {0}, x;
        while (f >> x)
            frecv[x]++;
        f.close();
        int impare = 0;
        for (int v = 1; v <= 1000; v++)
            if (frecv[v] % 2 == 1)
                impare++;
        if (impare <= 1)
            cout << "DA";
        else
            cout << "NU";
        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?