Olimpiada Republicană La Informatică Ediţia 2010 Moldova

February 10, 2023 | Author: Anonymous | Category: N/A
Share Embed Donate


Short Description

Download Olimpiada Republicană La Informatică Ediţia 2010 Moldova...

Description

 

 

Ministerul Educaţiei al Republicii Moldova

Olimpiada Republicană la Informatică  Ediţia 2010

Chişinău 2010

 

Olimpiada Republicană la Informatică. Ediţia 2010. 2010. 

Lucrarea conţine problemele propuse la Olimpiada Republicană la Informatică a elevilor, ediţia 20 10. Pentru fiecare problemă sunt descrise algoritmul şi soluţia respectivă în limbajul de programare PASCAL. Materialele Olimpiadei pot fi de un real folos la studierea Informaticii atât el evilor, cât şi profesorilor de Informatică.

 La elaborarea ediţiei au contribuit : Anatol Gremalschi,  Ion Bolun, Iurie Mocanu, Viorel Afteni  Dumitru Codreanu, Dumitru Ciubatîi,   Bogdănaş Denis  Constantin Dolghieru,

 

doctor habilitat, profesor universitar, UTM doctor habilitat, profesor universitar, ASEM Ministerul Educaţiei  Ministerul Educaţiei  Universitatea Bucureşti  Universitatea Bucureşti  Universitatea Tehnică, Iaşi  Universitatea Politehnică, Bucureşti 

2

 

Cuprins

CLASELE 7

9.......... ........... ........... ........... ........... ........... ........... ........... ........... ........... .......   4

EXPRESII .................... ........................................... ............................................. ............................................ ............................................ ............................................. ....................... 5 IEPURAŞII ...................... ............................................. ............................................. ............................................ ............................................. .......................................... ................... 7 SEGMENTE .................... ........................................... ............................................. ............................................ ............................................. ........................................ ................. 11 PĂTRATE .................... ........................................... ............................................. ............................................ ............................................ ........................................... ..................... 15 NUMERE .................... ........................................... ............................................. ............................................ ............................................ ........................................... ..................... 17 LUPTA MARITIMĂ ...................... ............................................. .............................................. ............................................. ............................................ ............................ ...... 19 CLASELE 10

12 .......... ........... ........... ........... ........... .......... ........... ........... ........... ........... ..  22

VÂSLAŞII .................... ........................................... ............................................. ............................................ ............................................ ........................................... ..................... 23 IEPURAŞII ...................... ............................................. ............................................. ............................................ ............................................. ........................................ ................. 26 SEGMENTE .................... ........................................... ............................................. ............................................ ............................................. ........................................ ................. 30 ........................................... ............................................. ............................................ ............................................ ........................................... ..................... 35 ŞARPELE ....................

DESCOMPUNERI ..................... ............................................ ............................................. ............................................ ............................................ ................................ .......... 39 RADIOUL .................... ........................................... ............................................. ............................................ ............................................ ........................................... ..................... 42

 

3

 

Clasele 7 Denumirea problemei

Numărul de puncte alocat problemei

9

Denumirea fişierului sursă 

Denumirea fişierului de intrare

Denumirea fişierului de ieşire 

100

EXPRES.PAS EXPRES.C EXPRES.CPP

EXPRES.IN

EXPRES.OUT

Iepuraşii 

100

IEPURE.PAS IEPURE.C IEPURE.CPP

IEPURE.IN

IEPURE.OUT

Segmente

100

SEGMENT.PAS SEGMENT.C SEGMENT.CPP

SEGMENT.IN

SEGMENT.OUT

100

PATRAT.PAS PATRAT.C PATRAT.CPP

PATRAT.IN

PATRAT.OUT

100

NUMERE.PAS NUMERE.C NUMERE.CPP

NUMERE.IN

NUMERE.OUT

LUPTA.IN

LUPTA.OUT

Expresii

Pătrate 

 Numere

LUPTA.PAS

 

Lupta maritimă 

100

Total

600

LUPTA.C LUPTA.CPP

-

4

-

-

 

Expresii

Se consideră expresiile booleene de de forma: A  B  C  D = Q 

unde A, B, C, D  şi Q  sunt numere întregi fără semn, iar s1, s 2  şi s3    operatorii aritmetici +, - . Exemple:    17  57 ; 12  6  34 8  12  45    92 926 6  63 ; 21  2   4  6  21.

Elaboraţi un program care, cunoscând valorile numerelor A, B, C, D  şi Q, selectează, dacă-i posibil, operatorii s1, s2  şi s3  în aşa mod, încât expresia booleană  Sarcină.

A  B  C  D = Q 

să ia valoarea de adevăr true. Date de intrare. Fişierul text EXPRES.IN  conţine A, B, C, D şi Q, separate prin spaţiu. 

pe o  singură linie numerele întregi

Date de ieşire. Fişierul text EXPRES.OUT va conţine pe o singură linie un

şir  format  format din operatorii s1, s2  şi s3. Dacă problema admite mai multe soluţii, în fişierul de ieşire se va scrie doar una, oricare din ele. Dacă problema nu are soluţie, în fişierul de ieşire se va scrie şirul de caractere ???. Exemplu1 1. EXPRES.IN 2 6 34 17 47

EXPRES.OUT -++

Exemplu1 2. EXPRES.IN

EXPRES.OUT

8 12 45 9 26

???

Timpul de execuţie nu va depăşi 0,1 secunde. Programul va folosi cel mult 32 Megaocteţi de memorie operativă. Fişierul sursă va avea denumirea EXPRES.PAS, EXPRES.C sau EXPRES.CPP. Restricţii. 0   A,  B  , C , D  109 .

Rezolvare

Conform restricţiilor problemei, 0   A,  B  , C , D  109 . Prin urmare, pentru a evita erorile de depăşire, variabilele A, B, C, D şi Q trebuie declarate cu tipul de date longint.   ExpresiiBooleene; Program  { Clasele 07-09 } var Intrare, Iesire : text;

A, B, C, D, Q : longint; S : string;

 

5

 

 begin 

{ citirea datelor de intrare } assign(Intrare, 'EXPRES.IN'); reset(Intrare); readln(Intrare, A, B, C, D, Q); close(Intrare); { deschiderea fisierului de iesire } assign(Iesire, 'EXPRES.OUT'); rewrite(Iesire); S:='???'; if(A+B+C+D=Q) if(A+B+C-D=Q) if(A+B-C+D=Q) if(A+B-C-D=Q) if(A-B+C+D=Q) if(A-B+C-D=Q) if(A-B-C+D=Q) if(A-B-C-D=Q)

then S:='+++'; then S:='++-'; then S:='+-+'; then S:='+--'; then S:='-++'; then S:='-+-'; then S:='--+'; then S:='---';

{ scrierea datelor de iesire } writeln(Iesire, S); close(Iesire); . end 

 

6

 

Iepuraşii Iepuraşii  

În cartea sa  Liber Abaci  (Cartea Abacului), editată în anul 1202, marele matematician  Fibonacci  (cunoscut şi sub numele  Leonardo Pisano) a rezolvat „problema înmulţirii iepuraşilor”, care constă în calcularea numărului de iepuraşi într -o -o populaţie ce evoluează  pornind de la o pereche iniţială. Conform acestei cărţi, dezvoltarea populaţiei de iepuraşi se descrie cu ajutorul şirului 1, 1, 2, 3, 5, 8, 13, ... , denumit  şirul lui Fibonacci Fibon acci. Formal, acest şir se defineşte cu ajutorul următoarelor for mule: mule:  F 1    1 ,  F 2    1 ,  F 3    2 ,  F 4    3 ,

...,  F i 1   F    i   F i 1 , ... ,

unde F i reprezintă numărul de perechi de iepuraşi în luna i. Sarcină. Elaboraţi un program care calculează suma S  a  a primelor n numere din şirul lui

Fibonacci. Date de intrare. Fişierul text IEPURE.IN conţine pe o singură linie numărul

întreg n.

Date de ieşire. Fişierul text IEPURE.OUT va conţine pe singură linie numărul întreg S . Exemplu. IEPURE.IN 4

IEPURE.OUT 7

Timpul de execuţie nu va depăşi 0,5 secunde. Programul va folosi cel mult 32 Megaocteţi de memorie operativă. Fişierul sursă va avea denumirea IEPURE.PAS, IEPURE.C sau IEPURE.CPP. Restricţii. 2   n  30 300 0.

Rezolvare

În general, problema nu prezintă dificultăţi de algoritmizare, întrucât suma S   poate fi calculată printr -o singură parcurgere a şirului lui Fibonacci. Mai mult ca atât, nu este necesară nici memorarea întregului şir, întrucât numărul curent poate fi calculat prin însumarea doar a celor două numere precedente din şir . Prin F1, F2  şi F3  vom nota oricare trei numere consecutive din şirul lui Fibonacci. Evident, suma S poate  poate fi calculată calculată cu ajutorul următoare următoareii secvenţe de algoritm: F1:=1; F2:=1; S:=F1; i:=2; repeat

S:=S+F2; F3:=F1+F2; F1:=F2; F2:=F3; i:=i+1; until i>n;

Implementând această secvenţă cu ajutorul declaraţiilor de variabile  var S, F1, F2, F3 : integer;

 

7

 

 prin experimente de calcul ne convingem, că începând cu  n  20 , la calcularea valorilor variabilelor în studiu au loc erori de depăşire.  Cei care cunosc alte tipuri de date, ar putea să încerce declaraţia  var S, F1, F2, F3 : longint;

din Turbo Pascal sau tipurile de date Longword, Int64, Qword din Object Pascal. Însă şi în astfel de cazuri, pentru valorile mari ale lui n apar erori de depăşire.  Pentru a evita erorile de depăşire, vom reprezenta numerele mari S, F1, F2  şi  F3  prin tablouri, formate din K  elemente. Fiecare element al tabloului memorează câte o cifra a numărului respectiv. 1 



... 



 K  

Dacă în procesul adunării a două numere mari  A  şi  B, formate din câte  K   cifre, transportul calculat în cazul însumării cifrelor A[1], B[1] şi transportului din rangul precedent diferă de zero, are loc o depăşire şi programul va semnaliza o eroare. În programul ce urmează, pentru a realiza experimentul de calcul, în componenţa  procedurii Adunare a fost inclusă următoarea secvenţă de instrucţiuni:  if Transport=1 then   begin 

writeln('Depasire'); readln; end  ;

Evident, în condiţiile problemei, această secvenţă de instrucţiuni nu va fi executată nici o dată numai atunci, când valoarea lui K  va fi stabilită suficient de mare. Această valoare  poate fi determinată cu ajutorul experimentelor de calcul, atribuindu-i lui n  valoarea limită 300 0 , aşa cum este indicat în restricţiile problemei.  n  30 Program    Iepurasii;  Iepurasii;

{ Clasele 07-09 } const K = 70; { numarul de cifre ale numerelor foarte mari } type Cifra = 0..9; Numar = array[1..K] of Cifra; var n : integer;

S : Numar;  procedure Citeste;

{ Citeste numarul n din fisierul de intrare } var Intrare : text;  begin  assign(Intrare, 'IEPURE.IN'); reset(Intrare); readln(Intrare, n); close(Intrare); end  ; { Citeste }  procedure  Scrie; { Scrie suma S in fisierul de iesire } var Iesire : text;

j : integer;

 

8

 

 begin 

assign(Iesire, 'IEPURE.OUT'); rewrite(Iesire); j:=1;  while S[j]=0 do j:=j+1;  while jm then n:=n-m else m:=m-n; k:=k+1; end  ; { while } { scrierea datelor de iesire } assign(Iesire, 'PATRAT.OUT'); rewrite(Iesire); writeln(Iesire, k); close(Iesire); end  .

 while n  m , care,  Numărul de iteraţii din instrucţiunea poatecomparabilă depăşi valoare conform restricţiilor problemei este de ordinul 10 10 , nu mărime cu capacitatea de  prelucrare a calculatoarelor moderne. Prin urmare, timpul de calcul va fi mai mic decât 1 secundă.

 

16

 

Numere 

Se consideră o mulţime finită, elementele căreia sînt numere naturale mai mici ca 32 700. Scrieţi un program, care selectează din această mulţime numerele prime.  Date de intrare. Fişierul text NUMERE.IN  conţine pe fiecare linie câte un număr natural.

Date de text ieşire.   Fişierul NUMERE.OUT  va conţine pe fiecare linie cuvîntul DA  dacă numărul natural din linia respectivă a fişierului de intrare este un număr prim şi NU în caz contrar. Exemplu.  NUMERE.IN 41 4 53

NUMERE.OUT DA NU DA

Restricţii.

Fişierul de intrare NUMERE.IN  conţine cel mult 100 ddee linii. Timpul de execuţie nu va depăşi 0.5 secunde. Fişierul sursă va avea denumirea NUMERE.PAS, NUMERE.C sau NUMERE.CPP.

Rezolvare

Conform definiţiei, numărul i, i  2, este prim dacă el se împarte fără rest numai la 1 şi la el însuşi. Această definiţie poate fi aplicată direct împărţind numărul i la 2, 3, 4, ..., (i div  2). Evident, timpul cerut de un astfel de algoritm T  i. Luînd în considerare faptul că valoarea maximă a numărului i  este 32 700, iar fişierul de intrare conţine cel mult 100 de numere, timpul de execuţie T  32700  100  3  106. Intrucît capacitatea de prelucrare a calculatorului  personal este de ordinul 109 instrucţiuni pe secundă, timpul de execuţie T  va  va fi mai mic ca 0,5 secunde.

Program    Numere;  Numere;

{ Clasele 07-09 } var i : integer; Finput, Foutput : text; function  EsteNumarPrim(i : integer) : string;

{ Returneaza DA daca numarul i este prim si NU in caz contrar } label 1; var j : integer;  begin  EsteNumarPrim:='DA'; if (i=0) or (i=1) then  begin  EsteNumarPrim:='NU'; goto 1; end  ; for j:=2 to (i div 2) do   j)=0 then   j)=0 if (i mod   begin  EsteNumarPrim:='NU';

 

17

 

goto 1; ; end  1: end  ; { EsteNumarPrim }  begin 

assign(Finput, 'NUMERE.IN'); assign(Foutput, 'NUMERE.OUT'); reset(Finput); rewrite(Foutput);  while not eof(Finput) do   begin  readln(Finput, i); writeln(Foutput, EsteNumarPrim(i)); end  ; close(Finput); close(Foutput); end  .

 

18

 

Lupta maritimă maritimă  

În cunoscutul joc „Lupta  maritimă”, acţiunea are loc pe o fo aie de hârtie, liniată în  pătrăţele, cu dimensiunile m  rânduri şi n  coloane. Pe câmpul de joc se pot afla corăbii distincte de formă arbitrară. Fiecare corabie reprezintă o figură   conexă (figura se numeşte conexă dacă din orice pătrăţel al ei se poate ajunge la oricare alt pătrăţel din componenţa acesteia, deplasarea din pătrăţelul curent în unul din cele  patru  pătrăţele vecine efectuându-se  prin latura comună).  Oricare două corăbii nu au puncte comune şi nu se ating la colţuri  (vezi desenul exemplu). În din procesul jocului, fiecare din corăbii se poate afla în una din următoarele trei stări:    dacă în corabie nu s-a „nimerit” nici o dată, ea se consideră „vie”;    dacă în fiecare din pătrăţelele din componenţa unei cor abii abii s-a „nimerit”, ea se consideră “ucisă”;    în caz contrar corabia se consideră „rănită”. Sarcină.

Elaboraţi un program care calculează numărul corăbiilor „vii”, numărul corăbiilor „ucise” şi numărul corăbiilor „rănite”.   Fişierul text LUPTA.IN  conţine pe o singură linie numerele întregi m  şi n, separate prin spaţiu. Fiecare din următoarele m linii ale fişierului de intrare conţine câte n  numere întregi, separate prin spaţiu. Aceste numere pot lua următoarele valori:   0 –acest pătrăţel nu nu aparţine nici la o corabie (este apă);    1 –  acest pătrăţel aparţine unei corăbii, dar în el nu s -a „nimerit”;   -1 –  acest pătrăţel aparţine unei corăbii şi în el s -a „nimerit”. Date de intrare.

Fişierul text LUPTA.OUT  va conţine pe singură linie trei numere întregi, separate prin spaţiu: numărul de corăbii „vii” , numărul de corăbii „ucise”  şi numărul de corăbii „rănite”. Date de ieşire.

Exemplu. LUPTA.IN 7 8 0 0 1 0 -1 -1 0 1 1 0 0 0 0 0 0 0 1 0 1 1 1 1 1 0 -1 0 1 0 0 0 1 0 0 0 1 1 1 -1 1 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0

LUPTA.OUT 3 1 2

Timpul de execuţie nu va depăşi 0,1 secunde. Programul va folosi cel mult 32 Megaocteţi de memorie operativă. Fişierul sursă va avea denumirea LUPTA.PAS, LUPTA.C sau LUPTA.CPP. Restricţii. 1  m  , n  25 .

Rezolvare

Din analiza enun enunţului ţului problemei se oobservă bservă că operaţia operaţia de bază, ce trebuie efectuată de mai multe ori, constă în determinarea tuturor pătrăţele lor, care formează o corabie. Această operaţie poate fi făcută recursiv după cum  urmează.   x,  y) aparţine unei corăbii. În procesul de analiză a Presupunem ( x  pătrăţelului curent, că în pătrăţelul funcţie de curent valoarea respectivă, vom incrementa unul din contoarele k 1 

 

19

 

(nu s-a nimerit) sau k 2 (s-a nimerit). Pentru a exclude pătrăţelul curent din analizele ulterioare, înscriem în el valoarea „0”.   În continuare, vom analiza recursiv  pătrăţelul de sus (  xx-1,  y), cel din dreapta (  xx,  y+1), cel din stânga ( x  x, y-1) şi cel de jos ( x  x+1, y). După parcurgerea tuturor pătrăţelelor din componenţa unei corăbii, în funcţie de valorile k 1 şi k 2, incrementăm unul din contoarele t 1 (vii), t 2 (ucise) sau t 3 (rănite).  Pentru a evita verificările de la marginile câmpului de joc, în programul ce urmează el este încadrat în zerouri.     LuptaMaritima;  LuptaMaritima; Program  { Clasele 07-09 } const 

mmax=25; nmax=25; { tablouri ce defines coordonatele patratelelor vecine } dx : array [1..4] of integer = (-1, 1, 0 ,0); dy : array [1..4] of integer = (0, 0, -1 ,1); var  A : array [0..mmax+1, 0..nmax+1] of integer; { campul de joc } m, n : integer; { dimensiunile curente ale campului de joc } t1, t2, t3 : integer; { numarul de corabii: t1 - vii; t2 - ucise; t3 - ranite } k1, k2 : integer; { k1 - numarul patratelelor in care nu s-a nimerit } { k2 - numarul patratelilor in care s-a nimerit }  procedure Citeste; var i, j : integer;

Intrare : text;  begin  assign(Intrare, 'LUPTA.IN'); reset(Intrare); readln(Intrare, readln(Intr are, m, n); { formam cadrul de zerouri al campului de joc } for i:=0 to m+1 do A[i, 0]:=0; { marginea stanga } for j:=0 to n+1 do A[0, j]:=0; { marginea de sus } for j:=0 to n+1 do A[m+1, j]:=0; { marginea de jos } for i:=0 to m+1 do A[i, n+1]:=0; { marginea dreapta } { citim patratelele din fisierul de intrare } for i:=1 to m do   begin  for j:=1 to n do  read(Intrare, A[i, j]); readln(Intrare); end  ; { for } close(Intrare); end  ; { Citeste }  procedure Scrie; var Iesire : text;  begin 

assign(Iesire, 'LUPTA.OUT'); rewrite(Iesire); writeln(Iesire, t1, ' ', t2 , ' ', t3); close(Iesire); end  ; { Scrie }  procedure Corabie(x, y : integer);

{ Exploreaza patratelele unei corabii }

var i : integer;  begin  if (A[x, y] 0) then 

 

20

 

 begin 

{ patratelul apartine corabiei } if (A[x,y]=1) then k1:=k1+1 else k2:=k2+1;

A[x, y]:=0; { analizam patratelele vecine } for i:=1 to 4 do  Corabie(x+dx[i], y+dy[i]); ; { if } end  end  ; { Corabie }  procedure NumaraCorabiile; NumaraCorabiile;

{ Numara corabiile de pe campul de joc } var i, j : integer;  begin 

t1:=0; t2:=0; t3:=0; for i:=1 to m do   begin  for j:=1 to n do  if A[i,j]0 then   begin  k1:=0; k2:=0; Corabie(i, j); if (k2=0) then t1:=t1+1 else  if (k1=0) then t2:=t2+1 else t3:=t3+1; end  ; { if } ; { for } end  end  ; { NumaraCorabiile NumaraCorabiile }  begin 

Citeste; NumaraCorabiile; Scrie; end  .

Din analiza textului procedurii NumaraCorabiile  se observă că apelul procedurii Corabie va fi efectuat de cel mult mn  ori. În cel mai rău caz, în procedura Corabie   vor fi  parcurse toate cel mn pătrăţele  pătrăţele. Prin urmare, numărul de operaţii cerut d e program va fi de ordinul (mn) 2 . Evident,  pentru m, n   25 , număr ul ul respectiv de operaţii va fi cu mult mai mic decât capacitatea de  prelucrare a calculatoarelor calculatoarelor moderne moderne..

 

21

 

Clasele 10

Denumirea problemei

Vâslaşii 

Iepuraşii 

Segmente

Şarpele 

Descompuneri

Radioul

Total

 

Numărul de puncte alocat problemei

12

Denumirea fişierului de intrare

Denumirea fişierului de ieşire 

100

VASLASI.PAS VASLASI.C VASLASI.CPP

VASLASI.IN

VASLASI.OUT

100

IEPURE.PAS IEPURE.C IEPURE.CPP

IEPURE.IN

IEPURE.OUT

100

SEGMENT.PAS SEGMENT.C SEGMENT.CPP

SEGMENT.IN

SEGMENT.OUT

100

SARPE.PAS SARPE.C SARPE.CPP

SARPE.IN

SARPE.OUT

100

DESC.PAS DESC.C DESC.CPP

DESC.IN

DESC.OUT

100

RADIO.PAS RADIO.C RADIO.CPP

RADIO.IN

RADIO.OUT

600

Denumirea

fişierului sursă 

-

22

-

-

 

Vâslaşii   Vâslaşii

În sfârşit, în anul 2009, informaticienii au  putut rezolva problema, care de mult titimp mp îi chinuia pe vâslaşii-sportivi. Se consideră o barcă lungă cu vâsle, în care sunt amplasaţi n  vâslaşi. Fiecare vâslaş are câte o vâslă, cu care el vâsleşte doar pe o singură parte a bărcii   −  partea stânga sau partea dreapta. Evident, vâslind, fiecare sportiv comunică bărcii o accelerare nu doar strict în direcţia mişcării  bărcii, bărcii, dar şi perpendicular pe ea. Apare întrebarea, cum trebuie să orientăm v âslele sportivilor din barcă, pentru ca ea să nu aibă oscilaţii, perpendiculare pe direcţia mişcării.

Din punct de vedere matematic, soluţia problemei se reduce la amplasarea semnelor „+”  (vâsla pe partea stângă) şi „-” (vâsla pe partea dreaptă) în faţa numerelor de vâslaşi 1, 2, 3, ... n  în aşa mod, încât suma obţinută să fie egală cu zero.  De exemplu, pentru n  4 , avem  1  2  3  4  0 . Prin urmare, vâslaşii 1 şi 4 vor vâsli pe partea stânga, iar vâslaşii 2 şi 3 − pe  partea dreapta dreapta a bărcii. Elaboraţi un program care amplasează semnele „+”, „ -”  în faţa numerelor din şirul 1, 2, 3, ..., n în aşa mod, încât suma obţinută să fie egală cu zero.  Sarcină.

Date de intrare. Fişierul text VASLASI.IN conţine pe o singură linie numărul

întreg n.

Date de ieşire.  Fişierul

text VASLASI.OUT  va conţine pe o singură linie un şir din n  caractere, format din semnele +, -. Dacă problema are mai multe soluţii, în fişierul de ieşire se va scrie doar una, oricare din ele. Dacă problema nu are soluţii, în fişierul de ieşire se va scrie un şir din n caractere, format din semnul ?. Exemplul 1. VASLASI.IN 4

VASLASI.OUT +--+

Exemplul 2. VASLASI.IN 5

VASLASI.OUT ?????

Timpul de execuţie nu va depăşi 2,0 secunde. Programul va folosi cel mult 32 Megaocteţi de memorie operativă. Fişierul sursă va avea denumirea VASLASI.PAS, VASLASI.C sau VASLASI.CPP. Restricţii. 2   n  21 .

Rezolvare

Problema poate fi rezolvată prin metoda trierii, examinând toate variantele posibile de amplasare a semnelor „+”, „-” în faţa numerelor din şirul 1, 2, 3, ..., n. i  a a genera variantele de iamplasare, vom folosistângă numărul binarşiOrientare căruiaPentru   ia valoarea 0 daca vâslaşul   are vâsla pe partea a bărcii valoarea, 1cifra în caz contrar.

 

23

 

Iniţial, număr ul ul binar Orientare are valoarea 00...000. În continuare, la fiecare iteraţie vom aduna la acest număr valoarea binară “1”, operaţie cunoscută în informatică ca incrementare. În programul ce urmează, numărul binar Orientare este reprezentat prin tabloul cu acelaşi nume, iar operaţia de incrementare se realizează r ealizează cu ajutorul procedurii Increment.   Vaslasii;  Vaslasii; Program  { Clasele 10-12 } const nmax=21; var n : integer; { numarul de vaslasi } S : string; { raspunsul } Orientare : array [1..nmax] of integer; {orientarea vaslelor }

Transport : integer;  procedure Citeste;

{ citirea datelor de intrare } var Intrare : text;  begin  assign(Intrare, 'VASLASI.IN'); reset(Intrare); readln(Intrare, n); close(Intrare); end  ; { Citeste }  procedure Scrie;

{ srierea datelor de iesire } var Iesire : text;  begin  assign(Iesire, 'VASLASI.OUT'); rewrite(Iesire); writeln(Iesire, S); close(iesire); end  ; { Scrie }  procedure Increment;

{ incrementarea numarului binar Orientare } var i : integer;  begin 

Transport:=1; for i:=1 to n do   begin  Orientare[i]:=Orientare[i]+Transport; if Orientare[i]n;

Implementând această secvenţă cu ajutorul declaraţiilor de variabile  var S, F1, F2, F3 : integer;

 

26

 

 prin experimente de calcul ne convingem, că începând cu  n  20 , la calcularea valorilor variabilelor în studiu au loc erori de depăşire.  Cei care cunosc alte tipuri de date, ar putea să încerce declaraţia  var S, F1, F2, F3 : longint;

din Turbo Pascal sau tipurile de date Longword, Int64, Qword din Object Pascal. Însă şi în astfel de cazuri, pentru valorile mari ale lui n apar erori de depăşire.  Pentru a evita erorile de depăşire, vom reprezenta numerele mari S, F1, F2  şi  F3  prin tablouri, formate din K  elemente. Fiecare element al tabloului memorează câte o cifra a numărului respectiv. 1 



... 



 K  

Dacă în procesul adunării a două numere mari  A  şi  B, formate din câte  K   cifre, transportul calculat în cazul însumării cifrelor A[1], B[1] şi transportului din rangul precedent diferă de zero, are loc o depăşire şi programul va semnaliza o eroare. În programul ce urmează, pentru a realiza experimentul de calcul, în componenţa  procedurii Adunare a fost inclusă următoarea secvenţă de instrucţiuni:  if Transport=1 then   begin 

writeln('Depasire'); readln; end  ;

Evident, în condiţiile problemei, această secvenţă de instrucţiuni nu va fi executată nici o dată numai atunci, când valoarea lui K  va fi stabilită suficient de mare. Această valoare  poate fi determinată cu ajutorul experimentelor de calcul, atribuindu-i lui n  valoarea limită 300 0 , aşa cum este indicat în restricţiile problemei.  n  30 Program    Iepurasii;  Iepurasii;

{ Clasele 10-12 } const K = 70; { numarul de cifre ale numerelor foarte mari } type Cifra = 0..9; Numar = array[1..K] of Cifra; var n : integer; S : Numar;  procedure Citeste;

{ Citeste numarul n din fisierul de intrare } var Intrare : text;  begin 

assign(Intrare, 'IEPURE.IN'); reset(Intrare); readln(Intrare, n); close(Intrare); end  ; { Citeste }  procedure Scrie;

{ Scrie suma S in fisierul de iesire } var Iesire : text; j : integer;

 

27

 

 begin 

assign(Iesire, 'IEPURE.OUT'); rewrite(Iesire); j:=1;  while S[j]=0 do j:=j+1;  while j b.x then exit(1); 

{a.x = b.x}  if a.y < b.y then exit(-1);  if a.y > b.y then exit(1); 

exit(0);  ; { ComparaPuncte ComparaPuncte }   end   procedure Qsort(var data : TPuncte; a, b : longint );

{ Sortarea rapida a subsirul a..b al sirului de puncte data }  

var left, right : longint; 

aux, pivot : TPunct;  

 begin 

pivot := data[(a + b) div 2];  left := a;  right := b;   while left 0 do right := right - 1;    while ComparaPuncte(data[ if left a then qsort(data, a, right); { sortam subsirul STANGA }   if b > left then qsort(data, left, b); { sortam subsirul DREAPTA }  end  ; { Qsort }  var i: longint; 

{ Nod - elementul de baza al Rooted Tree Forest }   type TNod = record   

tata: longint;  sz: longint;  end  ;

{ setul de arbori inversati: Rooted Tree Forest }   var retele: array[1.. 2 * MAXN] of TNod;  function  AflaComponenta(a : longint): longint;

{ Returneaza identificatorul retelei in care se afla elementul a }  var pozitie, z, nextPos : longint;  

 begin 

z := 1;  pozitie := a; 

 while  retele[pozitie].tata a > retelei 0 do pozitie := retele[pozitie].tata;  z :=  retele[pozitie].tat pozitie; {salvam id-ul in z} 

pozitie := a;   while pozitie z do  { parcurgem arborele "de jos in sus" }  

 begin 

nextPos := retele[pozitie].tata;  retele[pozitie].tata := z;  pozitie := nextPos;  end  ;  AflaComponenta := z;  end  ; { AflaComponenta AflaComponenta }    procedure Uneste(a, b : longint);

{ Proceseaza informatia ca a si b sunt in aceeasi componenta }   var componentaA, componentaB : longint; 

 begin 

componentaA := AflaComponenta(a);  componentaB := AflaComponenta(b);  if componentaA = componentaB then exit; { nu e nimic de facut, componentele sunt deja unite }   if retele[componentaA].sz < retele[componentaB].sz then   begin  { componenta A e mai mica decat B, deci punem pe A sub B }   retele[componentaA].tata := componentaB;  inc(retele[componentaB].sz, retele[componentaA].sz); 

end    else   begin {invers; componenta B e mai mica decat A, deci punem pe B sub A}  

retele[componentaB].tata := componentaA;  inc(retele[componentaA].sz, retele[componentaB].sz);  end  ;  end  ; { Uneste }  var capDeRetea : array[1..MAXN] of boolean  boolean;  rezultat, componenta : longint;  f : text; 

 

33

 

 begin { programul principal }  

{ Etapa I }  Citeste;   Qsort(capete, 1, 2 * n);   { Etapa II }  for i := 1 to 2 * n do  { initializam setul de arbori: fiecare segment e singur, } { neconectat cu nimeni }    begin 

retele[i].tata := -1; { nu are tata, deci e singur }   retele[i].sz := 1; { un singur element in set - segmentul insusi }  

end;  for i := 2 to 2 * n do 

{ procesam informatia despre conexiunile dintre segmente }  

 begin  if ComparaPuncte(capete[i-1], capete[i]) = 0 then 

Uneste(capete[i-1].segment, capete[i].segment); 

;  end  fillchar(capDeRetea, sizeof(capDeRetea), false);  for i := 1 to n do   begin 

componenta := AflaComponenta(i);  capDeRetea[componenta] := true; 

end; 

rezultat := 0; 

for i := 1 to n do  if capDeRetea[i] then inc(rezultat);  

assign(f, 'segmente.out');  rewrite(f);   writeln(f, rezultat);  close(f);   .  end 

Din analiza operaţiilor   efectuate în cadrul Etapelor I şi II rezultă, că complexitatea    300 300 000 000 . temporală a programului este O(n log   n) . Conform restricţiilor problemei, 3   n Prin urmare, numărul de operaţii va fi de ordinul 10 7 , mărime comparabilă cu capacitatea de  prelucrare a calculatoarelor personale din laboratorul de informatică.  Menţionăm, că numerele reale ce reprezintă coordonatele extremităţilor de segmente conţin cel mult trei cifre după virgulă. P utem folosi acest fapt pentru a trece de la coordonatele reale laîncele întregi,Citeste care, evident, sunt reale, procesate mai rapid. Anume, sunt din aceste considerente, procedura , numerele cititemult din fişierul de intrare înmulţite cu 1 000  şi transformate în numere întregi.  

 

34

 

Şarpele   Şarpele

Intr-o versiune simplificată a  binecunoscu  binecunoscutul tul joc clasic de calculator Snake (Şarpele), un şarpe trebuie sa mănânce toate merele dintr-o livada. Regulile acestui joc sunt foarte simple: 1.  În livada sunt împrăştiate  pe pământ n  mere, poziţia fiecărui mar i  fiind definită prin coordonatele carteziene întregi ( x  xi, yi). 2.  Originea sistemului de coordonate se află în colţul stânga -jos al livezii. Axa de coordonate 0X este orientată de la stânga la dreapta, iar axa 0Y –  de  de jos în sus. 3.  La începutul jocului, în livada intra un şarpe, care are drept scop să mănânce toate merele din livada. 4.  Poziţia curentă a şarpelui este definită  prin coordonatele carteziene întregi (  xx s, y s). 5.  Poziţia iniţială a şarpelui este (1, 1). 6.  Repertoriul de comenzi ale şarpelui include instrucţiunile de deplasare SUS, JOS, STÂNGA, DREAPTA. Execuţia unei astfel de comenzi constă în deplasarea şarpelui în direcţia respectivă exact cu o unitate de lungime.  7.  Atunci când coordonatele şarpelui devin egale cu coordonatele unui măr, şarpele  mănâncă mărul respectiv. Scopul jocului constă în deplasarea şarpelui în aşa mod, încât toate merele să fie mâncate, iar drumul parcurs de şarpe să fie cât mai scurt. Dorin este împătimit de jocul Snake. El îl joaca de multă   vreme şi a stabilit mai multe recorduri. Din  păcate, pe consola lui de jocuri s-a defectat butonul comenzii JOS. În consecinţă, şarpele, indiferent de  poziţia în care se afla, poate executa doar comenzile SUS, STÂNGA, DREAPTA. Dorin insă nu s-a descurajat şi consideră  această  defecţiune  o nouă provocare. Întrucât Dorin a devenit foarte priceput la acest joc, el doreşte  să stabilească un nou record. El nu se îndoieşte deloc de abilităţile lui de a direcţiona şarpele pe orice drum posibil, dar vrea să ştie  lungimea celui mai scurt drum, deplasând deplasându-se u-se pe care şarpele şarpele ar mânca toate merele. Sarcină. Elaboraţi un program, care, cunoscând coordonatele celor n mere, calculează  lungimea L a celui mai scurt drum, deplasându-se pe care şarpele şarpele ar mânca toate merele. Date de intrare.

Fişierul  text

SARPE.IN  conţine  pe

prima linie numărul  întreg n.

 xi,  yi, separate Fiecare din. Linia următoarele  linii ale de fişierului intrare conţine numerele i.  prin spaţiu i  1  a  n fişierului intrare  de conţine  coordonatele măruluiîntregi Date de ieşire. Fişierul text SARPE.OUT va conţine pe singură linie numărul întreg L. Exemplu. SARPE.IN 5 2 2 5 3 7 3 8 4 4 6

SARPE.OUT 16

   10 000 000 ; 1   xi ,  yi  10 000 Restricţii. 1   n 000 . Timpul de

execuţie  nu va depăşi  0,1

secunde. Programul va folosi cel mult 32 Megaocteţi  de memorie operativă.  Fişierul  sursă va avea denumirea SARPE.PAS, SARPE.C sau SARPE.CPP.

 

35

 

Rezolvare

Pentru a reduce numărul de cazuri particulare, vom include în mulţimea merelor încă unul, aflat pe poziţia (1, 1).  În continuare, introducem în studiu un set de m  linii drepte, paralele cu axa de coordonate X , pe fiecare din care se află cel puţin câte un măr. Evident, fiecare din aceste linii  poate fi definită univoc prin coordonata  y p,  y p   { y1 ,   y 2 ,   ..., y m } . Întrucît avem garantat un măr pe poziţia (1, 1), rezultă că  y1    1 . Prin  x  vom nota abcisa celui mai din stânga, iar prin  x  − abcisa celui mai din dreapta măr de pe linia y p. Deoarece repertoriul de comenzi ale şarpelui nu mai conţine comanda JOS, odată ajuns pe o linie cu mere, şarpele trebuie să mănînce toate merele de pe această linie  şi abia apoi să se deplaseze în sus.  În aceste condiţii, lungimea celui mai scurt drum poate fi calculată prin metoda  programării dinamice, pornind de la linia cea de mai jos şi terminând cu linia cea de mai 



 p

 p

sus. Pentru fiecare linie, şarpele poate termina  parcurgerea ei în una din două poziţii: la capătul stâng sau la capătul drept al liniei. Pentru a formaliza acest proces, introducem în studiu următoarele funcţii:   L( y p )   − lungimea celui mai scurt drum, parcurgându -l pe care şarpele mănâncă toate merele de pe liniile de mai jos şi de pe linia curentă, rămânând în poziţia celui mai din stânga măr de pe linia curentă y   y p;  L( y p )   − lungimea celui mai scurt drum, parcurgându-l pe care şarpele mănâncă toate merele de pe liniile de mai jos şi de pe linia curentă, rămânând în poziţia celui mai din dreapta măr de pe linia curentă y p. Valorile acestor funcţii pot fi calculate după următoarele formule recurente:     p   L(1)  2 * x   x p  1 ;  L(1)    x p  1 ;

 L( y p )  ( y p   y p 1 )  min[ L( y p 1 ) |  x p     x p 1 |,  L  ( y p 1 ) |  x p   x p 1 |]  ( x p  xp ) ;  L( y p )  ( y p   y p 1 )  min[ L( y p 1 ) |  x p   1    x p |,  L  ( y p 1 ) |  x p 1   x p |]  ( x p  xp ) .

Evident, lungimea celui mai scurt drum va fi:  L  min[ L  ( ym ),  L   ( ym )] .

unde ym este coordonata celei mai de sus linii. Program    Sarpele;  Sarpele; { Clasele 10-12 } const MAXPOZ = 10000; n:longint; var 

px, py, num, minx, maxx, costMinX, costMaxX :array[1..MAXPOZ] of longint;

 

36

 

costMin:longint;  procedure Citeste; fin:text; var 

i:longint;  begin

assign(Intrare, 'SARPE.IN'); reset(Intrare); readln(Intrare, n); for i := 1 to n do  readln(Intrare, px[i], py[i]); close(Intrare); end  ; { Citeste }  procedure GruparePeLinii; GruparePeLinii; var i,x,y:longint;  begin

num[1] := 1; minx[1] := 1; maxx[1] := 1; for i := 1 to n do   begin  x := px[i]; y := py[i]; inc(num[y]); if (num[y] = 1) then   begin  minx[y] := x; maxx[y] := x;   end  else   begin  if (x < minx[y]) then minx[y] := x; if (maxx[y] < x) then maxx[y] := x; end  ; end  ; end  ; { GruparePeLinii GruparePeLinii } function  min(a, b: longint):longint;  begin if (a < b) then min := a else min := b; end  ;  procedure  CalculCosturiMin; var i, prevY, y, dy :longint; var costMinInMin, costMaxInMin, costMinInMax, costMaxInMax: longint;  begin

costMinX[1] := 2 * maxx[1] - minx[1] - 1; costMaxX[1] := maxx[1] - 1; prevY := 1; for i := 2 to MAXPOZ do  if (num[i] > 0) then   begin  y := i; dy := y - prevY; costMinInMin := costMinX[prevY] + abs(maxx[y]-minx[prevY]); costMaxInMin := costMaxX[prevY] + abs(maxx[y]-maxx[prevY]); costMinInMax := costMinX[prevY] + abs(minx[y]-minx[prevY]); costMaxInMax := costMaxX[prevY] + abs(minx[y]-maxx[prevY]); costMinX[y] := min(costMinInMin, costMaxInMin) + dy + (maxx[y] - minx[y]); costMaxX[y] := min(costMinInMax, costMaxInMax)

 

37

 

+ dy + (maxx[y] - minx[y]); prevY := y; end  ; costMin := min(costMinX[prevY], costMaxX[prevY]); end  ; { CalculCosturiMin CalculCosturiMin }  procedure Scrie; var fout: text;  begin

assign(Iesire, 'SARPE.OUT'); rewrite(Iesire); writeln(Iesire, costMin); close(Iesire); end  ;  begin

Citeste; GruparePeLinii; CalculCosturiMin; Scrie; end  .

Dina analiza textului procedurii GruparePeLinii   se observă că  pentru determinarea coordonatelor  y p,  x   şi  x   este suficientă o singură parcurgere liniară a datelor de intrare, deci complexitatea acestei proceduri este O(n) . În procedura CalculCosturiMin, valorile 

 p



 p

 L( y p ) şi  L( y p )  se calculează de m ori. Întrucât m  n , complexitatea acestei proceduri va fi, de asemenea, O(n) . Conform restricţiilor din enunţul problemei, n  10 000 000 . Prin urmare,

numărul de operaţii cerut de algoritm va fi de ordinul 10 4, mărime cu mult mai mică decât capacitatea de prelucrare a calculatoarelor din laboratorul de informatică.  

 

38

 

Descompuneri

 Numim k-descompunere  a numărului natural nenul  N   reprezentarea acestuia ca o sumă de exact k   numere naturale nenule, scrise în ordine strict crescă toare. În general, în dependenţă de valorile  N   şi k , numărul  N   poate poate să nu aibă nici una, să aibă doar una sau să aibă mai multe k-descompuneri.  Exemple:

 

99 = = 49 +este o 1-odescompunere a numărului 9;  9;  5 este 2 -descompuner 2descompunere e a numărului descompunere re a numărului 9;    9 = 3 + 6 este o altă 2-descompune   9 = 1 + 3 + 5 este o 3-descompunere a numărului 9;   9 = 1 + 2 + 6 este o altă 3-descompune descompunere re a numărului 9. 

  

Contraexemple:  

9 = 3 + 1 + 5 nu este o 3-descompunere a numărului 9, întrucât în scrierea respectivă termenii 3 şi 1 nu apar în ordine crescătoare;   9 = 1 + 1 + 7 nu este o 3-descompunere a numărului 9, întrucât în scrierea respectivă termenii 1 şi 1 nu apar în ordine strict crescătoare;   9 = 0 + 9 nu este o 2-descompunere a numărului 9, întrucât în scrierea respectivă apare numărul 0.  Sarcină. Elaboraţi un program, care, cunoscând numerele naturale  N   şi k , calculează  numărul T  de  de k -descompuneri -descompuneri posibile ale lui  N . Deoarece numărul  T  poate   poate fi foarte mare, în fişierul de ieşire se va scrie doar restul împărţirii lui T  la  la 1000000000 (un miliard). Date de intrare.

Fişierul text DESC.IN  conţine pe singura linie numerele întregi  N   şi k ,

separate prin spaţiu.  Date de ieşire. Fişierul text DESC.OUT   va numărului întreg T  la  la 1000000000 (un miliard).

conţine pe singură linie restul împărţirii

Exemple: 1)

2) 3)

DESC.IN

DESC.OUT

12 3

7

DESC.IN

DESC.OUT

90 1

1

DESC.IN

DESC.OUT

300 9

382665027

Restricţii. 1  k    N   700 700 . Timpul de execuţie nu va depăşi 0,5 secunde. Programul va

folosi cel mult 32 Megaocteţi de memorie operativă. Fişierul sursă va avea denumirea DESC.PAS, DESC.C sau DESC.CPP. Rezolvare

Problema poate fi rezolvată prin metoda programării dinamice. În acest scop, introducem în studiu funcţia t (k ,  a, b) . Această funcţie reprezintă numărul de k -descompuneri -descompuneri ale numărului a, care au ca termen minim pe b. Evident, t (1, a,  b)  1   dacă a   b   şi t (1, a,  b)  0   în caz contrar. În general, se poate demonstra că funcţia în studiu poate fi scrisă într -o formă recurentă:   

39

 

a b

t (k , a, b) 

 t (k   1, a  b, i) . i b 1

Prin urmare, numărul T   poate fi calculat prin însumarea valorilor t (k ,  N    , j )   pentru  j  1 , 2, ...,  N  :  N 

 N   N   j

 j 1

 j 1 i   j 1

T    t (k ,  N ,  j ) 

 t (k   1,  N    j, i) .

Complexitatea temporală a unui algoritm bazat pe formula recurentă de mai sus este O(kN 3 ) . În cazul restricţiilor problemei, numărul de operaţii cerut de algorit m va fi de ordinul 10 14 , mărime cu mult mai mare decât capacitatea de prelucrare a calculatoarelor  personale din laboratorul de informatică informatică..  Pentru a reduce complexitatea temporală a algoritmului vom lua în considerare faptul că  pentru valorile lui i   a  b  funcţia t (k , a , b)  0 . În consecinţă, vom calcula doar sumele din “dreapta” indicelui respectiv. În acest caz complexitatea algoritmului va fi O( N   2  N ) , iar numărul cerut de operaţii va fi de ordinul 10 8 , mărime comparabilă cu capacitatea de  

 prelucrare a calculatoarelor calculatoarelor din labo laboratorul ratorul de informatica. Menţionăm faptul, că în procesul de efectuare a calculelor nu se cere memorarea tuturor valorilor t (k ,  a, b) , fiind suficiente doar valorile iteraţiei curente şi termenii din „dreapta”, în total circa 4 Megaocteţi de memorie operativă.  Program Descompuneri;

{ Clasele 10-12 } const MAXN = 1000; const MODULO = 1000 * 1000 * 1000; type TMatrice = array[1..MAXN, 1..MAXN] of longint; var f: text; n, m: longint; a: TMatrice; sumaLaDreapta: TMatrice; i, j, k: longint; res: longint; existaElementNenul: boolean;  procedure scrieRezultat(q: scrieRezultat(q: longint); { Scrie rezultatul în fişierul de ieşire şi termină programul }   var f: text;  begin 

assign(f, 'DESC.OUT'); rewrite(f); writeln(f, res); close(f); halt(0); end  ; { Scrie }  begin 

fillchar(a, fillchar(a , sizeof(a), 0); fillchar(sumaLaDreapta, sizeof(sumaLaDreapta), 0); assign(f, 'DESC.IN'); reset(f); readln(f, n, m);

 

40

 

close(f); { construim cazul de baza: t[1, x, y] } for j := 1 to n do  for k := 1 to n do   begin  if (j = k) then a[j, k] := 1 else a[j, k] := 0; end  ; { partea principală: calcularea calcularea t[k, x, y] pentru k > 1 }   for i := 2 to m do   begin  { calculăm sumaLaDreapta }  for j := 1 to n do  for k := j downto  1 do 

sumaLaDreapta[j, k] := (a[j, k] + sumaLaDreapta[j, k + 1])  mod    MODULO; { calculăm t[i, j, k], care e memorat în a[j, k] }  existaElementNenul := false; {detector de valori nenule in a}   for j := 1 to n do  for k := 1 to n do   begin 

a[j, k] := sumaLaDreapta[j - k, k + 1]; if a[j, k] > 0 then existaElementNenul := true; end  ; { in cazul in care existaElementNenul e false, toate elementele lui a } { calculate ulterior vor fi nule. Prin urmare, terminam calculele } existaElementNenul then  scrieRezultat(0); if not existaElementNenul end  ; { calculam raspunsul } res := 0; for k := 1 to n do   begin  inc(res, a[n, k]); res := res mod   MODULO;  MODULO; end;  scrieRezultat(res); end  .

 

41

 

Radioul

Postul de radio “Bitul Liber” are la dispoziţie n  emiţătoare, amplasate în n  localităţi distincte. Poziţia fiecărui emiţător i, i  1,  2, 3, ..., n , este definită prin coordonatele carteziene întregi ( xi ,  yi ) . Fiecare emiţător are una şi aceiaşi putere de emisie  R. Evident, cu cât emiţătorul este mai puternic, cu atât este mai mare şi distanţa la care se propagă undele emise de el. În scopuri didactice, se consideră, că undele unui emiţător de puterea  R  se propaga până la distanţa de R kilometri. Deşi emiţătoarele au una şi aceiaşi putere   R, fiecare din ele poate fi acordat în mod individual să emită pe una din frecvenţ ele disponibile  frecvenţa F 1 sau frecvenţa F 2. Este cunoscut faptul, că undele radio interferează şi, în consecinţă, dacă un receptor este supus acţiunii concomitente concomitente a două unde de aceiaşi frecvenţă, frecvenţă, calitatea recepţiei scade brus brusc. c. În general, conform regulilor de radiodifuziune, calitatea recepţiei se consideră bună doar atunci, când nu există nici un sector de arie nenulă, pe care ajung unde radio, emise de două emiţătoare ce au aceiaşi frecvenţă de emisie.   Este evident faptul, că pentru a extinde aria pe care pot fi recepţionate emisiunile  postului de radio “Bitul Liber”, puterea de emisie  R  trebuie mărită. Concomitent, frecvenţele de emisie  F 1,  F 2  pentru fiecare din emiţătoare trebuie alese în aşa mod, încât să se asigure calitatea recepţiei emisiunilor respective. Sarcină . Scrieţi un program, care, cunoscând coordonatele calculeazăa  R, ce mai  puterea ma ximală de emisie permite încă alegerea pentruemiţătoarelor, fiecare din emiţătoare unor astfel de frecvenţe, încât se asigură calitatea recepţiei. r ecepţiei.  Date de intrare. Fişierul text RADIO.IN  conţine pe prima linie numărul întreg n. Fiecare din următoarele n linii ale fişierului de intrare conţine numerele întregi   xxi,  yi, separate  prin spaţiu. Linia i  1  a fişierului de intrare conţine coordonatele emiţătorului i. Date de ieşire. Fişierul text RADIO.OUT  va conţine  pe pe prima linie numărul real  R, scris -8 cu o precizie nu mai mică de 10 . Linia a doua a fişierului de ieşire va conţine n numere întregi, separate prin spaţiu. Numărul care apare pe locul i  de pe această linie va fi egal cu 1, dacă emiţătorul i  trebuie să emită pe frecvenţa  F 1, şi egal cu 2, dacă emiţătorul respectiv trebuie să emită pe frecvenţa  F 2. Dacă problema admite mai multe soluţii, în fişierul de ieşire se va scrie doar una din ele. Exemplu. RADIO.IN 4 0 0 0 1 1 0 1 1

RADIO.OUT 0.70710678118654752 1 2 2 1

Timpul de execuţie nu va depăşi 2,0 secunde. Programul va folosi cel mult 64 Megaocteţi de memorie operativă Fişierul sursă va avea denumirea RADIO.PAS, RADIO.C sau RADIO.CPP.    1 200 200 ;  10 4   x  ,  yi  10 4 . Restricţii. 3   n

Rezolvare

Din enunţul problemei rezultă că puterea maximală nu poate depăşi jumătate din distanţa dintre emiţătoarele aflate la cea mai mare distanţă unul de altul. Prin urmare, valoarea

 

42

 

concretă a lui  R trebuie căutată în intervalul [0,  Lmax ] , unde  Lmax  poate fi calculat conform unor formule evidente:  xmin   min( x1  ,  x2 , ...,  xn )

;

 ymin   min(  y1  ,  y2 , ...,  yn )

;

 xmax   max( x1  ,  x2 , ...,  xn )

;

 ymax   max( y1  ,  y2 , ...,  yn ) .  Lmax 

( xmax   xmin ) 2   ( y max   y min ) 2  

2

 1.

Presupunem, că avem la dispoziţie o funcţie Test ( R) , care ia valoarea 1, dacă pentru  puterea de emisie  R  putem stabili frecvenţele emiţătoarelor în aşa mod, încât să garantăm calitatea recepţiei, şi 0 în caz contrar. Evident, având o astfel de funcţie, putem calcula puterea maximală prin metoda înjumătăţirii, pornind de la intervalul iniţial [0,  Lmax ]  şi  R    Lmax / 2 . Pentru a construi funcţia Test ( R) , reunim cu câte o linie emi ţătoarele, distanţa dintre care este strict mai mică de 2 R . Evident, oricare două emiţătoare, ce sunt reunite printr -o -o astfel de linie, trebuie să aibă frecvenţe de emisie diferite. În continuare, vom încerca să partiţionăm  mulţimea emiţătoarelor în două submulţimi, notate prin  A   şi B . În cadrul fiecărei submulţimi, emiţătoarele respective nu trebuie să fie reunite între ele. Dacă acest lucru ne reuşeşte, funcţia Test ( R)   va lua valoarea 1. În caz contrar, adică a rămas cel puţin un emiţător, ce nu po ate fi incluse nici în submulţimea A , nici în submulţimea B , funcţia Test ( R)  va lua valoarea 0.

Test ( R )  1  

Test ( R )  0  

Formarea submulţimilor A  şi B  poate  poate fi simulată prin „vopsirea” „vopsirea” fiecă fiecărui rui emiţător în una din cele două culori: albă sau neagră.  Iniţial, vopsim un emiţător arbitrar în culoare albă sau,  prin alte cuvinte, îl includem în submulţimea A . În continuare, determinăm toate emiţătoarele, reunite cu emiţătorul proaspăt vopsit, şi le vopsim în culoarea neagră sau, prin alte cuvinte, le includem în submulţimea B . În general, la fiecare pas al algoritmului, ce încearcă vopsirea Greedy, vecinilor emiţătorului curent în culoarea „opusă” complexitatea unui astfel de algoritm este O (n  2 ) . . În cazul tehnicii de programare

 

43

 

Evident, după determinarea valorii maximale R, pentru care funcţia Test ( R)  mai ea încă valoarea 1, tuturor emiţătoarelor din mulţimea A   li se atribuie una din frecvenţe, de exemplu,  F 1, iar celor din submulţimea B   cealaltă frecvenţă, de exemplu, frecvenţa F 2. Program    Radio;  Radio;

{ Clasele 10-12 } var n : Integer; var x, y :  Array[1..1200] of LongInt; var Freq : Array [1..1200] of Byte;

{ Frecventa asociata fiecarui emitator radio } var f : Text;

i, j : Integer; Left, Right, Med : Longint; MaxSQDist : Longint; function  SQDist(i,j:Integer) : LongInt;

{ Intoarce patratul distantei intre emitatoarele i si j }  begin  SQDist := (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]); end  ; function  Test(R_SQ_4: Longint) : boolean;

{parametrul este 4*R*R} { verifica daca cu raza de emisie R se poate atribui }

{ frecvente emitatoarelor } var List : Array [1..1200] of Integer; var ListSize : Integer; { numarul de noduri in lista } var i, j, t,curent : Integer;  begin  FillByte(Freq, n, 0); for i := 1 to n do   begin  if Freq[i]0 then continue; { frecventa pentru emitatorul i a fost } { aleasa deja } Freq[i] := 1; {alege frecventa 1 pentru emitatorul i} { Initializeaza lista cu un singur element : i } List[1] := i; ListSize := 1; j:=1;  begin   while j Left+1 do   begin  Med := (Left + Right) div 2; if Test(Med) then Left:=Med else Right:=Med; ; end  { mai apeleaza inca o data pentru a seta Freq[...] } Test(Left); { Scrie raspunsul } Assign(f,'RADIO.OUT'); Rewrite(f); writeln(f,(sqrt(Extended(Left))/2):0:18); for i:=1 to n do Write(f, Freq[i],' '); writeln(f); Close(f); end  .

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF