Sunteți pe pagina 1din 53

MINISTERUL EDUCAIEI AL REPUBLICII MOLDOVA

MHCTEPCTBO IIPOCBEEH PECJIK MO

Olimpiada Republican la Informatic Ediia 2013

Chiinu 2013

Olimpiada Republican la Informatic. Ediia 2013. Lucrarea conine problemele propuse la Olimpiada Republican la Informatic a elevilor, ediia 2013. Pentru fiecare problem sunt descrise algoritmul i soluia respectiv n limbajul de programare PASCAL. Materialele Olimpiadei pot fi de un real folos la studierea Informaticii att elevilor, ct i profesorilor de Informatic.

La elaborarea ediiei au contribuit: Anatol Gremalschi Ion Bolun doctor habilitat, profesor universitar, Institutul de Politici Publice. doctor habilitat, profesor universitar, Academia de Studii Economice a Moldovei. ef de direcie, Ministerul Educaiei. consultant, Ministerul Educaiei. informatician. informatician.

Iurie Mocanu Angela Priscaru Dumitru Ciubati Constantin Dolghieru

Cuprins

CLASELE 7

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

CEASUL ...........................................................................................................5 IMAGINI ...........................................................................................................8 BLOCURI DE PIATR .......................................................................................11 FORMULE .......................................................................................................15 FERESTRE ......................................................................................................17 PARCARE AUTO ..............................................................................................21 PUNCTAJUL TOTAL ACUMULAT DE FIECARE COMPETITOR ..............................26 CLASELE 10 12 ................................................................................................27

CEASUL .........................................................................................................28 IMAGINI .........................................................................................................31 BLOCURI DE PIATR .......................................................................................34 FORMULE .......................................................................................................40 FERESTRE ......................................................................................................43 PARCARE AUTO ..............................................................................................47 PUNCTAJUL TOTAL ACUMULAT DE FIECARE COMPETITOR ..............................53

Clasele 7
Denumirea problemei Ceasul Numrul de puncte alocat problemei 100

9
Denumirea fiierului de intrare
CEAS.IN

Denumirea fiierului surs


CEAS.PAS CEAS.C CEAS.CPP IMAGINI.PAS IMAGINI.C IMAGINI.CPP BLOCURI.PAS BLOCURI.C BLOCURI.CPP FORMULE.PAS FORMULE.C FORMULE.CPP FERESTRE.PAS FERESTRE.C FERESTRE.CPP PARCARE.PAS PARCARE.C PARCARE.CPP -

Denumirea fiierului de ieire


CEAS.OUT

Imagini

100

IMAGINI.IN

IMAGINI.OUT

Blocuri de piatr

100

BLOCURI.IN

BLOCURI.OUT

Formule

100

FORMULE.IN

FORMULE.OUT

Ferestre

100

FERESTRE.IN

FERESTRE.OUT

Parcare auto

100

PARCARE.IN

PARCARE.OUT

Total

600

Ceasul Ana a primit un cadou special un ceas digital, care indic timpul curent n formatul HH:MM, unde HH reprezint ora, iar MM minutele. Specificul acestui ceas const n faptul c n momentul n care timpul indicat de el reprezint un palindrom, ceasul reproduce o melodie din renumitul film In Time. Ana iubete att de mult aceast melodie, nct de fiecare dat cum se uit la ceas, imediat dorete s tie, cnd din nou va fi redat melodia respectiv. Amintim, c un ir de caractere este un palindrom, dac el se citete n acelai fel att de la stnga la dreapta, ct i de la dreapta la stnga. De exemplu, irul de caractere 12:21 este un palindrom. Sarcin. Elaborai un program, care, cunoscnd timpul curent n formatul HH:MM, determin cel mai apropiat momentul de timp n care din nou va fi redat melodia din filmul In Time. Date de intrare: Fiierul text CEAS.IN conine pe o singur linie un ir de caractere timpul curent scris n formatul HH:MM. Date de ieire: Fiierul text CEAS.OUT va conine pe o singur linie un ir de caractere cel mai apropiat moment de timp n care din nou va fi redat melodia din renumitul film In Time. Momentul de timp va fi scris n formatul HH:MM. Restricii: 00 HH < 24; 00 MM < 60. Timpul de execuie nu va depi 0,1 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea CEAS.PAS, CEAS.C sau CEAS.CPP. Exemplu 1. CEAS.IN 14:53 CEAS.OUT 15:51

Exemplu 2. CEAS.IN 23:45 CEAS.OUT 00:00

Rezolvare Din enunul problemei, rezult c melodia va fi redat n momentele de timp: 00:00, 01:10, 02:20, 03:30, 04:40, 05:50, 10:01, 11:11, 12:21, ..., 22:22, 23:32, n total, 16 valori. Prin urmare, este suficient s comparm timpul curent, citit din fiierul de intrare, cu valorile de mai sus i s o alegem pe cea potrivit.
Program Ceasul; { Clasele 07-09 } var HH, MM : array [1..16] of string; { palindromurile: ore, minute } TCH, TCM : string; { timpul curent din fisierul de intrare } TRMH, TRMM : string; { timpul de redare a melodiei } procedure Initializare;

v ar i : begin HH[1] HH[2] HH[3] HH[4] HH[5] HH[6]

integer; :='00'; :='01'; :='02'; :='03'; :='04'; :='05'; MM[1] MM[2] MM[3] MM[4] MM[5] MM[6] :='00'; :='10'; :='20'; :='30'; :='40'; :='50';

HH[7] :='10'; HH[8] :='11'; HH[9] :='12'; HH[10]:='13'; HH[11]:='14'; HH[12]:='15';

MM[7] :='01'; MM[8] :='11'; MM[9] :='21'; MM[10]:='31'; MM[11]:='41'; MM[12]:='51';

HH[13]:='20'; MM[13]:='02'; HH[14]:='21'; MM[14]:='12'; HH[15]:='22'; MM[15]:='22'; HH[16]:='23'; MM[16]:='32'; end; { Initializare } procedure Citeste; var Intrare : text; S : string; begin assign(Intrare, 'CEASUL.IN'); reset(Intrare); readln(Intrare, S); close(Intrare); TCH:=S[1]; TCH:=TCH+S[2]; TCM:=S[4]; TCM:=TCM+S[5]; end; { Citeste } procedure Calculeaza; { Calculeaza momentul redarii melodii } var i : integer; begin i:=0; repeat i:=i+1; until TCH<=HH[i]; if (TCH=HH[i]) and (TCM>=MM[i]) then i:=i+1; if i>16 then i:=1; TRMH:=HH[i]; TRMM:=MM[i]; end; { Calculeaza } procedure Scrie; var Iesire : text; begin assign(Iesire, 'CEASUL.OUT'); rewrite(Iesire); writeln(Iesire, TRMH+':'+TRMM); close(Iesire); end; { Scrie } begin Initializare; Citeste; Calculeaza; Scrie; end.

ntruct instruciunile din unicul ciclu repeat se vor executa cel mult de 16 ori, timpul de execuie al programului va fi cu mult mai mic dect o secund. Punctajul acumulat de fiecare competitor

Ceasul, 07-09
100 90 80 70

60
50

40
30

20
10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

Imagini Imaginile color (vezi desenul) pot fi codificate cu ajutorul unui tablou bidimensional cu n linii bij i m coloane B . Elementul bij indic printr-un numr natural culoarea microzonei
n m

respective, folosind n acest scop un sistem prestabilit de codificare a culorilor, de exemplu: alb (bij = 0), neagr (bij = 1), roie (bij = 2) etc. Pentru a colora imaginile editoarele grafice ofer un instrument special denumit Umple-cu-culoare, aplicarea cruia imit procesul de scurgere a vopselei din borcan n microzona curent, din ea n microzonele adiacente de aceeai culoare .a.m.d. Evident, vopseaua poate curge dintr-o microzon n alta numai atunci cnd ele au o latur comun. Sarcin. Elaborai un program pentru realizarea instrumentului Umple-cu-culoare.

Aplicarea instrumentului Umple-cu-culoare: a - imaginea iniial; b - imaginea final; c - codificarea culorilor

Date de intrare. Fiierul text IMAGINI.IN conine pe prima linie numerele naturale n, m separate prin spaiu. Fiecare din urmtoarele n linii conine cte m numere separate prin spaiu. Linia i +1 a fiierului de intrare conine numerele bi1, bi2, ..., bim ale imaginii iniiale. Ultima linie a fiierului conine trei numere naturale p, q, k separate prin spaiu. Numerele p, q indic coordonatele zonei asupra creia trebuie aplicat instrumentul Umple-cu-culoare, iar numrul k indic codul culorii din borcan. Date de ieire. Fiierul text IMAGINI.OUT va conine pe fiecare din cele n linii cte m numere separate prin spaiu. Linia i a fiierului de ieire conine numerele bi1, bi2, ..., bim ale imaginii finale. Restricii. 1 n, m 20, 0 bij, k 10, bij k . Timpul de execuie nu va depi 0,1 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea IMAGINI.PAS, IMAGINI.C sau IMAGINI.CPP. Exemplu. Pentru desenul de mai sus avem:
IMAGINI.IN 7 1 0 0 0 0 1 0 2 7 0 1 0 1 1 1 1 3 0 1 1 0 0 1 0 2 0 1 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 IMAGINI.OUT 1 0 0 0 0 1 0 0 2 0 1 1 1 1 0 2 2 0 0 1 0 0 2 0 0 0 1 0 2 2 2 2 0 0 0 0 0 2 0 1 0 1 1 0 0 0 1 0 1

Rezolvare Vom nota prin s culoarea microzonei asupra creia trebuie aplicat instrumentul Umple-cuculoare. Evident, s = bpq. Pentru a imita procesul de scurgere a vopselei din borcan n microzona (p, q), iar din ea n microzonele adiacente de aceeai culoare .a.m.d., vom elabora o procedur recursiv, denumit Vopsea, care efectueaz urmtoarele operaii: dac culoarea microzonei curente nu coincide cu s, atunci n procedura Vopsea nu se efectueaz nici o operaie; dac culoarea microzonei curente coincide cu s, atunci microzona n studiu este vopsit n culoarea k, iar procedura Vopsea este apelat recursiv pentru cele patru microzonele adiacente: cea de sus (p-1, q), cea din dreapta (p, q+1), cea de jos (p+1, q) i cea din stnga (p, q-1). ntruct k bpq , la execuia apelurilor recursive Vopsea(p,q) microzona deja colorat nu mai este examinat a doua oar, fapt ce exclude ciclarea programului. De asemenea, pentru a evita verificrile necesare n cazul microzonelor de la margini, vom ncadra imaginea ntru-un chenar, nscriind n celulele respective ale tabloului B valoarea -1.
Program Imagini; { Clasele 07-09 } const nmax=21; mmax=21; var n, m, p, q, k, i, j : integer; B : array[0..nmax, 0..mmax] of -1..255; Finput, Foutput : text; procedure UmpleCuCuloare(p, q, k : integer); var i, j, s : integer; { s - culoarea initiala a microzonei (i, j) } procedure Vopsea(p, q : integer); { Simulam scurgerea vopselei } begin if B[p, q]=s then begin { vopsim microzona (p, q) } B[p, q]:=k; { vopsim microzona de sus } Vopsea(p-1, q); { vopsim microzona din dreapta } Vopsea(p, q+1); { vopsim microzona de jos } Vopsea(p+1, q); { vopsim microzona din stinga } Vopsea(p, q-1); end; { then } end; { Vopsea } begin { memoram in s culoarea microzonei (p, q) } s:=B[p, q]; { bordam tabloul B cu -1 } for i:=0 to n+1 do begin B[i, 0]:=-1; B[i, m+1]:=-1; end; for j:=0 to m+1 do begin B[0, j]:=-1; B[n+1, j]:=-1; end; Vopsea(p, q); end; { UmpleCuCuloare } begin assign(Finput, 'IMAGINI.IN'); assign(Foutput, 'IMAGINI.OUT');

reset(Finput); rewrite(Foutput); readln(Finput, n, m); for i:=1 to n do begin for j:=1 to m do read(Finput, B[i, j]); readln(Finput); end; readln(Finput, p, q, k); close(Finput); UmpleCuCuloare(p, q, k); for i:=1 to n do begin for j:=1 to m do write(Foutput, B[i, j], ' '); writeln(Foutput); end; close(Foutput); end.

Evident, numrul de apeluri recursive ale procedurii Vopsea nu poate depi numrul de microzone ale imaginii. Prin urmare, timpul de execuie T n m, iar spaiul necesar de memorie n stiv Vs n m. Conform restriciilor problemei, dimensiunile imaginii n, m 20, deci timpul de execuie T <<2 s, iar necesarul de memorie Vs < 16 Koctei. Punctajul acumulat de fiecare competitor

Imagini, 07-09
100 90 80 70

60
50

40
30

20
10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

10

Blocuri de piatr InfoCity este un ora modern i foarte frumos. Oraul este n permanent extindere i a ajuns deja la marginea rului InfoRiver. Primarul oraului dorete s extind InfoCity pe cellalt mal al rului, intenionnd s construiasc n acest scop un pod. Pentru a se integra organic n arhitectura oraului, podul va avea exact doi piloni, ce vor fi construii din blocuri de piatr. Pentru construcia unui pilon sunt necesare p blocuri de piatr. Primria oraului dispune de n seturi de blocuri de piatr, numerotate prin 1, 2, 3, ..., i, ..., n. Setul i conine ai blocuri de piatr. Evident, exist mai multe variante distribuire a seturilor de blocuri de piatr ntre cei doi piloni n curs de construcie. Sarcin. Elaborai un program, care calculeaz numrul de variante posibile de distribuire a seturilor respective ntre cei doi piloni ai podului n aa mod, nct fiecruia din piloni s-i revin cel puin p blocuri de piatr. Date de intrare: Fiierul text BLOCURI.IN conine dou linii. Prima linie a fiierului de intrare conine numerele ntregi n i p, separate prin spaiu. Linia a doua a fiierului de intrare conine numerele ntregi a1, a2, ..., ai, ..., an, separate prin spaiu, unde ai reprezint numrul de blocuri de piatr din setul i. Date de ieire: Fiierul text BLOCURI.OUT va conine pe o singur linie un numr ntreg numrul de variante posibile de distribuire a seturilor de blocuri de piatr. Restricii: 1 n 14; 1 p 10000; 1 ai 109. Timpul de execuie nu va depi 1 secund. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea BLOCURI.PAS, BLOCURI.C sau BLOCURI.CPP. Exemplu 1.
BLOCURI.IN 4 6 3 1 4 6 BLOCURI.OUT 6

Explicaie. Seturile de blocuri i = 1, 2, 3, 4, pot fi distribuite dup cum urmeaz:


Varianta 1 2 3 4 5 6 Pilonul 1 1, 2, 3 1, 3 2, 4 4 1, 3 4 Pilonul 2 4 2, 4 1, 3 1, 2, 3 4 1, 3

Exemplu 2.
BLOCURI.IN 3 7 5 3 6 BLOCURI.OUT 0

Explicaie. ntruct avem doar trei seturi, pentru oricare din variantele de distribuire, unuia din piloni i va reveni doar un singur set. ntruct nici unul din seturi nu conine cel puin 7 blocuri de piatr, nu exist nici o variant de distribuire a seturilor de blocuri, ce ar corespunde enunului problemei.
11

Rezolvare Vom genera toate variante posibile de distribuire a seturilor de blocuri de piatr ntre cei doi piloni. Din variantele generate le vom contabiliza doar pe acelea n care fiecruia din cei doi piloni i revin cte cel puin p blocuri de piatr. Pentru a genera toate variante posibile de distribuire a seturilor de blocuri ntre cei doi piloni ai podului vom utiliza tabloul V[1..n], fiecare din componentele cruia poate lua valorile 0, 1, 2. Valoarea 0 a componentei V[i] indic faptul, c blocul i nu a fost alocat nici unuia din piloni, valoarea 1 c blocul i a fost alocat pilonului 1, iar valoarea 2 c blocul i a fost alocat pilonului 2. Componentele tabloului V pot fi tratate ca cifre ale unui numr natural, scris n sistemul ternar de numeraie. Evident, fiecrei valori distincte a acestui numr ternar i corespunde o variant de distribuire a seturilor de blocuri ntre cei doi piloni. Pentru a genera toate variantele posibile, iniial i atribuim lui V valoarea 0. Presupunem c V are deja o anumit valoare ternar. n continuare, mrim numrul V cu o unitate ternar .a.m.d., pn cnd ajungem la valoarea 3n 1.
Program Blocuri; { Clasele 07-09 } const nmax=15; { numarul maximal de seturi } var V : array[1..nmax] of integer; A : array[1..nmax] of longint; n : integer; p : integer; K : longint; { numarul de variante posibile } D : integer; { indicatorul de depasire la incrementarea lui V } procedure Citeste; var Intrare : text; i : integer; begin assign(Intrare, 'BLOCURI.IN'); reset(Intrare); readln(Intrare, n, p); for i:=1 to n do read(Intrare, A[i]); close(intrare); end; { Citeste } procedure Scrie; var Iesire : text; begin assign(iesire, 'BLOCURI.OUT'); rewrite(Iesire); writeln(Iesire, K); close(Iesire); end; { Scrie } procedure Initializare; { Initializeaza V in zero } var i : integer; begin for i:=1 to n do V[i]:=0; end; { initializare } procedure Incrementare; { Mareste V cu o unitate in sistemul ternar } var i : integer; begin

12

D:=1; for i:= 1 to n do begin V[i]:=V[i]+D; D:=0; if V[i]=3 then begin V[i]:=0; D:=1; end; end; end; { Incrementare } procedure Contabilizeaza; var i : integer; p1, p2 : longint; {numarul de pietre per pilon } begin p1:=0; p2:=0; for i:=1 to n do begin if V[i]=1 then p1:=p1+A[i]; if V[i]=2 then p2:=p2+A[i]; end; if (p1>=p) and (p2>=p) then K:=K+1; end; { Contabilizeaza } procedure Calculeaza; var i : integer; begin Initializare; K:=0; repeat Contabilizeaza; Incrementare; until D=1; end; { Calculeaza } begin Citeste; Calculeaza; Scrie; end.

Timpul cerut de procedura Calculeaza este proprional cu numrul de apeluri ale procedurilor Contabilizeaza i Incrementare din ciclul repeat. Evident, acest numr este egal cu 3n. Fiecare din procedurile Contabilizeaza i Incrementare conine cte un ciclu, care se va executa de cel mult n ori. Prin urmare, timpul cerut de program va fi proporional cu 3nn. Conform restriciilor problemei, n 14. Evident, pentru n = 14, timpul cerut de program va fi proporional cu 314 14 6,7 107. ntruct aceast valoare mai mic dect capacitatea de prelucrare a calculatoarelor personale, timpul de execuie nu va depi o secund.

13

Punctajul acumulat de fiecare competitor

Blocuri, 07-09
90 80 70 60 50 40 30 20 10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

14

Formule Se consider urmtoarele formule metalingvistice: Cifr :: = 0 1 2 3 4 5 6 7 8 9 Numr :: = Cifr Semn ::= + - * / Expresie :: = Numr Expresie Semn Expresie Sarcin. Scriei un program care returneaz valoarea DA dac irul de caractere S este conform definiiei unitii lexicale Expresie i NU n caz contrar. Date de intrare. Fiierul text FORMULE.IN conine pe fiecare linie cte un ir de caractere S. Date de ieire. Fiierul text FORMULE.OUT va conine pe fiecare din linii valoarea DA dac irul de caractere din linia respectiv a fiierului de intrare corespunde definiiei i NU n caz contrar. Restricii. irul nevid S conine cel mult 250 de caractere. Fiierul de intrare conine cel mult 200 de linii. Timpul de execuie nu va depi 0,2 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea FORMULE.PAS, FORMULE.C sau FORMULE.CPP. Exemplu.
FORMULE.IN 1+3014-4+629/1235-3*2 +1+3469 4509/293+1 FORMULE.OUT DA NU DA

Cifr

Rezolvare Din analiza formulelor metalingvistice se observ c irul nevid S este conform definiiei unitii lexicale Expresie atunci i numai atunci cnd se respect urmtoarele condiii: 1) n ir apar numai caracterele 0,1, ..., 9, +, -, *, /; 2) primul i ultimul caracter ale irului sunt cifre; 3) dup fiecare din caracterele +, -, *, / urmeaz cel puin o cifr. n programul ce urmeaz verificarea condiiilor respective se efectueaz cu ajutorul funciei Corespunde prin cel mult trei parcurgeri ale irului S. Evident, timpul de execuie T(n) ~ 3n, unde n este lungimea irului S. Pentru n 250 timpul de execuie T(n) << 1 s .
Program Formule; { Clasele 07-09 } var S : string; Finput, Foutput : text; function Corespunde(S : string) : string; label 1; var i, n : integer; begin

15

Corespunde:='DA'; n:=length(S); for i:=1 to n do if not (S[i] in ['0'..'9', '+', '-', '*', '/']) then begin Corespunde:='NU'; goto 1; end; if not ((S[1] in ['0'..'9'] ) and (S[n] in ['0'..'9'])) then begin Corespunde:='NU'; goto 1; end; for i:=1 to n-1 do if (S[i] in ['+', '-', '*', '/']) and not (S[i+1] in ['0'..'9']) then begin Corespunde:='NU'; goto 1; end; 1: end; { Corespunde } begin assign(Finput, 'FORMULE.IN'); reset(Finput); assign(Foutput, 'FORMULE.OUT'); rewrite(Foutput); while not eof(Finput) do begin readln(Finput, S); writeln(Foutput, Corespunde(S)); end; close(Finput); close(Foutput); end.

Punctajul acumulat de fiecare competitor

Formule, 07-09
100 90 80 70

60
50

40
30

20
10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

16

Ferestre Trecerea la interfeele grafice a simplificat cu mult interaciunea om-calculator. Amintim, c n cazul interfeelor grafice ecranul monitorului simbolizeaz o mas de lucru, pe care apar ferestre. Concomitent, trecerea la interfeele grafice a pus nceputul unui ir interminabil de glume, una din ele referindu-se la faptul c, n sfrit, calculatoarele ne ofer posibilitatea s avem pe mas virtual de lucru aceiai dezordine, pe care o avem i pe mas propriu-zis. Vasile folosete un sistem de operare, care deschide pe ecran numeroase ferestre. n acest sistem de operare ecranul monitorului este mprit n ptrate elementare cu dimensiunile 11, care formeaz un rastru. Liniile rastrului sunt numerotate de la 1 de sus n jos, iar coloanele sunt numerotate de la 1 de la stnga la dreapta. Astfel, fiecare ptrat elementar de pe ecran poate fi identificat specificnd numrul liniei i numrul coloanei pe care se afl. Fiecare fereastr este un dreptunghi format din unul sau mai multe ptrate elementare. O fereastr nou deschis poate s se suprapun parial sau total peste alte ferestre, deschise n prealabil. Evident, ptrelele ferestrelor deschise anterior, ce au fost acoperite de fereastra numai ce deschis, devin invizibile. Putem nchide o fereastr dac executm un clic n ptratul elementar ce constituie colul din dreapta sus al ferestrei, cu condiia c acesta este vizibil. Sarcin. Scriei un program care s determine numrul minim de click-uri necesare pentru a nchide fereastr pe care am deschis-o prima. Date de intrare. Fiierul text FERESTRE.IN conine pe prima linie un numr natural n, reprezentnd numrul de ferestre deschise pe ecran. Fiecare dintre urmtoarele n linii ale fiierului de intrare conine cte patru numere naturale ls, cs, ld, cd, separate prin spaiu, cu semnificaia "am deschis o fereastr care are colul din stnga sus pe linia ls i coloana cs, respectiv colul din dreapta jos pe linia ld i coloana cd". Ferestrele au fost deschise n ordinea n care apar n fiierul de intrare. Date de ieire. Fiierul text FERESTRE.OUT va conine o singur linie pe care va fi scris numrul minim de click-uri, necesare pentru a nchide prima fereastr deschis. Restricii. 0 n 100 ; 1 ls ld 10000; 1 cs cd 10000 . Timpul de execuie nu va depi 0,2 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea FERESTRE.PAS, FERESTRE.C sau FERESTRE.CPP. Exemplul 1.
FERESTRE.IN 3 3 1 6 4 1 2 4 6 2 3 5 5 FERESTRE.OUT 3

Exemplul 2.
FERESTRE.IN 3 4 1 6 3 2 2 5 5 1 4 3 6 FERESTRE.OUT 3

Exemplul 3.
FERESTRE.IN 3 3 3 4 4 1 1 2 2 5 5 6 6 FERESTRE.OUT 1

17

Rezolvare Vom calcula numrul minim de click-uri necesare pentru a nchide prima fereastr pe care am deschis-o prin metoda recursiei. Vom elabora n acest scop procedura InchideFereastra(j), unde j va comunica procedurii numrul ferestrei ce trebuie nchise. Prin c vom nota numrul minimal de click-uri, necesare pentru a nchide fereastra j. Este cunoscut faptul, c pentru o definire corect a unui algoritm recursiv trebuie s existe: cazuri elementare, care se rezolv direct; cazuri care nu se rezolv direct, ns procesul de calcul n mod obligatoriu progreseaz ctre un caz elementar. Conform condiiilor problemei, elementar va fi cazul n care fereastra j este deschis, iar colul dreapta sus al acestei ferestre este vizibil. n astfel de cazuri nchidem fereastra j, adic facem un click (stabilim c:=c+1) i marcm fereastra respectiv ca fiind una nchis. Cazul care nu se rezolv direct apare atunci cnd fereastra j este deschis, ns colul dreapta sus al acestei ferestre nu este vizibil. n astfel de cazuri apelm recursiv procedura pentru ultima din ferestrele deschise ce acoper colul dreapta sus al ferestrei curente j. n programul ce urmeaz cazurile elementare i cele ce nu se rezolv direct sunt identificate cu ajutorul funciei booleene EstePeste i tabloului de indicatori EsteInchisa.
Program Ferestre; { Clasele 10-12 } const nmax=100; { numarul maximal de ferestre } type Window = record ls: integer; { linia coltului stanga sus } cs: integer; { coloana coltului stanga sus } ld: integer; { linia coltului dreapta jos } cd: integer; { coloana coltului dreapta jos } end; var n: integer; { numarul de ferestre deschise } F: array [1..nmax] of Window; { ferestrele deschise } c: integer; { numarul necesar de click-uri } EsteInchisa: array[1..nmax] of boolean; { indicatorul ferestrelor inchise } procedure Citeste; var i: integer; Intrare: text; begin assign(Intrare, 'FERESTRE.IN'); reset(Intrare); readln(Intrare, n); for i:=1 to n do readln(Intrare, F[i].ls, F[i].cs, F[i].ld, F[i].cd); close(Intrare); end; { Citire } procedure Scrie; var Iesire: text; begin assign(Iesire, 'FERESTRE.OUT');

18

rewrite(Iesire); writeln(Iesire, c); close(Iesire); end; { Scrie } function EstePeste(a: integer; b: integer): boolean; { Retutneaza TRUE daca fereastra a acopera coltul } { dreapta sus al ferestrei b si FALSE in caz contrar } begin EstePeste:=FALSE; if (F[b].ls>=F[a].ls) and (F[b].ls<=F[a].ld) and (F[b].cd>=F[a].cs) and (F[b].cd<=F[a].cd) then EstePeste:=TRUE; end; { EstePeste } procedure InchideFereastra(j: integer); { Inchide recursiv fereastra j } var i: integer; begin for i:=n downto j+1 do if (not EsteInchisa[i] and EstePeste(i, j)) then InchideFereastra(i); EsteInchisa[j]:=TRUE; c:=c+1; { facem un click pentru a nchide fereastra j } end; { InchideFereastra } procedure Calculeaza; { calculeaza numarul de clicuri } var i: integer; begin for i:=1 to n do EsteInchisa[i]:=FALSE; c:=0; InchideFereastra(1); end; { Calculeaza } begin Citeste; Calculeaza; Scrie; end.

Din analiza textului procedurii recursive InchideFereastra rezult c ea va fi apelat de cel mult n3 ori. Conform restriciilor problemei, 0 n 100 . Prin urmare, timpul cerut de program va fi de ordinul 106, mrime cu mult mai mic dect capacitatea de prelucrare a calculatoarelor personale.

19

Punctajul acumulat de fiecare competitor

Ferestre, 07-09
100 90 80 70

60
50

40
30

20
10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

20

Parcare auto O parcare auto este format dintr-un ir (rnd) lung de locuri de parcare. Locurile de parcare sunt numerotate de la stnga la dreapta prin 1, 2, 3, ..., N. Toate locurile de parcare sunt ocupate de automobile. Fiecare automobil este de un anumit tip, iar unele automobile din ir pot avea tipuri identice. Tipurile sunt simbolizate prin numerele ntregi 1, 2, 3, ..., M. Un grup format din doi muncitori au decis s ordoneze automobilele parcate astfel, nct tipurile respective s fie n ordine cresctoare de la stnga la dreapta. Pentru a ordona automobilele, muncitorii folosesc urmtoarea metod. Prin definiie, o rund const din urmtoarele operaii consecutive: 1) mai nti, fiecare din muncitori se urc n cte o main; 2) n continuare, muncitorii scot simultan din ir mainile n care se afl; 3) dup aceasta, muncitorii parcheaz mainile scoase n locurile disponibile i se coboar din ele. S considerm urmtorul exemplu. Parcarea are 5 locuri, toate fiind ocupate de automobile. Automobilele parcate sunt de tipurile 1, 2, 3 i 4. Plasarea iniial a automobilelor, de la stnga la dreapta, redat prin tipul lor, este (1, 3, 2, 4, 3). Runda 1. Schimbm cu locul automobilele de pe poziiile 2 i 3. Obinem plasarea (1, 2, 3, 4, 3). Runda 2. Schimbm cu locul automobilele de pe poziiile 4 i 5. Obinem plasarea (1, 2, 3, 3, 4). Sarcin. Scriei un program care calculeaz o secven de runde, ce ordoneaz automobilele parcate n aa mod, nct tipurile lor s fie n ordine cresctoare de la stnga la dreapta. Date de intrare. Fiierul text PARCARE.IN conine pe prima linie numerele ntregi N i M, separate prin spaiu. Linia a doua a fiierului de intrare conine N numere ntregi, separate prin spaiu, unde al i-lea numr reprezint tipul automobilului de pe locul de parcare i. Date de ieire. Prima linie a fiierului text PARCARE.OUT va conine un numr ntreg R numrul de runde. Fiecare din urmtoarele R linii ale fiierului de ieire va conine cte dou numere ntregi, separate prin spaiu. Numerele de pe linia j a fiierului de ieire reprezint locurile de parcare, automobilele de pe care au fost reamplasate n runda j 1 . Rundele apar n fiierul de ieire n ordine efecturii lor. Dac problema admite mai multe soluii, n fiierul de ieire se va scrie doar una, oricare din ele. Restricii. 1 N 20000; 2 M 50. Exist cel puin cte un automobil de fiecare tip. Nu se admit soluiile ce conin mai mult de N 1 de runde. Timpul de execuie nu va depi 1,0 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea PARCARE.PAS, PARCARE.C sau PARCARE.CPP. Exemplu.
PARCARE.IN PARCARE.OUT

5 4 1 3 2 4 3

2 2 3 4 5

21

Rezolvare Pentru a gsi una din soluiile problemei, vom simula procesul de lucru al celor doi muncitori. Fie S un tablou format din numere ntregi, ce reprezint starea iniial a parcrii, iar F un tablou formar din numere ntregi, ce reprezint starea final a parcrii. Evident, tabloul F poate fi obinut din tabloul S prin sortarea acestuia n ordine cresctoare. Presupunem c la un anumit pas al algoritmului, tabloul S reprezint starea curent a parcrii. Pentru a simula o rund ce reamplaseaz automobilele conform cerinelor din enunul problemei executm urmtorii pai: 1) parcurgnd tablourile S i F, identificm n S prima din poziiile pe care se afl un automobil nepotrivit i memorm aceast poziie n variabila a; 2) examinnd poziiile a 1, a 2 .a.m.d. din tabloul S, identificm n el prima din poziiile ce conine un automobil potrivit i memorm aceast poziie n variabila b; 3) reamplasm automobilele din poziiile a i b, schimbnd cu locul elementele respective ale tabloului S. Evident, procesul de calcul se va termina dup parcurgerea complet a tablourilor S i F, iar numrul de runde nu va depi valoarea de N 1 , stabilit n restriciile problemei. n programul ce urmeaz, sortarea tabloului F se efectueaz prin metoda bulelor. Amintim c n aceast metod se compar elementele vecine F[ j], F[ j 1] ale tabloului F, parcurgerea tabloului efectundu-se de cel mult ( N 1) ori. Dac F[ j] F[ j 1] , elementele vecine se schimb cu locul.
Program Parcare; { Clasele 07-09. Metoda BubleSort } const Nmax = 20000; Mmax = 50; var S, F: array[1..Nmax] of integer; A, B: array[1..Nmax] of integer; N: integer; M: integer; R: integer; procedure Input; var InputFile: text; i: integer; begin assign(InputFile, 'PARCARE.IN'); reset(InputFile); readln(InputFile, N, M); for i:=1 to N do read(InputFile, S[i]); close(InputFile); end; { Input } procedure Output; var OutputFile: text; j: integer; begin assign(OutputFile, 'PARCARE.OUT'); rewrite(OutputFile);

22

writeln(OutputFile, R); if R<>0 then for j:=1 to R do writeln(OutputFile, A[j], ' ', B[j]); close(OutputFile); end; { Output } procedure Sort; { Sortarea prin metoda bulelor } var i, j, k: integer; begin for i:=1 to N-1 do for j:=1 to N-1 do if F[j]>F[j+1] then begin k:=F[j]; F[j]:=F[j+1]; F[j+1]:=k; end; end; { Sort } procedure Process; var i, j, k: integer; begin F:=S; Sort; R:=0; for i:=1 to N-1 do if S[i]<>F[i] then for j:=i+1 to N do if F[i]=S[j] then begin k:=S[i]; S[i]:=S[j]; S[j]:=k; R:=R+1; A[R]:=i; B[R]:=j; break; end; { if } end; { Process } begin Input; Process; Output; end.

Din analiza textului procedurii Sort rezult c complexitatea temporal a acesteia este de ordinul O ( N 2 ) . Complexitatea temporal a procedurii Process este, de asemenea, de ordinul O ( N 2 ) . Prin urmare, timpul cerut de program va fi de ordinul O ( N 2 ) . Conform restriciilor problemei, N 20000. Evident, n cel mai dificil caz, timpul de calcul va fi proporional cu 2 20 000 2 8 10 8 10 9 . ntruct aceast mrime este comparabil cu capacitatea de prelucrare a calculatoarelor personale, exist riscul ca programul de mai sus s nu se ncadreze n limita de 2 secunde, stabilit n restriciile problemei. O reducere a timpului de calcul poate fi obinut prin alegerea unei metode mai rapide de sortare a tabloului F. Una din soluiile posibile ar fi utilizarea algoritmului QuickSort (sortarea rapid), bazat pe utilizarea tehnicii mparte i stpnete. Ideea acestei tehnici const n divizarea tabloului iniial n dou sub-tablouri, care sunt sortate separat. La rndul lor, pentru a fi sortate, fiecare din aceste sub-tablouri sunt din nou divizate n cte dou sub-tablouri .a.m.d. De obicei, algoritmul QuickSort se implementeaz prin metoda recursiei.

23

n general, de la competitorii din clasele a 7-a a 9-a nu se cere cunoaterea acestor metode, ntruct procedura respectiv este deja implementat n mediului de dezvoltare a programelor Free Pascal. Este suficient ca ei s o poat apela din bibliotecile standard. Pentru informare, prezentm mai jos o nou versiune a procedurii Sort, bazat pe utilizarea algoritmului QuickSort.
Program Parcare; { Clasele 07-09. Metoda QuickSort } const Nmax = 20000; Mmax = 50; var S, F: array[1..Nmax] of integer; A, B: array[1..Nmax] of integer; N: integer; M: integer; R: integer; procedure Input; var InputFile: text; i: integer; begin assign(InputFile, 'PARCARE.IN'); reset(InputFile); readln(InputFile, N, M); for i:=1 to N do read(InputFile, S[i]); close(InputFile); end; { Input } procedure Output; var OutputFile: text; j: integer; begin assign(OutputFile, 'PARCARE.OUT'); rewrite(OutputFile); writeln(OutputFile, R); if R<>0 then for j:=1 to R do writeln(OutputFile, A[j], ' ', B[j]); close(OutputFile); end; { Output } type Stare = array[1..Nmax] of integer; Procedure Sort(var G: Stare); { Sortare prin metoda QuickSort } var x, t: byte; Procedure Qs(l, r: integer); { Algoritmul QuickSort } var i, j: integer; begin i:=l; j:=r; x:=G[(longint(l)+r)div 2]; while i<=j do begin while G[i]<x do inc(i); while x<G[j] do dec(j); if i<=j then

24

begin t:=G[i]; G[i]:=G[j]; G[j]:=t; inc(i); dec(j); end; end; if i<r then Qs(i,r); if l<j then Qs(l,j); end; { Qs } begin Qs(1, N); end; { Sort } procedure Process; var i, j, k: integer; begin F:=S; Sort(F); R:=0; for i:=1 to N-1 do if S[i]<>F[i] then for j:=i+1 to N do if F[i]=S[j] then begin k:=S[i]; S[i]:=S[j]; S[j]:=k; R:=R+1; A[R]:=i; B[R]:=j; break; end; { if } end; { Process } begin Input; Process; Output; end.

Complexitatea temporal a algoritmului QuickSort este de ordinul O ( N log 2 N ) , comparativ cu O ( N 2 ) n cazul metodei bulelor. Prin urmare, ne putem atepta la o reducere a timpului de N sortare de circa ori. Pentru N = 20000, aceast reducere va fi de circa 1400 de ori. log 2 N Prin experiene de calcul ne convingem, c pentru N = 20000, programul n care tabloul F este ordonat prin metoda QuickSort se ncadreaz n limitele de timp, stabilite n restriciile problemei.

25

Punctajul acumulat de fiecare competitor

Parcare, 07-09
100 90 80 70

60
50

40
30

20
10 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

Punctajul total acumulat de fiecare competitor

Total, 07-09
500 450 400 350

300
250

200
150

100
50 0

9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

26

Clasele 10

12

Denumirea problemei Ceasul

Numrul de puncte alocat problemei 100

Denumirea fiierului surs


CEAS.PAS CEAS.C CEAS.CPP IMAGINI.PAS IMAGINI.C IMAGINI.CPP BLOCURI.PAS BLOCURI.C BLOCURI.CPP FORMULE.PAS FORMULE.C FORMULE.CPP FERESTRE.PAS FERESTRE.C FERESTRE.CPP PARCARE.PAS PARCARE.C PARCARE.CPP

Denumirea fiierului de intrare


CEAS.IN

Denumirea fiierului de ieire


CEAS.OUT

Imagini

100

IMAGINI.IN

IMAGINI.OUT

Blocuri de piatr

100

BLOCURI.IN

BLOCURI.OUT

Formule

100

FORMULE.IN

FORMULE.OUT

Ferestre

100

FERESTRE.IN

FERESTRE.OUT

Parcare auto

100

PARCARE.IN

PARCARE.OUT

Total

600

27

Ceasul Ana a primit un cadou special un ceas digital, care indic timpul curent n formatul HH:MM:SS, unde HH reprezint ora, MM minutele, iar SS secundele. Specificul acestui ceas const n faptul c n momentul n care timpul indicat de el reprezint un palindrom, ceasul reproduce o melodie din renumitul film In Time. Ana iubete att de mult melodia din filmul In Time, nct de fiecare dat cum se uit la ceas, imediat dorete s tie, cnd din nou va fi redat melodia respectiv. Prin definiie, timpul indicat de ceas este un palindrom, dac indicaiile ceasului se citesc n acelai fel att de la stnga la dreapta, ct i de la dreapta la stnga. De exemplu, timpul 15:22:51 este un palindrom. Sarcin. Elaborai un program, care, cunoscnd indicaiile curente ale ceasului, determin cel mai apropiat momentul de timp n care din nou va fi redat melodia din filmul In Time. Date de intrare: Fiierul text CEAS.IN conine pe o singur linie un ir de caractere timpul curent scris n formatul HH:MM:SS. Date de ieire: Fiierul text CEAS.OUT va conine pe o singur linie un ir de caractere cel mai apropiat moment de timp n care din nou va fi redat melodia din filmul In Time. Momentul de timp va fi scris n formatul HH:MM:SS. Restricii: 00 HH < 24; 00 MM < 60, 00 SS < 60. Timpul de execuie nu va depi 0,1 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea CEAS.C, CEAS.CPP sau CEAS.PAS. Exemplu 1.
CEAS.IN 15:11:52 CEAS.OUT 15:22:51

Exemplu 2.
CEAS.IN 23:56:32 CEAS.OUT 00:00:00

Rezolvare Vom rezolva problema prin metoda forei brute, gsind palindromul din enunul problemei prin trierea secundelor, pornind de la timpul curent. Conform restriciilor problemei, timpul curent poate lua valori de pn la 24 de ore sau, n baza unor calcule elementare, pn la 86 400 de secunde. Prin urmare, pentru memorarea timpului vom folosi variabile de tipul longint.
Program Ceasul; { Clasele 10-12 } uses Sysutils;

{ unitatea Free Pascal ce contine functia IntToStr }

var TC : longint; { timpul curent in secunde }

28

TM : string;

{ timpul de redare a melodii in formatul HH:MM:SS }

procedure Citeste; var i : integer; Intrare : text; C : string; { indicatiile curente ale ceasului } H, M, S : longint; { indicatiile curente: ore, minute, secunde } R : string; begin assign(Intrare, 'CEASUL.IN'); reset(Intrare); readln(Intrare, C); close(Intrare); R:=C[1]; R:=R+C[2]; H:=StrToInt(R); R:=C[4]; R:=R+C[5]; M:=StrToInt(R); R:=C[7]; R:=R+C[8]; S:=StrToInt(R); TC:= H*3600+M*60+S; end; { Citeste } function Format(T : longint) : string; { Transforma timpul T din secunde in formatul HH:MM:SS } var HH, MM, SS : string; R : string; begin HH:=IntToStr(T div 3600); if length(HH)=1 then HH:='0'+HH; T:=T mod 3600; MM:=IntToStr(T div 60); if length(MM)=1 then MM:='0'+MM; T:=T mod 60; SS:=IntToStr(T); if length(SS)=1 then SS:='0'+SS; Format:=HH+':'+MM+':'+SS; end; { Format } function EstePalindrom(Q : string) : boolean; { Returneaza TRUE daca Q este un palindrom si FALSE in caz contrar } var i : integer; L : integer; begin L:=length(Q); EstePalindrom:=TRUE; for i:=1 to (L div 2) do if Q[i]<>Q[L-i+1] then EstePalindrom:=FALSE; end; { EstePalindrom } procedure Calculeaza; { Calculeaza momentul redarii melodii } var T : longint; begin T:=TC; repeat T:=T+1; if T>=24*3600 then T:=0; TM:=Format(T); until EstePalindrom(TM); end; { Calculeaza } procedure Scrie; var Iesire : text;

29

begin assign(Iesire, 'CEASUL.OUT'); rewrite(Iesire); writeln(Iesire, TM); close(Iesire); end; { Scrie } begin repeat Citeste; Calculeaza; Scrie; until false; end.

Instruciunile din ciclul repeat al procedurii Calculeaza se va executa de cel mult 86 400 106 ori. n procedura Calculeaza sunt apelate funciile Format i EstePqalindrom, complexitatea temporal a crora este de ordinul 101. Prin urmare, complexitatea temporal a programului elaborat este de ordinul 107, mrime cu mult mai mic dect capacitatea de prelucrare a calculatoarelor personale. Evident, timpul de execuie va fi mai mic ca o secund. Punctajul acumulat de fiecare competitor

Ceasul, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

30

Imagini Imaginile color (vezi desenul) pot fi codificate cu ajutorul unui tablou bidimensional cu n linii bij i m coloane B . Elementul bij indic printr-un numr natural culoarea microzonei
n m

respective, folosind n acest scop un sistem prestabilit de codificare a culorilor, de exemplu: alb (bij = 0), neagr (bij = 1), roie (bij = 2) etc. Pentru a colora imaginile editoarele grafice ofer un instrument special denumit Umple-cu-culoare, aplicarea cruia imit procesul de scurgere a vopselei din borcan n microzona curent, din ea n microzonele adiacente de aceeai culoare .a.m.d. Evident, vopseaua poate curge dintr-o microzon n alta numai atunci cnd ele au o latur comun. Sarcin. Elaborai un program pentru realizarea instrumentului Umple-cu-culoare.

Aplicarea instrumentului Umple-cu-culoare: a - imaginea iniial; b - imaginea final; c - codificarea culorilor

Date de intrare. Fiierul text IMAGINI.IN conine pe prima linie numerele naturale n, m separate prin spaiu. Fiecare din urmtoarele n linii conine cte m numere separate prin spaiu. Linia i +1 a fiierului de intrare conine numerele bi1, bi2, ..., bim ale imaginii iniiale. Ultima linie a fiierului conine trei numere naturale p, q, k separate prin spaiu. Numerele p, q indic coordonatele zonei asupra creia trebuie aplicat instrumentul Umple-cu-culoare, iar numrul k indic codul culorii din borcan. Date de ieire. Fiierul text IMAGINI.OUT va conine pe fiecare din cele n linii cte m numere separate prin spaiu. Linia i a fiierului de ieire conine numerele bi1, bi2, ..., bim ale imaginii finale. Restricii. 1 n, m 20, 0 bij, k 10, bij k . Timpul de execuie nu va depi 0,1 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea IMAGINI.PAS, IMAGINI.C sau IMAGINI.CPP. Exemplu. Pentru desenul de mai sus avem:
IMAGINI.IN 7 1 0 0 0 0 1 0 2 7 0 1 0 1 1 1 1 3 0 1 1 0 0 1 0 2 0 1 0 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 1 0 1 1 0 0 0 1 0 1 IMAGINI.OUT 1 0 0 0 0 1 0 0 2 0 1 1 1 1 0 2 2 0 0 1 0 0 2 0 0 0 1 0 2 2 2 2 0 0 0 0 0 2 0 1 0 1 1 0 0 0 1 0 1

31

Rezolvare Vom nota prin s culoarea microzonei asupra creia trebuie aplicat instrumentul Umple-cuculoare. Evident, s = bpq. Pentru a imita procesul de scurgere a vopselei din borcan n microzona (p, q), iar din ea n microzonele adiacente de aceeai culoare .a.m.d., vom elabora o procedur recursiv, denumit Vopsea, care efectueaz urmtoarele operaii: dac culoarea microzonei curente nu coincide cu s, atunci n procedura Vopsea nu se efectueaz nici o operaie; dac culoarea microzonei curente coincide cu s, atunci microzona n studiu este vopsit n culoarea k, iar procedura Vopsea este apelat recursiv pentru cele patru microzonele adiacente: cea de sus (p-1, q), cea din dreapta (p, q+1), cea de jos (p+1, q) i cea din stnga (p, q-1). ntruct k bpq , la execuia apelurilor recursive Vopsea(p,q) microzona deja colorat nu mai este examinat a doua oar, fapt ce exclude ciclarea programului. De asemenea, pentru a evita verificrile necesare n cazul microzonelor de la margini, vom ncadra imaginea ntru-un chenar, nscriind n celulele respective ale tabloului B valoarea -1.
Program Imagini; { Clasele 10-12 } const nmax=21; mmax=21; var n, m, p, q, k, i, j : integer; B : array[0..nmax, 0..mmax] of -1..255; Finput, Foutput : text; procedure UmpleCuCuloare(p, q, k : integer); var i, j, s : integer; { s - culoarea initiala a microzonei (i, j) } procedure Vopsea(p, q : integer); { Simulam scurgerea vopselei } begin if B[p, q]=s then begin { vopsim microzona (p, q) } B[p, q]:=k; { vopsim microzona de sus } Vopsea(p-1, q); { vopsim microzona din dreapta } Vopsea(p, q+1); { vopsim microzona de jos } Vopsea(p+1, q); { vopsim microzona din stinga } Vopsea(p, q-1); end; { then } end; { Vopsea } begin { memoram in s culoarea microzonei (p, q) } s:=B[p, q]; { bordam tabloul B cu -1 } for i:=0 to n+1 do begin B[i, 0]:=-1; B[i, m+1]:=-1; end; for j:=0 to m+1 do begin B[0, j]:=-1; B[n+1, j]:=-1; end; Vopsea(p, q); end; { UmpleCuCuloare } begin assign(Finput, 'IMAGINI.IN'); assign(Foutput, 'IMAGINI.OUT');

32

reset(Finput); rewrite(Foutput); readln(Finput, n, m); for i:=1 to n do begin for j:=1 to m do read(Finput, B[i, j]); readln(Finput); end; readln(Finput, p, q, k); close(Finput); UmpleCuCuloare(p, q, k); for i:=1 to n do begin for j:=1 to m do write(Foutput, B[i, j], ' '); writeln(Foutput); end; close(Foutput); end.

Evident, numrul de apeluri recursive ale procedurii Vopsea nu poate depi numrul de microzone ale imaginii. Prin urmare, timpul de execuie T n m, iar spaiul necesar de memorie n stiv Vs n m. Conform restriciilor problemei, dimensiunile imaginii n, m 20, deci timpul de execuie T <<0,1 s, iar necesarul de memorie Vs < 16 Koctei. Punctajul acumulat de fiecare competitor

Imagini, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

33

Blocuri de piatr InfoCity este un ora modern i foarte frumos. Oraul este n permanent dezvoltare i a ajuns deja la marginea rului InfoRiver. Primarul oraului dorete s extind InfoCity pe cellalt mal al rului, intenionnd s construiasc n acest scop un pod. Pentru a se integra organic n arhitectura oraului, podul va avea exact doi piloni, ce vor fi construii din blocuri de piatr. Pentru construcia unui pilon sunt necesare p blocuri de piatr. Primria oraului dispune de n seturi de blocuri de piatr, numerotate prin 1, 2, 3, ..., i, ..., n, setul i coninnd ai blocuri. Pentru construcia fiecruia din cei doi piloni sunt necesare cte p blocuri de piatr. Toate seturile de blocuri de piatr trebuie distribuite ntre cei doi piloni n curs de construcie. Evident, exist mai multe modaliti de a distribui seturile de blocuri de piatr ntre cei doi piloni. Sarcin. Elaborai un program, care calculeaz numrul de variante posibile de distribuire a seturilor respective ntre cei doi piloni ai podului n aa mod, nct toate seturile s fie distribuite, iar fiecruia din piloni s-i revin cel puin p blocuri de piatr. Date de intrare: Fiierul text BLOCURI.IN conine dou linii. Prima linie a fiierului de intrare conine numerele ntregi n i p, separate prin spaiu. Linia a doua a fiierului de intrare conine numerele ntregi a1, a2, ..., ai, ..., an, separate prin spaiu, unde ai reprezint numrul de blocuri de piatr din setul i. Date de ieire: Fiierul text BLOCURI.OUT va conine pe o singur linie un numr ntreg numrul de variante posibile de distribuire a seturilor de blocuri. Restricii: 1 n 50; 1 p 10000; 1 ai 109. Timpul de execuie nu va depi 1 secund. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea BLOCURI.PAS, BLOCURI.C sau BLOCURI.CPP. Exemplu 1.
BLOCURI.IN 4 6 3 1 4 6 BLOCURI.OUT 4

Explicaie. Seturile de blocuri i = 1, 2, 3, 4, pot fi distribuite dup cum urmeaz:


Varianta 1 2 3 4 Pilonul 1 1, 2, 3 1, 3 2, 4 4 Pilonul 2 4 2, 4 1, 3 1, 2, 3

Exemplu 2.
BLOCURI.IN 3 7 5 3 6 BLOCURI.OUT 0

Explicaie. ntruct avem doar trei seturi, pentru oricare din variantele de distribuire, unuia din piloni i va reveni doar un singur set. ntruct nici unul din seturi nu conine cel puin 7 blocuri de piatr, nu exist nici o variant de distribuire a seturilor de blocuri, ce ar corespunde enunului problemei.

34

Rezolvare Vom ncerca mai nti s rezolvm problema prin metoda trierii. n acest scop, vom genera toate variante posibile de distribuire a seturilor de blocuri de piatr ntre cei doi piloni. Din variantele generate le vom contabiliza doar pe acelea n care fiecruia din cei doi piloni i revin cte cel puin p blocuri de piatr. Pentru a genera toate variante posibile de distribuire a seturilor de blocuri ntre cei doi piloni ai podului vom utiliza tabloul V[1..n], fiecare din componentele cruia poate lua valorile 0, 1. Valoarea 0 a componentei V[i] indic faptul, c blocul i a fost alocat a fost alocat pilonului 1, iar valoarea 1 c blocul i a fost alocat pilonului 2. Componentele tabloului V pot fi tratate ca cifre ale unui numr natural, scris n sistemul binar de numeraie. Evident, fiecrei valori distincte a acestui numr binar i corespunde o variant de distribuire a seturilor de blocuri ntre cei doi piloni. Pentru a genera toate variantele posibile, iniial i atribuim lui V valoarea 0. Presupunem c V are deja o anumit valoare binar. n continuare, mrim numrul V cu o unitate binar .a.m.d., pn cnd ajungem la valoarea 2n 1.
Program BlocuriMetodaTrierii; { Clasele 10-12 } const var V A n p K D nmax=50; { numarul maximal de seturi } : array[1..nmax] of integer; : array[1..nmax] of longint; : integer; : integer; : longint; { numarul de variante posibile } : integer; { indicatorul de depasire la incrementarea lui V }

procedure Citeste; var Intrare : text; i : integer; begin assign(Intrare, 'BLOCURI.IN'); reset(Intrare); readln(Intrare, n, p); for i:=1 to n do read(Intrare, A[i]); close(intrare); end; { Citeste } procedure Scrie; var Iesire : text; begin assign(iesire, 'BLOCURI.OUT'); rewrite(Iesire); writeln(Iesire, K); close(Iesire); end; { Scrie } procedure Initializare; { Initializeaza V in zero } var i : integer; begin for i:=1 to n do V[i]:=0; end; { initializare }

35

procedure Incrementare; { Mareste V cu o unitate in sistemul binar } var i : integer; begin D:=1; for i:= 1 to n do begin V[i]:=V[i]+D; D:=0; if V[i]=2 then begin V[i]:=0; D:=1; end; end; end; { Incrementare } procedure Contabilizeaza; var i : integer; p1, p2 : longint; {numarul de pietre per pilon } begin p1:=0; p2:=0; for i:=1 to n do begin if V[i]=0 then p1:=p1+A[i]; if V[i]=1 then p2:=p2+A[i]; end; if (p1>=p) and (p2>=p) then K:=K+1; end; { Contabilizeaza } procedure Calculeaza; var i : integer; begin Initializare; K:=0; repeat Contabilizeaza; Incrementare; until D=1; end; { Calculeaza } begin Citeste; Calculeaza; Scrie; end.

Timpul cerut de procedura Calculeaza este proprional cu numrul de apeluri ale procedurilor Contabilizeaza i Incrementare din ciclul repeat. Evident, acest numr este egal cu 2n . Fiecare din procedurile Contabilizeaza i Incrementare conine cte un ciclu, care se va executa de cel mult n ori. Prin urmare, timpul cerut de program va fi proporional cu 2nn. Conform restriciilor problemei, n 50. Evident, pentru n = 50, timpul cerut de program va fi proporional cu 250 50 5,7 1016. ntruct aceast valoare este cu mult mai mare dect capacitatea de prelucrare a calculatoarelor personale ( 109 operaii pe secund), timpul de execuie va fi de ordinul 108 secunde, adic de circa trei ani. Prin urmare, metoda trierii poate fi aplicat doar n cazul unor valori mici ale lui n. Prin experimente pe calculator ne putem convinge c programul de mai sus se ncadreaz n dou secunde doar pentru valorile n 20. Pentru a reduce timpul de calcul, vom soluiona problema prin metoda programrii dinamice. Amintim c aceast metod se bazeaz pe utilizarea formulelor recurente, care, n cazul nostru,

36

trebuie s ne permit calcularea numrului variantelor de distribuire a q seturi de blocuri n condiiile n care numrul variantelor respective pentru 0, 1, 2, ..., (q 1) seturi de blocuri este deja cunoscut. Pentru a deduce formula de care avem nevoie, vom nota prin mqj numrul variantelor de distribuire a q seturi de blocuri ntre cei doi piloni n aa mod, nct primului pilon s-i revin exact j blocuri de piatr. Evident, condiiilor problemei vor corespunde doar variantele de distribuire pentru care ( j p ) i (t q j p) , unde tq reprezint numrul total de blocuri de piatr din seturile n studiu. Numrul de variante posibile de distribuire a celor q seturi de blocuri, astfel nct fiecrui pilon s-i revin cel puin p blocuri de piatr, poate fi calculat cu ajutorul urmtoarei formule recurente:
mqj
j

mq

1, j

pentru j

p i (t q

j)

p.

n programul ce urmeaz, variabilele mqj sunt memorate n tabloul Modes.


Program BlocuriProgramareaDinamica; { Clasele 10-12 } const MaxN = 50; MaxP = 10000; var Modes: array[0..1, 0..MaxN*MaxP] of Int64; Blocuri: array[1..MaxN] of LongInt; N, P: LongInt; Res: Int64; procedure InputData; var f: Text; i: LongInt; begin Assign(f, 'BLOCURI.IN'); Reset(f); Readln(f, N, P); for i := 1 to N do Read(f, Blocuri[i]); Close(f); end; procedure ProcessData; var i, j, k, Total: LongInt; begin for i := 1 to N do if Blocuri[i] > P then Blocuri[i] := P; Total := 0; for i := 1 to N do Total := Total + Blocuri[i]; for i := 0 to N * P do Modes[0, i] := 0; for i := 0 to N * P do Modes[0, i] := 0; Modes[0, 0] := 1; k := 0; for i := 1 to N do begin for j := 0 to N * P do

37

if Modes[k, j] > 0 then begin Modes[1 - k, j] := Modes[1 - k, j] + Modes[k, j]; Modes[1 - k, j + Blocuri[i]] := Modes[1 - k, j + Blocuri[i]] + Modes[k, j]; end; k := 1 - k; for j := 0 to N * P do Modes[1 - k, j] := 0; end; for i := P to N * P do if (Total - i >= P) then Res := Res + Modes[k, i]; end; procedure OutputData; var f: Text; begin Assign(f, 'BLOCURI.OUT'); ReWrite(f); Writeln(f, Res); Close(f); end; begin InputData; ProcessData; OutputData; end.

Din analiza textului programului de mai sus rezult c soluia propus are complexitatea O(n p). Conform restriciilor problemei, 1 n 50 i 1 p 10000. Prin urmare, n cazul celui mai complicat test, numrul de operaii va fi de ordinul 2,5 107, mrime comparabil cu capacitatea de prelucrare a calculatoarelor personale.
2

Menionm faptul, c la fiecare pas q sunt necesare doar valorile mqj, fapt ce permite reducerea volumului de memorie alocat tabloului Modes de la O(n2p) pn la doar O(np).

38

Punctajul acumulat de fiecare competitor

Blocuri, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

39

Formule Se consider urmtoarele formule metalingvistice: Cifr :: = 0 1 2 3 4 5 6 7 8 9 Numr :: = Cifr Semn ::= + - * / Expresie :: = Numr ( Expresie ) Expresie Semn Expresie Sarcin. Scriei un program care returneaz valoarea DA dac irul de caractere S este conform definiiei unitii lexicale Expresie i NU n caz contrar. Date de intrare. Fiierul text FORMULE.IN conine pe fiecare linie cte un ir de caractere S. Date de ieire. Fiierul text FORMULE.OUT va conine pe fiecare linie valoarea DA dac irul de caractere din linia respectiv a fiierului de intrare corespunde definiiei i NU n caz contrar. Restricii. irul nevid S conine cel mult 250 de caractere. Fiierul de intrare conine cel mult 200 de linii. Timpul de execuie nu va depi 0,2 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea FORMULE.PAS, FORMULE.C sau FORMULE.CPP. Exemplu.
FORMULE.IN 1+(3-4)+6/12-3*2 +1+ 4/(3435+(684-2)*11) FORMULE.OUT DA NU DA

Cifr

Rezolvare Conform formulelor metalingvistice din enunul problemei, orice secven de cifre din componena irului S delimitat de caracterele +, -, *, / sau (, ) este un numr care, la rndul su, poate fi tratat ca o expresie. Prin urmare, prin una sau dou parcurgeri ale irului S putem nlocui fiecare numr cu un simbol ce ar reprezenta unitatea lexical <Expresie>, de exemplu, E. n particular, pentru irul 4/(3435+(684-2)*11)obinem: E/(E+(E-E)*E). Din aceleai considerente, orice caracter +, -, *, / poate fi nlocuit cu un simbol ce ar reprezenta unitatea lexical <Semn>, de exemplu #. n cazul irului de mai sus obinem E#(E#(E#E)#E). n continuare, conform formulelor metalingvistice din enunul problemei, vom nlocui fiecare secven E#E i (E) prin E. Evident, irul de caractere S este conform definiiei unitii lexical <Expresie> numai atunci cnd n rezultatul tuturor substituirilor vom obine un ir ce conine un singur caracter, i anume, simbolul E. n programul ce urmeaz substituirile se efectueaz iterativ, iar numrul iteraiilor nu depete valoarea n, unde n este lungimea irului S. Prin urmare, timpul de execuie T(n) n3. Evident, pentru n 250, timpul de execuie T(n) 3 s.
Program Formule; { Clasele 10-12 } var S : string; Finput, Foutput : text;

40

function Substituire(S : string) : string; { Inlocuieste semnele +, -, *, / cu caracterul #, } { iar numerele cu caracterul E } var i : integer; begin { din fiecare numar lasam numai prima cifra } i:=1; while i<=length(S)-1 do if (S[i] in ['0'..'9']) and (S[i+1] in ['0'..'9']) then Delete(S, i+1, 1) else i:=i+1; { substituim cifrele cu E } for i:=1 to length(S) do if S[i] in ['0'..'9'] then S[i]:='E'; { substituim semnele +, -, *, / cu caracterul # } for i:=1 to length(S) do if S[i] in ['+', '-', '*', '/'] then S[i]:='#'; Substituire:=S; end; { Substituire } function Expresie(S : string) : string; { Returneaza DA daca S este o expresie si NU in caz contrar } var i : integer; Indicator : boolean; begin S:=Substituire(S); Indicator:=true; while Indicator do begin Indicator:=false; i:=1; while i<length(S)-1 do begin i:=i+1; if (S[i-1]='(') and (S[i]='E') and (S[i+1]=')') or (S[i-1]='E') and (S[i]='#') and (S[i+1]='E') then begin Delete(S, i-1, 3); Insert('E', S, i-1); Indicator:=true; end; { then } end; { while } end; { while } if S='E' then Expresie:='DA' else Expresie:='NU'; end; { Expresie } begin assign(Finput, 'FORMULE.IN'); assign(Foutput, 'FORMULE.OUT'); reset(Finput); rewrite(Foutput); while not eof(Finput) do begin readln(Finput, S); writeln(Foutput, Expresie(S)); end; close(Finput); close(Foutput); end.

41

Punctajul acumulat de fiecare competitor

Formule, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

42

Ferestre Trecerea la interfeele grafice a simplificat cu mult interaciunea om-calculator. Amintim, c n cazul interfeelor grafice ecranul monitorului simbolizeaz o mas de lucru, pe care apar ferestre. Concomitent, trecerea la interfeele grafice a pus nceputul unui ir interminabil de glume, una din ele referindu-se la faptul c, n sfrit, calculatoarele ne ofer posibilitatea s avem pe mas virtual de lucru aceiai dezordine, pe care o avem i pe mas propriu-zis. Vasile folosete un sistem de operare, care deschide pe ecran numeroase ferestre. n acest sistem de operare ecranul monitorului este mprit n ptrate elementare cu dimensiunile 11, care formeaz un rastru. Liniile rastrului sunt numerotate de la 1 de sus n jos, iar coloanele sunt numerotate de la 1 de la stnga la dreapta. Astfel, fiecare ptrat elementar de pe ecran poate fi identificat specificnd numrul liniei i numrul coloanei pe care se afl. Fiecare fereastr este un dreptunghi format din unul sau mai multe ptrate elementare. O fereastr nou deschis poate s se suprapun parial sau total peste alte ferestre, deschise n prealabil. Evident, ptrelele ferestrelor deschise anterior, ce au fost acoperite de fereastra numai ce deschis, devin invizibile. Putem nchide o fereastr dac executm un clic n ptratul elementar ce constituie colul din dreapta sus al ferestrei, cu condiia c acesta este vizibil. Sarcin. Scriei un program care s determine numrul minim de click-uri necesare pentru a nchide fereastr pe care am deschis-o prima. Date de intrare. Fiierul text FERESTRE.IN conine pe prima linie un numr natural n, reprezentnd numrul de ferestre deschise pe ecran. Fiecare dintre urmtoarele n linii ale fiierului de intrare conine cte patru numere naturale ls, cs, ld, cd, separate prin spaiu, cu semnificaia "am deschis o fereastr care are colul din stnga sus pe linia ls i coloana cs, respectiv colul din dreapta jos pe linia ld i coloana cd". Ferestrele au fost deschise n ordinea n care apar n fiierul de intrare. Date de ieire. Fiierul text FERESTRE.OUT va conine o singur linie pe care va fi scris numrul minim de click-uri, necesare pentru a nchide prima fereastr deschis. Restricii. 0 n 100 ; 1 ls ld 10000; 1 cs cd 10000 . Timpul de execuie nu va depi 0,2 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea FERESTRE.PAS, FERESTRE.C sau FERESTRE.CPP. Exemplul 1.
FERESTRE.IN 3 3 1 6 4 1 2 4 6 2 3 5 5 FERESTRE.OUT 3

Exemplul 2.
FERESTRE.IN 3 4 1 6 3 2 2 5 5 1 4 3 6 FERESTRE.OUT 3

Exemplul 3.
FERESTRE.IN 3 3 3 4 4 1 1 2 2 5 5 6 6 FERESTRE.OUT 1

43

Rezolvare Vom calcula numrul minim de click-uri necesare pentru a nchide prima fereastr pe care am deschis-o prin metoda recursiei. Vom elabora n acest scop procedura InchideFereastra(j), unde j va comunica procedurii numrul ferestrei ce trebuie nchise. Prin c vom nota numrul minimal de click-uri, necesare pentru a nchide fereastra j. Este cunoscut faptul, c pentru o definire corect a unui algoritm recursiv trebuie s existe: cazuri elementare, care se rezolv direct; cazuri care nu se rezolv direct, ns procesul de calcul n mod obligatoriu progreseaz ctre un caz elementar. Conform condiiilor problemei, elementar va fi cazul n care fereastra j este deschis, iar colul dreapta sus al acestei ferestre este vizibil. n astfel de cazuri nchidem fereastra j, adic facem un click (stabilim c:=c+1) i marcm fereastra respectiv ca fiind una nchis. Cazul care nu se rezolv direct apare atunci cnd fereastra j este deschis, ns colul dreapta sus al acestei ferestre nu este vizibil. n astfel de cazuri apelm recursiv procedura pentru ultima din ferestrele deschise ce acoper colul dreapta sus al ferestrei curente j. n programul ce urmeaz cazurile elementare i cele ce nu se rezolv direct sunt identificate cu ajutorul funciei booleene EstePeste i tabloului de indicatori EsteInchisa.
Program Ferestre; { Clasele 10-12 } const nmax=100; { numarul maximal de ferestre } type Window = record ls: integer; { linia coltului stanga sus } cs: integer; { coloana coltului stanga sus } ld: integer; { linia coltului dreapta jos } cd: integer; { coloana coltului dreapta jos } end; var n: integer; { numarul de ferestre deschise } F: array [1..nmax] of Window; { ferestrele deschise } c: integer; { numarul necesar de click-uri } EsteInchisa: array[1..nmax] of boolean; { indicatorul ferestrelor inchise } procedure Citeste; var i: integer; Intrare: text; begin assign(Intrare, 'FERESTRE.IN'); reset(Intrare); readln(Intrare, n); for i:=1 to n do readln(Intrare, F[i].ls, F[i].cs, F[i].ld, F[i].cd); close(Intrare); end; { Citire } procedure Scrie; var Iesire: text; begin assign(Iesire, 'FERESTRE.OUT');

44

rewrite(Iesire); writeln(Iesire, c); close(Iesire); end; { Scrie } function EstePeste(a: integer; b: integer): boolean; { Retutneaza TRUE daca fereastra a acopera coltul } { dreapta sus al ferestrei b si FALSE in caz contrar } begin EstePeste:=FALSE; if (F[b].ls>=F[a].ls) and (F[b].ls<=F[a].ld) and (F[b].cd>=F[a].cs) and (F[b].cd<=F[a].cd) then EstePeste:=TRUE; end; { EstePeste } procedure InchideFereastra(j: integer); { Inchide recursiv fereastra j } var i: integer; begin for i:=n downto j+1 do if (not EsteInchisa[i] and EstePeste(i, j)) then InchideFereastra(i); EsteInchisa[j]:=TRUE; c:=c+1; { facem un click pentru a nchide fereastra j } end; { InchideFereastra } procedure Calculeaza; { calculeaza numarul de clicuri } var i: integer; begin for i:=1 to n do EsteInchisa[i]:=FALSE; c:=0; InchideFereastra(1); end; { Calculeaza } begin Citeste; Calculeaza; Scrie; end.

Din analiza textului procedurii recursive InchideFereastra rezult c ea va fi apelat de cel mult n3 ori. Conform restriciilor problemei, 0 n 100 . Prin urmare, timpul cerut de program va fi de ordinul 106, mrime cu mult mai mic dect capacitatea de prelucrare a calculatoarelor personale.

45

Punctajul acumulat de fiecare competitor

Ferestre, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

46

Parcare auto O parcare auto este format dintr-un ir (rnd) lung de locuri de parcare. Locurile de parcare sunt numerotate de la stnga la dreapta prin 1, 2, 3, ..., N. Toate locurile de parcare sunt ocupate de automobile. Fiecare automobil este de un anumit tip, iar unele automobile din ir pot avea tipuri identice. Tipurile sunt simbolizate prin numerele ntregi 1, 2, 3, ..., M. Un grup format din W muncitori a decis s ordoneze automobilele parcate astfel, nct tipurile respective s fie n ordine cresctoare de la stnga la dreapta. Pentru a ordona automobilele, muncitorii folosesc urmtoarea metod. Prin definiie, o rund const din urmtoarele operaii consecutive: 4) mai nti, fiecare din muncitori se urc n cte o main; 5) n continuare, muncitorii scot simultan din ir mainile n care se afl; 6) dup aceasta, muncitorii parcheaz mainile scoase n locurile disponibile i se coboar din ele. Pentru eficien, se cere ca ordonarea s se realizeze ntr-un numr ct mai mic de runde. Nu este obligatoriu ca n fiecare din runde s participe toi muncitorii din grup. S considerm urmtorul exemplu. Parcarea are 10 locuri, toate fiind ocupate de automobile. Automobilele parcate sunt de tipurile 1, 2, 3 i 4. Sunt disponibili 4 muncitori. Plasarea iniial a automobilelor, redat prin tipul lor de la stnga la dreapta, este: 2 3 3 4 4 2 1 1 3 1. n acest exemplu numrul minim de runde este trei. Dup fiecare din runde, amplasarea automobilelor ar putea fi, de exemplu, urmtoarea: 1 3 3 4 2 2 1 3 4 1 dup runda 1; 1 2 1 4 2 3 3 3 4 1 dup runda 2; 1 1 1 2 2 3 3 3 4 4 dup runda 3. Sarcin. Scriei un program care calculeaz o secven care ar include un numr ct mai mic de runde i care ordoneaz automobilele parcate n aa mod, nct tipurile lor s fie n ordine cresctoare de la stnga la dreapta. Date de intrare. Fiierul text PARCARE.IN conine pe prima linie numerele ntregi N, M i W, separate prin spaiu. Linia a doua a fiierului de intrare conine N numere ntregi, separate prin spaiu, unde al i-lea numr reprezint tipul automobilului de pe locul de parcare i. Date de ieire. Fiierul text PARCARE.OUT conine pe prima linie numrul ntreg R numrul de runde. Urmtoarele R linii descriu rundele n ordinea efecturii lor. Pe fiecare din aceste linii, primul numr ntreg este C numrul automobilelor mutate n runda respectiv. Urmeaz 2C numere ntregi, formnd C perechi, corespunztoare reamplasrilor mainilor, utiliznd numerele locurilor de parcare. Prima pereche descrie reamplasarea unui automobil: primul ntreg reprezint numrul locului de parcare de la nceputul rundei, iar al doilea numrul locului de parcare de la sfritul rundei. Urmtorii doi ntregi formeaz o pereche care descrie cum este mutat un alt automobil .a.m.d. Numerele de pe liniile respective sunt separate prin spaiu. ntruct pentru numrul R pot exista mai multe soluii distincte, programul va scrie n fiierul de ieire numai una , oricare din ele. Restricii. 1 N 20000; 2 M 50; 2 W M. Exist cel puin cte un automobil de fiecare tip. Timpul de execuie nu va depi 1,0 secunde. Programul va folosi cel mult 32 Megaoctei de memorie operativ. Fiierul surs va avea denumirea PARCARE.PAS, PARCARE.C sau PARCARE.CPP.
47

Exemplu.
PARCARE.IN 10 4 4 2 3 3 4 4 2 1 1 3 1 PARCARE.OUT 3 4 9 8 5 9 1 5 8 1 4 3 6 7 3 2 7 6 2 3 4 10 2 4 10 2

Punctaj. Presupunem c dup o executare, n fiierul de ieire a fost scris numrul R. Dac n fiierul de ieire cel puin una din cele R runde nu este descris corect sau secvena respectiv de runde nu realizeaz amplasarea automobilelor n ordinea cerut, vi se acord 0 puncte. n caz contrar, punctajul pentru fiecare test va fi calculat astfel:

R Q ................................10 puncte (punctajul maximal), unde Q


Q R 1,25 Q ..................7 puncte.
R 1,50 Q ..........5 puncte.

N /(W 1) .

1,25 Q

1,50 Q

R 1,75 Q ..........2 puncte.

R 1,75 Q ..........................0 puncte.

Rezolvare1 ntruct n enunul problemei nu se cere gsirea secvenelor de lungime minim, pentru a calcula o secvena de runde ce reamplaseaz automobilele vom folosi metoda Greedy. Aceast metod este aplicabil, ntruct avnd W muncitori, n fiecare rund putem muta pe locurile corecte cel puin (W 1) automobile. Evident, dup D /(W 1) runde, unde D este numrul automobilelor ce iniial se afl pe poziiile nepotrivite, toate automobilele vor fi parcate corect. ntruct D N , pentru fiecare test vom lua numrul maximal de puncte. Evident, un program ce implementeaz metoda Greedy va avea complexitatea O ( N 2 ) . Competitorii, care nu cunosc metoda Greedy, ar putea s implementeze Fie S un tablou format din numere ntregi, ce reprezint starea iniial a parcrii, iar F tablou formar din numere ntregi, ce reprezint starea final a parcrii. un

Tabloul F poate fi obinut din tabloul S prin sortarea acestuia n ordine cresctoare. n funcie de metoda de sortare aleas, acest lucru poate fi fcut cu ajutorul unor proceduri de complexitatea O (N 2 ) metoda bulelor, O ( N log N ) metoda QuickSort sau O (M N ) sortarea binar. Evident, n condiiile restriciilor din enunul problemei, metoda bulelor ar fi prea lent. Presupunem c tabloul S conine starea curent a parcrii, iar muncitorii sunt numerotai prin 1, 2, 3, ..., W. Algoritmul de calcul al rundei ce mut pe locuri corecte cel puin ( W 1) automobile include urmtoarele operaii: 1. Parcurgnd tablourile S i F, gsim primul din locurile de parcare pe care se afl un automobil nepotrivit. Memorm acest loc n variabila A[1] i-l desemnm pe muncitorul numrul 1 ca fiind responsabil de mutarea acestui automobil. Deocamdat el nc nu tie pe care loc trebuie s mute automobilul respectiv.
1

Programator Shao Zheng, IOI 2000.

48

2. Presupunem c la o anumit etap, n variabila A[i] se pstreaz poziia curent pe care se afl un automobil nepotrivit, pentru care a fost desemnat deja muncitorul i. 3. Parcurgnd n continuare tabloul S, gsim unul din locurile de parcare pe care se afl un automobil nepotrivit i tipul cruia permite ca el s fie reamplasat pe locul A[i]. Memorm acest loc n variabila A [i 1] i desemnm muncitorul (i 1) din grup ca fiind responsabil de mutarea automobilului de pe locul A [i 1] pe locul A[i]. 4. Continum acest proces pn cnd sunt repartizai toi muncitorii din grup sau pn cnd nu mai sunt automobile care sunt parcate pe locuri nepotrivite. 5. Comunicm primului muncitor, c el trebuie s mute automobilul de pe locul A[1] pe locul A[k], unde k este numrul de muncitori din grup, desemnai n aceast rund pentru a muta automobile. Evident, k W , iar locul A[k] ar putea s fie nepotrivit pentru automobilul A[1]. Prin urmare, o rund va include urmtoarele reamplasri de automobile: A[1] A[k], A[2] A[1], A[3] A[2], A[k] A[k 1] .
Program Parcare; { Clasele 10-12 } { Programmer: Shao Zheng } { Email: shaoz@sina.com } { Date: 2000.09.23 } { Algorithm: Simple Greedy } const fin='PARCARE.IN'; {Input File Name} fon='PARCARE.OUT'; {Output File Name} MaxCarCount=20010; {Data Boundary} MaxModeCount=120; {Data Boundary} MaxWorkerCount=120; {Data Boundary} Type TState=array[1..MaxCarCount]of byte; {To Store the cars' state} var fi,fo:text; {Input and Output File} CarCount,ModeCount,WorkerCount:integer; {The Number of Cars, Modes and Workers} Original,Final:TState; {Original and Final State} NeedPrint:Boolean; Procedure Sort(var A:TState); {QuickSort Algorithm} var x,t:byte; Procedure qs(l,r:integer); var i,j:integer; begin i:=l;j:=r; x:=a[(longint(l)+r)div 2]; while i<=j do begin while a[i]<x do inc(i); while x<a[j] do dec(j); if i<=j then begin t:=a[i];a[i]:=a[j];a[j]:=t; inc(i);dec(j); end; end;

49

if i<r then qs(i,r); if l<j then qs(l,j); end; begin qs(1,CarCount); end; Procedure Init; {Initialization} var i:integer; begin assign(fi,fin); assign(fo,fon); reset(fi); readln(fi,CarCount,ModeCount,WorkerCount); for i:=1 to CarCount do read(fi,Original[i]); close(fi); Final:=Original; Sort(Final); end; Function Find(carno:integer):integer; var i,j,k:integer; begin i:=1;j:=CarCount; while i<=j do begin k:=(longint(i)+j)div 2; if final[k]=carno then begin find:=k;exit;end; if final[k]>carno then j:=k-1 else i:=k+1; end; {error occured!} find:=1; writeln('Car No. not Found! Error!'); readln; end; var usedslot:array[1..MaxCarCount] of boolean; Function FindSlot(const now:TState;car:integer):integer; var i,mid:integer; begin mid:=find(car); for i:=mid to carcount do if final[i]<>car then break else if (now[i]<>car)and not usedslot[i] then begin findslot:=i;exit;end; for i:=mid-1 downto 1 do if final[i]<>car then break else if (now[i]<>car)and not usedslot[i] then begin findslot:=i;exit;end; findslot:=0; end; Function GetFirstDif(const now,final:TState):integer; var i:integer; begin for i:=1 to CarCount do if now[i]<>final[i] then begin GetFirstDif:=i;exit;end; GetFirstDif:=-1; {No difference} end;

50

var ChangeList:array[1..MaxWorkerCount,1..2]of integer; ChangeCount:integer; Procedure Change(var Now:TState;const Final:TState;var rest:integer;dif:integer); var workers:array[1..MaxWorkerCount]of integer; j,w,nextcar:integer; begin fillchar(usedslot,sizeof(usedslot),false); w:=1; workers[w]:=dif; usedslot[dif]:=true; while (w<rest) do begin nextcar:=now[workers[w]]; inc(w); workers[w]:=findslot(now,nextcar); if workers[w]=0 then begin dec(w);break;end;{circle found} usedslot[workers[w]]:=true; end; {Change Now} nextcar:=now[workers[w]]; for j:=w downto 2 do begin now[workers[j]]:=now[workers[j-1]]; inc(ChangeCount); ChangeList[ChangeCount,1]:=workers[j-1]; ChangeList[ChangeCount,2]:=workers[j]; end; now[workers[1]]:=nextcar; inc(ChangeCount); ChangeList[ChangeCount,1]:=workers[w]; ChangeList[ChangeCount,2]:=workers[1]; dec(rest,w); end; Function Process:integer; var i,j:integer; result:integer; dif:integer; Now,Last:TState; Rest:integer; begin result:=0; Now:=Original; dif:=GetFirstDif(Now,Final); {find the first different position in Now and Final} while dif<>-1 do begin Last:=Now; Rest:=WorkerCount; ChangeCount:=0; while (rest>=2)and(dif<>-1) do begin Change(Now,Final,rest,dif); dif:=GetFirstDif(Now,Final); end; inc(result); if needprint then begin write(fo,ChangeCount);

51

for i:=1 to ChangeCount do write(fo,' ',ChangeList[i,1],' ',ChangeList[i,2]); writeln(fo); end; end; Process:=result; end; Type TAnswer=Integer; Var Answer,Best,Need:TAnswer; t:Integer; difcount:integer; time:Longint; begin Init; {Initialization} {Answers}

{Calculate the limits} difcount:=0; for t:=1 to CarCount do if Original[t]<>Final[t] then inc(DifCount); Best:=(DifCount-1) div WorkerCount+1; Need:=(DifCount-1) div (WorkerCount-1)+1; {Simple Greedy Algorithm} NeedPrint:=false; Answer:=Process; {Output Answer} rewrite(fo); writeln(fo,Answer); NeedPrint:=true; Answer:=Process; close(fo); end.

Prin experimente de calcul ne putem convinge c programul de mai sus se ncadreaz n limitele temporale indicate n restriciile din enunul problemei. n literatura de specialitate se menioneaz c calcularea unei o secvene ce conine un numr minimal de runde este o problem de complexitate non-polinomial. n consecin, n enunul problemei o astfel de sarcin nu a fost inclus. Accentum faptul, c elevii care nu cunosc metoda Greedy trebuie s ncerce s obin un anumit numr de puncte prin implementarea unor abordri euristice. Faptul c astfel de soluii sunt acceptabile rezult din algoritmul de acordare a punctelor, inclus n enunul problemei.

52

Punctajul acumulat de fiecare competitor

Parcare, 10-12
100 90 80 70 60 50 40 30 20 10 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

500 450 400 350 300 250 200 150 100 50 0

Not: Pe orizontal sunt competitorii, simbolizai prin numerele 1, 2, 3, ... .a.m.d., iar pe vertical punctajul fiecruia din ei

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96 101 106 111

Punctajul total acumulat de fiecare competitor

Total, 10-12

53