Tag: științe ale naturii

Rezolvarea subiectelor de informatică de la examenul de bacalaureat național, sesiunea august 2015 (2)

Filiera teoretică, profilul real, specializarea științe ale naturii

Enunțul subiectelor precum și baremul de corectare pot fi descărcate de pe site-ul Ministerului Educației Naționale.

Pe contul de GitHub poate fi consultat codul sursă corespunzător subiectelor care solicită elaborarea de programe C/C++.

SUBIECTUL I (30 de puncte)


Acest subiect este identic cu cel de la specializarea matematică-informatică.

 

SUBIECTUL al II-lea (30 de puncte)


1. Expresia C/C++ are valoarea 1 (adevărat) dacă variabila întreagă x aparține reuniunii de intervale (-∞, -3) ∪ (-1, 1) ∪ (3, +∞).

Analizăm, pe rând, fiecare dintre variantele de răspuns:

a) abs(x) > 3 && x == 0

|x| = x, x ∈ [0, +∞) și |x| = -x, x ∈ (-∞, 0)

Relația abs(x) > 3 devine astfel:

x > 3, x ∈ [0, +∞) și -x > 3, x ∈ (-∞, 0)

sau încă

x > 3, x ∈ [0, +∞) și x < -3, x ∈ (-∞, 0)

Condiția inițială devine:

x ∈ (-∞, -3) ∪ {0} ∪ (3, +∞), ceea ce contravine condiției din enunț.

Varianta a este incorectă.

b) abs(x) < 1 || abs(x) > 3

|x| = x, x ∈ [0, +∞) și |x| = -x, x ∈ (-∞, 0)

Relația abs(x) < 1 devine astfel:

x < 1, x ∈ [0, +∞) și -x < 1, x ∈ (-∞, 0)

sau încă

x < 1, x ∈ [0, +∞) și x > -1, x ∈ (-∞, 0)

Condiția inițială devine:

x ∈ (-∞, -3) ∪ (-1, 1) ∪ (3, +∞), ceea ce corespunde condiției din enunț.

Varianta b este corectă.

c) abs(x-3) < 1

|x-3| = x-3, x ∈ [3, +∞) și |x-3| = 3-x, x ∈ (-∞, 3)

Relația abs(x-3) < 1 devine astfel:

x-3 < 1, x ∈ [3, +∞) și 3-x < 1, x ∈ (-∞, 3)

sau încă

x < 4, x ∈ [3, +∞) și x > 2, x ∈ (-∞, 3)

Condiția inițială devine:

x ∈ (2, 4), ceea ce contravine condiției din enunț.

Varianta c este incorectă.

d) abs(x-1) > 3

|x-1| = x-1, x ∈ [1, +∞) și |x-1| = 1-x, x ∈ (-∞, 1)

Relația abs(x-1) > 3 devine astfel:

x-1 > 3, x ∈ [1, +∞) și 1-x > 3, x ∈ (-∞, 1)

sau încă

x > 4, x ∈ [1, +∞) și x < -2, x ∈ (-∞, 1)

Condiția inițială devine:

x ∈ (-∞, -2) ∪ (4, +∞), ceea ce contravine condiției din enunț.

Varianta d este incorectă.

Ca atare, răspunsul corect este b.

2. Potrivit secvenței de cod:

while (x >= y)
        x = x - y;
z = x;

 din variabila x se scade valoarea y atâta vreme cât x >= y, cu alte cuvinte x = x – [x/y] * y. Se observă faptul că valoarea rămasă în x este egală cu restul împărțirii lui x la y (x%y).

Ca atare, răspunsul corect este c.

3. Având declarate variabilele:

float re, im;

 care reprezintă partea reală, respectiv partea imaginară a unui număr complex z, pătratul modulului acestuia (∑ = |z|2 = re2 + im2) se poate calcula astfel:

float s = 0.0;
s = re * re + im * im;

 Dacă variabilele sunt declarate având tipul double, se poate face uz de funcția pow din biblioteca math.h:

double re, im;
double s = 0.0;
s = pow (re, 2) + pow (im, 2);

 4.

a) Algoritmul descris în pseudocod analizează fiecare cifră în parte a numărului n și, în măsura în care aceasta este un număr prim, este adăugată la suma cerută de enunțul exercițiului. Parcurgerea cifră cu cifră a numărului de analizat se face prin împărțiri succesive la 10 până ce numărul devine nul, cifra din pasul curent al algoritmului (care este analizată pentru a se verifica dacă este sau nu număr prim) fiind reprezentată de restul împărțirii la 10. Pentru fiecare cifră, se decide dacă aceasta este număr prim sau nu în urma parcurgerii tuturor valorilor cuprinse între 2 și rădăcina sa pătrată (interval în care se pot găsi potențialii divizori), verificându-se restul împărțirii cifrei la fiecare dintre aceste valori. În situația în care o singură valoare divide cifra, se poate concluziona că aceasta nu reprezintă un număr prim. În cazul în care nici una dintre valori nu divide cifra, se poate concluziona că aceasta reprezintă un număr prim. Cazurile în care cifra are valoarea 0 sau 1 sunt tratate în mod separat.

citește n
suma ← 0
cât timp n > 0 execută
    cifra_curentă ← n % 10
    prim ← 1
    dacă cifra_curentă = 0 sau cifra_curentă = 1 atunci prim ← 0
        altfel
        pentru divizor = 2, √cifra_curentă execută
             dacă cifra_curentă % divizor = 0 atunci prim ← 0
    dacă prim = 1 atunci suma ← suma + cifra_curentă
    n ← n / 10
tipărește suma

b) Datele de intrare sunt reprezentate de variabila n, de tip întreg, reprezentând numărul pentru care se calculează suma cifrelor prime. Aceasta se citește de la tastatură înainte ca algoritmul să fie executat.

Datele de ieșire sunt reprezentate de variabila suma, de tip întreg, reprezentând suma cifrelor prime a numărului n. Aceasta se afișează pe ecran în urma execuției algoritmului.

Alte variabile folosite în cadrul algoritmului sunt:

  • cifra_curentă reprezintă o cifră a numărului n (obținută ca rest al împărțirii numărului n la 10) analizată în pasul curent al algoritmului, pentru a se determina dacă este număr prim sau nu, în urma acesteia luându-se decizia de a se adăuga la sumă sau nu;
  • prim este o variabilă având ca valori posibile 1 (adevărat) sau 0 (fals) în funcție de proprietatea cifrei analizate în pasul curent a algoritmului de a fi sau nu număr prim;
  • divizor este o variabilă, luând valori cuprinse între 2 și rădăcina pătrată a cifrei curente, reprezentând potențialii divizori ai cifrei curente; în măsura în care unul dintre aceștia verifică proprietatea de a divide cifra curentă (restul împărțirii cifrei curente la el este nul), se poate conchide faptul că numărul analizat nu este prim; altfel, dacă nici un număr din intervalul menționat nu verifică proprietatea de a divide cifra curentă, se poate conchide faptul că numărul analizat este prim.

 

SUBIECTUL al III-lea (30 de puncte)


1. Se observă faptul că pe fiecare poziție 1 ≤ i, j ≤ 5 se găsește o valoare egală cu indicele coloanei la care se adaugă valoarea maximă de pe linia precedentă (aceasta din urmă fiind determinată prin înmulțirea indicelui liniei cu numărul de elemente de pe o linie, adică 5).

Ca atare, valoarea afișată pe poziția i, j este (i – 1) * 5 + j.

Varianta corectă este a.

2. Se caută, prin metoda căutării binare, valoarea x = 5 în tabloul unidimensional ordonat (1, 3, 5, 7, 12, 21, 49).

Se pornește căutarea de la mijlocul vectorului (poziția 4), adică cu valoarea 7. Pentru că x = 5 < 7, se continuă căutarea în jumătatea stângă a vectorului, adică între pozițiile (1, 3).

Se continuă căutarea cu mijlocul părții stângi a vectorului (poziția 2), adică cu valoarea 3. Pentru că x = 5 > 3, se continuă căutarea în jumătatea dreaptă a părții stângi a vectorului, adică între pozițiile (3, 3).

Se continuă căutarea cu mijlocul jumătății drepte a părții stângi a vectorului care conține un singur element, adică cu valoarea 5. Pentru că x = 5 == 5, se termină procesul de căutare.

În concluzie, valorile cu care se face comparația sunt 7, 3 și 5.

3. Rezolvarea problemei presupune parcurgerea, element cu element, a vectorului, și marcarea momentului în care a fost întâlnit un element par, respectiv a unui element impar diferit de 2015. Se afișează rezultatul DA în situația în care a fost întâlnit cel puțin un element par și nici un element impar diferit de 2015, în caz contrar afișându-se rezultatul NU.

#include <iostream>

using namespace std;

int main() {
    int n, odd_encountered = 0, even_encountered = 0;
    long *v;
    cout << "n="; cin >> n;
    v = new long [n];
    for (int k = 0; k < n; k++) {
        cout << "v[" << k << "]=";
        cin >> v[k];
    }
    for (int k = 0; k < n; k++) {
        if (v[k] % 2 == 0) {
            even_encountered = 1;
        } else if (v[k] != 2015) {
            odd_encountered = 1;
        }
    }
    if (even_encountered && !odd_encountered) {
        cout << "DA";
    } else {
        cout << "NU";
    }
    delete v;
    return 0;
}

4.

a) Fie x1, x2, …, xi numerele impare aflate printre primii n termeni ai șirului aflați în fișier și y1, y2, …, yp numerele pare aflate printre ultimii n termeni ai șirului.

Problema cere calcularea sumei:

∑ = x1 * y1 + x1 * y2 + … + x1 * yp + x2 * y1 + x2 * y2 + … + x2 * yp + … + xi * y1 + xi * y2 + … + xi * yp = x1 * (y1 + y2 + … + yp) + x2 * (y1 + y2 + … + yp) + … + xi * (y1 + y2 + … + yp) = (x1 + x2 + … + xi) * (y1 + y2 + … + yp)

Prin urmare, este suficient să se calculeze suma elementelor impare aflate printre primii n termeni ai șirului, respectiv suma elementelor pare aflate printre ultimii n termeni ai șirului, realizându-se ulterior produsul acestora pentru a se obține rezultatul solicitat de enunțul problemei.

Se notează:

  • sum_first_odd: suma tuturor numerelor impare aflate între primii n termeni ai șirului;
  • sum_last_even: suma tuturor numerelor pare aflate între ultimii n termeni ai șirului.

Rezultatul problemei va fi, în această situație sum_first_odd * sum_last_even.

În acest fel, complexitatea în timp a algoritmului este liniară O(n), șirul de numere fiind parcurs o singură dată, asigurându-se în același timp și eficiența din punctul de vedere al memoriei folosite întrucât sunt alocate doar două variabile de tip întreg.

b)

#include <iostream>
#include <fstream>

using namespace std;

int parity(int n) {
    return n % 2;
}

int main() {
    ifstream file("bac.txt");
    int n, crt_pos = 0, temp, sum_first_odd = 0, sum_last_even = 0;
    if (file.is_open()) {
        file >> n;
        while (file >> temp) {
            if (crt_pos++ < n) {
                if (parity(temp)) {
                    sum_first_odd += temp;
                }
            } else {
                if (!parity(temp)) {
                    sum_last_even += temp;
                }
            }
        }
        cout << "Suma este " << (sum_first_odd * sum_last_even) << endl;
        file.close();
    }
    return 0;
}

 

Rezolvarea subiectelor de informatică de la examenul de bacalaureat național, sesiunea iulie 2015 (2)

Filiera teoretică, profilul real, specializarea științe ale naturii

 

Enunțul subiectelor precum și baremul de corectare pot fi descărcate de pe site-ul Ministerului Educației Naționale.

Pe contul de GitHub poate fi consultat codul sursă corespunzător subiectelor care solicită elaborarea de programe C/C++.

SUBIECTUL I (30 de puncte)


Acest subiect este identic cu cel de la specializarea matematică-informatică.

 

SUBIECTUL al II-lea (30 de puncte)


1. Vom analiza, pe rând, fiecare dintre expresiile propuse spre evaluare:

a) x = sqrt(x);

Această expresie este corectă din punct de vedere sintactic, întrucât variabilei reale x (x > 0), inițializată anterior, i se asociază o valoare egală cu rădăcina sa pătrată.

b) x = sqrt(sqrt(16));

Această expresie este corectă din punct de vedere sintactic, întrucât în urma evaluării expresiei, variabila reală x va fi inițializată cu valoarea 2.0 (sqrt(16) = 4.0, sqrt(4.0) = 2.0), pierzându-se astfel valoarea stocată anterior;

c) cin >> sqrt(4); sau scanf(“%f”, &sqrt(4));

Această expresie este incorectă din punct de vedere sintactic, întrucât expresia sqrt(4) este o constantă (evaluată la valoarea 2.0), astfel încât nu poate fi citită, de la tastatură, o altă valoare care să fie atribuită ulterior acesteia. Atribuirea de valori de la tastatură este posibilă numai pentru variabile, aceasta constituind o modalitate pentru inițializarea sa.

d) cout << sqrt(4)+1; sau printf(“%f”, sqrt(4)+1);

Această expresie este corectă din punct de vedere sintactic, întrucât, în urma execuției acesteia, pe monitor se va afișa valoarea 3.0 (expresia sqrt(4) este evaluată ca fiind 2.0, ulterior această valoare fiind incrementată).

Răspunsul corect este c.

2. Pentru determinarea celui mai mare divizor comun, se folosește de regulă algoritmul lui Euclid, care este disponibil în două variante (prin scăderi și împărțiri succesive), implementarea putând fi atât iterativă, cât și recursivă.

În exemplele din problemă, sunt prezentate variantele iterative, prin scăderi și împărțiri succesive:

a) prin scăderi succesive:

if (x == 0) {
    x = y;
}
while (y != 0) {
    if (x > y) {
        x = x - y;
    } else {
        y = y - x;
    }
}

b) prin împărțiri succesive:

while (y != 0) {
    aux = y;
    y = x % y;
    x = aux;
}

Se observă că secvența S1 este echivalentă cu algoritmul de la punctul a).

Se observă că secvența S2 NU este echivalentă cu algoritmul de la punctul b), întrucât valoarea reținută de variabila x se pierde, odată ce se stochează în ea restul împărțirii lui x la y, stocarea lui y în variabila temporară z neavând nici un sens, de vreme ce aceasta nu mai este utilizată ulterior. De asemenea, y primește valoarea lui x, astfel că ciclul repetitiv se va termina după cel mult 2 iterații.

Prin urmare, răspunsul corect este a.

3. În urma majorării cu 50%, cartea va avea următorul preț:

preț = preț + preț * 50% = preț + preț * 0,5 = preț * (1 + 0,5) = preț * 1,5 = preț * 3 /2

Așadar, instrucțiunile C/C++ prin care valoarea unei variabile reale p (declarată ca float p; sau double p; și inițializată corespunzător) pot fi:

a) p = p * 1.5;

b) p = p * 3/2;

4.

a) Întrucât se cere algoritmul de rezolvare în pseudocod, este mai facil ca soluția pentru această problemă să fie iterativă și să nu se folosească de alte funcții ajutătoare (pentru determinarea unui element din șirul lui Fibonacci sau pentru verificarea parității unui număr).

Astfel, într-un ciclu repetitiv, se vor calcula termenii șirului lui Fibonacci, începând cu f(1). Dacă un termen din șir este impar, atunci se scade din valoarea lui n o unitate, semn că un număr dintre cele care îndeplinesc condiția solicitată a fost găsit, căutarea terminându-se în momentul în care n ajunge 0. Calcularea unui termen din șirul lui Fibonacci (dacă pasul curent din iterație este k, se va calcula fibonacci(k)) se face reținând în permanență cele 2 valori anterioare: fibonacci(k-1) și fibonacci(k-2) astfel încât să se poată aplica formula de recurență cunoscută: fibonacci(k) = fibonacci(k-1) + fibonacci(k-2).

intreg n, k = 1, fibonacci1, fibonacci2, fibonnaci
citeste n
cat timp n > 0 executa
    daca k = 1 atunci
        fibonacci1 = 1
        fibonacci = 1
    altfel daca k = 2 atunci
        fibonacci2 = 1
        fibonacci = 1
    altfel
        fibonacci = fibonacci1 + fibonacci2
        fibonacci1 = fibonacci2
        fibonacci2 = fibonaaci
    sfarsit daca
    daca fibonacci % 2 != 0 atunci
        n = n - 1
    sfarsit daca
    k = k + 1;
sfarsit cat timp
afiseaza fibonacci

Implementarea în C/C++ a algoritmului în pseudocod prezentat anterior este:

using namespace std;

#include <iostream>

int main() {
    int n, k = 1, fibonacci1 = 0, fibonacci2 = 0, fibonacci;
    cout << "n = "; cin >> n;
    while (n > 0) {
        switch (k) {
            case 1:
                fibonacci1 = 1;
                fibonacci = 1;
                break;
            case 2:
                fibonacci2 = 1;
                fibonacci = 1;
                break;
            default:
                fibonacci = fibonacci1 + fibonacci2;
                fibonacci1 = fibonacci2;
                fibonacci2 = fibonacci;
                break;
        }
        if (fibonacci % 2 == 1) {
            n--;
        }
        if (n != 0) {
            k++;
        }
    }
    cout << "Elementul cautat se gaseste pe pozitia " << k << " si are valoarea " << fibonacci << endl;
    return 0;
}

b) Datele de intrare sunt reprezentate de variabila n, număr natural nenul, reprezentând al câtelea termen impar din șirul lui Fibonacci se dorește a fi determinat. Valoarea sa se citește de la tastatură.

Datele de ieșire sunt reprezentate de variabila fibonacci, număr natural nenul, reprezentând al n-lea termen impar din șirul lui Fibonacci. Valoarea sa se calculează folosind formula de recurență prin care se definește șirul lui Fibonacci fibonacci(k) = 1, k = 1 sau 2, fibonacci(k) = fibonacci(k-2) + fibonacci(k-1), altfel și se afișează pe monitor.

S-au mai utilizat următoarele variabile:

  • k, pasul curent de iterație, reprezentând al câtelea termen din șirul lui Fibonacci se calculează la momentul de timp respectiv (indiferent dacă acesta este par sau impar); este inițializat cu 1 și este incrementat la fiecare pas al ciclului repetitiv atâta vreme cât nu s-a obținut al n-lea termen impar din șirul lui Fibonacci;
  • fibonacci1, reprezintă termenul din șirul lui Fibonacci aflat cu 2 poziții înainte de termenul curent (dacă pasul curent este k, fibonacci1 reține f(k-2), unde f este funcția Fibonacci); este inițializat cu 1 pentru k = 1;
  • fibonacci2, reprezintă termenul din șirul lui Fibonacci aflat cu 1 poziție înainte de termenul curent (dacă pasul curent este k, fibonacci2 reține f(k-1), unde f este funcția Fibonacci); este inițializat cu 1 pentru k = 2.

 

SUBIECTUL al III-lea (30 de puncte)


1. Se observă că:

pentru i = 1, se afișează valorile 6 – j, oricare ar fi j = 1, 5

pentru i = 2

  • se afișează valoarea 6 – i, pentru j = 1
  • se afișează valorile 6 – j, pentru j = 2, 5

pentru i = 3

  • se afișează valorile 6 – i, pentru j = 1, 2
  • se afișează valorile 6 – j, pentru j = 3, 5

pentru i = 4

  • se afișează valorile 6 – i, pentru j = 1, 3
  • se afișează valorile 6 – j, pentru j = 4, 5

pentru i = 5

  • se afișează valorile 6 – i, pentru j = 1, 4
  • se afișează valoarea 6 – j, pentru j = 5

Ca o regulă generală, se afișează 6 – i pentru j < i și 6 – j altfel.

Prin urmare, condiția instrucțiunii if este i < j. Răspunsul corect este a.

2. Având în vedere că tablourile A și B sunt deja sortate (A – crescător, B – descrescător), acestea pot fi parcurse simultan (A – în sens invers, B – în sens normal) pentru construirea elementelor tabloului C.

Fie A = (a[0], a[1], a[2], a[3], a[4]) și B = (b[0], b[1], b[2], b[3], b[4]).

Rezultă că rezulatul va fi tabloul C = (c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], c[8], c[9]), având un număr de elemente egal cu suma elementelor celor două tablouri care sunt interclasate.

a) a[4] > b[0] => c[0] = a[4] = 16

b) a[3] < b[0] => c[1] = b[0] = 15

c) a[3] = b[1] => c[2] = a[3] = 10

d) a[2] < b[1] => c[3] = b[1] = 10

e) a[2] < b[2] => c[4] = a[2] = 9

f) a[2] < b[3] => c[5] = a[3] = 8

g) a[2] > b[4] => c[6] = a[2] = 7

h) a[1] < b[4] => c[7] = b[4] = 3

i) parcurgerea vectorului b s-a terminat => c[8] = a[1] = 2

j) parcurgerea vectorului b s-a terminat => c[9] = a[0] = 1

Prin urmare se obține ca rezultat tabloul C = (16, 15, 10, 10, 9, 8, 7, 3, 2, 1), care nu este altceva decât reuniunea elementelor din tablourile A și B, sortată descrescător (construirea se face însă pe măsura parcurgerii celor două tablouri, exploatând faptul că acestea sunt deja sortate, pentru a reduce complexitatea ordonării ulterioare a rezultatului obținut).

3. Rezolvarea problemei presupune citirea celor n elemente ale vectorului, după care acesta mai este parcurs încă o dată, fie crescător (de la pozițiile mici spre pozițiile mari), fie descrescător (de la pozițiile mari spre pozițiile mici), reținându-se pe fiecare poziție a vectorului elementul anterior / următor (în funcție de sensul de parcurgere). Totuși, într-o variabilă temporară trebuie reținut ultimul element, astfel încât valoarea acestuia să fie atribuită primului element, operație care va fi realizată manual, în afara structurii repetitive.

Având în vedere că elementele vectorului pot lua valori în intervalul [0, 109], acesta trebuie declarat de tip long, astfel încât să se aloce în memorie spațiu suficient pentru stocarea unor astfel de date.

using namespace std;

#include <iostream>

int main() {
    int n, k;
    long *v;
    cout << "n = "; cin >> n;
    v = new long[n];
    for (k = 0; k < n; k++) {
        cout << "v[" << k << "] = ";
        cin >> v[k];
    }
    long temp = v[n - 1];
    for (k = n - 1; k > 0; k--) {
        v[k] = v[k - 1];
    }
    v[0] = temp;
    for (k = 0; k < n; k++) {
        cout << v[k] << " ";
    }
    cout << endl;
    delete[] v;
    return 0;
}

4.

a) Soluția evidentă a acestei probleme constă în stocarea valorilor citite din fișier într-un vector, sortarea acestuia urmată de parcurgerea sa, perechile fiind reprezentate de valorile adiacente a căror diferență este mai mare sau egală cu 2. Totuși, cei mai buni algoritmi de sortare (heapsort, mergesort) au de regulă complexitatea O(nlogn), ceea ce face ca o astfel de abordare să nu fie eficientă.

O soluție în timp liniar presupune utilizarea unui tablou de apariții, de maxim 101 elemente, având în vedere că numerele care apar în fișier pot avea doar valori din intervalul [0, 100]. Semnificația unui element  de pe o anumită poziție din acest vector este următoarea:

  • 0 – numărul corespunzător poziției respective nu se regăsește în șir
  • 1 – numărul corespunzător poziției respective se regăsește în șir, cel puțin o dată

Se asigură în acest mod și eficiența din punctul de vedere al memoriei folosite, întrucât se alocă doar un vector de 101 elemente, în timp ce numărul de termeni din șir poate atinge un milion.

Se parcurge ulterior vectorul de apariții, o singură dată (astfel încât complexitatea algoritmului este O(n)), reținându-se, la fiecare pas, indicele poziției la care a fost întâlnit cel mai apropiat element nenul. În situația în care se întâlnește un element nenul (corespunzător unui termen care se regăsește în șir), se verifică dacă anterior a mai fost întâlnit un alt element nenul și în caz afirmativ, se determină dacă diferența dintre poziții (deci dintre termeni) este mai mare sau egală cu 2, situație în care a fost identificată o pereche care respectă condițiile problemei, afișându-se mesajul DA și terminându-se căutarea. Trebuie să se aibă grijă ca de fiecare dată când se întâlnește un element nenul, să se actualizeze valoarea elementului precedent nenul întâlnit.

În situația în care căutarea a ajuns la ultimul element, înseamnă că nu a fost identificată nici o pereche și prin urmare se afișează mesajul NU.

b)

using namespace std;

#define MAX_SIZE 100

#include <iostream>
#include <fstream>

int main() {
    ifstream file("bac.txt");
    int *exists = new int[MAX_SIZE + 1], n, last_position = -1;
    for (n = 0; n <= MAX_SIZE; n++) {
        exists[n] = 0;
    }
    if (file.is_open()) {
        while (file >> n) {
            exists[n] = 1;
        }
        file.close();
        for (n = 0; n <= MAX_SIZE; n++) {
            if (exists[n]) {
                if ((last_position != -1) && (n - last_position >= 2)) {
                    cout << "DA" << endl;
                    break;
                }
                last_position = n;
            }
        }
    }
    if (n == MAX_SIZE + 1) {
        cout << "NU" << endl;
    }
    delete[] exists;
    return 0;
}

Rezolvarea subiectelor de informatică de la examenul de bacalaureat național, sesiunea august 2014 (2)

Filiera teoretică, profilul real, specializarea științe ale naturii

 

Enunțul subiectelor precum și baremul de corectare pot fi descărcate de pe site-ul Ministerului Educației Naționale.

Pe contul de GitHub poate fi consultat codul sursă corespunzător subiectelor care solicită elaborarea de programe C/C++.

SUBIECTUL I (30 de puncte)


Acest subiect este identic cu cel de la specializarea matematică-informatică.

SUBIECTUL II (30 de puncte)


1. Pentru ca expresia sqrt(x/10+x%10)==4 să aibă valoarea 1 (adică valoarea de adevăr adevărat), este necesar ca expresia de sub radical să aibă valoarea 16, adică x/10+x%10=16. Se cere valoarea maximă a lui x, acesta fiind un număr întreg cu 2 cifre.

Pentru x ≥ 90, x/10 = 9, aceasta fiind valoarea maximă pe care o poate avea această expresie. Prin urmare x%10 = 16 – x/10 = 16 – 9 = 7. Singura valoare care întrunește simultan condițiile x ≥ 90 și x%10=7 este x=97.

Într-adevăr, 97/10+97%10=9+7=16 și aceasta este valoarea maximă a unui întreg format din 2 cifre care să respecte condiția dată.

Răspuns corect: d.

2. Pentru a determina formula de calcul a sumei numerelor dintr-un interval [k, n], k<n, numere naturale, se recurge la formula de calcul a unor numere în progresie aritmetică, cu termenul inițial a1=1 și rația r = 1:

1 + 2 + … + n = n(n + 1) / 2

1 + 2 + … + (k-1) = k(k – 1) / 2

de unde Sn,k = k + … + n = 1 + 2 + … + n – (1 + 2 + … + (k-1)) = n(n + 1) / 2 – k(k – 1) / 2 = (n2 + n – k2 + k) / 2 = (n2 – k2 + n + k) / 2 = ((n + k)(n – k) + (n + k)) / 2 = (n + k)(n – k + 1) / 2

Ultima cifră a sumei se determină ca rest al împărțirii la 10: Sn,k % 10 = ((n + k)(n – k + 1) / 2) % 10.

a) Se observă că secvența S1 folosește o formulă de calcul prescurtat pentru ultima cifră a sumei, având aceeași expresie ca cea determinată mai sus și prin urmare, corectă.

b) În secvența S2 sunt adunate, în cadrul unui ciclu repetitiv for, toate numerele cuprinse între k și n, reținându-se în fiecare pas al iterației doar ultima cifră,  această metodă de calcul fiind de asemenea corectă.

c) În secvența S3 se adaugă, tot în cadrul unui ciclu repetitiv for, un număr din intervalul [k + 1, n] la ultima cifră a sumei calculată până la pasul respectiv al iterației. O astfel de abordare prezintă două erori:

c.1) omite numărul k, iterația realizându-se de la k+1;

c.2) nu determină întotdeauna ultima cifră a sumei, pentru valori ale lui n > 9 obținându-se de fapt rezultatul adunării ultimului număr al intervalului (n) cu ultima cifră a sumei numerelor din intervalul [k + 1, n – 1].

Prin urmare, numai secvențele S1 și S2 furnizează rezultatul dorit.

Răspuns corect: a.

Exercițiul reprezintă o capcană pentru candidații insuficient pregătiți la matematică, pe care formula din secvența S1 îi poate induce în eroare, cu atât mai mult cu cât există ca variantă de răspuns care dă drept corectă doar secvența de cod S2.

3. Problema presupune citirea unei variabile de tip char și prelucrarea ei (incrementare / decrementare) într-o instrucțiune switch care testează dacă caracterul aparține mulțimii {‘a’, ‘e’, ‘i’} sau nu.

using namespace std;

#include <iostream>

int main() {
    char c;
    cout << "c="; cin >> c;
    switch (c) {
        case 'a':
        case 'e':
        case 'i':
            c++;
            break;
        default:
            c--;
    }
    cout << c << endl;
    return 0;
}

4. Acest subiect este identic cu cerința 3, subiectul III de la specializarea matematică-informatică, cu excepția faptului că nu se solicită scrierea programului C/C++ corespunzător, ci descrierea algoritmului în pseudocod, fără utilizarea de subprograme.

a) Se generează toate combinațiile posibile pentru x ∈ [0, n], respectiv y ∈ [x + 1, n] (astfel încât să se respecte restricția x < y), urmând să se verifice dacă există un z întreg, y < z, calculat după formula z = (n – x * y) / y.

Valorile pentru x și y vor fi generate prin cicluri repetitive de tip pentru, cu pasul de incrementare 1, testându-se pentru fiecare pereche (x, y) astfel generată dacă respectă condiția impusă:

repetă

    citește n

până când n≥2

pentru x = 0, n; pas 1

    pentru y = x + 1, n; pas 1

        z = (n – x * y) / y

        dacă (n – x * y) % y == 0 și y < z atunci

            tipărește “(“,x,”,”,y,”,”,z,”)”

b) Data de intrare este reprezentată de numărul natural n. Datele de ieșire sunt reprezentate de soluțiile ecuației (x, y, z).

Variabilele x și y sunt generate în cadrul unui ciclu repetitiv cu număr cunoscut de pași de tip pentru (cu pasul de incrementare 1), luând valori în intervalele [0, n], respectiv [x + 1, n], calculându-se valoarea lui z în funcție de acestea. Dacă valoarea astfel determinată satisface restricțiile impuse de problemă (z întreg și y < z), atunci se afișează soluția găsită.

SUBIECTUL III (30 de puncte)


1. Verificăm, succesiv, care sunt valorile testate pentru fiecare dintre variantele de răspuns:

a) (16, 17, 21, 29, 49, 80, 95) – vector cu 7 elemente

Se caută elementul pe poziția 4; acesta este 29, dar 21 < 29 și se continuă căutarea în partea stângă a vectorului (16, 17, 21).

Se caută elementul pe poziția 2; acesta este 17, dar 21 > 17 și se continuă căutarea în partea dreaptă a vectorului (21).

Se caută elementul pe poziția 3; acesta este 21, elementul a fost găsit.

Elementele cu care s-a realizat compararea au fost (29, 17, 21) – nu corespund cu valoarea indicată în enunț.

b) (4, 16, 21, 49, 56, 70, 85) – vector cu 7 elemente

Se caută elementul pe poziția 4; acesta este 49, dar 21 < 49 și se continuă căutarea în partea stângă a vectorului (4, 16, 21).

Se caută elementul pe poziția 2; acesta este 16, dar 21 > 16 și se continuă căutarea în partea dreaptă a vectorului (21).

Se caută elementul pe poziția 3; acesta este 21, elementul a fost găsit.

Elementele cu care s-a realizat compararea au fost (49, 16, 21) – corespund cu valoarea indicată în enunț.

c) (7, 9, 10, 16, 21, 45, 49) – vector cu 7 elemente

Se caută elementul pe poziția 4; acesta este 16, dar 21 > 16 și se continuă căutarea în partea dreaptă a vectorului (21, 45, 49).

Se caută elementul pe poziția 6; acesta este 45, dar 21 < 45 și se continuă căutarea în partea stângă a vectorului (21).

Se caută elementul pe poziția 5; acesta este 21, elementul a fost găsit.

Elementele cu care s-a realizat compararea au fost (16, 45, 21) – nu corespund cu valoarea indicată în enunț.

d) (16, 20, 21, 49, 50, 56, 59) – vector cu 7 elemente

Se caută elementul pe poziția 4; acesta este 49, dar 21 < 49 și se continuă căutarea în partea stângă a vectorului (16, 20, 21).

Se caută elementul pe poziția 2; acesta este 20, dar 21 > 20 și se continuă căutarea în partea dreaptă a vectorului (21).

Se caută elementul pe poziția 3; acesta este 21, elementul a fost găsit.

Elementele cu care s-a realizat compararea au fost (49, 20, 21) – nu corespund cu valoarea indicată în enunț.

Răspuns corect: b.

3. În rezolvarea problemei se presupune inițial că toate numerele citite sunt strict mai mici decât 2014 (ok=1), valoarea acesteia modificându-se la 0 în structura repetitivă cu număr cunoscut de pași de tip for în cazul în care s-a citit un număr în variabila x care nu respectă o astfel de condiție.

using namespace std;

#include <iostream>

int main() {
    int ok = 1, i, x;
    for (i = 1; i <= 10; i++) {
        cin >> x;
        if (x >= 2014) ok = 0;
    }
    cout << ok << endl;
    return 0;
}

Secvența poate fi optimizată în sensul opririi procesului de citire în condițiile în care s-a citit deja un număr mai mare sau egal cu 2014, citirea următoarelor numere nemodificând în nici un fel rezultatul:

for (i = 1; i <= 10 && ok; i++) {
    // ...
}

3. Acest subiect reprezintă o variantă simplificată a cerinței 5, subiectul II de la specializarea matematică-informatică, solicitându-se generarea numerelor pare nedivizibile cu 5 într-un vector în loc de o matrice.

Generarea numerelor pare nedivizibile cu 5 nu comportă probleme: se pornește de la valoarea 2 și se realizează incrementarea cu 2 atâta vreme cât valoarea obținută nu este divizibilă cu 5, altfel se trece mai departe. Valorile sunt completate în ordine, în vector, de la poziția cea mai mică spre poziția cea mai mare.

using namespace std;

#include <iostream>

int main() {
    int n, *vector, k, numar_curent = 2;
    do {
        cout << "n=";
        cin >> n;
    } while (n < 2 || n > 50);
    vector = new int [n];
    for (k = 0; k < n; k++) {
        while (numar_curent % 5 == 0)
            numar_curent += 2;
        vector[k] = numar_curent;
        numar_curent += 2;
    }
    for (k = 0; k < n; k++)
        cout << vector[k] << " ";
    cout << endl;
    delete[] vector;
    return 0;
}

4. Acest subiect reprezintă o variantă simplificată a celui omolog de la specializarea matematică-informatică, cerându-se doar determinarea numărului aflat pe o anumită poziție după identificarea valorilor distincte și sortarea acestora în ordine crescătoare.

a) O soluție eficientă trebuie să țină cont de formatul datelor din fișier, și anume puteri ale lui 10 mai mici sau egale cu 9. În acest sens, se poate construi un vector care să rețină, pentru fiecare putere în parte, dacă numărul corespunzător acesteia apare sau nu în fișier. Suma valorilor acestui vector reprezintă, astfel, numărul de valori distincte. Ulterior, numărul aflat pe poziția cerută este puterea pentru care suma aparițiilor (0 sau 1) de până la el este mai mică sau egală cu poziția respectivă.

Astfel, complexitatea algoritmului propus este O(1) – întrucât se parcurge un vector cu 10 elemente. În situația în care datele din fișier ar fi fost stocate ca atare într-un vector, și s-ar fi aplicat un algoritm de sortare clasic (quick-sort, de exemplu), eliminându-se valorile duplicate, complexitatea ar fi fost în medie O(nlogn) sau O(n2) în cazul cel mai defavorabil. De remarcat faptul că eficiența se manifestă nu doar în privința timpului de execuție, ci și a memoriei folosite întrucât se folosește un vector de întregi de 10 elemente (10*2octeți = 20 octeți); dacă s-ar fi reținut toate numerele din fișier, s-ar fi putut utiliza până la 106 * 4 octeți (variabile de tip long) ≅ 4 MB de memorie.

b)

using namespace std;

#define MAX 10

#include <iostream>
#include <fstream>

int numar_putere(long n) {
    int rezultat = 0;
    while (n != 1)
        if (n % 10 == 0) {
        rezultat++;
        n /= 10;
        }
        else
            return -1;
    return rezultat;
}

long putere_numar(int putere) {
    int rezultat = 1;
    while (putere) {
        rezultat *= 10;
        putere--;
    }
    return rezultat;
}

int main() {
    long n, numar_curent;
    int index, total = 0, *aparitii = new int[MAX];
    for (index = 0; index < MAX; index++)
        aparitii[index] = 0;
    // deschidere fisier
    ifstream fisier("bac.txt");
    if (fisier.is_open()) {
        fisier >> n;
        while (fisier >> numar_curent) {
            // determinare putere p a numarului de forma 10^p citit din fisier
            index = numar_putere(numar_curent);
            if (index != -1) { // numarul citit din fisier are forma corecta
                if (!aparitii[index])
                    // numarul de pe pozitia index nu a mai fost descoperit pana acum
                    // incrementare total de valori distincte
                    total++;
                // macare a numarului de pe pozitia index ca distinct
                aparitii[index] = 1;
            }
        }
        // inchidere fisier
        fisier.close();
    }
    if (total < n)
        cout << "Nu exista" << endl;
    else {
        index = 0;
        total = 0; // total valori distincte pana la indexul curent
        while (total < n) // nu s-a ajuns la pozitia cautata
            // incrementare total valori distincte, daca este cazul
            total += aparitii[index++];
        cout << putere_numar(--index) << endl;
    }
    delete[] aparitii;
    return 0;
}

Rezolvarea subiectelor de informatică de la examenul de bacalaureat național, sesiunea iulie 2014 (2)

Filiera teoretică, profilul real, specializarea științe ale naturii

 

Enunțul subiectelor precum și baremul de corectare pot fi descărcate de pe site-ul Ministerului Educației Naționale.

Pe contul de GitHub poate fi consultat codul sursă corespunzător subiectelor care solicită elaborarea de programe C/C++.

SUBIECTUL I (30 de puncte)


Acest subiect este identic cu cel de la specializarea matematică-informatică.

 

SUBIECTUL II (30 de puncte)


1. Subiectul urmărește să verifice cunoașterea funcțiilor predefinite din limbajul C/C++ (abs) precum și abilități cu privire la rezolvarea unor probleme.

Pentru x ∈ [45, 55], valorile pe care le poate lua expresia x/10 sunt 4 (pentru x ∈ [45, 49]) sau 5 (pentru x ∈ [50, 55]) iar ale expresiei x%10 pot fi cuprinse între 0 (pentru x=50) și 9 (pentru x=49). Așadar, diferența maximă dintre cele două expresii (în modul) poate fi 5, aceasta obținându-se atât pentru x=49 (abs(4-9)=5) cât și pentru x=50(abs(5-0)=0).

Răspunsul corect este b.

 

2. Prin acest exercițiu se dorește să se verifice capacitatea de înțelegere a unui algoritm precum și posibilitatea de completare a acestuia.

În enunț se precizează faptul că m>n, cu alte cuvinte m-n>0. De asemenea, se observă că pe fiecare iterație a instrucțiunii repetitive cu test final x este incrementat cu 1, y este decrementat cu 1, astfel încât diferența x-y va fi incrementată cu 2. Pentru a se satisface condiția de terminare a ciclului repetitiv (x<y ⇔ x-y<0), trebuie să se realizeze un număr de iterații egal cu:

a) (m-n)/2, dacă n-m este par, astfel încât diferența inițială (negativă) n-m (valoarea lui x-y) să fie anulată (la sfârșitul ciclului repetitiv cu test final x=y)

În aceste condiții r=m-n (după înmulțirea cu 2) numai dacă r reflectă numărul de iterații ale ciclului repetitiv cu test final, adică r = r + 1

b) (m-n)/2 + 1, dacă n-m este impar, astfel încât diferența inițială (negativă) n-m (valoarea lui x-y) să fie devină pozitivă (la sfârșitul ciclului repetitiv cu test final x = y + 1)

În aceste condiții r=m-n(+1) (după înmulțirea cu 2 și decrementarea în urma testului de egalitate dintre x și y – din rezultat ar fi trebuit să se scadă 2 și nu 1) numai dacă r reflectă numărul de iterații ale ciclului repetitiv cu test final, adică r = r + 1

Răspunsul corect este c.

 

3. Acest subiect reprezintă o variantă a celui omolog de la specializarea matematică-informatică, propunându-și să verifice capacitatea unui elev de a elabora un algoritm relativ simplu. Nu este testată capacitatea elevului de a lucra cu structuri de date.

Și pentru această problemă trebuie tratate cele trei cazuri:

a) minutul de start este mai mic decât minutul de stop (momentul de start este anterior momentului de stop) ⇒ rezultat acceptat;

b) minutul de start este egal cu minutul de stop:

    1. secunda de start este mai mică decât secunda de stop (momentul de start este anterior momentului de stop) ⇒ rezultat acceptat;

    2. secunda de start este egală sau mai mare decât secunda de stop (momentul de start coincide cu momentul de stop sau este ulterior momentului de stop) ⇒ rezultat respins.

c) minutul de start este mai mare cu minutul de stop (momentul de start este ulterior momentului de stop) ⇒ rezultat respins.

using namespace std;

#include <iostream>

int main() {
    int minut_start, secunda_start, minut_stop, secunda_stop;
    cout<<“start”<<endl;
    cout<<“minut:”; cin>>minut_start;
    cout<<“secunda:”; cin>>secunda_start;
    cout<<“stop”<<endl;
    cout<<“minut:”; cin>>minut_stop;
    cout<<“secunda:”; cin>>secunda_stop;
    if (minut_start<minut_stop)
        cout<<“acceptat”<<endl;
    else if (minut_start==minut_stop) {
        if (secunda_start<secunda_stop)
            cout<<“acceptat”<<endl;
        else
            cout<<“respins”<<endl;
    } else if (minut_start>minut_stop)
        cout<<“respins”<<endl;
    return 0;
}

 

4. Acest subiect este identic cu cerința 3, subiectul III de la specializarea matematică-informatică, cu excepția faptului că nu se solicită scrierea programului C/C++ corespunzător ci descrierea algoritmului în pseudocod, fără utilizarea de subprograme.

a) Este evident că trebuie respectate simultan condițiile:

  • n! ∈ [a, b]
  • (n-1)! ∉ [a, b]
  • (n+1)! ∉ [a, b]
  • b-a maxim

de unde rezultă automat faptul că a = (n-1)! + 1 și b=(n+1)! – 1.

Algoritmul în pseudocod este următorul:

citește n

factorial ← 1

pentru contor = 2, n-1

    factorial ← factorial * contor

a ← factorial + 1

b ← factorial * n * (n + 1) – 1

afișează a, b

b) Datele de intrare sunt n, care trebuie să respecte condiția de a face parte din intervalul [2, 10].

Datele de ieșire sunt a și b, reprezentând limita inferioară, respectiv limita superioară a intervalului factorial.

A fost utilizată o variabilă contor, pentru a indica iterația curentă în ciclul repetitiv cu număr cunoscut de pași și variabila factorial, în care se calculează valoarea (n-1)!, utilizată ulterior pentru determinarea limitei inferioare, respectiv a limitei superioare a intervalului factorial.

Având formulele pentru limita inferioară, respectiv limita superioară determinate mai sus, algoritmul nu trebuie decât să calculeze (n-1)! (printr-un algoritm iterativ, folosind un ciclu repetitiv cu număr cunoscut de pași – factorial = 1 * 2 * … * (n-1)) și pe baza sa a (n+1)! care sunt ulterior incrementate, respectiv decrementate pentru a se obține valorile dorite.

 

SUBIECTUL III (30 de puncte)


1. Interclasarea a doi vectori presupune introducerea elementelor unui vector neordonat între elementele unui vector ordonat (de obicei crescător), astfel încât după această operație să se mențină proprietatea de ordine între elementele vectorului rezultat (xi < xj, ∀i<j).

În cazul de față se cunosc A = (4, 11, 14, 18, 21) și A ∪ B = (3, 4, 8, 11, 14, 14, 17, 18, 21, 46). Pentru determinarea vectorului B, trebuie realizată operația de diferență dintre A ∪ B și A.

Procedând astfel, se obține că B = (A ∪ B) \ A = (3, 4, 8, 11, 14, 14, 17, 18, 21, 46) \ (4, 11, 14, 18, 21) = (3, 8, 14, 17, 46). Acestea sunt valorile pe care vectorul B trebuie să le conțină, nu neapărat în această ordine, întrucât sortarea se realizează în cadrul operației de interclasare, fiecare element din B fiind plasat în A ∪ B pe poziția corespunzătoare, astfel încât să se mențină proprietatea de ordine.

Dintre toate variantele de răspuns, se observă că doar varianta b conține toate elementele vectorului B și numai pe cele aparținându-i acestuia.

 

2. Exercițiul reprezintă o problemă clasică de căutare a unei valori într-o mulțime neordonată.

În secvența dată se citesc 10 valori de la tastatură și se cere ca variabila ok să rețină rezultatul căutării (0 dacă valoarea nu face parte din mulțime, 1 dacă aceasta este identificată printre elementele mulțimii).

Prin urmare, valoarea ok va fi inițializată cu 0 (inițial, valoarea nu a fost găsită), urmând ca în ciclul repetitiv cu număr cunoscut de pași să se modifice valoarea acesteia (în 1) în condițiile în care, în urma unui instrucțiuni de tip decizional, elementul citit este identificat ca fiind cel căutat.

ok = 0; // elementul nu a fost gasit printre valorile citite

for(i = 1; i <= 10; i++) {

    cin>>x;

    if (x == 2014)

        ok = 1; // elementul a fost gasit printre valorile citite

}

 

3. Subiectul vizează verificarea modului de lucru cu tablouri (citire, scriere, indexare, modificare a valorilor conform unei condiții). De asemenea, deși baremul nu o precizează explicit, ar trebui urmărit modul de alocare / dealocare (dinamică) a memoriei pentru tablou, respectiv verificarea restricțiilor precizate în enunț pentru datele de intrare (n și x cuprinse între anumite valori, elementele vectorului de maxim 4 cifre, minim un element par în vector).

Prin urmare, algoritmul:

  • va citi variabila n, urmărind respectarea restricțiilor specificate în enunț;
  • va aloca tabloul dinamic (pentru fix atâtea elemente câte urmează să fie citite);
  • va citi fiecare element al tabloului, într-o secvență repetitivă cu număr cunoscut de pași, verificând, pentru fiecare în parte, dacă a fost respectat criteriul de validare
  1. pentru fiecare element al tabloului în parte, să aibă maxim 4 cifre (să fie mai mic decât 10000);
  2. doar la ultimul element, să fie existat anterior cel puțin un element par (restul împărțirii la 2 să fie 0) – întânirea unui astfel de element se face pentru fiecare element al tabloului care respectă criteriul de validare;
  • va citi variabila x, urmărind respectarea restricțiilor specificate în enunț;
  • va parcurge tabloul, scăzând valoarea x din elementul curent în cazul în care acesta este par;
  • va scrie fiecare element al tabloului, acesta fiind separat de celelalte printr-un spațiu;
  • va dealoca spațiul de memorie rezervat pentru tablou.

using namespace std;

#include <iostream>

int main() {
    int n, *vector, x, contor, par = 0;
    do {
        cout<<“n=”;
        cin>>n;
    } while (n <= 2 || n >= 50);
    vector = new int[n];
    for (contor=0; contor < n; contor++) {
        int conditie = 0;
        do {
            cout<<“vector[“<<(contor+1)<<“]=”;
            cin>>vector[contor];
            if (vector[contor] < 10000) {
                if (vector[contor] % 2 == 0)
                    par = 1;
                if (contor == (n – 1)) {
                    if (par)
                        conditie = 1;
                }
                else
                    conditie = 1;
            }
        } while (!conditie);
    }
    do {
        cout<<“x=”;
        cin>>x;
    } while (x <= 0 || x >= 10);
    for (contor = 0; contor < n; contor++)
        if (vector[contor] %2 == 0)
            vector[contor] -= x;
    for (contor = 0; contor < n; contor++)
        cout<<vector[contor]<<” “;
    cout<<endl;
    delete vector;
    return 0;
}

 

4. Acest subiect reprezintă o variantă simplificată a  celui omolog de la specializarea matematică-informatică, solicitându-se identificarea cifrelor cu apariție maximă, nu a subnumerelor (de 2 cifre).

a) Se determină toate cifrele unui număr (ca rest al împărțirii la 10 al acestuia), eliminându-se succesiv ultima cifră (prin împărțirea sa la 10) până când acesta devine nul (nu mai conține cifre). Valorile cifrelor și numărul de apariții al fiecărui subnumăr va fi contorizat în cadrul a doi vectori, unul care reține valorile (cifre), iar celălalt care stochează numărul de apariții (ocurente). De fiecare dată se verifică, prin căutare, dacă cifra respectivă există anterior. (S-ar fi putut inițializa un vector cu 10 elemente corespunzătoare fiecărei cifre de la 0 la 9, eliminându-se altfel vectorul care reține cifrele propriu-zise precum și căutarea care se realizează de fiecare dată pentru a se verifica dacă cifra respectivă există sau nu). Se determină maximul numărului de ocurențe și valoarea (valorile) corespunzătoare acestui maxim se afișează.

Complexitatea algoritmului propus este O(n) întrucât vectorul este parcurs de 2 ori, odată pentru determinarea cifrelor și odată pentru determinarea maximului numărului de ocurențe (stocarea valorilor cifrelor în vector presupune și ea o parcurgere pentru căutare, însă și aceasta se realizează tot în timp liniar și poate fi eliminată prin varianta amintită).

b)

Soluția 1:

using namespace std;

#include <iostream>
#include <fstream>

#define MAX 10 // pot fi maxim 10 cifre, insa nu este obligatoriu ca toate sa se regaseasca in fisier

int main() {
    long numar;
    // vectori ce contin
    // – valorile cifrelor aferente numerelor din fisier
    // – numarul de aparitii pentru fiecare cifra
    int *cifre, *ocurente, dimensiune = 0;
    // alocare memorie
    cifre = new int[MAX];
    ocurente = new int[MAX];
    // deschidere fisier
    ifstream fisier(“bac.txt”);
    if (fisier.is_open()) {
        // citire numar din fisier
        while (fisier>>numar) {
            while (numar != 0) {
                // determinare cifra
                int cifra = numar % 10, gasit = 0;
                // cautare cifra in vector
                for (int contor = 0; contor < dimensiune && !gasit; contor++)
                    // cifra a fost gasita in vector, se incrementeaza numarul de ocurente
                    if (cifre[contor] == cifra) {
                        ocurente[contor]++;
                        gasit = 1;
                    }
                // cifra nu a fost gasit in vector, se stocheaza (numarul de ocurente este 1)
                if (!gasit) {
                    cifre[dimensiune] = cifra;
                    ocurente[dimensiune] = 1;
                    dimensiune++;
                }
                numar /= 10;
            }
        }
        // inchidere fisier
        fisier.close();
    }
    // determinare numar maxim de ocurente
    int maxim = 1;
    for (int contor = 0; contor < dimensiune; contor++)
        if (ocurente[contor] >= maxim)
            maxim = ocurente[contor];
    // afisarea subnumerelor care apar de cele mai multe ori
    for (int contor = 0; contor < dimensiune; contor++)
        if (ocurente[contor] == maxim)
            cout<<cifre[contor]<<” “;
    cout<<endl;
    // dealocare memorie
    delete cifre;
    delete ocurente;
    cin>>maxim;
    return 0;
}

Soluția 2:

using namespace std;

#include <iostream>
#include <fstream>

#define MAX 10 // pot fi maxim 10 cifre, insa nu este obligatoriu ca toate sa se regaseasca in fisier

int main() {
    long numar;
    // vector ce contine numarul de aparitii pentru fiecare cifra
    // ocurente[i] – numarul de aparitii pentru cifra i, i=0..9
    int *ocurente, dimensiune = 0;
    // alocare memorie
    ocurente = new int[MAX];
    for (int contor = 0; contor < MAX; contor++)
        ocurente[contor] = 0;
    // deschidere fisier
    ifstream fisier(“bac.txt”);
    if (fisier.is_open()) {
        // citire numar din fisier
        while (fisier>>numar) {
            while (numar != 0) {
                // determinare cifra
                int cifra = numar % 10;
                // incrementarea numarului de ocurente pentru cifra curenta
                ocurente[cifra]++;
                numar /= 10;
            }
        }
        // inchidere fisier
        fisier.close();
    }
    // determinare numar maxim de ocurente
    int maxim = 1;
    for (int contor = 0; contor < MAX; contor++)
        if (ocurente[contor] >= maxim)
            maxim = ocurente[contor];
    // afisarea subnumerelor care apar de cele mai multe ori
    for (int contor = 0; contor < MAX; contor++)
        if (ocurente[contor] == maxim)
            cout<<contor<<” “;
    cout<<endl;
    // dealocare memorie
    delete ocurente;
    return 0;
}