www.agora.ro

Al doilea bacalaureat în informatică

BACALAUREAT 2000

Prezentarea 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]