Subiect și barem BAC 2017 Informatică C/C++ (mate-info)
2017
Sesiune specială
Varianta 3
Rezolvare explicată

Rezolvare BAC 2017 Informatică C/C++ (mate-info) — Sesiune specială, varianta 3

Rezolvarea completă a subiectului de Bacalaureat 2017 la Informatică, limbajul C/C++, profil mate-info, sesiunea specială, varianta 3. Pentru fiecare item ai răspunsul, raționamentul pas cu pas, codul C++ complet și punctajul din baremul oficial.

Sfat: încearcă întâi singur fiecare cerință, apoi verifică aici. La programe, baremul punctează orice soluție corectă — nu trebuie să scrii exact codul de mai jos.

Subiectul I (30 de puncte)

1. x are exact trei cifre → a. x/1000==0 && x/100!=0 (4p)

x/1000==0 înseamnă x < 1000 (cel mult trei cifre), iar x/100!=0 înseamnă x ≥ 100 (cel puțin trei cifre). Ambele trebuie să fie adevărate, deci &&. Variantele c și d folosesc restul (%), care nu spune nimic despre numărul de cifre.

2. Algoritmul în pseudocod

După eventuala interschimbare, a ≤ b. Pentru fiecare x din [a, b], bucla „cât timp” caută cel mai mic divizor c ≥ 2 al lui x. Algoritmul afișează suma acestor divizori.

a) Pentru 7 și 4 → 16 (6p)

Se interschimbă: a = 4, b = 7.

x4567
cel mai mic divizor ≥ 22527

s = 2 + 5 + 2 + 7 = 16.

b) Patru seturi din [2, 9] cu rezultatul 7 (4p)

Câteva sume posibile: [2, 4] → 2 + 3 + 2 = 7; [4, 5] → 2 + 5 = 7; [5, 6] → 5 + 2 = 7; [7, 7] → 7. Ordinea citirii nu contează (se face interschimbare). Răspuns: 2 4; 4 5; 5 6; 7 7 (sau 4 2, 5 4, 6 5).

c) „cât timp” înlocuit cu structură cu test final (6p)

textcod
citește a,b (numere naturale, a≥2, b≥2) ┌dacă a>b atunci x ← a; a ← b; b ← x └■ s ← 0 ┌pentru x ← a,b execută │ c ← 2 │ ┌dacă x%c>0 atunci │ │ ┌repetă │ │ │ c ← c+1 │ │ └până când x%c=0 │ └■ │ s ← s+c └■ scrie s

Bucla „cât timp” poate să nu se execute deloc (când x e par), de aceea „repetă” este protejat de un dacă.

d) Programul C/C++ (10p)

cppcod
#include <iostream> using namespace std; int main() { int a, b, x, s, c; cin >> a >> b; if (a > b) { x = a; a = b; b = x; } s = 0; for (x = a; x <= b; x++) { c = 2; while (x % c > 0) c = c + 1; s = s + c; } cout << s; return 0; }

Barem: variabile 1p, citire 1p, afișare 1p, decizie 2p, repetitive 3p, atribuiri 1p, corectitudine 1p.

Subiectul al II-lea (30 de puncte)

Răspunsuri: 1 – b, 2 – b (câte 4 puncte).

1. Rădăcina pentru vectorul de tați (5,4,6,0,3,2,6,9,7) → b. 4

Rădăcina este nodul fără tată, adică cel care are 0 în vector: poziția 4.

2. Numărul maxim de cicluri disjuncte → b. 2

Muchiile din desen: [1,2], [2,3], [1,4], [2,4], [2,5], [2,6], [3,6], [4,5], [5,6], [4,7], [4,8], [5,8], [6,8], [6,9], [7,8], [8,9].

Fiecare ciclu are cel puțin 3 noduri, deci 3 cicluri disjuncte ar folosi toate cele 9 noduri. Nodul 1 are doar vecinii 2 și 4, deci ciclul lui conține nodul 2; nodul 3 are doar vecinii 2 și 6, deci și ciclul lui conține nodul 2. Două cicluri disjuncte nu pot avea amândouă nodul 2 → nu putem avea 3 cicluri.

Două se pot obține, de exemplu 1-2-4-1 și 5-6-8-5. Maximul este 2.

3. Structura poligon (6p)

cppcod
struct poligon { int numar; struct { float x, y; } varf[100]; } p;

p.varf[0].x arată că varf este un tablou de structuri cu câmpurile x și y. Numărul de vârfuri este cel mult 99, deci 100 de elemente ajung.

4. Completarea tabloului 9×9 (6p)

Valorile a formează un triunghi deasupra ambelor diagonale: strict deasupra diagonalei principale (i < j) și strict deasupra diagonalei secundare (i + j < 8).

cppcod
for(i=0;i<9;i++) for(j=0;j<9;j++) if (i < j && i + j < 8) a[i][j] = 'a'; else a[i][j] = 'b';

Verificare: linia 0 are a pe coloanele 1…7, linia 3 doar pe coloana 4 ✔.

5. Cuvinte care conțin o notă muzicală (10p)

Separăm cuvintele cu strtok și căutăm fiecare notă în cuvânt cu strstr.

cppcod
#include <iostream> #include <cstring> using namespace std; int main() { char s[101], *p; char note[7][4] = {"DO", "RE", "MI", "FA", "SOL", "LA", "SI"}; int gasit = 0; cin.getline(s, 101); p = strtok(s, " "); while (p) { int are = 0; for (int k = 0; k < 7 && !are; k++) if (strstr(p, note[k])) are = 1; if (are) { cout << p << '\n'; gasit = 1; } p = strtok(NULL, " "); } if (!gasit) cout << "nu exista"; return 0; }

Verificare pe exemplu: se afișează REMI, DOMINO, SI, DENUMIRI, SIMILARE ✔.

Subiectul al III-lea (30 de puncte)

1. Al șaselea număr generat → c. 262 (4p)

După 208 urmează, în ordine crescătoare, numerele pare cu suma cifrelor 10 care încep cu 2: 226 (are două cifre 2 alăturate — respins), 244 (două cifre 4 alăturate — respins), 262 ✔. Numerele 217, 235, 253 sunt impare.

2. Ce afișează f(4) → 1234123121 (6p)

f(n) afișează 1, 2, …, n, apoi apelează f(n−1):

  • f(4): 1234
  • f(3): 123
  • f(2): 12
  • f(1): 1
  • f(0): nimic

Rezultat: 1234123121.

3. Subprogramul identice (10p)

Nu are rost să testăm fiecare număr din [a, b]. Numerele cu toate cifrele identice sunt de forma c⋅rc \cdot r, unde c este o cifră 1…9 și r este un repunit (11, 111, 1111, …). Le generăm în ordine crescătoare (după lungime, apoi după cifră) și le afișăm pe cele din interval.

cppcod
void identice(int a, int b) { int gasit = 0; for (int r = 11; r <= 1111111; r = r * 10 + 1) // 11, 111, 1111, ... for (int c = 1; c <= 9; c++) if (c * r >= a && c * r <= b) { cout << c * r << ' '; gasit = 1; } if (!gasit) cout << "nu exista"; }

Verificare: a = 700, b = 1500 → 777 888 999 1111 ✔.

4. Poziția de inserare a unui șir în altul

a) Descrierea algoritmului (2p)

Ambele șiruri sunt strict crescătoare, deci din primul șir contează doar primul termen p și ultimul u. Citim al doilea șir și numărăm termenii mai mici decât p (k termeni; fiind ordonați, ei sunt la început), reținând și primul termen care nu este mai mic decât p. Inserarea este posibilă dacă există cel puțin un termen înainte (k ≥ 1, inserarea se face între două elemente) și dacă termenul următor există și este strict mai mare decât u. Atunci poziția cerută este k + 1; altfel afișăm „imposibil”.

Eficiență: fiecare număr este citit o singură dată → timp liniar O(m + n); nu memorăm șirurile, ci doar câteva valori → memorie O(1).

b) Programul C/C++ (8p)

cppcod
#include <fstream> #include <iostream> using namespace std; int main() { ifstream f("bac.in"); int m, n, x, p, u, k = 0, urm = 0; f >> m >> n; for (int i = 1; i <= m; i++) { f >> x; if (i == 1) p = x; u = x; } for (int i = 1; i <= n; i++) { f >> x; if (x < p) k++; else if (urm == 0) urm = x; // primul termen din B care nu e mai mic decât p } if (k >= 1 && urm > u) cout << k + 1; else cout << "imposibil"; f.close(); return 0; }

Verificare: pentru primul exemplu p = 15, u = 19; în al doilea șir 7, 10, 12 sunt mai mici (k = 3), următorul este 20 > 19 → se afișează 4 ✔. Pentru al doilea exemplu următorul termen este 18 < 19 → imposibil ✔; pentru al treilea, k = 0 → imposibil ✔.

Ce merită reținut din varianta 3

  • Număr de cifre: folosește împărțirea întreagă la puteri ale lui 10, nu restul.
  • „cât timp” → „repetă”: protejează bucla cu un dacă pe aceeași condiție.
  • Vectorul de tați: rădăcina are tatăl 0.
  • Cicluri disjuncte: nodurile de grad 2 forțează vecinii în ciclu — de aici vin contradicțiile.
  • Numere cu cifre identice = cifră × 11…1; generează-le direct.
  • Șiruri ordonate: de multe ori ajung primul și ultimul termen, fără a memora tot șirul.

Alte subiecte Informatică C/C++ (mate-info) rezolvate

Reclamă