Al doilea bacalaureat în informatică BACALAUREAT 2000Prezentarea subiectelor de Bacalaureat propuse în cartea Bac Info' 2000 continuă cu varianta nr. 19.
1. Se consideră funcția caut care ar trebui să returneze true dacă numărul nr se găsește în șirul x. În variabila k se va păstra poziția pe care s-a găsit numărul căutat sau -1 dacă numărul nu se găsește în șir. Găsiți greșeala și scrieți funcția corectă:
Varianta Pascal: var x:array[1..10] of Real; function caut(nr:Real; var k:Byte):Boolean; begin caut:=false; k:=-1; for i:=1 to 10 do begin caut:=x[i]=nr; k:=i end end;
Varianta C: float x[10]; int caut(float nr,int& k){ int c=0; k=-1; for (int i=0;i<10;i++) c=(x[i]==nr),k=i; return c; }
Soluție Greșeala constă în faptul că datorită structurii repetitive for, în funcție, practic, se suprascrie valoarea identificatorului caut și a variabilei k. Rezultatul va fi corect doar dacă numărul căutat este chiar al n-lea, adică ultimul. O posibilă variantă corectă trebuie să asigure oprirea căutării dacă numărul căutat este găsit și tratarea separată a cazului căutării fără succes. Deoarece în funcție nu putem testa valoarea lui caut (ar însemna un autoapel), avem nevoie de o variabilă auxiliară (gasit). În cazul variantei Pascal mai apare o greșeală "minoră", și anume: k este declarat de tip Byte, dar printre valorile posibile pe care această variabilă le poate lua este și -1. Rezultă că trebuie să fie declarat de tipul Shortint sau Integer, tipuri care admit și valori negative. O funcție corectă este prezentată în continuare.
Varianta Pascal: var x:array[1..10] of Real; function caut(nr:Real; var k:Shortint): Boolean; var i:Byte; gasit:Boolean; begin gasit:=false; k:=-1; i:=1; while (i<=n) and not gasit do if nr=x[i] then begin gasit:=true; k:=i end else i:=i+1; caut:=gasit end;
Varianta C: float x[10]; int caut(float nr,int& k){ int c=0,gasit=0; k=-1; while (i<n && !gasit) if (nr==x[i]) gasit=1,k=i; else i++; return gasit; }
2. Scrieți un subprogram care calculează și afișează media aritmetică a elementelor pozitive, diferite de 0 de pe diagonala principală, respectiv diagonala secundară a unui tablou bidimensional pătratic de numere întregi.
Soluție Elementele pe diagonala principală au indicele de linie egal cu indicele de coloană, iar cele de pe diagonala secundară sunt de forma i,n-i+1 (în cazul în care numerotarea indicilor începe de la 1 - limbajul Pascal), respectiv i,n-i-1 (în cazul în care numerotarea indicilor începe de la 0 - limbajul C). De fiecare dată, când un element se adaugă sumei s, trebuie mărit contorul k, deoarece pentru a putea calcula media aritmetică trebuie să știm câte elemente au format suma.
Varianta Pascal: const DimMax=100; type tab=array[1..DimMax,1..DimMax] of Integer; var a:tab; i,j,n:Byte;
procedure calcule(a:tab; n:Byte); var i,j,k:Byte; s:Real; begin s:=0; k:=0; for i:=1 to n do begin if a[i,i]>0 then begin s:=s+a[i,i]; Inc(k) end; if a[i,n-i+1]>0 then begin s:=s+a[i,n-i+1]; Inc(k) end end; s:=s/k; Writeln('Media aritmetica: ',s:10:2) end;
Varianta C:
#define DimMax 100; typedef int tab[DimMax][DimMax]; tab a; int i,j,n;
void calcule(tab a, int n){ int i,j,k; float s=k=0; for (i=0;i<n;i++){ if (a[i][i]>0) s+=a[i][i],k++; if (a[i][n-i-1]>0) s+=a[i][n-i-1],k++; } s/=k; printf("Media aritmetica: %10.2f\n",s); }
3. Se consideră următoarea secvență de instrucțiuni, re-prezentată în pseudocod. Ce valoare se va afișa pentru m=64?
citește m d Ź 2 cât timp m ± 0 execută dacă rest[m/d] = 0 atunci scrie d altfel d Ź d + 1 sfârșit dacă m Ź [m/d] sfârșit cât timp
Transcrieți această secvență de program într-un limbaj de programare (Pascal sau C).
Soluție Secvența de algoritm afișează factorii primi ai numărului citit (m). Pentru m=64 se va afișa 2 2 2 2 2 2. Implementările Pascal și C ale algoritmului sunt prezentate în continuare:
Varianta Pascal: Program factori_primi; var m,d:Byte; Begin Write('m='); Readln(m); d:=2; while m<>0 do begin if m mod d=0 then Writeln(d) else Inc(d); m:=m div d end End.
Varianta C:
#include <stdio.h> void main(void){ int m,d=2; printf("m="); scanf("%d",&m); while (m){ if (!(m%d)) printf("%d\n",d) else d++; m/=d; } }
1. Se numesc numere "superprime" acele numere prime ale căror prefixe sunt toate numere prime. De exemplu, numărul 239 este superprim, deoarece numerele 2, 23 și 239 sunt prime, dar numărul 241 nu este superprim, deoarece chiar dacă 241 și 2 sunt prime, numărul 24 nu este prim. Scrieți un program comentat, care stabilește dacă numărul n, citit de la tastatură, este superprim sau nu! Programul va trebui să afișeze și prefixele numărului dat.
Soluție Varianta Pascal:
Listing SUPER.PAS Program superprime; var n,nn, { nn este dublura lui n, } { deoarece se va distruge } { pe parcursul algoritmului } putere:Longint; { puterile lui 10 } { cu care il impartim pe n } superprim:Boolean; { variabila } { logica, purtatoare a } { proprietatii cautate }
function prim(n:Longint):Boolean; { se verifica proprietatea de "prim" } { pentru n si prefixele sale } var d, { divizori posibili } rad:Longint; { vom cauta divizori } { doar pana la parte intreaga din } { radical din n } e_prim:Boolean; { variabila loca- } { la purtatoare a proprietatii } { cautate (n actual e prim sau } { nu), valoarea sa se va atribui } { lui prim, identificatorul } { functiei } begin if not Odd(n) { daca numarul este } { par, atunci el este prim numai } { daca are valoarea 2 } then e_prim:=n=2 else begin { initializarea variabilei locale } e_prim:=true; d:=3; { primul divizor posibil al } { unui numar impar <>1 } rad:=Trunc(Sqrt(n)); { parte intreaga din radical de n } while (d<=rad) and e_prim do { cautam divizori pana la radical } { din n, sau pana cand gasim unul } if n mod d=0 then e_prim:=false else Inc(d,2) { divizorii posi- } { bili ai unor numere impare } { sunt numere impare } end; prim:=e_prim end;
Begin Write('n='); Readln(n); superprim:=true; { presupunem ca numarul e superprim } nn:=n; { dublura lui n } putere:=10; { prima putere a lui 10 } { pentru a obtine ultimul prefix } { al lui n } while (n>0) and superprim do
begin { verificam daca n actual } { este prim sau nu } if not prim(n) then superprim:=false { daca nu, } { n dat nu e superprim } else begin n:=nn div putere; { urmatorul prefix } Writeln(n); { afisarea prefixului } putere:=putere*10 { urmatoarea putere al lui 10 } end end; if superprim then Writeln('Numarul ',nn, ' este superprim.') else Writeln('Numarul ',nn, ' nu este superprim.') End. Varianta C:
Listing SUPER.CPP
#include <stdio.h> #include <math.h>
long n,nn; // nn este dublura lui n, // deoarece se va distruge // pe parcursul algoritmului long putere; // puterile lui 10, cu // care impartim pe n int superprim; // variabila logica, // purtatoare a pro- // prietatii cautate int prim(long n){ // se verifica pro- // prietatea de "prim" pentru n si // prefixele sale long d=3; // divizori posibili - 3 // este primul divizor // posibil al unui numar // impar diferit de 1 long rad=floor(sqrt(n)); // vom cauta // divizori doar pana la parte // intreaga din radical din n int e_prim=1; // variabila locala, // purtatoare a proprietatii // cautate (n este prim sau nu) if (!(n&1)) // daca numarul este // par, atunci el este // prim numai daca are // valoarea 2 e_prim=n==2; else{ while (d<=rad && e_prim){ // cautam divizori pana la // radical din n, sau pana cand // gasim unul if (!(n%d)) e_prim=0; else d+=2; // divizorii posibili // ai unor numere // impare sunt numere // impare } } return e_prim; }
void main(void){ printf("n="); scanf("%d",&n); superprim=1; // presupunem ca // numarul e superprim nn=n; // dublura lui n putere=10; // prima putere a lui 10, // pentru a obtine ul- // timul prefix al lui n while (n>0 && superprim){ if (!prim(n)) // verificam daca n // actual e prim sau nu superprim=0; // daca nu, n dat // nu e superprim else{ n=nn/putere; // urmatorul prefix printf("%d\n",n); // afisarea // prefixului putere*=10; // urmatoarea putere // a lui 10 } } if (superprim) printf("Numarul %d este \ superprim.\n",nn); else printf("Numarul %d nu este \ superprim.\n",nn); } 2. Scrieți un subprogram cerc care leagă ultimul element de primul element într-o listă liniară, având o structură oarecare. Subprogramul va avea ca parametri de intrare pointerii la primul, respectiv la ultimul element din listă. Scrieți un alt subprogram care, după operația cerută mai sus, va afișa conținutul listei.
Soluție
Varianta Pascal: type lista=^element; element=record info:Byte; leg:lista end; var primul,ultimul:lista;
procedure cerc(primul:lista; var ultimul:lista); begin ultimul^.leg:=primul end;
procedure afiseaza(primul,ultimul:lista); var p:lista; begin p:=primul; while p<>ultimul do { avansam pana la ultimul } begin Writeln(p^.info); p:=p^.leg end; Writeln(ultimul^.info) { ultimul element se afiseaza separat } end;
Varianta C: struct lista{ int info; lista* leg; }primul,ultimul:lista;
void cerc(lista* primul, lista* &ultimul){ ultimul->leg:=primul; }
void afiseaza(lista *primul, lista *ultimul){ lista *p=primul; while (p!=ultimul){ // avansam pana la ultimul printf("%d\n",p->info); p=p->leg; } printf("%d\n",ultimul->info); // ultimul element se afiseaza separat } }
Se consideră n (1<n<10) operatori din mulțimea {+,*} și un număr natural val (val>100). Să se scrie un program comentat, care, folosind numere naturale, pune între fiecare doi operatori (respectiv înainte și după aceștia) câte un număr, astfel încât rezultatul evaluării să fie numărul val.
Soluție Expresia va fi împărțită în termeni (separați prin +), iar termenii vor fi împărțiți în factori (separați prin *). Vom alege valoarea primului termen ca fiind val (valoarea expresiei), valorile celorlalți termeni (dacă aceștia există) vor fi 0. Pentru ca valoarea primului termen să fie val, valoarea primului factor al acestui termen va fi val, iar valorile celorlalți factori (dacă aceștia există) vor fi 1.
Varianta Pascal:
Listing OPER.PAS Program Operatori; var s:string[10]; a:array[1..11] of Longint; val:Longint; k,n:Integer; Begin Write('Introduceti operatorii:'); Readln(s); n:=length(s); Write('Introduceti valoarea ', 'expresiei:'); Readln(val); k:=2; a[1]:=val; { valoarea primului fac- } { tor din primul termen } while s[k-1]='*' do begin a[k]:=1; Inc(k) end; { valoarea celorlalti factori din } { primul termen } while k<=n+1 do begin a[k]:=0; Inc(k) end; { valoarea factorilor din } { restul termenilor } for k:=1 to n do Write(a[k],s[k]); { afisarea expresiei } Writeln(a[n+1],'=',val); End. Varianta C: [cuprins] |