Subiect oficial de bacalaureat

BAC Informatică C/C++ - iunie 2023 (Varianta 5)

180 de minute90 de puncte + 10 din oficiu15 cerințe

Toate subiectele sunt obligatorii. Se acordă zece puncte din oficiu. Timpul de lucru efectiv este de trei ore. Identificatorii utilizați în rezolvări trebuie să respecte precizările din enunț.

Subiectul I

Subiectul I.14 puncte

Indicați expresia C/C++ care are cea mai mare valoare, comparativ cu celelalte trei expresii.

a. 20*23/(2*2) b. 20/2*23/2 c. (20*23)/2 d. (20*23)/2*2

Rezolvare

Operatorii * și / au aceeași prioritate și se aplică de la stânga la dreapta (împărțire întreagă).

  • a. 20*23/(2*2) =460/4=115= 460/4 = 115
  • b. 20/2*23/2 =10⋅23/2=230/2=115= 10 \cdot 23 / 2 = 230/2 = 115
  • c. (20*23)/2 =460/2=230= 460/2 = 230
  • d. (20*23)/2*2 =230⋅2=460= 230 \cdot 2 = 460

Cea mai mare valoare este 460460, deci răspunsul corect este d.

Barem

Item grilă: se cerea expresia C/C++ cu cea mai mare valoare dintre a. 2023/(22), b. 20/223/2, c. (2023)/2, d. (2023)/22. Barem: 4 puncte pentru litera d. Justificare: operatorii și / au aceeași prioritate și se evaluează de la stânga la dreapta, deci a = 460/4 = 115, b = 1023/2 = 115, c = 460/2 = 230, d = 460/22 = 2302 = 460 (cea mai mare). Fără punctaj parțial.

Învață lecția: Elemente de bază ale limbajului C++
Subiectul I.24 puncte

Subprogramul f este definit alăturat. Indicați ce se afișează în urma apelului f(23);.

void f(int n)
{ if(n!=0) f(n/2);
  cout<<n%2;
}

a. 100111 b. 111010 c. 010111 d. 01251123

Rezolvare

Apelurile recursive se fac înaintea afișării, deci afișarea are loc la revenirea din recursivitate:

f(23)→f(11)→f(5)→f(2)→f(1)→f(0)f(23) \to f(11) \to f(5) \to f(2) \to f(1) \to f(0)

La revenire se afișează, în ordine: 0%2=00\%2=0, 1%2=11\%2=1, 2%2=02\%2=0, 5%2=15\%2=1, 11%2=111\%2=1, 23%2=123\%2=1.

Pe ecran apare 010111, adică reprezentarea binară a lui 2323 (1011110111) precedată de un 00. Răspunsul corect este c.

Barem

Item grilă: subprogram recursiv void f(int n) { if(n!=0) f(n/2); cout<<n%2; } apelat cu f(23); se cerea ce se afișează. Barem: 4 puncte pentru litera c (se afișează 010111). Justificare: apelurile recursive coboară f(23)->f(11)->f(5)->f(2)->f(1)->f(0), iar afișările se fac la revenire, în ordinea 0%2=0, 1%2=1, 2%2=0, 5%2=1, 11%2=1, 23%2=1, adică 010111 (reprezentarea binară a lui 23 precedată de 0). Fără punctaj parțial.

Învață lecția: Recursivitate
Subiectul I.34 puncte

Variabila k este de tip întreg, iar variabila s permite memorarea unui șir de maximum 50 de caractere. Indicați valoarea variabilei k în urma executării secvenței alăturate.

strcpy(s,"bac2023");
s[s[2]-'a']='\0';
k=strlen(s);

a. 7 b. 6 c. 2 d. 1

Rezolvare

După strcpy, șirul este "bac2023". Caracterul s[2] este 'c', iar 'c'-'a' =2= 2.

Atribuirea s[2]='\0' trunchiază șirul la primele două caractere: "ba".

Astfel k=strlen(s) =2= 2. Răspunsul corect este c.

Barem

Item grilă: după strcpy(s,"bac2023"); s[s[2]-'a']='\0'; k=strlen(s); se cerea valoarea lui k. Barem: 4 puncte pentru litera c (k=2). Justificare: s[2]='c', 'c'-'a'=2, deci s[2] primește '\0' și șirul devine "ba", cu lungimea 2. Fără punctaj parțial.

Învață lecția: Șiruri de caractere
Subiectul I.44 puncte

Indicați un vector de „tați” corespunzător unui arbore cu 7 noduri, în care cel puțin unul dintre noduri are trei ascendenți.

a. 0,1,2,1,1,1,2 b. 3,0,2,1,3,2,1 c. 4,3,0,3,4,4,3 d. 5,4,3,0,2,3,4

Rezolvare

La varianta b, vectorul de tați (3,0,2,1,3,2,1) descrie arborele cu rădăcina în nodul 22 (singurul cu tatăl 00):

  • tatăl nodului 11 este 33, tatăl nodului 33 este 22;
  • tatăl nodului 44 este 11.

Lanțul de ascendenți ai nodului 44 este: 11, apoi 33, apoi 22 (rădăcina), deci nodul 44 are exact trei ascendenți.

La varianta a, adâncimea maximă este 2 (niciun nod cu trei strămoși), iar variantele c și d nu oferă un nod cu trei ascendenți în structura de arbore cerută. Răspunsul corect este b.

Barem

Item grilă: se cerea vectorul de tați al unui arbore cu 7 noduri în care cel puțin un nod are trei ascendenți (strămoși), dintre a. 0,1,2,1,1,1,2; b. 3,0,2,1,3,2,1; c. 4,3,0,3,4,4,3; d. 5,4,3,0,2,3,4. Barem: 4 puncte pentru litera b. Justificare: la varianta b rădăcina este nodul 2 (tată 0), iar nodul 4 are tatăl 1, care are tatăl 3, care are tatăl 2, deci nodul 4 are trei ascendenți (1, 3, 2). Celelalte variante fie nu au un nod cu trei ascendenți, fie nu descriu un arbore valid. Fără punctaj parțial.

Învață lecția: Grafuri și arbori - terminologie, proprietăți și reprezentare
Subiectul I.54 puncte

O companie de colectare a fructelor are 6 depozite, numerotate de la 1 la 6: depozitele 1, 3 și 5 conțin mere, depozitele 2 și 4 conțin pere, iar depozitul 6 conține piersici. Compania a construit 4 benzi de transport unidirecțional: de la depozitul 1 la depozitul 5, de la depozitul 5 la depozitul 2, de la depozitul 5 la depozitul 4 și de la depozitul 6 la depozitul 1. Dacă depozitele reprezintă vârfurile unui graf orientat, iar benzile de transport reprezintă arcele acestuia, indicați numărul minim de benzi de transport care pot fi adăugate, astfel încât graful obținut să aibă trei componente tare conexe, fiecare dintre acestea având vârfuri care corespund depozitelor cu același tip de fructe.

a. 4 b. 3 c. 2 d. 1

Rezolvare

Componentele tare conexe cerute sunt {1,3,5}\{1,3,5\} (mere), {2,4}\{2,4\} (pere) și {6}\{6\} (piersici).

  • Pentru {1,3,5}\{1,3,5\}: există doar arcul 1→51 \to 5. Un circuit care trece prin cele trei vârfuri necesită minimum 3 arce, deci trebuie adăugate încă 2 (de exemplu 5→35 \to 3 și 3→13 \to 1).
  • Pentru {2,4}\{2,4\}: nu există niciun arc între ele, deci sunt necesare 2 arce (2→42 \to 4 și 4→24 \to 2).
  • {6}\{6\}: un vârf singur formează o componentă tare conexă, nu necesită arce.

Arcele existente 5→25 \to 2, 5→45 \to 4, 6→16 \to 1 leagă componente diferite și nu strică proprietatea. Total minim: 2+2=42+2=4 arce. Răspunsul corect este a.

Barem

Item grilă: graf orientat cu 6 vârfuri și arcele 1->5, 5->2, 5->4, 6->1; se cerea numărul minim de arce de adăugat pentru trei componente tare conexe formate din depozitele cu același tip de fructe: {1,3,5} (mere), {2,4} (pere), {6} (piersici). Barem: 4 puncte pentru litera a (4 arce). Justificare: pentru {1,3,5} există doar arcul 1->5, deci sunt necesare încă 2 arce (de exemplu 5->3 și 3->1) pentru un circuit; pentru {2,4} nu există niciun arc între ele, deci sunt necesare 2 arce (2->4 și 4->2); {6} este tare conexă ca vârf izolat în componentă. Total minim: 2+2=4. Fără punctaj parțial.

Învață lecția: Grafuri și arbori - terminologie, proprietăți și reprezentare

Subiectul al II-lea

Algoritmul următor 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.

citește x (număr natural)
p ← 1; m ← -1
┌cât timp p≤x execută
│ c ← [x/p]%10
│┌dacă c>m atunci
││ m ← c; p ← p*10
││altfel
││ x ← [x/(p*10)]*p+x%p
│└■
└■
┌dacă m≥0 atunci scrie x
│ altfel scrie "nul"
└■
Subiectul II.1.a6 puncte

Scrieți valoarea afișată dacă se citește numărul 6907512.

Rezolvare

Algoritmul parcurge cifrele de la unități spre stânga; p indică poziția curentă, iar m reține cea mai mare cifră întâlnită. Dacă cifra curentă c este strict mai mare decât m, este păstrată; altfel este eliminată din număr.

Trasare pentru x=6907512x = 6907512:

  • c=2>−1c=2 > -1: se păstrează, m=2m=2, p=10p=10
  • c=1≤2c=1 \le 2: se elimină, x=690752x=690752
  • c=5>2c=5 > 2: se păstrează, m=5m=5, p=100p=100
  • c=7>5c=7 > 5: se păstrează, m=7m=7, p=1000p=1000
  • c=0≤7c=0 \le 7: se elimină, x=69752x=69752
  • c=9>7c=9 > 7: se păstrează, m=9m=9, p=10000p=10000
  • c=6≤9c=6 \le 9: se elimină, x=9752x=9752
  • p=10000>9752p=10000 > 9752: bucla se oprește

Cum m=9≥0m=9 \ge 0, se afișează 9752.

Barem

Pseudocod: citește x; p=1, m=-1; cât timp p<=x: c=[x/p]%10; dacă c>m atunci m=c, p=p10, altfel x=[x/(p10)]*p+x%p; la final, dacă m>=0 scrie x, altfel scrie "nul". Se cerea valoarea afișată pentru x=6907512. Barem: 6 puncte pentru răspunsul corect 9752. Algoritmul elimină, de la dreapta spre stânga, fiecare cifră care nu este strict mai mare decât toate cifrele din dreapta ei; din 6907512 rămân cifrele 9, 7, 5, 2. Fără punctaj parțial precizat în barem.

Învață lecția: Prelucrarea cifrelor unui număr
Subiectul II.1.b6 puncte

Scrieți două valori distincte din intervalul [100,999][100,999] care pot fi citite astfel încât, în urma executării algoritmului, pentru fiecare dintre acestea, să se afișeze o valoare identică cu cea citită.

Rezolvare

Numărul rămâne neschimbat doar dacă nicio cifră nu este eliminată, adică fiecare cifră este strict mai mare decât toate cifrele din dreapta ei. Asta înseamnă că cifrele numărului sunt în ordine strict descrescătoare de la stânga la dreapta.

Exemple de răspunsuri corecte: 321321 și 964964 (sau 875875, 210210, 953953 etc.).

Verificare pentru 321321: c=1c=1 se păstrează (m=1m=1), c=2>1c=2>1 se păstrează (m=2m=2), c=3>2c=3>2 se păstrează (m=3m=3); nimic nu se elimină, se afișează 321321.

Barem

Pentru pseudocodul care elimină din x fiecare cifră ce nu este strict mai mare decât toate cifrele aflate în dreapta ei, se cereau două valori distincte din [100,999] pentru care valoarea afișată este identică cu cea citită. Barem: 6 puncte, câte 3 puncte pentru fiecare dintre cele două numere conform cerinței. Corect este ORICARE număr de trei cifre cu cifrele în ordine strict descrescătoare (de exemplu 321, 964, 875, 210). Un număr fără această proprietate nu primește punctele respective.

Învață lecția: Prelucrarea cifrelor unui număr
Subiectul II.1.c10 puncte

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

Rezolvare
#include <iostream>
using namespace std;

int main() {
    long long x, p, m, c;
    cin >> x;
    p = 1;
    m = -1;
    while (p <= x) {
        c = (x / p) % 10;
        if (c > m) {
            m = c;
            p = p * 10;
        } else {
            x = x / (p * 10) * p + x % p;
        }
    }
    if (m >= 0)
        cout << x;
    else
        cout << "nul";
    return 0;
}

Împărțirea întreagă din C/C++ realizează direct [x/p], iar cele două structuri de decizie și bucla while urmează fidel pseudocodul.

Barem

Se cerea programul C/C++ corespunzător pseudocodului: citește x; p=1, m=-1; cât timp p<=x: c=[x/p]%10; dacă c>m atunci m=c, p=p10, altfel x=[x/(p10)]*p+x%p; la final, dacă m>=0 se afișează x, altfel se afișează textul nul. Barem (10 puncte): variabile declarate conform cerinței 1p; date citite conform cerinței 1p; date afișate conform cerinței 1p; instrucțiune repetitivă conform cerinței 2p; instrucțiuni de decizie conform cerinței 3p (se acordă numai 2p dacă doar una dintre instrucțiunile de decizie este corectă); atribuiri conform cerinței 1p; corectitudine globală a programului (structură, sintaxă) 1p. Împărțirile [x/p] se realizează ca împărțiri întregi.

Învață lecția: Structuri repetitive
Subiectul II.1.d6 puncte

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

Rezolvare

Structura cu test final execută corpul cel puțin o dată, deci trebuie protejată pentru cazul x=0x=0 (când bucla inițială nu se execută deloc):

citește x (număr natural)
p ← 1; m ← -1
┌dacă p≤x atunci
│┌repetă
││ c ← [x/p]%10
││┌dacă c>m atunci
│││ m ← c; p ← p*10
│││altfel
│││ x ← [x/(p*10)]*p+x%p
││└■
│└până când p>x
└■
┌dacă m≥0 atunci scrie x
│ altfel scrie "nul"
└■

Testul final până când p>x este negația condiției p≤x, iar decizia exterioară asigură echivalența și pentru x=0x=0 (se afișează "nul", ca în algoritmul dat).

Barem

Se cerea rescrierea în pseudocod a algoritmului dat, înlocuind structura cât timp...execută cu o structură repetitivă cu test final (repetă...până când). Barem (6 puncte): structură repetitivă de tipul cerut 2p (se acordă chiar dacă algoritmul obținut nu este echivalent; orice formă de structură cu test final este acceptată: repetă...până când, repeat...until etc.); aspecte specifice ale secvenței obținute prin înlocuire 3p (se acordă numai 2p dacă doar unul dintre aspecte este corect: expresia logică pentru testul final, respectiv păstrarea echivalenței pentru cazul x=0, când corpul buclei inițiale nu se execută deloc, de exemplu protejând bucla cu o decizie dacă p≤x); algoritm complet, corectitudine globală 1p.

Învață lecția: Structuri repetitive
Subiectul II.26 puncte

Utilizând metoda backtracking, se generează toate amestecurile de apă provenită din surse distincte din mulțimea {lac, mare, ocean, ploaie, râu}, astfel încât o sursă să fie de apă sărată și una sau două surse să fie de apă dulce. Marea și oceanul sunt surse de apă sărată, iar lacul, ploaia și râul sunt surse de apă dulce. Două amestecuri sunt distincte dacă diferă prin cel puțin o sursă a apei. Primele patru soluții obținute sunt, în această ordine: (lac, mare), (lac, mare, ploaie), (lac, mare, râu) și (lac, ocean). Scrieți soluția generată imediat înainte și soluția generată imediat după (ocean, ploaie).

Rezolvare

Soluțiile sunt generate în ordinea lexicografică a submulțimilor cu elemente în ordinea lac, mare, ocean, ploaie, râu, păstrând doar amestecurile valide (o sursă sărată + una sau două surse dulci):

(lac,mare), (lac,mare,ploaie), (lac,mare,râu), (lac,ocean), (lac,ocean,ploaie), (lac,ocean,râu), (mare,ploaie), (mare,ploaie,râu), (mare,râu), (ocean,ploaie), (ocean,ploaie,râu), (ocean,râu)

Imediat înainte de (ocean,ploaie) se generează (`mare`,`râu`), iar imediat după se generează (`ocean`,`ploaie`,`râu`).

Barem

Backtracking pe submulțimile mulțimii ordonate {lac, mare, ocean, ploaie, râu}, reținând amestecurile cu exact o sursă de apă sărată (mare sau ocean) și una sau două surse de apă dulce (lac, ploaie, râu); primele patru soluții: (lac,mare), (lac,mare,ploaie), (lac,mare,râu), (lac,ocean). Se cereau soluția generată imediat înainte și cea imediat după (ocean,ploaie). Barem: 6 puncte, câte 3 puncte pentru fiecare soluție: imediat înainte este (mare,râu), imediat după este (ocean,ploaie,râu). Ordinea completă a soluțiilor: (lac,mare), (lac,mare,ploaie), (lac,mare,râu), (lac,ocean), (lac,ocean,ploaie), (lac,ocean,râu), (mare,ploaie), (mare,ploaie,râu), (mare,râu), (ocean,ploaie), (ocean,ploaie,râu), (ocean,râu).

Învață lecția: Metoda backtracking
Subiectul II.36 puncte

Variabila f memorează, pentru fiecare dintre cele 10 soiuri de lalele care se vând într-o florărie, caracteristicile acestora: denumirea (șir de maximum 20 de caractere) și stocul, exprimat prin numărul de fire și prețul unui fir, în lei (numere naturale). Știind că expresiile de mai jos au ca valori denumirea primului soi de lalele, respectiv suma, în lei, necesară pentru a cumpăra toate lalelele din acest soi, scrieți în limbajul C/C++ definiția unei structuri cu eticheta lalea, care să permită memorarea informațiilor menționate pentru un soi de lalea, și declarați corespunzător variabila f.

f[0].denumire
f[0].stoc.nrFire*f[0].stoc.pretFir
Rezolvare
struct lalea {
    char denumire[21];
    struct {
        int nrFire;
        int pretFir;
    } stoc;
};

struct lalea f[10];

Câmpul denumire are 21 de caractere (20 utile plus terminatorul '\0'), câmpul stoc este o structură imbricată cu nrFire și pretFir, iar f este un tablou cu 10 elemente de tip lalea, câte unul pentru fiecare soi.

Barem

Se cerea definiția unei structuri C/C++ cu eticheta lalea (denumire: șir de maximum 20 de caractere; stoc: structură imbricată cu câmpurile nrFire și pretFir, numere naturale) și declararea variabilei f ca tablou de 10 elemente de acest tip, compatibilă cu expresiile f[0].denumire și f[0].stoc.nrFire*f[0].stoc.pretFir. Barem (6 puncte): structură/înregistrare definită conform cerinței 4p (câte 1p pentru: definire principial corectă a unei structuri, câmpuri de pe primul nivel, câmpuri de pe al doilea nivel, etichetă/nume conform cerinței); variabilă declarată conform cerinței (tablou cu 10 elemente de tip lalea) 1p; corectitudine globală a secvenței 1p.

Învață lecția: Tipul înregistrare (struct)

Subiectul al III-lea

Subiectul III.110 puncte

Un număr natural nenul, n, se numește număr abundent dacă S(n)n>S(k)k\frac{S(n)}{n} > \frac{S(k)}{k}, pentru orice număr natural nenul k (k≤n−1k \le n-1), unde s-a notat cu S(i)S(i) suma divizorilor pozitivi ai numărului natural nenul ii.

Subprogramul abundent are un singur parametru, n, prin care primește un număr natural (n∈[2,106]n \in [2, 10^6]). Subprogramul returnează valoarea 1, dacă n este un număr abundent, sau valoarea 0, în caz contrar. Scrieți definiția completă a subprogramului.

Exemplu: pentru n=6, subprogramul returnează valoarea 1 (S(6)/6=2S(6)/6=2, iar cel mai mare raport obținut pentru valori strict mai mici decât 6 este S(4)/4=1.75S(4)/4=1.75), iar pentru n=7 sau n=8, subprogramul returnează valoarea 0 (S(7)/7=1.14S(7)/7=1.14, S(8)/8=1.87S(8)/8=1.87).

Rezolvare

Calculăm suma divizorilor cu un subprogram auxiliar, apoi comparăm raportul lui n cu maximul rapoartelor pentru k<nk < n, folosind împărțire reală:

int sumaDiv(int x) {
    int s = 0;
    for (int d = 1; d <= x; d++)
        if (x % d == 0)
            s = s + d;
    return s;
}

int abundent(int n) {
    double rmax = 0, r;
    for (int k = 1; k < n; k++) {
        r = 1.0 * sumaDiv(k) / k;
        if (r > rmax)
            rmax = r;
    }
    if (1.0 * sumaDiv(n) / n > rmax)
        return 1;
    return 0;
}

Înmulțirea cu 1.0 forțează împărțirea reală (altfel raportul s-ar trunchia la întreg). Pentru n=6n=6: S(6)/6=12/6=2S(6)/6 = 12/6 = 2, iar maximul pentru k<6k<6 este S(4)/4=7/4=1.75S(4)/4 = 7/4 = 1.75, deci se returnează 1. Suma divizorilor se poate calcula și mai eficient, parcurgând doar divizorii dd cu d⋅d≤xd \cdot d \le x și adunând perechea x/dx/d.

Barem

Se cerea definiția completă a subprogramului abundent cu un parametru n (număr natural din [2,10^6]), care returnează 1 dacă S(n)/n > S(k)/k pentru orice k natural nenul, k<=n-1 (S(i) = suma divizorilor pozitivi ai lui i), respectiv 0 în caz contrar. Exemplu: abundent(6)=1, abundent(7)=abundent(8)=0. Barem (10 puncte): antet al subprogramului conform cerinței 2p (câte 1p pentru structură și parametrul de intrare); proprietate verificată conform cerinței 6p (câte 1p pentru fiecare aspect: identificarea unui divizor al unui număr, algoritm de bază pentru calculul sumei unei serii de valori, divizorii corecți însumați, împărțire reală pentru raport, algoritm principial corect de verificare a proprietății, numerele suport verificate corect - toate valorile k de la 1 la n-1); instrucțiune de returnare a rezultatului conform cerinței 1p; variabile locale declarate, corectitudine globală a subprogramului 1p. Atenție la capcana împărțirii întregi: rapoartele S(i)/i trebuie calculate cu împărțire reală.

Învață lecția: Subprograme (funcții)
Subiectul III.210 puncte

Pentru a identifica punctele în care se concentrează apa în albia unui râu în cazul secetei, se determină talvegul acesteia, adică linia care unește punctele cele mai adânci ale albiei. În acest scop s-au stabilit ns secțiuni transversale pe cursul apei, numerotate începând de la 1, și în cadrul fiecărei secțiuni s-a măsurat adâncimea apei în np puncte, numerotate începând de la 1. Din fiecare secțiune, în ordine, se include în talveg cel mai adânc punct al acesteia, iar dacă în secțiune sunt mai multe puncte aflate la aceeași adâncime, maximă, se va lua în considerare doar primul dintre ele.

Scrieți un program C/C++ care citește de la tastatură două numere naturale, ns și np (ns∈[1,103]ns \in [1,10^3], np∈[1,50]np \in [1,50]), și cele ns⋅npns \cdot np elemente ale unui tablou bidimensional, valori naturale din intervalul [0,102][0,10^2]. Fiecare linie a tabloului corespunde câte unei secțiuni, în ordinea numerotării acestora, iar valorile memorate pe linie reprezintă adâncimile celor np puncte stabilite pentru acea secțiune, în ordinea numerotării lor. Programul afișează pe ecran, pentru fiecare secțiune, o pereche formată din numărul de ordine al secțiunii și numărul de ordine al punctului său care s-a inclus în talveg. Numerele din fiecare pereche sunt afișate separate prin câte un caracter : (două puncte), iar fiecare pereche este urmată de un spațiu.

Exemplu: pentru ns=6, np=4 și tabloul cu liniile (2 4 5 3), (2 6 6 3), (1 5 2 5), (1 3 3 3), (3 4 3 5), (0 1 2 1), se afișează pe ecran valorile: 1:3 2:2 3:2 4:2 5:4 6:3

Rezolvare
#include <iostream>
using namespace std;

int main() {
    int ns, np, a[1001][51];
    cin >> ns >> np;
    for (int i = 1; i <= ns; i++)
        for (int j = 1; j <= np; j++)
            cin >> a[i][j];
    for (int i = 1; i <= ns; i++) {
        int pmax = 1;
        for (int j = 2; j <= np; j++)
            if (a[i][j] > a[i][pmax])
                pmax = j;
        cout << i << ":" << pmax << " ";
    }
    return 0;
}

Comparația strictă a[i][j] > a[i][pmax] garantează că, la adâncimi egale, rămâne selectat primul punct de adâncime maximă din secțiune. Pentru exemplul dat se afișează 1:3 2:2 3:2 4:2 5:4 6:3.

Barem

Se cerea un program C/C++ care citește ns si np (ns<=1000, np<=50) și un tablou bidimensional ns x np cu valori naturale din [0,100], apoi afișează pentru fiecare linie (secțiune) perechea: numărul liniei, caracterul :, poziția primului element maxim de pe linie, fiecare pereche urmată de un spațiu. Exemplu: pentru liniile (2 4 5 3), (2 6 6 3), (1 5 2 5), (1 3 3 3), (3 4 3 5), (0 1 2 1) se afișează 1:3 2:2 3:2 4:2 5:4 6:3. Barem (10 puncte): variabilă de tip tablou bidimensional declarată conform cerinței 1p; date citite conform cerinței 1p; valori cu proprietatea cerută determinate 6p (câte 2p pentru fiecare aspect: algoritm de bază pentru determinarea valorii maxime dintr-o serie, determinarea poziției unui maxim - prima poziție la egalitate, valori corecte pentru fiecare secțiune); date afișate în formatul cerut (număr:poziție și spațiu după fiecare pereche) 1p; variabile simple declarate, corectitudine globală a programului 1p.

Învață lecția: Tablouri bidimensionale (matrice)

Un număr natural x este numit prefix al unui număr natural y dacă se obține din acesta prin eliminarea a cel puțin unei cifre de la dreapta sa, și este numit sufix al lui y dacă se obține din acesta prin eliminarea a cel puțin unei cifre de la stânga sa.

Exemplu: 15 este prefix pentru 154 sau 1521, este sufix pentru 3415 sau 5115, dar nu este nici prefix, nici sufix pentru 15.

Fișierul bac.txt conține maximum 10610^6 numere naturale din intervalul [10,104)[10, 10^4), separate prin câte un spațiu. Se cere să se afișeze pe ecran numărul valorilor de două cifre care apar de același număr de ori ca sufix, respectiv ca prefix al numerelor din șirul aflat în fișier. Proiectați un algoritm eficient din punctul de vedere al timpului de executare.

Exemplu: dacă fișierul are conținutul 342 1684 2134 5434 111 98 98 3405 3412 7016 8634 1010 102 310 se afișează pe ecran: 4 (pentru valorile 10, 11, 16, 34).

Subiectul III.3.a2 puncte

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

Rezolvare

Algoritm: Folosim doi vectori de frecvență cu indici de la 10 la 99: pf[v] numără de câte ori apare v ca prefix, iar sf[v] de câte ori apare ca sufix. Citim numerele din fișier unul câte unul, fără a le memora. Numerele de două cifre nu produc nici prefix, nici sufix de două cifre (ar trebui eliminată cel puțin o cifră). Pentru fiecare număr x cu x>99x > 99: sufixul de două cifre este x%100x \% 100 (numărat doar dacă este cel puțin 10), iar prefixul de două cifre este [x/10][x/10] dacă x are trei cifre, respectiv [x/100][x/100] dacă are patru cifre. La final numărăm valorile v∈[10,99]v \in [10,99] cu pf[v] = sf[v] și sf[v] nenul.

Eficiență: fișierul este parcurs o singură dată, deci timpul este liniar, O(N)O(N) pentru NN numere; memoria este constantă, două tablouri de cel mult 100 de elemente, fără a memora șirul de 10610^6 numere.

Barem

Pentru problema numărării valorilor de două cifre care apar de același număr de ori ca sufix și ca prefix al numerelor din fișierul bac.txt (maximum 10^6 numere din [10,10^4)), se cerea descrierea în limbaj natural a unui algoritm eficient și justificarea eficienței. Barem (2 puncte): descriere coerentă a algoritmului conform cerinței 1p (se acordă chiar dacă algoritmul ales nu este eficient); elemente de eficiență justificate conform cerinței 1p. Soluția eficientă așteptată: doi vectori de frecvență pf și sf (pentru prefixele, respectiv sufixele de două cifre); la citirea fiecărui număr x>99 se actualizează sf[x%100] (doar dacă x%100>=10) și pf[[x/10]] pentru x de trei cifre, respectiv pf[[x/100]] pentru x de patru cifre; la final se numără valorile v din [10,99] cu pf[v]=sf[v] și sf[v] nenul. Eficiență: o singură parcurgere a fișierului, timp liniar O(N), memorie O(1) (două tablouri de cel mult 100 de elemente), fără memorarea celor 10^6 numere.

Învață lecția: Analiza complexității unui algoritm
Subiectul III.3.b8 puncte

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

Rezolvare
#include <iostream>
#include <fstream>
using namespace std;

int main() {
    ifstream fin("bac.txt");
    int pf[100] = {0}, sf[100] = {0};
    int x, s, p, cnt = 0;
    while (fin >> x)
        if (x > 99) {
            s = x % 100;
            if (s >= 10)
                sf[s]++;
            if (x < 1000)
                p = x / 10;
            else
                p = x / 100;
            pf[p]++;
        }
    fin.close();
    for (int v = 10; v <= 99; v++)
        if (pf[v] == sf[v] && sf[v] != 0)
            cnt++;
    cout << cnt;
    return 0;
}

Fiecare număr de trei cifre are exact un prefix de două cifre ([x/10][x/10]), iar fiecare număr de patru cifre, de asemenea ([x/100][x/100]); sufixul de două cifre este x%100x \% 100, valid doar dacă este cel puțin 10. Algoritmul este liniar: o singură parcurgere a fișierului și doi vectori de frecvență de 100 de elemente. Pentru exemplul dat, valorile numărate sunt 10, 11, 16 și 34, deci se afișează 4.

Barem

Se cerea programul C/C++ care citește numerele din fișierul bac.txt (maximum 10^6 numere naturale din [10,10^4), separate prin spații) și afișează pe ecran numărul valorilor de două cifre care apar de același număr de ori ca sufix și ca prefix al numerelor din fișier (pentru exemplul dat: 4). Barem (8 puncte): operații cu fișiere (declarare, pregătire în vederea citirii, citire din fișier) 1p; valoarea cerută determinată corect 5p (se acordă numai 3p dacă algoritmul este principial corect dar nu oferă rezultatul cerut pentru toate seturile de date; aspecte: prefixele de două cifre sunt [x/10] pentru numere de trei cifre și [x/100] pentru patru cifre, sufixele x%100 doar dacă sunt >=10, numerele de două cifre nu contribuie, comparația finală pf[v]=sf[v] cu sf[v] nenul); eficiența algoritmului 1p (se acordă numai pentru un algoritm liniar, cu vectori de frecvență, fără memorarea întregului șir); variabile declarate, afișarea datelor, corectitudine globală 1p.

Învață lecția: Fișiere text

Alte subiecte de Informatică

Descarcă

Începe azi. Bacul nu așteaptă.

Descarcă Tomomi pe telefonul copilului tău și pornește perioada de probă gratuită.