www.agora.ro

Șiruri care folosesc la... prelucrarea șirurilor

Din secretele ȘIRURILOR

Sorin Groza
Analiza problemelor de informatică este o etapă care nu trebuie "sărită" niciodată. Pentru a vă convinge, vă prezentăm câteva "artificii" care îmbunătățesc în mod considerabil timpul de execuție al algoritmilor. Nu vă speriați, știm că această parte a GInfo se adresează "piticilor"; nu vom intra în prea multe detalii.

Problema 1: Numărul lipsă

Se citește de la tastatură un număr natural n și apoi n numere naturale distincte din intervalul [0,n]. Deoarece în intervalul [0,n] sunt n+1 numere naturale, rezultă că unul dintre numere lipsește. Scrieți un program care afișează numărul absent.

Date de intrare:

n=7

2 6 1 4 7 0 5

Date de ieșire:

lipseste numarul 3

Rezolvare:

Prima idee de rezolvare a problemei constă în a păstra într-un șir toate cele n numere și apoi, pentru fiecare număr de la 0 la n, trebuie verificat dacă este prezent sau nu în șir. În momentul în care se descoperă primul număr absent, acesta se va afișa, deoarece se știe că lipsește unul singur.

O altă idee este de a ordona crescător șirul numerelor. Se verifică apoi diferența dintre fiecare două elemente consecutive. Când aceasta este diferită de 1, atunci a fost găsit numărul lipsă.

Ambii algoritmi au un timp de răspuns mare, pentru o valoare mare a lui n.

Vom prezenta o implementare bazată pe prima idee, dar care nu necesită căutarea fiecăruia dintre numere, ceea ce ar putea însemna, în cazul cel mai defavorabil, parcurgerea integrală a șirului dat, de n ori. Pentru a evita aceste parcurgeri, vom folosi un șir v având n elemente, în care elementul v[i] indică prezența numărului i în șir. În momentul introducerii valorii i în șirul a, v[i] devine true. Este clar că în final toate elementele șirului vor fi egale cu true, mai puțin unul care rămâne cu valoarea false.

Pentru a afla care este numărul absent, vom parcurge șirul v, iar elementul v[i]=false semnalează faptul că numărul i nu există în șirul dat.

 Listing: ABSENT.PAS  
 Program Absent; 
 const n_max=100; 
 var n,i:Integer; 
 gasit:Boolean; 
 v:array[0..n_max] of Boolean; 
 a:array[0..n_max] of Integer; 
 
 Begin 
 Write('n= '); Readln(n); 
 Writeln(n,' numere distincte'); 
 for i:=0 to n_max do v[i]:=false;    
 for i:=1 to n do 
 
begin
 Read(a[i]); v[a[i]]:=true 
 end; 
 Readln; 
 gasit:=false; i:=0; 
 while not gasit do 
 if v[i] then Inc(i) 
 else 
 begin 
 Writeln('Lipseste numarul ',i); 
 gasit:=true 
 end; 
 Readln 
 End. 

Problema 2: Aeroportul

Un grup de teroriști ce pregătesc o lovitură de stat, își propun să ocupe un aeroport strategic. Ei dețin harta zborurilor între cele n aeroporturi, adică m perechi (i,j) ce indică faptul că există zbor din aeroportul i în aeroportul j. Ei vor ocupa acel aeroport din care se poate ajunge în fiecare din celelalte aeroporturi, dar în care nu se poate ajunge. Scrieți un program care găsește aeroportul care trebuie ocupat.

Date de intrare:

n=3

m=3

1 3

2 1

2 3

Date de ieșire:

Aeroportul ocupat este 2

Rezolvare:

Trebuie găsit acel aeroport i, corespunzător numărului i care apare exact de n-1 ori în șirul care conține plecările din aeroporturi și de 0 ori în șirul care conține sosirile. Se va testa fiecare număr de la 1 la n dacă verifică această condiție. Când se găsește numărul, acesta se va afișa, deoarece reprezintă aeroportul căutat. Și în cazul acestei probleme se va folosi ideea de mai sus. Astfel, vom folosi 2 șiruri: un șir plec (plec[i] va arăta spre câte aeroporturi se poate zbura din aeroportul i); un alt șir sos (sos[j] va arăta din câte aeroporturi se poate ajunge în aeroportul j).

Cum se construiesc cele 2 șiruri?

Se citește o pereche (p s), iar plec[p] și sos[s] se măresc cu 1, deoarece s-a introdus faptul că din aeroportul p se pleacă, iar în aeroportul s se sosește. Se parcurg cele două șiruri, iar poziția pentru care plec[i]=n-1 și sos[i]=0 indică faptul că aeroportul este i.

 
 
Listing: AEROPORT.PAS
 Program Aeroport;
  const n_max=100; 
 var n,m,i,p,s:Integer; 
 gasit:Boolean; 
 plec,sos:array[0..n_max] of Integer; 
 Begin 
 Write('Numarul de aeroporturi: ); 
 Readln(n); 
 Write('Numarul legaturilor: '); Readln(m); 
 for i:=1 to m do 
 begin 
 Write('Introduceti legatura ',i,': '); 
 Read(p,s); 
 Inc(plec[p]); Inc(sos[s]) 
 end; 
 Readln; 
 gasit:=false; i:=0; 
 while not gasit do 
 begin 
 if (plec[i]=n-1) and (sos[i]=0) 
 
then
 begin 
 Writeln('Aeroportul ocupat este ',i); 
 gasit:=true 
 end; 
 Inc(i) 
 end; 
 Readln 
 End. 

Problema 3: Litera preferată

Un grup de n copii din clasa I sunt solicitați de către doamna învățătoare să noteze pe un bilețel litera (mică) preferată (după studiul alfabetului). Scrieți un program care afișează:

- câte litere distincte ale alfabetului au fost folosite;

- care este litera preferată a clasei și numărul copiilor care au ales-o.

Date de intrare:

n=10

a b a a c b d a c b

Date de ieșire:

4 litere distincte

litera preferata: a

a fost aleasa de 4 copii

Rezolvare:

Pentru rezolvarea problemei vom folosi un șir litera cu 26 de elemente, unde litera[i] reprezintă de câte ori a fost aleasă litera de pe poziția i din alfabet (de exemplu litera[3] arată de câte ori a fost aleasă litera c). Se va parcurge șirul litera, iar numărul elementelor diferite de 0 va arăta câte litere distincte au fost folosite. Aflarea literei preferate se reduce astfel la aflarea maximului șirului cu frecvența literelor (fie acesta max) și a poziției acestuia (notată poz). Litera preferată este litera care se află pe poziția poz în alfabet și a fost aleasă de max copii. Pentru exemplul nostru poz=1, deci litera preferată este a și max=4, adică a fost aleasă de 4 copii.

Cum se construieste șirul litera?

În momentul citirii unei litere lit se va determina poziția ei în alfabet: pozitie=Ord(lit)-Ord('a')+1. Valoarea elementului litera[pozitie] se va mări cu 1. După citirea ultimei litere va fi construit șirul cu numărul de apariții a fiecărei litere introduse.

 Listing ALFABET.PAS   
 Program Alfabet;
  var n,i,max,Poz,pozitie,nr_lit:Integer; 
 litera:array[1..26] of Integer; 
 lit,ales:Char; 
 Begin 
 Write('Numarul de litere '); 
 Readln(n); 
 for i:=1 to n do 
 begin 
 Write('Introduceti litera ',i,' '); 
 Readln(lit); 
 pozitie:=Ord(lit)-Ord('a')+1; 
 Inc(litera[pozitie]) 
 end; 
 for i:=1 to 26 do 
 begin 
 if litera[i]<>0 then Inc(nr_lit);    
 if litera[i]>max 
 then begin max:=litera[i]; Poz:=i end    
 end; 
 ales:=Chr(Poz+Ord('a')-1); 
 Writeln(nr_lit,' litere distincte'); 
 Writeln('Litera preferata: ',ales); 
 Writeln('a fost aleasa de ',max,' copii'); 
 End. 

În încheiere vă propunem câteva probleme de rezolvat, pentru a oferi posibilitatea verificării modului de aplicare a ceea ce ați învățat nou din cele prezentate anterior.

Problema 4: Moșul cel uituc

Moșul cel bun a primit scrisori de la toți copiii cuminți, scrisori pe care le-a numerotat în ordinea sosirii, începând de la 1. Plecând la drum, se gândește că din grabă a uitat unele scrisori. Scoate din sac câte o scrisoare, una câte una, notând pe o foaie numărul fiecăreia. Știind că a primit n scrisori, scrieți un program care afișează cele pe care le-a uitat acasă. Se dă numărul de scrisori (n) și numerele scrisorilor existente în sac. Enumerarea lor se va termina cu 0 (zero).

Date de intrare:

n=10

8 3 6 1 7 2 10 5 0

Date de ieșire:

Scrisori uitate: 4 9

Problema 5: Străzi și piețe

Într-un oraș există n intersecții. Se citesc de la intrare perechi de forma (i j) cu semnificația că din intersecția i se poate ajunge direct în intersecția j fără a trece prin alte intersecții.

Numim piață o intersecție în care numărul străzilor care intră, plus numărul străzilor care ies din ea este cel puțin 4. Piața centrală este intersecția cu cel mai mare număr de străzi care intră și care ies (este unică). Să se afle toate piețele și să se stabilească piața centrală.

Observație:

Sfârșitul perechilor este dat de perechea (0 0).

Date de intrare:

n=6

1 2

1 4

1 6

2 3

2 6

3 4

4 1

4 5

4 6

5 2

5 3

0 0

Date de ieșire:

3 piete: 1 2 4

piata centrala: 4

Problema 6: Și iar litere

Pe plaja de la Năvodari au sosit copii care își petrec vacanța la mare. Profesorul însoțitor organizează următorul joc: copiii se împart în două grupe. Copiii din fiecare grupă vor scrie pe nisip litere ale alfabetului, obținându-se astfel două șiruri de litere. Apoi, toți copiii vor studia atent cele două șiruri de litere, dorind să descopere literele alfabetului care apar de același număr de ori în cele două șiruri. Un copil mai isteț, văzând care este jocul, scrie un program care, plecând de la cele două șiruri de litere, obține literele care apar de același număr de ori în cele două șiruri. Scrieți și voi un astfel de program.

Date de intrare:

msbsshbl - primul șir

skxbbsmmsk - al doilea șir

Date de ieșire:

Litere cu acelasi numar de aparitii:

s b

Domnul Sorin Groza este cadru didactic la Clubul Copiilor din Aiud; poate fi contactat prin intermediul redacției.

[cuprins]