Sunteți pe pagina 1din 64

MINISTERUL EDUCAÞIEI AL REPUBLICII MOLODOVA

Academia de Studii Economice din Moldova

Colegiul Republican de Informaticã

Olimpiada Republicană
la Informatică
(EDIŢIA 2003)

Chişinău, 2003
Olimpiada Republicanã la Informaticã. Ediþia 2003. Chiºinãu: Editura
ASEM, 2003. –64 p.

Lucrarea conþine problemele propuse la Olimpiada Republicanã la


Informaticã a elevilor, ediþia 2003, ºi unele informaþii despre Academia de
Studii Economice din Moldova – gazda Olimpiadei. Pentru toate problemele în
lucrare sunt descrise ºi soluþiile.
Materialele Olimpiadei pot fi de un real folos la studierea informaticii atât
elevilor, cât ºi profesorilor de informaticã, iar informaþiile despre Academia de
Studii Economice pot fi utile, de asemenea, elevilor, îndeosebi absolvenþilor de
ºcoli ºi licee din Republica Moldova.

Colegiul de redacþie:

Anatol Gremalschi, doctor habilitat, profesor universitar, UTM


Ion Bolun, doctor habilitat, profesor universitar, ASEM
Iurie Mocanu, Ministerul Educaþiei
Dumitru Codreanu, Universitatea Tehnicã, Bucureºti.

 Editura ASEM, 2003.

2
CUPRINS

Cuvînt înainte 5

1. Ziua 1
Clasele 7-9 8

Calcule 9
Cifru 11
Domino 15

Clasele 10-12 20

Calcule 21
Cifristul 23
Domino 27

2. Ziua 2
Clasele 7-9 35

Votul 36
Metroul 40
Roboþii 45

Clasele 10-12 48

Votul 49
Metroul 53
Cina 59

3
4
Dragi elevi,
Stimaþi profesori,
Informatica ne schimbã viaþa, uneori într -un mod
într-un
cu totul neaºteptat chiar ºi pentru cei iniþiaþi în domeniu.
Pentru a stãpîni schimbarea, pentru a fi competitivi, pentru
a beneficia din roadele acestei ºtiinþe, trebuie sã cunoaºtem
ºi sã putem aplica întregul arsenal de metode ºi tehnici
informaþionale studiate în ºcoalã.
Olimpiadele R epublicane la Informaticã au drept
Republicane
scop suprem atragerea elevilor în competiþii deschise ºi
oneste, educarea culturii informaþionale ºi a gîndirii
algoritmice, focalizarea interesului public pe tehnologiile
de vîrf
vîrf,, atragerea tineretului studios în domeniile de
perspectivã, atît în ºtiinþã, cît ºi pe piaþa muncii.
Sînt sigur cã pe parcursul competiþiilor
competiþiilor,, elevii ºi
profesorii au iniþiat noi colabor
colaborãã ri, au descoperit metode
originale de predare-învãþare, au ffãcut
ãcut un util schimb de
experienþã. Am cîºtigat noi cu toþii, cei care iubim atît
de mult Informatica.
Mulþumim din suflet tuturor participanþilor la
Olimpiadã pentru activismul manifestat ºi le dorim mari
succese în viitor
viitor..
În numele Consiliului Olimpic la Informaticã,
Anatol Gremalschi,
doctor habilitat,
profesor universitar, UTM

5
Ministerul Educaţie al Republicii Moldova

Olimpiada Republicană la Informatică


Chişinău 2003

Instrucţiune

I. Fiºiere ºi directoare

I.1. Dupã terminarea lucrului, participantul va transmite oficialului numai fiºierele sursã
ale programelor, câte unul pentru fiecare problemã.

I.2. Fiºierele sursã vor avea acelaºi nume ca ºi fiºierele de intrare/ieºire. De exemplu în
cazul fiºierelor de intrare/ieºire numite SORTARE.IN ºi SORTARE.OUT, fiºierul sursã
se va numi SORTARE.PAS, SORTARE.C, sau SORTARE.CPP.

I.3. Fiºierele sursã se vor afla într-un director cu numele format din primele 7 litere ale
numelui de familie, plus prima literã a numelui. De exemplu pentru elevul Tudor
Mãrgineanu, directorul se va numi MARGINET. Pentru elevul Tudor Roºu, directorul se
va numi ROSUT. Denumirile de directoare sînt indicate în fiºa de înregistrare.

II. Intrãri ºi ieºiri

II.1. Programul va citi ºi va scrie toate datele din fiºierele text indicate, cu excepþia
cazurilor în care se indicã altfel în enunþul problemei.

II.2. Fiºierele de intrare/ieºire vor fi citite/scrise în catalogul curent, evitându-se


introducerea cãilor absolute sau relative de acces. De exemplu, în cazul limbajului
Pascal ºi a fiºierului SORTARE.IN se va utiliza apelul assign(f,’sortare.in’). Pentru un
program în limbajul C se va utiliza apelul f=fopen(“sortare.in”,”rt”).

II.3. Programul nu va scrie nimic pe ecran, nu va citi nimic de la tastatura, nu va lucra cu


alte fiºiere, cu excepþia cazurilor în care se indicã altfel în enunþul problemei.

6
III. Limbaje de programare

III.1. Programul va utiliza numai mijloacele standard ale limbajului respectiv, evitându-se
includerea codului Asamblor, codului de maºinã, apelurilor de întreruperi, scrierea în
porturi, schimbarea timpului curent, scrierea directã în memorie, apelul altor programe,
funcþii ale sistemului de operare ºi altor posibilitãþi nestandard.

III.2. Programul Pascal va utiliza numai unit-ul system care este încãrcat de compilator
automat. Includerea altor unit-uri prin utilizarea clausei uses este interzisã, cu excepþia
cazurilor special prevãzute în enunþul problemei.
III.3. Soluþiile competitorilor nu vor include nici un fel de directive de compilare care
altereazã opþiunile prestabilite de compilare.

III.4. Competitorilor le vor fi puse la dispoziþie fiºierele C_PAS.BAT, C_CPP.BAT care vor
compila soluþiile lor cu exact aceleaºi opþiuni ca ºi în cadrul evaluãrii. Mediile integrate
vor fi configurate pentru a reflecta cât mai precis opþiunile de compilare din cadrul
evaluãrii.

IV. Alte restricþii

IV.1. Competitorul va lucra numai în mediul DOS oferit de organizatori, utilizând


programele DN, TP, TC. Utilizarea altor programe, inclusiv Windows este interzisã.

IV.2. În cazul încãlcãrii cerinþelor de mai sus, participantul poate fi sancþionat cu anularea
rezultatului pentru problema în cauzã, pentru ziua respectivã, sau cu înlãturarea de la
competiþie.

7
Ziua 1

Clasele 7-9

Descrierea problemelor

Numărul de Denumirea
Denumirea Denumirea Denumirea
puncte alocat fişierului de
problemei fişierului sursă fişierului de ieşire
problemei intrare

CALCULE.PAS
Calcule 100 CALCULE.C CALCULE.IN CALCULE.OUT
CALCULE.CPP

CIFRU.PAS
Cifru 100 CIFRU.C CIFRU.IN CIFRU.OUT
CIFRU.CPP

DOMINO.PAS
Domino 100 DOMINO.C DOMINO.IN DOMINO.OUT
DOMINO.CPP

Total 300 - - -

8
Calcule din antichitate

Se presupune cã unele din primele instrumente de calcul din antichitate au fost


degetele de la propriile mîini ºi beþiºoarele de socotit. Din punctul de vedere al ºtiinþei
moderne, calculele cu ajutorul beþiºoarelor de socotit pot fi descrise cu ajutorul
urmãtoarelor formule metalingvistice:

<Cifră> := I
<Număr> := <Cifră><Număr><Cifră>
<Semn> := +-
<Expresie> := <Număr><Număr><Semn><Expresie>

Exemple:
Numere Expresii
I III
III II-III
IIIIIIIIIII I+I-III+IIIIIII

Elaboraþi un program care evalueazã astfel de expresii.

Date de intrare.
Fiºierul text CALCULE.IN conþine pe o singurã linie un ºir de caractere –
expresia supusã evaluãrii.

Date de ieºire.
Fiºierul text CALCULE.OUT va conþine pe o singurã linie un numãr întreg zecimal
– rezultatul evaluãrii expresiei din fiºierul de intrare.

Exemplu.
CALCULE.IN CALCULE.OUT

I+I-III+IIIIIII 6

Restricþii.
O expresie poate include cel mult 250 de caractere. Timpul de execuþie nu va
depãºi 1 secundã. Fiºierul sursã va avea denumirea CALCULE.PAS,
CALCULE.C sau CALCULE.CPP.

9
Rezolvare

Program Calcule;
{ Clasele 7-9 }
var Expresie : string;
Intrare, Iesire : text;

function Evaluare(Expresie:string):integer;
var v : integer; { valoarea curenta a expresiei}
i : 1..256; { pozitia caracterului curent
in expresie }
Semn : char;
begin
v:=0;
Semn:=’+’;
for i:=1 to length(Expresie) do
case Expresie[i] of
’I’: if Semn=’+’ then v:=v+1 else v:=v-1;
’+’: Semn:=’+’;
’-’: Semn:=’-’;
end;
Evaluare:=v;
end; { Evaluare }

begin
assign(Intrare, ’CALCULE.IN’);
reset(Intrare);
readln(Intrare, Expresie);
close(Intrare);
assign(Iesire, ’CALCULE.OUT’);
rewrite(Iesire);
writeln(Iesire, Evaluare(Expresie));
close(Iesire);
end.

10
Cifru

Pentru a pãstra secretul corespondenþei, informaticienii Vasilicã ºi Petricã au elaborat


un algoritm de cifrare, care, în opinia lor, este foarte sigur. Mesajul ce trebuie cifrat
reprezintã un ºir de caractere imprimabile ale codului ASCII, farã spaþii, cu lungimea n.
Pentru a-l cifra, Vasilicã foloseºte un ºablon în formã de tabel cu m rînduri, m ≤ n,
numãrul de coloane stabilindu-se în procesul cifrãrii (vezi fig. 1). În fiecare celulã a
tabelului poate fi înscris cîte un singur caracter. Iniþial toate celulele tabelului conþin cîte
un spaþiu.
1 P G M E
2 R R A
m=3 O A R

Fig. 1.

În procesul cifrãrii, Vasilicã înscrie mesajul iniþial în tabel, cîte un caracter în fiecare
celulã, de sus în jos, pe coloane. Dupã completarea primei coloane, se trece la coloana
a doua º.a.m.d., pînã cînd tot mesajul va fi înscris în tabel. Pentru exemplificare, în
tabelul din figurã este înscris mesajul PROGRAMARE. Dupã completarea tabelului,
Vasilicã formeazã mesajul cifrat, copiind în acest scop conþinutul tabelului, celulã dupã
celulã, pe rînduri, rîndurile tabelului fiind selectate într-o anumitã ordine. Ordinea de
explorare a rîndurilor din tabel reprezintã cheia de descifrare, care se anexeazã la
mesajul cifrat. De exemplu, în cazul tabelului din fig. 1 ºi cheia (2, 3, 1), rîndurile vor fi
explorate în ordinea 2, 3 ºi 1, iar mesajul cifrat este

RRA OAR PGME

Primind cheia ºi mesajul cifrat, Petricã completeazã un tabel similar, de data aceasta
pe rînduri, de la stînga la dreapta, selectînd ordinea rîndurilor conform cheiei de
descifrare. Dupã completarea tabelului, Petricã copie caracterele din celule, coloanã
dupã coloanã, de sus în jos, obþinînd astfel mesajul iniþial.

Elaboraþi un program care, cunoscînd cheia ºi mesajul cifrat, reconstituie mesajul iniþial.

11
Date de intrare.
Fiºierul text CIFRU.IN constã din trei linii. Pe prima line este înscris numãrul
rîndurilor m. Linia a doua a fiºierului de intrare conþine m numere naturale ce
reprezintã cheia cifrului. Linia a treia conþine un ºir de caractere - mesajul cifrat.

Date de ieºire.
Fiºierul text CIFRU.OUT va conþine pe o singurã linie mesajul descifrat.

Exemplu.

CIFRU.IN CIFRU.OUT
3 PROGRAMARE
2 3 1
RRA OAR PGME

Restricþii.
n ≤ 200. Timpul de execuþie nu va depãºi 1 secundã. Fiºierul sursã va avea
denumirea CIFRU.PAS, CIFRU.C sau CIFRU.CPP.

12
Rezolvare

Program Cifru;
var n,m,t:longint;
A:array[0..400] of char;
B:array[0..200,0..200] of char;
r:array[0..400] of integer;
Result:array[0..400] of char;
num:integer;

procedure Citire;
var f:text;
i:integer;
begin
assign(f,’cifru.in’); reset(f);
readln(f,m);
for i:=1 to m do read(f,r[i]); readln(f);
while not(eoln(f)) do begin t:=t+1;read(f,A[t]);
end;
n:=t div m;
close(f);
end;

procedure Decodificare;
var k,i,j:integer;
begin
k:=1;
for i:=1 to m do
begin
for j:=1 to n do begin B[r[i],j]:=A[k];inc(k);
end;
end;
num:=0;
for j:=1 to n do
for i:=1 to m do
begin num:=num+1; Result[num]:=B[i,j]; end;
while Result[num]=’ ’ do dec(num);
end;

13
procedure Afisare;
var i,j:integer;
f:text;
begin
assign(f,’cifru.out’); rewrite(f);
for i:=1 to num do write(f,Result[i]);
writeln(f);
close(f);
end;

begin
Citire;
Decodificare;
Afisare;
End.

14
Domino

În jocul Domino se utilizeazã 28 de piese distincte plate, dreptunghiulare. Fiecare piesã


se identificã prin douã numere, simbolizate prin puncte (figura 1). Însemnarea acestor
numere pe fiecare placã se efectueazã prin divizarea feþei respective în douã pãrþi
egale, fiecare numãr fiind din mulþimea {0, 1, 2, 3, 4, 5, 6}.

Fig. 1 Fig. 2

Utilizînd n piese distincte de domino în calitate de vagoane imaginare, pe masã de


joc se construieºte un “tren” (fig. 2a). Trenul construit se numeºte tren perfect dacã
cele douã numere de pe pãrþile vecine ale oricãror douã piese adiacente sînt egale între
ele (fig. 2b). În unele cazuri, un tren obiºnuit poate fi transformat în unul perfect prin
rotaþia cu 180° a anumitor piese. De exemplu, trenul perfect din fig. 2b poate fi obþinut
din trenul obiºnuit din fig. 2a prin rotaþia celor douã piese indicate cu sãgeatã.

Elaboraþi un program care transformã, daca-i posibil, un tren obiºnuit în unul perfect.

Date de intrare.
Fiºierul text DOMINO.IN conþine pe prima linie numãrul de piese n. Urmãtoarele
n linii ale fiºierului de intrare conþin cîte douã numere întregi separate prin spaþiu,
fiecare linie reprezentînd o piesã de domino. Piesele sînt listate în ordinea apariþiei
lor în tren.

Date de ieºire.
Fiºierul text DOMINO.OUT va conþine pe prima linie cuvîntul DA dacã trenul din
fiºierul de intrare poate fi transformat în unul perfect ºi NU în caz contrar. În cazul
rãspunsului DA, urmãtoarele n linii ale fiºierului de ieºire vor conþine cîte douã
numere întregi separate prin spaþiu, fiecare linie reprezentînd o piesã de domino.
Piesele vor fi listate în ordinea apariþiei lor în fiºierul de intrare, astfel încît cele douã
numere de pe pãrþile vecine ale oricãror douã piese adiacente sã fie egale între ele.

15
Exemplu.
DOMINO.IN DOMINO.OUT
4 DA
2 1 1 2
2 6 2 6
5 6 6 5
5 4 5 4

Restricþii.
1 ≤ n ≤ 28. Timpul de execuþie nu va depãºi 1 secundã. Fiºierul sursã va avea
denumirea DOMINO.PAS, DOMINO.C sau DOMINO.CPP.

16
Rezolvare

Vom identifica piesele trenului prin perechile ordonate (ai, bi), i = 1, 2, ..., n. Evident,
operaþia de rotire a piesei i poate fi redatã prin notaþia (ai, bi) → (bi, ai).
Presupunem cã trenul iniþial poate fi transformat în unul perfect. În aceste condiþii sînt
posibile urmãtoarele cazuri:
a) piesa i = 1 ºi-a pãstrat poziþia iniþialã (ai, bi);
b) piesa i = 1 a fost rotitã, avînd în trenul perfect poziþia (bi, ai).
În continuare, vom încerca sã construim trenul perfect pentru cazurile a) ºi b) separat,
rotind, în caz de necesitate, piesele 2, 3, ..., n.
Admitem, cã în procesul examinãrii consecutive a pieselor din componenþa trenului,
piesele i =1, 2, ..., k –1 ºi-au ocupat deja poziþia lor corectã ºi se examineazã piesa k.
Evident, sînt posibile urmãtoarele cazuri:
1) bk-1 = ak. Evident, piesa k ocupã poziþia corectã. Se trece la piesa k + 1.
2) bk-1 = bk. În acest caz piesa k trebuie rotitã: (ak, bk) → (bk, ak). În continuare se
trece la piesa k + 1.
3) bk-1 ≠ ak, bk-1 ≠ bk. Evident, trenul nu poate fi transformat în unul perfect. Stop.
Accentuãm, cã piesa k – 1, care se aflã înaintea piesei curente k, nu mai poate fi
rotitã, întrucît poziþia ei este determinatã de poziþia piesei k – 2, poziþia cãreia, la rîndul
ei, este determinatã de poziþia piesei k – 3 º.a.m.d., pînã la piesa 1.
În programul ce urmeazã, fiecare piesã de domino este reprezentatã cu ajutorul tipului
de date
Piesa = record
a, b : 0..6;
end;

iar trenul T - cu ajutorul variabilei

T : array[1..28] of Piesa;

Evident,algoritmulcareverificãcondiþile1)–3)ºiroteºte,încazdenecesitate,
piesele respective, poate fi realizat printr-o singurã parcurgere a tabloului T.

17
Program Domino;
{ Clasele 7-9 }
type Piesa = record
a, b : 0..6;
end;
var T : array[1..28] of Piesa; { trenul }
n : 1..28; { numarul de vagoane in tren }
Perfect : boolean;
c : integer; { variabila de lucru }

procedure Citeste;
{ Citirea datelor din fisierul de intrare }
var i : integer;
Intrare : text;
begin
assign(Intrare, ’DOMINO.IN’);
reset(Intrare);
readln(Intrare, n);
for i:=1 to n do
readln(Intrare, T[i].a, T[i].b);
close(Intrare);
end; { Citeste }

procedure Scrie;
{ Scrierea datelor in fisierul de iesire }
var i : integer;
Iesire : text;
begin
assign(Iesire, ’DOMINO.OUT’);
rewrite(Iesire);
if not Perfect then writeln(Iesire, ’NU’)
else begin
writeln(Iesire, ’DA’);
for i:=1 to n do
writeln(Iesire, T[i].a, ’ ’, T[i].b);
end; { else }
close(Iesire);
end; { Scrie }

18
procedure Transforma;
var j, k : integer;
begin
Perfect:=true;
k:=2;
while ((k<=n) and Perfect) do
begin
if ((T[k-1].b<>T[k].a) and (T[k-1].b<>T[k].b))
then Perfect:=false;
if (T[k-1].b=T[k].b) then
begin
{ rotim piesa T[k] }
j:=T[k].a; T[k].a:=T[k].b; T[k].b:=j;
end; { then }
k:=k+1;
end; { while }
end; { Transforma }

begin
Citeste;
Transforma;
if not Perfect then
begin
{ rotim prima piesa }
c:=T[1].a; T[1].a:=T[1].b; T[1].b:=c;
Transforma;
end; { then }
Scrie;
end.

19
Ziua 1

Clasele 10 - 12

Descrierea problemelor

Numărul de Denumirea Denumirea


Denumirea Denumirea
puncte alocat fişierului de fişierului de
problemei fişierului sursă
problemei intrare ieşire
CALCULE.PAS
Calcule 100 CALCULE.C CALCULE.IN CALCULE.OUT
CALCULE.CPP

CIFRIST.PAS
Cifristul 100 CIFRIST.C CIFRIST.IN CIFRIST.OUT
CIFRIST.CPP

DOMINO.PAS
Domino 100 DOMINO.C DOMINO.IN DOMINO.OUT
DOMINO.CPP

Total 300 - - -

20
Calcule din antichitate

Se presupune cã unele din primele instrumente de calcul din antichitate au fost


degetele de la propriile mîini ºi beþiºoarele de socotit. Din punctul de vedere al ºtiinþei
moderne, calculele cu ajutorul beþiºoarelor de socotit pot fi descrise cu ajutorul
urmãtoarelor formule metalingvistice:

<Cifră> := I
<Număr> := <Cifră><Număr><Cifră>
<Semn> := +-
<Expresie> := <Număr><Număr><Semn><Expresie>

Exemple:
Numere Expresii
I III
III II-III
IIIIIIIIIII I+I-III+IIIIIII

Elaboraþi un program care evalueazã astfel de expresii.

Date de intrare.
Fiºierul text CALCULE.IN conþine pe o singurã linie un ºir de caractere –
expresia supusã evaluãrii.

Date de ieºire.
Fiºierul text CALCULE.OUT va conþine pe o singurã linie un numãr întreg zecimal
– rezultatul evaluãrii expresiei din fiºierul de intrare.

Exemplu.
CALCULE.IN CALCULE.OUT

I+I-III+IIIIIII 6

Restricþii.
O expresie poate include cel mult 32000 de caractere. Timpul de execuþie nu va
depãºi 1 secundã. Fiºierul sursã va avea denumirea CALCULE.PAS,
CALCULE.C sau CALCULE.CPP.

21
Rezolvare

Program Calcule; { Clasele 10-12 }


var Expresie : array [1..32000] of char;
n : 0..32000; {numarul de caractere in Expresie}
Intrare, Iesire : text;

function Evaluare : integer;


var v : integer; { valoarea curenta a expresiei }
i : 1..32000; { pozitia caracterului curent in
expresie }
Semn : char;
begin
v:=0;
Semn:=’+’;
for i:=1 to n do
case Expresie[i] of
’I’: if Semn=’+’ then v:=v+1 else v:=v-1;
’+’: Semn:=’+’;
’-’: Semn:=’-’;
end;
Evaluare:=v;
end; { Evaluare }

begin
assign(Intrare, ’CALCULE.IN’);
reset(Intrare);
n:=0;
while not Eoln(Intrare) do
begin
n:=n+1;
read(Intrare, Expresie[n]);
end;
close(Intrare);
assign(Iesire, ’CALCULE.OUT’);
rewrite(Iesire);
writeln(Iesire, Evaluare);
close(Iesire);
end.

22
Cifristul

Cifristul este un informatician care îºi cifreazã datele chiar ºi în cazurile cînd acest
lucru nu este necesar. Mai mult chiar, fiind distrat, el permanent uitã parolele, algoritmii
de descifrare, cheile cifrului º.a.m.d. Ultima lui invenþie reprezintã urmãtorul algoritm de
cifrare a mesajelor.
Mesajul iniþial reprezintã un ºir de caractere imprimabile ale codului ASCII, farã
spaþii, cu lungimea n. Pentru a cifra acest mesaj, cifristul foloseºte un ºablon în formã
de tabel cu m rînduri, m ≤ n, numãrul de coloane stabilindu-se în procesul cifrãrii (vezi
fig. 1). În fiecare celulã a tabelului poate fi înscris cîte un singur caracter. Iniþial toate
celulele tabelului conþin cîte un spaþiu.

1 P G M E
2 R R A
m=3 O A R

Fig. 1.

Mesajul iniþial se înscrie în tabel, cîte un caracter în fiecare celulã, de sus în jos, pe
coloane. Dupã completarea primei coloane, se trece la coloana a doua º.a.m.d., pînã
cînd tot mesajul va fi înscris în tabel. Pentru exemplificare, în tabelul din figurã este
înscris mesajul PROGRAMARE. Dupã completarea tabelului, se compune mesajul
cifrat, copiind în acest scop conþinutul tabelului, celulã dupã celulã, de la stînga la
dreapta, rîndurile tabelului fiind citite de sus în jos. De exemplu, în cazul tabelului din
fig. 1 mesajul cifrat este
PGMERRA OAR

iar numãrul m = 3 este cheia cifrului.

Pentru a descifra mesajul, cunoscînd cheia m, se construieºte un tabel cu m rînduri,


în celulele cãruia se înscrie mesajul cifrat, de data aceasta pe rînduri, de la stînga la
dreapta, de sus în jos. Dupã completarea tabelului, mesajul iniþial este reconstituit
copiind caracterele din celule, de sus în jos, coloanã dupã coloanã, de la stînga la
dreapta.
Fiind distrat, cifristul permanent uitã cheia cifrului, prin alte cuvinte, numãrul de
rînduri m ºi nu mai are acces la propriile date.
Elaboraþi un program care, cunoscînd mesajul iniþial ºi mesajul cifrat, calculeazã
cheia cifrului m.

23
Date de intrare.
Fiºierul text CIFRIST.IN constã din douã linii. Pe prima linie este înscris un ºir
de caractere - mesajul iniþial, iar pe a doua un alt ºir de caractere - mesajul cifrat.

Date de ieºire.
Fiºierul text CIFRIST.OUT va conþine pe o singurã linie cheia cifrului - numãrul
natural m.

Exemplu.

CIFRIST.IN CIFRIST.OUT

PROGRAMARE 3
PGMERRA OAR

Restricþii.
n ≤ 200. Timpul de execuþie nu va depãºi 2 secunde. Fiºierul sursã va avea
denumirea CIFRIST.PAS, CIFRIST.C sau CIFRIST.CPP.

24
Rezolvare

Program Cifristul;
var s,cifr:array[0..400] of char;
l,m,n:integer;

procedure Citire;
var f:text;
i:integer;
c:char;n1:integer;
begin
n1:=0;
assign(f,’cifrist.in’); reset(f);
while not eoln(f) do begin read(f,c);
inc(n1);s[n1]:=c; end;
readln(f);
l:=0;while not eoln(f) do
begin
read(f,c); inc(l);cifr[l]:=c;
end;
for i:=n1+1 to l do s[i]:=’ ’;
close(f);
end;

procedure Decodificare;
var i,j:integer; ok:boolean;
begin
m:=0;
repeat m:=m+1;
ok:=false;
if (l mod m)<>0 then continue;
ok:=true; n:=l div m;
for i:=1 to m do
begin
for j:=1 to n do
begin
if s[(j-1)*m+i]<>cifr[(i-1)*n+j] then
ok:=false;
if not(ok) then break;
end;
25
if not(ok) then break;
end;
if m>l then break;
until ok;
end;

procedure Afisare;
var i,j:integer;
f:text;
begin
assign(f,’Cifrist.out’); rewrite(f);
writeln(f,m);
close(f);
end;

begin
Citire;
Decodificare;
Afisare;
End.

26
Domino

În jocul Domino se utilizeazã 28 de piese distincte plate, dreptunghiulare. Fiecare


piesã se identificã prin douã numere, simbolizate prin puncte (figura 1). Însemnarea
acestor numere pe fiecare placã se efectueazã prin divizarea feþei respective în douã
pãrþi egale, fiecare numãr fiind din mulþimea {0, 1, 2, 3, 4, 5, 6}.

Fig. 1 Fig. 2
Utilizînd n piese distincte de domino în calitate de vagoane imaginare, pe masa de
joc poate fi construit un “tren” cu proprietatea ca cele douã numere de pe pãrþile vecine
ale oricãror douã piese adiacente sînt egale între ele (figura 2). Lungimea trenului se
defineºte prin numãrul de piese m din componenþa lui. Evident, m ≤ n.

Elaboraþi un program care calculeazã numãrul de plãci într-un “tren” de lungime


maximã, ce poate fi construit din n plãci distincte de domino.

Date de intrare.
Fiºierul text DOMINO.IN conþine pe prima linie numãrul de piese n. Urmãtoarele
n linii ale fiºierului de intrare conþin cîte douã numere întregi separate prin spaþiu,
fiecare linie reprezentînd o piesã de domino.

Date de ieºire.
Fiºierul text DOMINO.OUT va conþine pe prima linie numãrul de piese m într-un
tren de lungime maximã. Urmãtoarele m linii ale fiºierului de ieºire vor conþine cîte
douã numere întregi separate prin spaþiu, fiecare linie reprezentînd o piesã de
domino. Piesele vor fi listate în ordinea apariþiei lor în tren, astfel încît cele douã
numere de pe pãrþile vecine ale oricãror douã piese adiacente sînt egale între ele.

27
Exemplu.

DOMINO.IN DOMINO.OUT

4 3
3 6 0 3
3 5 3 6
3 0 6 6
6 6

Restricþii.
1 ≤ n ≤ 10. Timpul de execuþie nu va depãºi 5 secunde. Fiºierul sursã va avea
denumirea DOMINO.PAS, DOMINO.C sau DOMINO.CPP.

28
Rezolvare

Pentru a calcula numãrul de piese din componenþa unui tren de lungime maximã,
vom examina consecutiv toate trenurile posibile ce pot fi construite din piesele date. În
acest scop vom simula pe calculator acþiunile jucãtorului în domino. Introducem în
studiu douã mulþimi ordonate:
C0 - mulþimea pieselor disponibile;
X - trenul în curs de construcþie.
Se observã cã mulþimea X poate fi construitã pas cu pas, alegînd din mulþimea
pieselor disponibile cîte una care satisface condiþiile problemei:
1) Iniþial includem în mulþimea X prima piesã din mulþimea C0: X := (x1). Evident,
aceastã piesã trebuie exclusã din mulþimea pieselor disponibile: C1 := C0 \ {x1}.
2) Alegem din mulþimea pieselor rãmase C1 prima piesã care satisface condiþiile
problemei ºi stabilim: X := (x1, x2); C2 := C1 \ {x2}.
3) Presupunem cã acest proces a ajuns la pasul k, în mulþimea X fiind deja incluse
k-1 piese:
X = (x1, x2, ..., xk-1).

În continuare sînt posibile urmãtoarele cazuri:


A) În mulþimea pieselor rãmase Ck-1 mai existã piese care satisfac condiþiile
problemei. În astfel de cazuri stabilim
X := (x1, x2, ..., xk-1, xk), Ck := Ck-1 \ {xk}
ºi continuãm calculele.
B) În mulþimea Ck-1 nu mai existã piese care satisfac condiþiile problemei. Evident,
am obþinut un tren la care nu mai putem ataºa alte vagoane. Memorãm lungimea
acestui tren ºi revenim la pasul precedent, unde încercãm sã alegem din
mulþimea Ck-2 altã piese xk-1. Dacã în mulþimea Ck-2 astfel de piese nu mai existã,
revenim la mulþimea Ck-3 º.a.m.d.

Evident, algoritmul care simuleazã acþiunile jucãtorului poate fi realizat prin metoda
reluãrii, utilizînd în acest scop recursia.
În programul ce urmeazã, fiecare piesã de domino este reprezentatã cu ajutorul
tipului de date
Piesa = record
a, b : 0..6;
end;

29
iar mulþimile C ºi X - cu ajutorul structurilor

MultimePiese = record
k : integer;
p : array[1..28] of Piesa;
end;
Tren=MultimePiese;

Metoda reluãrii este realizatã în procedura cu acelaºi nume, iar trenul de lungime
maximã este memorat în variabila Xmax.

30
Program Domino; { Clasele 10-12 }
type Piesa=record
a, b : 0..6;
end;
MultimePiese=record
k : integer;
p : array[1..28] of Piesa;
end;
Tren=MultimePiese;
var n : integer;
C : MultimePiese;
X, Xmax : Tren;

procedure Citeste(var C : MultimePiese;


var n : integer);
{ Citirea datelor din fisierul de intrare }
var i : integer;
Intrare : text;
begin
assign(Intrare, ’DOMINO.IN’);
reset(Intrare);
readln(Intrare, n);
C.k:=n;
for i:=1 to n do
readln(Intrare, C.p[i].a, C.p[i].b);
close(Intrare);
end; { Citeste }

procedure Scrie(X : Tren);


{ Scrierea datelor in fisierul de iesire }
var i : integer;
Iesire : text;
begin
assign(Iesire, ’DOMINO.OUT’);
rewrite(Iesire);
writeln(Iesire, X.k);
for i:=1 to X.k do
writeln(Iesire, X.p[i].a, ’ ’, X.p[i].b);

31
close(Iesire);
end; { Scrie }

procedure AdaugaVagonul(var X : Tren; Q : Piesa);


{ Adauga vagonul Q la trenul X }
begin
X.k:=X.k+1;
X.p[X.k]:=Q;
end;

procedure ScoateVagonul(var X : Tren);


{ Scoate din trenul X ultimul vagon }
begin
X.k:=X.k-1;
end; { ScoateVagonul}

procedure ExcludePiesa(var Z : MultimePiese;


i : integer);
{ Exclude din multimea Z piesa i }
var j : integer;
begin
for j:=i to Z.k-1 do Z.p[j]:=Z.p[j+1];
Z.k:=Z.k-1;
end; { ExcludePiesa }

function Corespunde(X : MultimePiese; var Q : Piesa)


: boolean;
{ Returneaza TRUE daca vagonul Q poate fi atasat la
trenul X }
{ In caz de necesitate, roteste piesa Q }
label 1;
var i : integer;
begin
if X.k=0 then
begin
Corespunde:=true;
goto 1;
end; { if }

32
Corespunde:=false;
{ pozitia initiala a placii Q }
if X.p[X.k].b=Q.a then
begin
Corespunde:=true;
goto 1;
end;
if X.p[X.k].b=Q.b then
{ rotim placa Q }
begin
Corespunde:=true;
i:=Q.a;
Q.a:=Q.b;
Q.b:=i;
end;
1: end; { Corespunde }

procedure Reluare(C : MultimePiese; var X : Tren);


var C1 : MultimePiese;
Q : Piesa;
i : integer;
begin
for i:=1 to C.k do
begin
Q:=C.p[i];
if Corespunde(X, Q) then
begin
AdaugaVagonul(X, Q);
if X.k>Xmax.k then Xmax:=X;
C1:=C;
ExcludePiesa(C1, i);
Reluare(C1, X);
ScoateVagonul(X);
end; { if }
end; { for }
end; { Reluare }

33
procedure TrenMaxim(C : MultimePiese; X :Tren);
{ Cauta trenul de lungime maxima }
var i, j : integer;
Xmax : Tren;
begin
Xmax.k:=0;
X.k:=0;
Reluare(C, X);
{ rotim piesele cu care poate incepe trenul }
for i:=1 to C.k do
begin
j:=C.p[i].b; C.p[i].b:=C.p[i].a; C.p[i].a:=j;
end;
X.k:=0;
Reluare(C, X);
end; { Tren }

begin
Citeste(C, n);
TrenMaxim(C, X);
Scrie(Xmax);
end.

Complexitatea temporalã a programului Domino poate fi estimatã luînd în


consideraþie faptul cã numãrul permutãrilor posibile ale unei mulþimi C cu n elemente se
determinã ca Pn = n!. Conform restricþiilor problemei, n = 10, deci P! ≈ 4 × 106, mãrime
care este de acelaºi ordin ca ºi capacitatea de prelucrare a calculatoarelor personale.
Prin urmare, timpul de execuþie va fi de ordinul unei scunde. Întrucît în metoda reluãrii
nu se examineazã în mod obligatoriu toate permutãrile posibile, timpul de execuþie al
programului Domino va fi cu mult mai mic.

34
Ziua 2

Clasele 7-9

Descrierea problemelor

Numărul de Denumirea Denumirea


Denumirea Denumirea
puncte alocat fişierului de fişierului de
problemei fişierului sursă
problemei intrare ieşire

VOT.PAS
Votul 100 VOT.C VOT.IN VOT.OUT
VOT.CPP

METROU.PAS
Metroul 100 METROU.C METROU.IN METROU.OUT
METROU.CPP

ROBOTI.PAS
Roboţi 100 ROBOTI.C ROBOTI.IN ROBOTI.OUT
ROBOTI.CPP

Total 300 - - -

35
Votul

La începuturi, pe o insulã foarte îndepãrtatã, toate deciziile se adoptau la adunarea


generalã a alegãtorilor prin majoritate de voturi. Odatã cu creºterea numãrului de
alegãtori, convocarea adunãrilor generale a devenit practic imposibilã. Pentru a nu
bloca procesul de adoptare a deciziilor s-a convenit ca insula sã fie împãrþitã în
circumscripþii electorale, nu neapãrat cu acelaºi numãr de alegãtori, iar orice proiect de
decizie sã fie supus votului în fiecare circumscripþie separat. Decizia se considerã
adoptatã într-o circumscripþie, dacã pentru ea au votat mai mult de jumãtate din alegãtorii
din circumscripþia respectivã. Decizia se considerã adoptatã pentru întreaga insulã
dacã ea a fost aprobatã în mai mult din jumãtate din numãrul circumscripþiilor.

Evident, dacã în cazul adunãrilor generale deciziile se considerau adoptate numai


atunci cînd pentru ele votau majoritatea alegãtorilor de pe întreaga insulã, în cazul
circumscripþiilor acest lucru nu mai este necesar.

De exemplu, presupunem cã pe insulã locuiesc 17 alegãtori. În cazul adunãrilor


generale, pentru a aproba o decizie sînt necesare 9 voturi pro. Daca însã formãm 3
circumscripþii, ºi anume, prima cu 4, a doua cu 6 ºi a treia circumscripþie cu 7 alegãtori,
pentru adoptarea unei decizii este suficient ca ea sã fie votatã în cel puþin douã
circumscripþii, numãrul necesar de voturi fiind 7.

Scrieþi un program care, cunoscînd numãrul de circumscripþii ºi numãrul de alegãtori


din fiecare circumscripþie, calculeazã numãrul de voturi, necesare pentru adoptarea
unei decizii pentru întreaga insulã.

Date de intrare.
Fiºierul text VOT.IN constã din douã linii. Pe prima line este înscris numãrul
circumscripþiilor n. Linia a doua a fiºierului de intrare conþine n numere întregi
pozitive ce reprezintã numãrul alegãtorilor din fiecare circumscripþie.

Date de ieºire.
Fiºierul text VOT.OUT va conþine pe o singurã linie un numãr natural - numãrul
necesar de voturi.

36
Exemplu.
VOT.IN VOT.OUT
3 7
4 6 7

Restricþii.
n ≤ 1000. Numãrul de alegãtori pe insulã nu depãºeºte valoarea 30000.
Timpul de execuþie nu va depãºi 1 secundã. Fiºierul sursã va avea denumirea
VOT.PAS, VOT.C sau VOT.CPP.

37
Rezolvare

Reprezentãm numãrul de alegãtori din fiecare circumscripþie în forma unui vector


(tablou)
A = (a1, a2, a3, ..., an),

elementele cãruia sînt sortate în ordine crescãtoare:

a1 ≤ a2 ≤ a3 ≤ ... ≤ an.

Se observã cã numãrul minim de voturi m, necesare pentru adoptarea unei decizii


poate fi determinat ca

m = (a1 div 2 +1) + (a2 div 2 +1) +


+(a3 div 2 +1) + ...(ak div 2 + 1),

unde k = (n div 2) +1.

Program Votul;
{ Clasele 7-9 }
var A:array[1..1000] of integer;
n:integer;
vots:longint;

procedure InitData;
{ Citirea datelor de intrare }
var f:text; i:integer;
begin
assign(f,’vot.in’); reset(f);
readln(f,n);
for i:=1 to n do read(f,A[i]);
close(f);
end; { InitData }

procedure BubleSort;
{Sortarea vectorului A prin metoda bulelor }
var i,k,l,t:integer;
begin
l:=n-1;

38
while 1<=l do
begin
k:=0;
for i:=1 to l do
if A[i]>A[i+1] then
begin
t:=A[i]; A[i]:=A[i+1]; A[i+1]:=t;
k:=i;
end;
l:=k-1;
end;
end; { BubleSort }

procedure Calc;
{ Calcularea numarului minim de alegatori }
var i:integer;
begin
for i:=1 to (n div 2) +1 do
vots:=vots+((A[i] div 1)+1);
end; { Calc }

procedure Outputdata;
{ Extragerea datelor de iesire }
var f:text;
begin
assign(f,’vot.out’);
rewrite(f); writeln(f,vots);close(f);
end; { Outputdata }

begin
InitData;
BubleSort;
Calc;
OutputData;
end.

Din analiza procedurilor BubleSort ºi Calc se observã ca numãrul de operaþii


necesare pentru sortarea componentelor vectorului A este proporþional cu n2. Evident,
pentru n ≤ 1000, timpul de execuþie nu va depãºi o secundã.

39
Metroul

Metroul din Londra reprezintã un sistem complex, care transportã zilnic milioane de
pasageri (fig. 1). Din punctul de vedere al pasagerului, metroul poate fi tratat ca o
mulþime de linii de tren ºi o mulþime de staþii. În scopuri didactice, vom nota liniile de tren
prin literele mari A, B, C, D º.a.m.d. ale alfabetului latin, în total n linii, iar staþiile - prin
numerele naturale 1, 2, 3, ..., în total m staþii (fig. 2).

Fig. 1 Fig. 2

Liniile de tren ºi staþiile respective au fost proiectate în aºa fel, încît pasagerul, care
pleacã din orice staþie x, sã poatã ajunge în oricare altã staþie y. Evident, în cazurile în
care staþiile se aflã pe linii diferite, pasagerul este nevoit sã facã una sau mai multe
transbordãri, schimbînd trenul în staþiile în care se întîlnesc douã sau mai multe linii de
tren. De exemplu, pentru a ajunge din staþia 1 în staþia 8 (fig. 2), pasagerul poate sã
facã o singurã transbordare în staþia 2 sau douã transbordãri - prima în staþia 4 ºi a
doua în staþia 6.

În caz de reparaþii, unele staþii de metrou pot fi temporar închise pentru transbordarea
pasagerilor. În astfel de cazuri, nu întotdeauna pasagerul care pleacã din staþia x, poate
sã ajunge în oricare altã staþie y. De exemplu, dacã staþia 5 va fi închisã pentru
transbordãri (fig. 2), pasagerii care pleacã din staþia 1 nu mai pot ajunge în staþia 9. Un
alt exemplu poate servi închiderea staþiei 2, care însã, nu împiedicã pasagerii ce pleacã
din staþia 1 sã ajungã în oricare altã staþie de metrou.

Elaboraþi un program, care, cunoscînd planul metroului, staþia de plecare x, staþia


de sosire y ºi staþia închisã z, determinã dacã pasagerul poate ajunge din x în y.

40
Date de intrare.
Fiºierul text METROU.IN conþine pe prima linie numerele naturale n, m, x,
y, z separate prin spaþiu. Fiecare din urmãtoarele n linii ale fiºierului conþine
numere de staþii separate prin spaþiu. Linia a 2-a a fiºierului de intrare conþine
numerele de staþii ale liniei de tren A, linia a treia a fiºierului de intrare conþine
numerele de staþii ale liniei de tren B º.a.m.d.

Date de ieºire.
Fiºierul text METROU.OUT va conþine pe o singurã linie cuvîntul DA dacã pasagerul
poate ajunge din staþia x în staþia y ºi NU în caz contrar.

Exemplu.
METROU.IN METROU.OUT

4 9 1 8 2 DA
1 2 3 4 5
2 6 8
7 6 4
5 9

Restricþii.
2 ≤ n ≤ 26, 3 ≤ m ≤ 250, x ≠ y, x ≠ z, y ≠ z. Timpul
de execuþie nu va depãºi 5 secunde. Fiºierul sursã va avea denumirea
METROU.PAS, METROU.C sau METROU.CPP.

41
Rezolvare

Introducem în studiu mulþimile L1, L2, ..., Ln, fiecare mulþime reprezentînd cîte o linie
de tren. De exemplu, în cazul fig. 2, avem:
L1 = {1, 2, 3, 4, 5} - linia A;
L2 = { 2, 6, 8} - linia B;
L3 = {7, 6, 4} - linia C;
L4 = { 5, 9} - linia D.

Fie S mulþimea staþiilor de metrou la care se poate ajunge pornind din staþia x.
Aceastã mulþime poate fi calculatã iterativ dupã cum urmeazã:
1) Iniþial includem în mulþimea S0 toate staþiile de pe liniile pe care apare staþia x.
2) Presupunem cã la un anumit pas k avem deja calculatã mulþimea Sk-1. Mulþimea
Sk se obþine adãugînd la mulþimea Sk-1 toate staþiile de pe liniile pe care apare cel
puþin o staþie din mulþimea Sk-1. Evident, S0 ⊆ S1 ⊆ S2 ⊆ ...⊆ Sk, iar în
mulþimile S0, S1, S2, ..., Sk nu trebuie sã aparã staþia z, care este închisã pentru
transbordãri.
3) Indiferent de configuraþia liniilor de metrou, numãrul necesar de transbordãri
nu poate depãºi valoarea n-1. Prin urmare, mulþimile Sk trebuie calculate pentru
k = 1, 2, 3 º.a.m.d, în cel mai nefavorabil caz, pînã la k = n-1.

Pe calculator mulþimile S0, S1, S2, ..., Sk pot fi reprezentate cu ajutorul unui singur

vector (tablou) T = tj , denumit vectorul staþiilor accesibile. La fiecare pas k,


m
componentele tj ale acestui vector au urmãtoarea semnificaþie:
1, daca statia j apartine multimii S k ;
tij = 
0, in caz contrar.

În programul ce urmeazã liniile de tren ºi vectorul staþiilor accesibile sînt reprezentate


prin structurile de date
const nmax=26;
mmax=250;
type Linie = set of 1..mmax;
var L : array [1..26] of Linie;
n : 2..nmax;
m, x, y, z : 3..mmax;
T : array[1..mmax] of boolean;
iar apartenenþa staþiilor la anumite linii de metrou se verificã cu ajutorul operatorului in.

42
Program Metro;
{ Clasele 7-9 }
const nmax=26;
mmax=250;
type Linie = set of 1..mmax;
var L : array [1..26] of Linie;
n : 2..nmax;
m, x, y, z : 3..mmax;
T : array[1..mmax] of boolean;

procedure Citeste;
{ Citirea datelor de intrare }
var i, j : integer;
Intrare : text;
begin
assign(Intrare, ’METRO.IN’);
reset(Intrare);
readln(Intrare, n, m, x, y, z);
for i:=1 to n do
begin
L[i]:=[];
while not eoln(Intrare) do
begin
read(Intrare, j);
L[i]:=L[i]+[j];
end; { while }
readln(Intrare);
end; { for }
close(Intrare);
end; { Citeste }

procedure Scrie;
{ Scrierea datelor in fisierul de iesire }
var i, j, k : integer;
Iesire : text;
begin
assign(Iesire, ’METRO.OUT’);
rewrite(Iesire);

43
if T[y] then writeln(Iesire, ’DA’)
else Writeln(Iesire, ’NU’);
close(Iesire);
end; { Scrie }

procedure Accesibilitate;
{ Calculeaza vectorul T }
var i, j, k, q : integer;
begin
{excludem statia z din toate liniile de metrou}
for i:=1 to n do
if (z in L[i]) then L[i]:=L[i]-[z];
{ initializam vectorul T }
for j:=1 to m do T[j]:=false;
{ calculam multimea S0 }
for i:=1 to n do
if (x in L[i]) then
for j:=1 to m do
if (j in L[i]) then T[j]:=true;
{ calculam multimile Sk }
for k:=1 to n-1 do
for i:=1 to n do
for j:=1 to m do
if ((j in L[i]) and T[j]) then
for q:=1 to m do
if (q in L[i]) then T[q]:=true;
end; { Accesibilitate }

begin
Citeste;
Accesibilitate;
Scrie;
end.

Din analiza procedurii Accesibilitate se observã cã instrucþiunea


if (q in L[i]) then T[q]:=true
din interiorul celor patru cicluri imbricate se va efectua de cel mult n(n-1)m2 ori.
Conform restricþiilor problemei, n ≤ 26 ºi m ≤ 250. Prin urmare, în cazul cel mai
nefavorabil, numãrul necesar de operaþii este de ordinul 108, mãrime comparabilã cu
capacitatea de prelucrare a calculatoarelor personale.
44
Roboţi

O populaþie de roboþi se dezvoltã conform urmãtoarelor legi:


a) o datã în an roboþii se adunã în grupe de cîte 3 sau 5 indivizi în aºa mod încît
numãrul grupelor de cîte 3 indivizi este maxim;
b) fiecare grupã de cîte 3 roboþi asambleazã alþi 5 roboþi noi, iar fiecare grupã de
cîte 5 roboþi asambleazã alþi 9 roboþi noi;
c) dupã ce a fost asamblat, fiecare robot trãieºte exact 3 ani.

Presupunem, cã iniþial populaþia este formatã din k0 roboþi noi-nouþi. Elaboraþi un


program, care calculeazã numãrul de roboþi kn în populaþie peste n ani.

Date de intrare.
Fiºierul text ROBOTI.IN conþine pe o singurã linie numerele naturale k0 ºi n
separate prin spaþiu.

Date de ieºire.
Fiºierul text ROBOTI.OUT va conþine pe o singurã linie numãrul natural kn.

Exemplu.
ROBOTI.IN ROBOTI.OUT
8 2 60

Restricþii.
7 < k0 ≤ 25, 1 ≤ n ≤ 19. Timpul de execuþie nu va depãºi 1 secundã. Fiºierul sursã
va avea denumirea ROBOTI.PAS, ROBOTI.C sau ROBOTI.CPP.

45
Rezolvare

Introducem în studiu urmãtoarele notaþii:


r1 - numãrul de roboþi cu “vîrsta” de 1 an;
r2 - numãrul de roboþi cu “vîrsta” de 2 ani;
r3 - numãrul de roboþi cu “vîrsta” de 3 ani.

Evident, iniþial r1 = k0, r2 =0 ºi r3 =0, iar numãrul curent de roboþi se calculeazã ca

s = r 1 + r2 + r3 .

Vom nota x numãrul maxim de grupe de cîte 3 indivizi ce pot fi formate din populaþia
cu s roboþi, iar prin y - numãrul grupelor formate din cîte 5 roboþi. Notînd prin p restul
împãrþirii numãrului de roboþi s la 3 sau, prin alte notaþii, p = s mod 3, se observã cã
numerele x ºi y pot fi determinate ca:

a) pentru p = 0 avem x = (s div 3) ºi y = 0;


b) pentru p = 1 avem x = (s div 3) - 3 ºi y = 2;
c) pentru p = 2 avem x = (s div 3) - 1 ºi y = 1.

Cunoscînd numãrul curent de roboþi ºi divizarea lor în grupe, putem simula procesele
de “naºtere” ºi “îmbãtrînire” a roboþilor:

r3 := r2;
r2 := r1;
r1 := 5x + 9y.

Prin urmare, numãrul de roboþi kn în anul n poate fi calculat iterativ, cunoscînd


numãrul de roboþi în anul precedent pe categoriile de “vîrstã” r1, r2 ºi r3.

46
Program Roboti;
{ Clasele 7-9 }
var f:text;
i,N,k:integer;
r:array[1..3] of longint;
s:longint;
x,y,p:longint;
begin
assign(f,’roboti.in’); reset(f);
readln(f,k,N); close(f);
r[1]:=k; r[2]:=0; r[3]:=0; s:=k;
for i:=1 to n do
begin
x:=s div 3; p:=s mod 3;
if p=0 then y:=0;
if p=2 then begin x:=x-1; y:=1; end;
if p=1 then begin x:=x-3; y:=2; end;
r[3]:=r[2]; r[2]:=r[1]; r[1]:=5*x+9*y;
s:=r[1]+r[2]+r[3];
end;
assign(f,’roboti.out’); rewrite(f); writeln(f,s);
close(f);
end.

47
Ziua 2

Clasele 10 - 12

Descrierea problemelor

Numărul de Denumirea Denumirea


Denumirea Denumirea
puncte alocat fişierului de fişierului de
problemei fişierului sursă
problemei intrare ieşire

VOT.PAS
Votul 100 VOT.C VOT.IN VOT.OUT
VOT.CPP

METROU.PAS
Metroul 100 METROU.C METROU.IN METROU.OUT
METROU.CPP

CINA.PAS
Cina 100 CINA.C CINA.IN CINA.OUT
CINA.CPP

Total 300 - - -

48
Votul

La începuturi, pe o insulã foarte îndepãrtatã, toate deciziile se adoptau la adunarea


generalã a alegãtorilor prin majoritate de voturi. Odatã cu creºterea numãrului de
alegãtori, convocarea adunãrilor generale a devenit practic imposibilã. Pentru a nu
bloca procesul de adoptare a deciziilor s-a convenit ca insula sã fie împãrþitã în
circumscripþii electorale, nu neapãrat cu acelaºi numãr de alegãtori, iar orice proiect de
decizie sã fie supus votului în fiecare circumscripþie separat. Decizia se considerã
adoptatã într-o circumscripþie, dacã pentru ea au votat mai mult de jumãtate din alegãtorii
din circumscripþia respectivã. Decizia se considerã adoptatã pentru întreaga insulã
dacã ea a fost aprobatã în mai mult din jumãtate din numãrul circumscripþiilor.

Evident, dacã în cazul adunãrilor generale deciziile se considerau adoptate numai


atunci cînd pentru ele votau majoritatea alegãtorilor de pe întreaga insulã, în cazul
circumscripþiilor acest lucru nu mai este necesar.

De exemplu, presupunem cã pe insulã locuiesc 17 alegãtori. În cazul adunãrilor


generale, pentru a aproba o decizie sînt necesare 9 voturi pro. Daca însã formãm 3
circumscripþii, ºi anume, prima cu 4, a doua cu 6 ºi a treia circumscripþie cu 7 alegãtori,
pentru adoptarea unei decizii este suficient ca ea sã fie votatã în cel puþin douã
circumscripþii, numãrul necesar de voturi fiind 7.

Scrieþi un program care, cunoscînd numãrul de circumscripþii ºi numãrul de alegãtori


din fiecare circumscripþie, calculeazã numãrul de voturi, necesare pentru adoptarea
unei decizii pentru întreaga insulã.

Date de intrare.
Fiºierul text VOT.IN constã din douã linii. Pe prima line este înscris numãrul
circumscripþiilor n. Linia a doua a fiºierului de intrare conþine n numere întregi
pozitive ce reprezintã numãrul alegãtorilor din fiecare circumscripþie.

Date de ieºire.
Fiºierul text VOT.OUT va conþine pe o singurã linie un numãr natural - numãrul
necesar de voturi.

49
Exemplu.
VOT.IN VOT.OUT
3 7
4 6 7

Restricþii.
n ≤ 1000. Numãrul de alegãtori pe insulã nu depãºeºte valoarea 30000.
Timpul de execuþie nu va depãºi 1 secundã. Fiºierul sursã va avea denumirea
VOT.PAS, VOT.C sau VOT.CPP.

50
Rezolvare

Reprezentãm numãrul de alegãtori din fiecare circumscripþie în forma unui vector


(tablou)
A = (a1, a2, a3, ..., an),

elementele cãruia sînt sortate în ordine crescãtoare:

a1 ≤ a2 ≤ a3 ≤ ... ≤ an.

Se observã cã numãrul minim de voturi m, necesare pentru adoptarea unei decizii


poate fi determinat ca

m = (a1 div 2 +1) + (a2 div 2 +1) +


+(a3 div 2 +1) + ...(ak div 2 + 1),

unde k = (n div 2) +1.

Program Votul;
{ Clasele 7-9 }
var A:array[1..1000] of integer;
n:integer;
vots:longint;

procedure InitData;
{ Citirea datelor de intrare }
var f:text; i:integer;
begin
assign(f,’vot.in’); reset(f);
readln(f,n);
for i:=1 to n do read(f,A[i]);
close(f);
end; { InitData }

procedure BubleSort;
{Sortarea vectorului A prin metoda bulelor }
var i,k,l,t:integer;
begin
l:=n-1;

51
while 1<=l do
begin
k:=0;
for i:=1 to l do
if A[i]>A[i+1] then
begin
t:=A[i]; A[i]:=A[i+1]; A[i+1]:=t;
k:=i;
end;
l:=k-1;
end;
end; { BubleSort }

procedure Calc;
{ Calcularea numarului minim de alegatori }
var i:integer;
begin
for i:=1 to (n div 2) +1 do
vots:=vots+((A[i] div 1)+1);
end; { Calc }

procedure Outputdata;
{ Extragerea datelor de iesire }
var f:text;
begin
assign(f,’vot.out’);
rewrite(f); writeln(f,vots);close(f);
end; { Outputdata }

begin
InitData;
BubleSort;
Calc;
OutputData;
end.

Din analiza procedurilor BubleSort ºi Calc se observã ca numãrul de operaþii


necesare pentru sortarea componentelor vectorului A este proporþional cu n2. Evident,
pentru n ≤ 1000, timpul de execuþie nu va depãºi o secundã.

52
Metroul

Metroul din Londra reprezintã un sistem complex, care transportã zilnic milioane de
pasageri (fig. 1). Din punctul de vedere al pasagerului, metroul poate fi tratat ca o
mulþime de linii de tren ºi o mulþime de staþii. În scopuri didactice, vom nota liniile de tren
prin literele mari A, B, C, D º.a.m.d. ale alfabetului latin, în total n linii, iar staþiile - prin
numerele naturale 1, 2, 3, ..., în total m staþii (fig. 2).

Fig. 1 Fig. 2

Liniile de tren ºi staþiile respective au fost proiectate în aºa fel, încît pasagerul, care
pleacã din orice staþie x, sã poatã ajunge în oricare altã staþie y. Evident, în cazurile în
care staþiile se aflã pe linii diferite, pasagerul este nevoit sã facã una sau mai multe
transbordãri, schimbînd trenul în staþiile în care se întîlnesc douã sau mai multe linii de
tren.
De exemplu, pentru a ajunge din staþia 1 în staþia 8 (fig. 2), pasagerul poate sã facã
o singurã transbordare în staþia 2 sau douã transbordãri - prima în staþia 4 ºi a doua în
staþia 6.

Elaboraþi un program, care, cunoscînd planul metroului, staþia de plecare x ºi staþia


de sosire y, calculeazã numãrul minim de transbordãri.

Date de intrare.
Fiºierul text METROU.IN conþine pe prima linie numerele naturale n, m, x,
y separate prin spaþiu. Fiecare din urmãtoarele n linii ale fiºierului conþine numere
de staþii separate prin spaþiu. Linia a 2-a a fiºierului de intrare conþine numerele de
staþii ale liniei de tren A, linia a treia a fiºierului de intrare conþine numerele de staþii
ale liniei de tren B º.a.m.d.

53
Date de ieºire.
Fiºierul text METROU.OUT va conþine pe o singurã linie numãrul minim de
transbordãri.

Exemplu.

METROU.IN METROU.OUT

4 9 1 8 1
1 2 3 4 5
2 6 8
7 6 4
5 9

Restricþii.
2 ≤ n ≤ 26, 3 ≤ m ≤ 250, x ≠ y. Timpul de execuþie nu va depãºi
5 secunde. Fiºierul sursã va avea denumirea METROU.PAS, METROU.C sau
METROU.CPP.

54
Rezolvare

Introducem în studiu mulþimile L1, L2, ..., Ln, fiecare mulþime reprezentînd cîte o linie
de tren. De exemplu, în cazul fig. 2, avem:

L1 = {1, 2, 3, 4, 5} - linia A;
L2 = { 2, 6, 8} - linia B;
L3 = {7, 6, 4} - linia C;
L4 = { 5, 9} - linia D.

De asemenea, vom utiliza urmãtoarele notaþii:

S – mulþimea staþiilor de metrou;


Sk – mulþimea staþiilor de metrou la care se ajunge, pornind din staþia x, prin
exact k transbordãri.

Mulþimile S0, S1, S2, ..., Sk pot fi calculate iterativ, dupã cum urmeazã:

1) în mulþimea S0 se includ toate staþiile de pe liniile pe care apare staþia x;


2) în mulþimea S1 se includ toate staþiile de pe liniile pe care apare cel puþin o staþie
din mulþimea S0, dar care nu au fost deja incluse în S0;
3) în general, în mulþimea Sk se includ toate staþiile de pe liniile pe care apare cel
puþin o staþie din mulþimea Sk-1, dar care nu au fost deja incluse în mulþimile
S0, S1, S2, ..., Sk-1.

Întrucît numãrul minim de transbordãri nu poate depãºi valoarea n-1, calculele


recurente ale mulþimilor S0, S1, S2, ..., Sk se vor termina cînd k = n – 1.

Pe calculator mulþimile S0, S1, S2, ..., Sk pot fi reprezentate cu ajutorul unui singur

vector T = tj , denumit vectorul transbordãrilor. Componentele tj ale acestui vector


m
pot fi calculate iterativ dupã cum urmeazã:

- iniþial pentru toate componentele stabilim tj = - 1, fapt ce semnificã


S0 = S1 = S2 = ... = Sk = ∅;
- în continuare, pentru toate staþiile j din mulþimea Sk (k va lua consecutiv valorile
0, 1, 2 º.a.m.d.) stabilim tj = k.

55
În programul ce urmeazã liniile de tren ºi vectorul transbordãrilor sînt reprezentate
prin structurile de date

const nmax=26;
mmax=250;
type Linie = set of 1..mmax;
var L : array [1..26] of Linie;
n : 2..nmax;
m, x, y : 3..mmax;
T : array[1..mmax] of integer;

iar apartenenþa staþiilor la anumite linii de metrou se verificã cu ajutorul operatorului in.

Program Metro;
{ Clasele 10-12 }
const nmax=26;
mmax=250;
type Linie = set of 1..mmax;
var L : array [1..26] of Linie;
n : 2..nmax;
m, x, y : 3..mmax;
T : array[1..mmax] of integer;

procedure Citeste;
{ Citirea datelor de intrare }
var i, j : integer;
Intrare : text;
begin
assign(Intrare, ’METRO.IN’);
reset(Intrare);
readln(Intrare, n, m, x, y);
for i:=1 to n do
begin
L[i]:=[];
while not eoln(Intrare) do
begin
read(Intrare, j);

56
L[i]:=L[i]+[j];
end; { while }
readln(Intrare);
end; { for }
close(Intrare);
end; { Citeste }

procedure Scrie;
{ Scrierea datelor in fisierul de iesire }
var i, j, k : integer;
Iesire : text;
begin
assign(Iesire, ’METRO.OUT’);
rewrite(Iesire);
writeln(Iesire, T[y]);
close(Iesire);
end; { Scrie }

procedure Transbordari;
{ Calculeaza vectorul T }
var i, j, k, q : integer;
begin
{ initializam vectorul T }
for j:=1 to m do T[j]:=-1;
{ calculam multimea S0 }
for i:=1 to n do
if (x in L[i]) then
for j:=1 to m do
if (j in L[i]) then T[j]:=0;
{ calculam multimile Sk }
for k:=1 to n-1 do
for i:=1 to n do
for j:=1 to m do
if ((j in L[i]) and (T[j]=k-1)) then
for q:=1 to m do
if ((q in L[i]) and (T[q]=-1)) then
T[q]:=k;
end; { Transbordari }

57
begin
Citeste;
Transbordari;
Scrie;
end.

Din analiza procedurii Transbordari se observã cã complexitatea temporalã


a algoritmului respectiv este de ordinul O(n2m2). Conform restricþiilor problemei,
n ≤ 26 ºi m ≤ 250. Prin urmare, în cazul cel mai nefavorabil, numãrul necesar de
operaþii este de ordinul 108, mãrime comparabilã cu capacitatea de prelucrare a
calculatoarelor personale.

58
Cina

Pentru organizarea unei cine festive ar fi necesare d1 pîini de calitatea 1-a, d2 pîini
de calitatea a 2-a, d3 pîini de calitatea a 3-a, ..., dn pîini de calitatea n. Preþurile la pîine
diferã, astfel o pîine de calitatea 1-a costã c1 lei, o pîine de calitatea a 2-a costã c2 lei, ...,
o pîine de calitatea n costã cn lei. Se considerã, cã pîinea de calitatea 1-a este bunã, de
calitatea a 2-a - mai bunã, ..., iar de calitatea n - cea mai bunã. Evident, concomitent cu
îmbunãtãþirea calitãþii, cresc ºi preþurile respective, ºi anume, c1 < c2 < c3 < ... < cn. În
general, organizatorii cinei festive sînt de acord sã înlocuiascã pîinile de calitate bunã
prin acelaºi numãr de pîini de calitate ºi mai bunã, însã ar dori sã plãteascã cît mai puþini
bani.

Unica patiserie din oraº a stabilit cã la cumpãrarea oricãrei cantitãþi de pîine de


calitatea i se mai plãteºte suplimentar costul încã a 5 pîini de aceeaºi calitate. Prin
urmare, în unele cazuri, costul pîinii necesare pentru cina festivã poate fi micºorat prin
reducerea asortimentului sau, prin alte cuvinte, prin reducerea numãrului de feluri de
pîine cumpãratã, pãstrînd, totodatã, numãrul total de pîini d1 + d2 + d3 + ... + dn.

De exemplu, presupunem cã

d1 = 6, d2 = 1, d3 = 0, d4 = 6,
în total 13 pîini, ºi
c1 = 1, c2 = 4, c3 = 7, c4 = 8.

Dacã s-ar cumpãra asortimentul indicat, pentru pîini s-ar plãti 123 de lei. Dacã însã,
reducem asortimentul ºi cumpãrãm

d1 = 6, d2 = 0, d3 = 0, d4 = 7,

în total tot 13 pîini, vom plãti numai 107 lei.

Elaboraþi un program care calculeazã suma minimã de bani suficientã pentru


procurarea pîinii.

59
Date de intrare.
Fiºierul text CINA.IN conþine pe prima linie numãrul natural n. Fiecare din
urmãtoarele n linii ale fiºierului de intrare conþine cîte douã numere naturale separate
prin spaþiu. Pe linia i +1 sînt înscrise numerele ci, di, separate prin spaþiu.

Date de ieºire.
Fiºierul text CINA.OUT va conþine pe o singurã linie un numãrul natural - suma
minimã de bani necesarã pentru procurarea pîinii.

Exemplu.
CINA.IN CINA.OUT
4 107
1 6
4 1
7 0
8 6

Restricþii.
1 ≤ n ≤ 1000, 1 ≤ ci ≤ 10000, 0 ≤ di ≤ 100. Timpul de
execuþie nu va depãºi 1 secundã. Fiºierul sursã va avea denumirea CINA.PAS,
CINA.C sau CINA.CPP.

60
Rezolvare

Aceastã problemã admite o soluþie în cadrul programãrii dinamice. Vom extinde


problema la calcularea sumei minime pentru a satisface cerinþele cinei festive pentru
cererea de la calitatea 1 la calitatea i. Pentru i = 1, evident, aceastã sumã este

R1 = c1(d1+5).

Pentru început, se observã cã înlocuirea a unui numãr incomplet de pîini de o


anumitã calitate printr-o calitate mai bunã nu duce la micºorarea costului, ci dimpotrivã,
duce la mãrirea costului, astfel este evident cã vom înlocui toate pîinile de o anumitã
calitate printr-o calitate superioarã sau nu vom înlocui acea calitate deloc.
În continuare, sã observãm cã dacã se obþine micºorarea costului la înlocuirea
pîinilor de calitatea h prin calitatea t, atunci ºi la înlocuirea pîinilor de calitatea h prin
calitatea z, unde z este cea mai micã calitate dupã h, pentru care organizatorii au
solicitat un numãr nenul de pîini, tot va duce la o micºorare cel puþin la fel de bunã a
costului. Astfel putem considera ca schimbãrile de calitate vor fi efectuate in ºiruri
consecutive, adicã, vor fi ºiruri consecutive de calitãþi

i1, i1+1, i1+2, i1+3, …, i1+t,

care vor fi toate înlocuite prin calitatea i1+t+1.

Presupunem cã avem deja calculate toate rezultatele pentru i de la 1 la k-1, atunci


Rk se va calcula dupã cum urmeazã.
Se va încerca schimbarea tuturor calitãþilor, de la j la k-1, prin k. Dacã rezultatul este
mai bun, atunci el îl va înlocui pe rezultatul curent. Prin urmare, obþinem formula
recurentã pentru aflarea lui Rk:

Rk = min ( R j −1 + SD( j , k )ci ) ,


j =1, k

unde SD(j, k) este suma tuturor dh, h = j, ..., k.

61
Program Cina;
{ Clasele 10-12 }
var
C : array[0..1000] of integer;
D : array[0..1000] of integer;
R : array[0..1000] of longint;
{ suma minima pentru a satisface cererea
organizatorilor in calitatile 1..i}
S : array[0..1000] of longint;
{numarul piinilor care vor cerute de calitatea
1..i}
n: integer;
t: integer;
{indicele celei mai mari calitatii solicitate de
organizatori}

procedure CitesteDate;
{citeste datele din fisierul de intrare}
var f:text;
i:integer;
begin
assign(f,’Piini.in’); reset(f);
readln(f,n);
for i:=1 to n do readln(f,C[i],D[i]);
close(f);
end; { CitesteDate }

procedure Process;
var i,j,p:integer;
begin
R[0]:=0;
for i:=1 to n do if D[i]>0 then t:=i;
{t va reprezenta calitatea cea mai mare pentru
care organizatorii au solicitat piine }
s[0]:=0;
for i:=1 to n do s[i]:=s[i-1]+D[i];
for i:=1 to n do
begin
R[i]:=R[i-1]+(D[i]+5)*C[i];
for j:=i-1 downto 1 do

62
begin
if R[i]>R[j-1]+(s[i]-s[j-1]+5)*C[i]
then
R[i]:=R[j-1]+(s[i]-s[j-1]+5)*C[i];
{ incearca sa micsorezi pretul }
end; { for j }
end; { for i }
end; { Process }

procedure ScrieDate;
{Scrie datele in fisierul de iesire }
var f:text; i:integer;
begin
assign(f,’piini.out’); rewrite(f);
writeln(f,R[t]);
close(f);
end; { ScrieDate }

begin
CitesteDate;
Process;
ScrieDate;
end.

Complexitatea programului poate fi uºor stabilitã ca fiind O(n2) ºi se încadreazã cu


uºurinþã în timpul de 1 secundã.

63
64