ifstream f("bac.txt");FILE *f=fopen("bac.txt","r");assign(f,'bac.txt'); reset(f);Cum citești dintr-un fișier până la capăt, cum scrii într-unul și ce înseamnă algoritm eficient la barem. III.3 rezolvat pe patru lucrări, cu descrierea în cuvinte pentru a) și programul pentru b).

ții minte doar fișa asta și ești acoperit
Citirea: ifstream f("bac.txt"); apoi while(f>>x) citește până la capăt.
Scrierea: ofstream g("bac.txt"); apoi g<<x<<" "; exact ca la cout.
Truc: f>> ca cin, g<< ca cout.
III.3 b = 8 p: operații cu fișiere 1, valori determinate 5, eficiență 1, declarări și afișare 1.
III.3 a = 2 p: descriere coerentă 1 și justificarea eficienței 1.
Eficient, la barem: algoritm liniar. Dacă enunțul cere și memorie, nu memorezi tot șirul când n-ai nevoie.
Fără tablou mare: păstrezi doar ultima valoare sau ultimele două. Dacă valorile sunt mici, vector de frecvență.
Culorile din lecție:termenidee-cheie
Programul citește dintr-un fișier la fel cum citește de la tastatură. Îi spui o dată de unde citește, apoi folosești >> ca la cin.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ifstream f("bac.txt");
int x,s=0;
while(f>>x)
s=s+x;
f.close();
cout<<s;
return 0;
}
Oficial: fișierele text au acces secvențial: se parcurg de la început spre sfârșit. ifstream deschide pentru citire, ofstream pentru scriere. while(f>>x) se oprește când nu mai sunt valori de citit. Pentru scriere:
ofstream g("bac.txt");
g<<1<<" "<<2;
g.close();
ifstream f("bac.txt");FILE *f=fopen("bac.txt","r");assign(f,'bac.txt'); reset(f);ofstream g("bac.txt");FILE *g=fopen("bac.txt","w");assign(g,'bac.txt'); rewrite(g);f>>xfscanf(f,"%d",&x)read(f,x)while(f>>x)while(fscanf(f,"%d",&x)==1)while not eof(f) dog<<xfprintf(g,"%d",x)write(g,x)f.close();fclose(f);close(f)| Operație | C++ | C | Pascal |
|---|---|---|---|
| Deschidere pentru citire | ifstream f("bac.txt"); | FILE *f=fopen("bac.txt","r"); | assign(f,'bac.txt'); reset(f); |
| Deschidere pentru scriere | ofstream g("bac.txt"); | FILE *g=fopen("bac.txt","w"); | assign(g,'bac.txt'); rewrite(g); |
| Citire | f>>x | fscanf(f,"%d",&x) | read(f,x) |
| Până la sfârșit | while(f>>x) | while(fscanf(f,"%d",&x)==1) | while not eof(f) do |
| Scriere | g<<x | fprintf(g,"%d",x) | write(g,x) |
| Închidere | f.close(); | fclose(f); | close(f) |
Ce bibliotecă incluzi pentru ifstream?
Când enunțul zice „proiectați un algoritm eficient”, se referă la două criterii din programă: durata de executare și spațiul de memorie. Citește care dintre ele e cerut.
Enunțul spuneBaremul cere
| Enunțul spune | Baremul cere |
|---|---|
| eficient din punctul de vedere al timpului | algoritm liniar (model 2027) |
| eficient din punctul de vedere al timpului și al memoriei | algoritm liniar, care utilizează eficient memoria (iunie 2026, sesiunea specială 2026) |
Oficial, un algoritm liniar face un număr de operații proporțional cu numărul de valori. Baremul din rezerva 2026 îl numește „de complexitate O(n)”. Două bucle imbricate pe tot șirul nu sunt liniare.
a) descriere coerentă a algoritmului — 1p (chiar dacă algoritmul nu este eficient)
a) elemente de eficiență justificate — 1p
b) operații cu fișiere: declarare, pregătire în vederea citirii, citire — 1p
b) valori determinate — 5p (numai 3p dacă parcurge pașii necesari, dar cu detalii care nu duc la rezultat)
b) eficiență a algoritmului — 1p (numai pentru algoritm liniar, care utilizează eficient memoria)
b) variabile declarate, afișare, corectitudine globală — 1p
Fișierul bac.txt are cel mult 10⁴ numere, câte o pereche pe linie: poziția într-un clasament și tipul concursului (1 șah, 2 go), în ordine cronologică. Un rezultat e motivant dacă poziția e mai bună (mai mică) decât la concursul anterior de același tip. Afișează numărul de rezultate motivante la șah și la go. Pentru exemplul din enunț se afișează 3 2. (La SN se cere doar numărul de la șah.)
Ideea: nu ai nevoie de toate pozițiile. Pentru fiecare tip, ține minte doar ultima poziție.
Ce se întâmplă la fiecare pereche citită
Citești p și c
Compari p cu ultima poziție
de același tip; dacă e mai mică, contorul crește
Actualizezi ultima poziție
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ifstream f("bac.txt");
int p,c,ups=-1,upg=-1,ns=0,ng=0;
while(f>>p>>c)
if(c==1)
{ if(p<ups) ns++;
ups=p;
}
else
{ if(p<upg) ng++;
upg=p;
}
f.close();
cout<<ns<<" "<<ng;
return 0;
}
Inițializarea cu -1 face ca primul rezultat de fiecare tip să nu se numere: poziția e cel puțin 1, deci nu e mai mică decât -1.
Citesc din fișier, pe rând, câte o pereche (p, c). Pentru fiecare tip de concurs păstrez ultima poziție obținută, în ups și upg, inițializate cu -1, și câte un contor, ns și ng. Dacă poziția curentă este mai mică decât ultima de același tip, măresc contorul acelui tip. Apoi actualizez ultima poziție.
Algoritmul este eficient din punctul de vedere al timpului de executare, pentru că parcurge fișierul o singură dată, deci este liniar. Este eficient și din punctul de vedere al memoriei, pentru că folosește doar câteva variabile simple, fără să memoreze șirul.
Soluția din barem este chiar aceasta: ns, ng, ups, upg.
Cum reții ultimul rezultat pentru două tipuri de concurs?
Șirul lunar de pachete livrate e 0 3 9 21 45 93 189 381...: fiecare termen este termenul precedent plus dublul diferenței dintre ultimii doi. Se citesc de la tastatură ultimul și penultimul termen. Se scriu în bac.txt, în ordine descrescătoare, toți termenii până la 0. Pentru 189 și 93, fișierul conține 189 93 45 21 9 3 0.
Ideea: mergi înapoi. Dacă x e termenul dinainte, z penultimul, y ultimul, relația dă y=z+2(z-x), adică y=3z-2x. Deci x=(3z-y)/2. Nu memorezi nimic în tablou.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ofstream g("bac.txt");
int x,y,z;
cin>>y>>z;
g<<y<<" "<<z;
while(z>0)
{ x=(3*z-y)/2;
g<<" "<<x;
y=z;
z=x;
}
g.close();
return 0;
}
Barem: operații cu fișiere (declarare, pregătire pentru scriere, scriere) 1 p; valori determinate 5 p; algoritm eficient 1 p; declarări, citire și corectitudine globală 1 p. Baremul scrie x=[(3∙y-z)/2]: acolo y e ultima valoare afișată, iar z e cea dinaintea ei, adică invers decât aici.
La științele naturii, aceeași sesiune dă un șir mai simplu, 0 3 7 15 31 63 127 255..., în care fiecare termen e dublul precedentului plus 1, și se dă doar ultimul. Termenul anterior se obține cu x=(y-1)/2. Baremul adaugă: se oprește după ce s-a afișat 3, apoi se afișează 0, pentru că 3 nu se obține din 0 după aceeași regulă.
La curierat, cum afli termenul de dinaintea ultimilor doi?
Pe prima linie din bac.in este intervalul orar disponibil, apoi, pe câte o linie, intervalul fiecărui muzeu, în ordine. Un muzeu e convenabil dacă se poate vizita cel puțin o oră în timpul disponibil. Se afișează numărul de muzee convenabile și numărul de ordine al ultimului. Pentru exemplul din enunț, 3 4.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ifstream f("bac.in");
int h1,h2,c1,c2,v1,v2,nr=0,nv=0,ult=0;
f>>h1>>h2;
while(f>>c1>>c2)
{ nr++;
if(c1>h1) v1=c1; else v1=h1;
if(c2<h2) v2=c2; else v2=h2;
if(v1<v2)
{ nv++;
ult=nr;
}
}
f.close();
cout<<nv<<" "<<ult;
return 0;
}
Două intervale au o parte comună de la maximul începuturilor până la minimul sfârșiturilor. Dacă această parte are cel puțin o oră, muzeul e bun. Soluția din barem e exact aceasta.
Numerele din bac.txt sunt rezultate: numărul problemei (1, 2 sau 3), punctajul (0–99) și indicativul echipei (10–99), lipite. De exemplu 19912: problema 1, 99 de puncte, echipa 12. Câștigă echipa cu cel mai mare total; la egalitate, cea cu mai multe probleme de 99 de puncte; apoi cea înscrisă mai devreme. La SN nu există criteriul cu 99.
Ideea: valorile posibile pentru echipă sunt puține, de la 10 la 99. Deci poți ține câte o valoare pentru fiecare echipă, oricât de lung ar fi fișierul.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ ifstream f("bac.txt");
int p[100]={0},nr[100]={0},x,i,pct,em=10;
while(f>>x)
{ i=x%100;
x=x/100;
if(x>99) pct=x%100;
else pct=x%10;
p[i]=p[i]+pct;
if(pct==99) nr[i]++;
}
f.close();
for(i=11;i<=99;i++)
if(p[i]>p[em] || (p[i]==p[em] && nr[i]>nr[em]))
em=i;
cout<<em;
return 0;
}
De ce două cazuri la pct? Un număr ca 3010 înseamnă problema 3, 0 puncte, echipa 10. După x/100 rămâne 30, deci punctajul e 30%10. Baremul scrie exact această distincție.
Parcurgând de la 10 la 99 și schimbând doar la strict mai bun, la egalitate totală rămâne echipa înscrisă mai devreme.
| Tip de III.3 | Unde a apărut | Ce ții în memorie |
|---|---|---|
| Citești o valoare și o compari cu ultima | iunie 2026 var. 3 | ultima valoare, contor |
| Secvențe (scară, mesaj, perioadă) | iulie 2024 var. 3, august 2026 var. 1, august 2025 var. 4 | lungimea curentă, lungimea maximă |
| Valori puține, într-un interval mic | model 2027 | vector de frecvență |
| Scrii un șir înapoi în fișier | sesiunea specială 2026, rezervă 2026 var. 5 | ultima valoare sau ultimele două |
Citește atent ce se citește din fișier și ce se afișează pe ecran: la sesiunea specială 2026, datele vin de la tastatură, iar fișierul e pentru scriere.
while(!f.eof()), cu prelucrarea ultimei valori de două ori.bac.txt sau bac.in, și trebuie scris exact.