www.agora.ro

Admitere la UBB...

Conceptul de algoritm și importanța lui

Militon Frențiu

În ultimul timp numărul claselor de informatică din licee a crescut foarte mult, dar efectele acestui fapt nu sunt deloc benefice. Nivelul de pregătire al elevilor este din ce în ce mai scăzut. Deși au studiat patru ani informatica, mulți dintre candidații care s-au prezentat la concursul de admitere de la Universitatea Babeș-Bolyai din Cluj nu cunosc concepte fundamentale cum ar fi acela de (sub)algoritm.

În urma corectării lucrărilor scrise la proba de Informatică, dar și a examenelor de la disciplina Algoritmică și Programare cu studenții anului I, am observat că absolvenții claselor de informatică nu sunt deprinși să folosească și nu stăpânesc conceptul de subalgoritm.

Problemele date la concursul amintit sunt prezentate în continuare.

I. Să se scrie subalgoritmi pentru următoarele subprobleme:

1. suma a două polinoame;

2. produsul a două polinoame;

3. valoarea unui polinom într-un punct.

II. Să se scrie un program pentru rezolvarea următoarei probleme:

Se citesc mai multe polinoame. Un polinom se dă fie prin grad și coeficienți, fie prin monoamele sale (date prin coeficienți, exponenți) (programul va accepta ambele variante). Să se tipărească suma polinoamelor citite, produsul lor și polinomul pentru care valoarea în punctul a (dat) este maximă. Citirea se încheie când produsul polinoamelor citite are gradul mai mare decât 100, fiecare polinom citit având gradul cel mult 20.

Am formulat astfel enunțul și pentru a sugera candidaților procedurile care ar trebui folosite în programul Pascal, dar din 112 candidați numai 9 au înțeles acest lucru. Mai mult, marea majoritate a candidaților nu au reușit să scrie corect nici subalgoritmii ceruți la punctul I. Ei nu cunosc conceptul de subalgoritm!

Dintre cei 112 candidați 64 nu au folosit deloc proceduri în programul Pascal, iar 39 au folosit proceduri care conțineau erori.

Nu vom analiza cauzele care au dus aici (deși ar fi interesant și acest lucru). Vom încerca să dăm soluția așteptată de la ei, ca un ghid pentru elevii actuali și pentru viitorii candidați la admiterea în facultate.

Înainte de a trece la scrierea subalgoritmilor și a programului cerut vom insista puțin asupra conceptului de subalgoritm și a erorilor grave făcute de candidați.

Când vorbim de un algoritm ne gândim și la o problemă pe care o rezolvă acest algoritm. Iar când definim un subalgoritm trebuie să explicăm cele două părți ale acestui cuvânt: sub și algoritm. În primul rând el este un algoritm pentru rezolvarea unei probleme P. Numai că această problemă este o parte dintr-o problemă mai complexă C. Iar pentru algoritmul de rezolvarea a problemei C, algoritmul de rezolvare a problemei P este un subalgoritm. De aici provine și diferența dintre algoritm și subalgoritm. În orice problemă există date cunoscute și rezultate dorite. Algoritmul problemei C trebuie să citească datele cunoscute în problema C și trebuie să tipărească rezultatele obținute. Pentru subproblema P datele presupuse cunoscute sunt de multe ori rezultate intermediare obținute de algoritmul problemei C și nu sunt cunoscute de către programator, deci nu pot fi citite! De asemenea, rezultatele obținute de subalgoritmul problemei P nu sunt rezultatele problemei C care ne interesează, ele pot fi rezultate intermediare pentru continuarea rezolvării problemei C. Deci nu trebuie tipărite. De aici rezultă și semnificația listei parametrilor formali din definiția unui subalgoritm și, corespunzător, a listei parametrilor actuali. Aproape toți candidații care au știut scrie subalgoritmii ceruți au citit și tipărit în subalgoritmi și aproape toți au avut subalgoritmi fără listă de parametri formali. Este obligatoriu ca această listă să conțină variabilele care marchează datele presupuse cunoscute în subproblemă și variabilele care marchează rezultatele obținute. Este sarcina algoritmului care apelează subalgoritmul să decidă ce face cu aceste date și ce rezultate tipărește.

Cele prezentate mai sus provin și din scopul pentru care s-a inventat conceptul de algoritm. Nu este aici spațiul necesar să vorbim despre importanța subalgoritmilor în programare. Ne limităm să punctăm doar câteva avantaje:

  • Reutilizabilitate: subalgoritmii se pot refolosi ori de câte ori apare subproblema respectivă în alte probleme;
  • Mărirea productivității în programare și prin refolosirea subalgoritmilor existenți și prin simplificarea activității de programare. Fiind doar o parte din problema de rezolvat este mult mai ușor și mai sigur să proiectăm subalgoritmii respectivi;
  • Apare posibilitatea ca în rezolvarea unei probleme să lucreze mai mulți programatori, fiecare dintre ei scriind câteva proceduri.

Pentru a putea descrie algoritmi care operează asupra polinoamelor este necesar să alegem o reprezentare a unui polinom. Evident, considerăm cunoscut conceptul de polinom și faptul că un polinom poate fi dat prin grad și coeficienți sau prin monoamele sale.

În prima variantă polinomul

P(X) = p0 + p1-X + ... + pn-Xn

este dat prin gradul n și coeficienții (pi, i = 0, ..., n), iar în a doua variantă prin perechi (cj, ej), j = 1, ..., m, perechea (c, e) reprezentând monomul c-Xe.

Atunci când se cere valoarea unui polinom într-un punct, care se calculează cel mai ușor cu schema lui Horner, este avantajoasă prima reprezentare. În plus, putem conveni ca p-1 să păstreze valoarea lui n, deci polinomul P va fi un vector cu componentele p-1, p0, ..., pn, unde n este valoarea componentei cu indicele -1. Alegem această reprezentare.

Există două modalități de a obține suma S. Pentru comparație le dăm pe amândouă, explicațiile fiind date sub formă de comentarii.

Subalgoritmul SUMAPOL1(P,Q,S) este: { S:=P+Q }

fie m:=p-1

fie n:=q-1

dacă m<n

atunci s-1:=n

altfel s-1:=m

sfârșit dacă { s-a calculat gradul lui S }

pentru i:=0,m execută

si:=pi

sfârșit pentru { S:=P }

dacă m<n

atunci

pentru i:=m+1,n execută

si:=0

sfârșit pentru { s-a inițializat S }

sfârșit dacă

pentru i:=0,n execută

si:=si+qi

sfârșit pentru { S := S + Q = P + Q }

Subalgoritmul SUMAPOL2(P,Q,S) este:

{ S:=P+Q }

fie m:=p-1

fie n:=q-1;

dacă m<n

atunci s-1:=n

altfel s-1:=m

sfârșit dacă { s-a calculat gradul lui S }

dacă m<n

atunci

pentru i:=0,m execută

si:=pi+qi

sfârșit pentru

{ coeficienții de același grad }

pentru i:=m+1,n execută

si:=qi

sfârșit pentru

{ copiază coeficienții rămași din Q }

altfel

pentru i:=0,n execută

si:=pi+qi

sfârșit pentru

{ adună coeficienții de același grad }

pentru i:=n+1;m execută

si:=pi

sfârșit pentru

{ copiază coeficienții rămași din P }

sfârșit dacă

Subalgoritmul care calculează produsul a două polinoame este următorul:

Subalgoritmul PRODPOL(P,Q,R) este: { R:=P*Q }

s-1:=m+n; { s-a calculat gradul lui R }

pentru i:=0,m+n B

ri:=0

sfârșit pentru { R:=polinomul nul }

pentru i:=0,m execută

pentru j:=0,n execută

ri+j:=ri+j+pi*qj

sfârșit pentru

sfârșit pentru

Subalgoritmul care calculează valoarea polinomului P în punctul a, bazat pe schema lui Horner, este dat în continuare ca subalgoritm de tip funcție.

Funcția VALPOL(a,P) este:

{ VALPOL:= (a) }

fie n:=p-1; {n := gradul lui P}

fie v:=pn;

pentru i:=n-1,0 execută

v := v*a + pi

sfârșit pentru

VALPOL:=v

La scrierea programului Pascal mai apare o procedură: cea care citește un polinom. Ea apare în programul Pascal sub numele CITPOL(P) și acceptă ambele forme sub care se poate da un polinom, dar reține în memorie un vector P în care P[-1..grad] conține coeficienții și gradul polinomului. Subalgoritmul este explicat prin comentariile prezente. Scrierea programului Pascal este ușoară dacă este clar algoritmul folosit. Vom prezenta acest algoritm, restul explicațiilor fiind prezente în program sub formă de comentarii.

Algoritmul ADMITERE este:

fie s-1:=0

fie s0:=0

{ S este polinomul sumă cerut în problemă }

fie p-1:=0

fie p0:=1 { P:=1; P este produsul cerut }

fie r-1:=-1

{ R este polinomul cu valoare maximă }

repetă

apelează CITPOL(Q)

{ Q este polinomul citit }

apelează SUMAPOL(S,Q,S) { S:=S+Q }

apelează PRODPOL(P,Q,P) { P:=P*Q }

fie v:=VALPOL(a,Q)

dacă r-1=-1

atunci

R:=Q

vmax:=v { R:= primul polinom citit }

altfel

dacă v>vmax atunci

vmax:=v;

R:=Q

{ polinomul cu valoarea mai mare }

sfârșit dacă

sfârșit dacă

până când p-1>100

apelează TIPPOL(S);

apelează TIPPOL(P);

apelează TIPPOL(R)

Programul Pascal cerut este prezentat în continuare. Subliniem faptul că nu sunt reținute în memorie polinoamele citite, așa cum au crezut marea majoritate a candidaților.

Listing ADMITERE.PAS

Program admitere; {solutia problemei de admitere-2000}

type polinom=array[-1..120] of Integer;

var S,P,R,Q:polinom;

v,vmax:Integer;

procedure prodpol(P,Q:polinom;

var T:polinom);

{ T:=P*Q }

var m,n,i,j:Integer;

begin

m:=P[-1];

n:=Q[-1];

for i:=0 to m+n do

T[i]:=0; { P:=0 }

for i:=0 to m do

for j:=0 to n do

T[i+j]:=T[i+j]+P[i]*Q[j]

end;

function valpol(a:Integer;

P:polinom):Integer;

{ valpol:=P(a) }

var i,s:Integer;

begin

s:=0;

for i:=P[-1] downto 0 do

s:=s*a+P[i];

valpol:=s

end;

procedure sumapol(P,Q:polinom;

var S:polinom);

{ S:=P+Q }

var m,n,i:Integer;

begin

m:=P[-1];

n:=Q[-1];

if m<n

then S[-1]:=n

else S[-1]:=m;

for i:=0 to m do

S[i]:=P[i]; { S:=P }

if m<S[-1] then

for i:=m+1 to S[-1] do

S[i]:=0;

{ initializeaza toti coeficientii }

for i:=0 to n do

S[i]:=S[i]+Q[i]; { S:=S+Q }

while (S[-1]>0) and (S[S[-1]] = 0) do

{ se elimina monoamele nesemnificative }

S[-1]:=S[-1]-1

end;

procedure citpol(var Q: polinom);

{ citeste un polinom si-l pastreaza in Q }

{ Q[-1]=gradul; Q[0..Q[-1]]=coeficientii }

var i,ind,coef,expo:Integer;

begin

Write('Introduceti monoame sau grad si ');

Write('coeficienti? (monoame=0; ');

Writeln('grad+coef=1)');

Readln(ind);

case ind of

0: begin

Write('Dati coeficient, ');

Writeln('apoi exponent');

Write('(0,0) inseamna terminarea

Writeln(' citirii monoamelor.');

repeat

Readln(coef,expo);

if q[-1]=-1 then

{ primul monom din Q }

begin

Q[-1]:=expo; { gradul }

for i:=0 to expo-1 do

Q[i]:=0;

Q[expo]:=coef

end

else { adauga monomul in Q }

begin

if expo<=Q[-1] then

{ Gradul nu se schimba }

Q[expo]:=coef

else { Gradul se schimba }

begin

for i:=Q[-1]+1 to expo-1 do

Q[i]:=0;

Q[expo]:=coef;

Q[-1]:=expo { noul grad }

end

end

until coef=0

end;

1: begin

Writeln('Dati gradul:');

Readln(Q[-1]);

Write('Dati coeficientii in ');

Write('ordine crescatoare ');

Writeln('a exponentilor:');

for i:=0 to Q[-1] do

Read(Q[i])

end

end

end;

procedure tippol(Q:polinom);

{ Tipareste polinomul Q }

var i:Integer;

begin

Write('Coeficientii polinomului in ');

Write('ordine crescatoare ');

Writeln('a exponentilor=');

for i:=0 to Q[-1] do

Write(Q[i]:5);

{ sau Write(Q[i]:5,'* x^',I); }

{ ca polinom in X }

Writeln

end;

begin

S[-1]:=0;

S[0]:=0;

Q:=0 }

P[-1]:=0;

P[0]:=1;

{ P:=1 }

R[-1]:=-1; { R inca nu exista }

Writeln('Introduceti punctul a:');

Readln(a);

repeat

citpol(Q); sumapol(S,Q,S); { S:=S+Q }

prodpol(P,Q,P); { P:=P*Q }

v:=valpol(a,Q);

if R[-1]=-1 then { R:=primul polinom citit }

begin

vamx:=v;

R:=Q

end

else { R:=polinomul ca valoarea mai mare }

begin

vmax:=v;

R:=Q

end

until P[-1]>100;

writeln('suma polinoamelor este:');

tippol(S);

writeln('produsul polinoamelor este:');

tippol(P);

write('polinoamul cu valoarea ');

Writeln('maxima este:');

tippol(R);

End.

Dl. prof. dr. Militon Frențiu este cadru didactic la Universitatea Babeș-Bolyai din Cluj. Poate fi contactat prin e-mail la adresa mfrentiu@cs.ubbcluj.ro

Nota redacției

Chiar dacă un elev care termină clasa a X-a ar trebui să posede cunoștințele necesare scrierii acestui program, se pare că situația reală este alta. Probabil că vina nu este numai a elevilor, ci și a profesorilor care nu acordă suficientă atenție conceptelor fundamentale în predarea informaticii. Am publicat acest articol în scopul de a trage un semnal de alarmă adresat atât elevilor cât și profesorilor lor din licee.

[cuprins]