www.agora.ro

Primii pași...

Algoritmi ELEMENTARI

Sorin Groza

Pentru a putea rezolva cu succes o problemă de informatică este absolut necesar să cunoaștem câțiva algoritmi elementari. Vom prezenta în continuare probleme cu ajutorul cărora vom introduce algoritmi ce vor putea fi folosiți de către "pitici" în rezolvarea problemelor.

Concursul

La Clubul Copiilor se organizează un concurs la care participă n elevi, fiecare obținând un număr de puncte. Vor fi declarați câștigători toți cei cu punctaj maxim, fiecare primind câte un premiu.

Scrieți un program care va determina punctajul maxim și va comunica organizatorilor câte premii să pregătească.

Date de intrare:

n=11

16 72 9 7 72 41 12 16 72 16 16

Date de ieșire:

Se acorda 3 premii

Punctaj maxim: 72 puncte

Pentru rezolvarea aceastei probleme va trebui să găsim cel mai mare punctaj și să determinăm numărul de aparițtii al acestuia în șir. Aici apare unul din algoritmii cel mai des folosiți: determinarea maximului dintr-un șir de numere întregi. Vom considera că cel mai mare element al șirului este cel de pe prima poziție și îl vom păstra într-o variabilă (max). Vom lua, unul câte unul, fiecare element al șirului și le vom compara cu max. În cazul în care un element este mai mare decât max, vom păstra în max valoarea acestuia. După parcurgerea întregului șir, în variabila max vom avea cel mai mare element al șirului. Numărul de premii îl vom calcula cu ajutorul variabilei nr_premii; vom parcurge șirul și, în momentul în care un element este egal cu max, vom incrementa acestă variabilă.

Listing: CONCURS.PAS

var i,max,n,nr_premii:Integer;

p:array[1..100] of Integer;

Begin

Write('Introduceti nr. concurentilor: ');

Readln(n)

Writeln('Punctele concurentilor:');

for i:=1 to n do Read(p[i]);

max:=p[1];{ determinarea maximului sirului }

for i:=1 to n do

if p[i]>max then max:=p[i];

{ sfarsit determinare }

for i:=1 to n

do

if p[i]=max then Inc(nr_premii);

Writeln('Se acorda ',nr_premii,' premii.');

Writeln('Punctajul maxim ',max,' puncte.')

End.

Grupuri

În curte se joacă n copii. Ei doresc să formeze grupuri a câte trei copii, astfel încât fiecare grup să aibă proprietatea: înălțimea copilului din mijloc să fie media aritmetică a înălțimilor celorlalți doi copii. Scrieți un program care să afișeze toate grupurile care se pot forma.

Date de intrare:

n=6

150 155 154 160 152 156

Date de ieșire:

150 152 154

152 154 156

150 155 160

154 155 156

152 156 160

Pentru a rezolva problema vom genera toate tripletele (prim - mijloc - ultim) și vom verifica dacă respectă condiția cerută. Deoarece, la un moment dat, un grup identificat printr-un triplet nu are valorile ordonate crescător și astfel verificarea proprietății cerute ar fi greoaie, vom ordona crescător înălțimile copiilor. Astfel, fiecare grup format are cele trei valori în ordine crescătoare. Acest algoritm se numește ordonarea crescătoare a unui șir. Parcurgând șirul vom verifica dacă perechile de elemente vecine au valorile ordonate crescător. În caz contrar vom schimba între ele aceste valori. Vom face atâtea treceri până când nu mai au loc astfel de schimbări, moment în care șirul este ordonat crescător.

Listing: GRUPURI.PAS

var i,n,prim,mijloc,ultim,aux:Integer;

h:array[1..100] of Integer;

gata,se_poate:Boolean;

Begin

Write('Introduceti numarul copiilor ');

Readln(n);

Writeln('Inaltimile copiilor:');

for i:=1 to n do Read(h[i]);

repeat { ordonarea crescatoare a sirului }

gata:=true; { metoda "bulelor" }

for i:=1 to n-1 do

if h[i]>h[i+1]

then

begin

aux:=h[i];

h[i]:=h[i+1];

h[i+1]:=aux;

gata:=false

end;

until gata; { sfarsit ordonare }

for prim:=1 to n-2 do

for mijloc:=prim+1 to n-1 do

for ultim:=mijloc+1 to n do

if h[mijloc]-h[prim]=

h[ultim]-h[mijloc]

then

begin

Write(h[prim],' ',h[mijloc],' ');

Writeln(h[ultim]);

se_poate:=true

end;

if not se_poate

then

Writeln('Nu se pot forma astfel de grupuri')

End.

Hoții

Un număr de n hoți ajung la un tezaur care constă din m seifuri, în fiecare seif existând un anumit număr de bani. Hoții vor lua bani dintr-un număr de seifuri consecutive ce respectă proprietatea: suma banilor din aceste seifuri să se împartă exact la cei n hoți (fiecare hoț să "câștige" aceeași sumă) și să fie cea mai mare posibilă de câștigat.

Spuneți care dintre seifuri le vor deschide hoții. Dacă problema nu are soluție, se va afișa mesajul Ne lasam de meserie.

Date de intrare:

n=4

m=9

2 10 30 3 6 6 6 6 2

Date de ieșire:

Deschid seifurile: 2 3

Pentru această problemă vom prezenta doi algoritmi având complexități diferite, adică pentru același set de date timpul de execuție diferă. Rulați aceste două programe cu date identice și observați timpul de execuție!

Primul algoritm generează toate subșirurile cuprinse între două poziții i și j, pentru fiecare subșir calculându-se suma elementelor. Dacă această sumă se divide la numărul de hoți și este cea mai mare până în acest moment, se păstrează această secvență, adică poziția de început, poziția de sfârșit și suma elementelor ei. Acest algoritm nu este optim, deoarece face unele calcule de mai multe ori, ceea ce determină creșterea timpului de execuție.

Listing: HOTII_1.PAS

var a:array[1..100] of Byte;

i,j,x,n,s,nrhoti,max,poz1,poz2:Byte;

Begin

Write('Introduceti numarul hotilor: ');

Readln(nrhoti);

Write('Introduceti numarul de seifuri: ');

Readln(n);

Writeln('Introduceti sumele din seifuri:');

for i:=1 to n do Read(a[i]);

for i:=1 to n-1 do { generare subsiruri }

begin

for j:=i+1 to n do

begin

for x:=i to j do s:=s+a[x];

if s mod nrhoti=0

then

if s>max

then

begin max:=s;

poz1:=i; poz2:=j

end;

s:=0

end

end; { sfarsit generare }

if max=0

then

begin

Writeln('Ne lasam de meserie'); Halt

end;

Write('Deschid seifele:');

for i:=poz1 to poz2 do Write(i,' ')

End.

Al doilea algoritm utilizează un șir care reduce substanțial numărul calculelor și implicit timpul de execuție. Acest șir se numește șirul sumelor parțiale. Astfel, elementul sp[i] va fi egal cu suma tuturor elementelor șirului a de la început până în a i-a poziție:

sp[i]=a[1]+a[2]+...+a[i].

Deoarece:

sp[i]=a[1]+...a[i-1]+a[i]=sp[i-1]+a[i],

se observă relația de calcul a elementelor acestui șir:

sp[i]=sp[i-1]+a[i].

Pentru a determina suma valorilor seifurilor între două poziții i și j, nu mai este necesară însumarea a[i]+...+a[j], ci doar o simplă diferență sp[j]-sp[i-1].

Un exemplu concret ar fi următorul: dacă vrem să calculăm suma valorilor seifurilor de la 5 la 9, vom determina diferența dintre sp[9] și sp[4], adică vom scădea din suma primelor 9 seifuri suma primelor 4 seifuri, obținând suma seifurilor de la 5 la 9. Șirul sumelor parțiale poate fi utilizat în rezolvarea multor probleme. Dacă o astfel de secvență are suma mai mare și se divide la numărul hoților, se păstrează poziția de început, poziția de sfârșit și suma secvenței. În final se vor tipări indicii seifurilor ce constituie secvența sau, mesajul cerut în cazul în care nu există o astfel de secvență.

Listing HOTII_2.PAS

var a:array[1..100] of Byte;

sp:array[0..100] of Word;

i,n,nrhoti,max,poz1,poz2,v,p1,p2:Byte;

Begin

Write('Introduceti numarul hotilor: ');

Readln(nrhoti);

Write('Introduceti numarul de seifuri: ');

Readln(n);

Writeln('Introduceti sumele seifurilor:');

for i:=1 to n do Read(a[i]);

for i:=1 to n

do

sp[i]:=sp[i-1]+a[i];

{ creare sir sume partiale }

{ determinare subsir de seifuri }

for p1:=0 to n-1 do

for p2:=p1+1 to n

do

begin

v:=sp[p2]-sp[p1];

if (v>max) and (v mod nrhoti=0)

then

begin

max:=sp[p2]-sp[p1];

poz1:=p1; poz2:=p2

end

end; { sfarsit determinare }

if max=0

then

begin

Writeln('Ne lasam de meserie '); Halt

end;

Write('Deschid seifele: ');

for i:=poz1+1 to poz2 do Write(i,' ')

End.

În încheiere vă propunem să rezolvați câteva probleme. Încercați să scrieți algoritmi diferiți pentru aceeași problemă și să estimați care sunt mai performanți.

Expoziția

La expoziția auto de la New York sunt prezentate n mașini, pentru fiecare dintre ele cunoscându-se prețul de vânzare. Scrieți un program care calculează diferența maximă de preț dintre două mașini prezentate.

Date de intrare:

n = 5

180 66 90 20 60

Date de ieșire:

160

Vizita

Într-un sat este agitație, deoarece sosește în vizită o mare personalitate, iar persoana cea mai în vârstă din sat trebuie să o întâmpine cu pâine și sare. Deoarece nu se știe cine este această persoană, este necesar ca toți locuitorii satului să-și declare data nașterii (ziua, luna, anul). Scrieți un program care, plecând de la aceste date, afișează pe ecran data nașterii persoanei celei mai în vârstă din sat.

Date de intrare:

n = 5

10 11 1915

22 12 1934

9 1 1955

18 8 1915

25 11 1960

Date de ieșire:

persoana cea mai in varsta este nascuta in 18 8 1915

Competiția

La un concurs de tras cu frânghia, desfășurat pe plaja din Malibu, participă n persoane, fiecare dintre ele fiind caracterizată de un număr ce reprezintă puterea acesteia. Primii p (pŁn) participanți aparțin echipei stanga, iar ceilalți începând cu poziția p+1, până la ultimul formează echipa dreapta.

Se va considera câștigătoare echipa care are suma puterilor participanților cea mai mare

a) citind o poziție p să se spună care echipă va fi învingătoare.

b) să se găsească o poziție astfel încât cele două echipe formate să lupte la infinit, adică să aibă aceeași sumă a puterilor. Dacă nu este posibil, să se afișeze mesajul IMPOSIBIL.

Date de intrare:

n=7

8 1 3 2 5 3 2

p=4

Date de ieșire:

STANGA

3

Domnul Sorin Groza este profesor la Clubul Copiilor din Aiud și poate fi contactat prin intermediul redacției.

[cuprins]