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

doctor habilitat, profesor universitar, Institutul de Politici Publice.

Ion Bolun

doctor habilitat, profesor universitar, Academia de Studii


Economice a Moldovei.

Iurie Mocanu

ef de direcie, Ministerul Educaiei.

Angela Priscaru

consultant, Ministerul Educaiei.

Dumitru Ciubati

informatician.

Constantin Dolghieru

informatician.

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

Imagini

Blocuri de
piatr

Formule

Ferestre

Parcare auto

Total

Numrul de
puncte alocat
problemei

Denumirea
fiierului surs

Denumirea
fiierului de
intrare

Denumirea
fiierului de
ieire

100

CEAS.PAS
CEAS.C
CEAS.CPP

CEAS.IN

CEAS.OUT

100

IMAGINI.PAS
IMAGINI.C
IMAGINI.CPP

IMAGINI.IN

IMAGINI.OUT

100

BLOCURI.PAS
BLOCURI.C
BLOCURI.CPP

BLOCURI.IN

BLOCURI.OUT

100

FORMULE.PAS
FORMULE.C
FORMULE.CPP

FORMULE.IN

FORMULE.OUT

100

FERESTRE.PAS
FERESTRE.C
FERESTRE.CPP

FERESTRE.IN

FERESTRE.OUT

100

PARCARE.PAS
PARCARE.C
PARCARE.CPP

PARCARE.IN

PARCARE.OUT

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;

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

integer;
:='00';
:='01';
:='02';
:='03';
:='04';
:='05';

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

MM[1]
MM[2]
MM[3]
MM[4]
MM[5]
MM[6]

:='00';
:='10';
:='20';
:='30';
:='40';
:='50';

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

IMAGINI.OUT
0
0
1
0
1
0
1

1
0
0
0
1
0
1

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

BLOCURI.OUT

3 7

5 3 6

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

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

FORMULE.OUT

1+3014-4+629/1235-3*2
+1+3469
4509/293+1

DA
NU
DA

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

Exemplul 2.
FERESTRE.OUT
3

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

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

FERESTRE.OUT
1

17

FERESTRE.OUT
3

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

Denumirea
problemei

Numrul de
puncte alocat
problemei

12

Denumirea
fiierului surs

Denumirea
fiierului de
intrare

Denumirea
fiierului de
ieire

Ceasul

100

CEAS.PAS
CEAS.C
CEAS.CPP

CEAS.IN

CEAS.OUT

Imagini

100

IMAGINI.PAS
IMAGINI.C
IMAGINI.CPP

IMAGINI.IN

IMAGINI.OUT

Blocuri de
piatr

100

BLOCURI.PAS
BLOCURI.C
BLOCURI.CPP

BLOCURI.IN

BLOCURI.OUT

100

FORMULE.PAS
FORMULE.C
FORMULE.CPP

FORMULE.IN

FORMULE.OUT

100

FERESTRE.PAS
FERESTRE.C
FERESTRE.CPP

FERESTRE.IN

FERESTRE.OUT

100

PARCARE.PAS
PARCARE.C
PARCARE.CPP

PARCARE.IN

PARCARE.OUT

Formule

Ferestre

Parcare auto

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

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

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

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

IMAGINI.OUT
0
0
1
0
1
0
1

1
0
0
0
1
0
1

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

31

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 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

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

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

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

BLOCURI.OUT

3 7

5 3 6

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

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

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

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

39

Formule
Se consider urmtoarele formule metalingvistice:
Cifr :: = 0 1 2 3 4 5 6 7 8 9
Numr :: = Cifr

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

FORMULE.OUT

1+(3-4)+6/12-3*2
+1+
4/(3435+(684-2)*11)

DA
NU
DA

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

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

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

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

Exemplul 2.
FERESTRE.OUT
3

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

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

FERESTRE.OUT
1

43

FERESTRE.OUT
3

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

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

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

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

PARCARE.OUT

10 4 4

2 3 3 4 4 2 1 1 3 1

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

N /(W 1) .

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

1,25 Q

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

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

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

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

Punctajul total acumulat de fiecare competitor

Total, 10-12

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

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

53

S-ar putea să vă placă și