Documente Academic
Documente Profesional
Documente Cultură
Toaz - Info 260368076 Manual Informaticapdf PR
Toaz - Info 260368076 Manual Informaticapdf PR
'
INFORMATICĂ
Referenţi ştiinţifici :
l. Tudor. Sorin
004(075.35)
..~ ..- .."' Definiţia 1.1. Un tablou este o structură omogenă (formată din elemente
~
.$ lntrebări posibile
a) Dacă magazinul vinde 5 produse, câte elemente are tabloul?
b) Care sunt indicii de adresare în tablou pentrt.~ a afla vânzările din produsul
5 în luna septembrie? · -
c) Cum se poate calcula suma încasată în luna mai?
8 Capitolul 1. Tablouri
d) Ştiind că, din punct de vedere economic, anul este împărţit în patru
trimestre şi că fiecare trimestru are trei luni, .cum se poate calcula suma
încasărilor din trimestrul patru al anului?
e) Cum putem determina produsul din vânzarea căruia s-a incasat anual
suma maximă?
f) Care este luna cu cele mai mari încasări?
2. Tot aşa, se poate memora, sub formă de tablou, situaţia la învăţătură a celor m
elevi ai unei clase. Dacă numerotăm elevii cu 1, 2, ... , m şi materiile pe care aceştia
le studiază cu 1, 2, ... , n , atunci a 1 d reprezintă media pe care o are elevul i la
materia j.
J~ Întrebări posibile
a) Dacă în clasă sunt 30 de elevi şi aceştia studiază 8 materii, câte elemente
are matricea?
b) Care este materia la care elevii au cele mai bune rezultate?
c) Care este media generală a elevului i?
d) Care este media generală a elevilor unei clase?
Şirul exemplelor ar putea continua pentru că sunt foarte multe situaţii in care
se utilizează tablouri bidimensionale (matrice).
var astablou1
sau direct
var asarray [1 •• 10,1 •• 9) of real;
+ În Pascal, matricea are liniile 1,2,... ,10 şi coloanele 1,2, ... ,9 şi, de exemplu,
elementul de pe linia a treia şi coloana a patra se adresează prin a [ 3, 4 l .
+ În C++, matricea are liniile 0,1, ... ,9 şi coloanele 0,1, ... ,8 şi, de exemplu,
elementul de pe linia a treia şi coloana a patra se adresează prin a[2] [3] .
Uneori, pentru simplitate, vom folosi liniile şi coloanele matricei Tncepand de
la 1 . ln aceste cond iţii se pierde o linie şi o coloană, fJecare de indice o.
Consideram acest fapt neesenţial.
Manual de Informatică pentru clasa a Xl-a 9
Programul care-I utilizeaza va f uncţiona corect daca avem cel mult a linii şi
cel m uit s coloane.
(~ !!]
În urma interschimbării liniilor 2 şi 3 se obţine:
afişate
(CJ]
in ordinea:
Elementele vor fi
1 2 3 6 9 8 7 4 5.
/-------"'
char
n,m,i,j,dir:~e;
int n,m,i,j,dir,p,pt;
p,pt ~integer;
ifstream f(•tabla.txt•);
f:textl
begin
void main()
aaaign(f, 1 tabla.txt 1 )1 {
reaet(f); f>>n>>m;
readln(f,n,m); for(i•lti<•nti++)
for i ~·l to n do for(:f•1I:f <•ml:f++)
begin f.»a [il [j) 1
for js•l tom do pt=O;
read(f,a[i,:fl)l for(i=1;i<• nii++)
readln(f) for(j•ll:f <-.m;:f++)
endl if (a[i][:fll• 1 , ' )
pt ~·o,
{
for i ~·1 to n do if(a[ill:fl •• 'A'I 1
for j :,.1 to m do 1
if a[i,j]<>',' then a[i) [j] •• E' 11
a[i) [:fl •• 'J:'
begin
a[i) [:fl •• 1 0' 1
if (a[i,j]c'A') or a[iJ[:fl •• 'U')
(a[i.j)•'E') or p=li
(a[i,:f]• 1 l: 1 ) or alsa p•:ZI
(a[i, j)= 1 0') or dir•QI
(a[i,:f]= 1 U') then P ~•1 if (i>l && a[i-1] [:f]l•', 1
1
a o, i~ 1
• 1 &n+l, i~ 1 •
1
~
14 Capitolul 1. Tablouri
Se mai poate analiza şi cazul in care o literă nu are nici un vecin pe niciuna
dintre d irecţiile orizontală sau verticală (caz Tn care litera nu s-ar puncta deloc), însă
problema precizează că literele sunt aşezate corect conform jocului de scrabble,
deci nu pot fi amplasate litere izolate.
Cl Aplicaţia 1.4. Sortarea fără comparaţii este o metodă de sortare care permite
sortarea an numere naturale, fără a face nici măcar o comparaţie intre ele.
Pentru memorarea numerelor care aparţin fiecărei clase vom utiliza o matrice,
denumită Mat, cu 10 coloane, in care prima linie are indicele o. Elementele din linia o
reţin numărul de elemente din şir care se găsesc pe coloana respectivă:
o 1 2 3 4 5 6 7 8 9
11 215
1 :·: 1 . 1 o 1 o 1 o 1 1 .:. 1 o 1 o 1 o 1
1: 1 o 1
215
1 :·~ 1 :: 1 o 1 o 1 o 1 o 1o 1
Manual de informatică pentru clasa a Xl-a 15
~ Observaţii
../ Dacă k este numărul maxim de cifre a numerelor din şir, operaţia de
împărţire a numerelor în 10 clase se va relua de k ori.
(~}
elementele sunt: 1 , s şi 9.
Se cere:
tele aflate pe
b) Pentru un tablou pătratic A, numim diagonală secundară, elemen
•unia" care uneşte A (n, 11 cu A [l,nl .
(~}
elementele sunt: 7 , s şi 3.
Se cere:
în linia k ,
2. lnterschimbaţi coloanele unei matrice c1~ m linii şi n coloane astfel încât
elementele să fie in ordine crescătoare.
Manual de informatică pentru clasa a Xl-a 17
3. Un teren este dat sub forma unui tablou A cu n linii şi m coloane. Elementul
A [i 1 j l reţine altitudinea pătrăţelului de coordonate i şi j. Să se afişeze
coordonatele "pătrăţelelor vârf" (un pătrăţel este vârf dacă toţi vecinii săi au o
altitudine strict mai mică).
../ Indicaţie. Atenţie! Maximele sau minimele pe linii sau coloane pot să nu fie
unice. Dacă vom considera numai o valoare dintre acestea, s-ar putea să pierdem
soluţii.
Exemplu: m=4 , n=4. Matricea iniţială şi submatricele sunt prezentate mai jos:
1 2 3 lf
5 G7 8 1 2 3 2 3 lf 5 G7 G7 8
9 H> 11 12 5 G7 G7 8 9 1 o 11 10 11 12
13 1LJ 15 1G 9 1o 11 10 11 12 13 1lf 15 1LJ 15 1G
10. Fiind dată o matrice cum linii şi n coloane, se cere să se afişeze elementele în
ordinea sugerată în figura de mai jos:
.+
i~
Figura 1.2. Exemplu
18 Capitolul 1. Tablouri
a)
for j:=l tom do
V[j+(i-l)*m):=Mat[i,j]; V[j+(i-l)*m)•Mat[i] [j];
!>) for i:•l to m do b) for (i•l;i<-m;i++l
for j:=1 to n do for (j•1;j<•n;j++)
V[j+(i-l)*n):•Mat[i,j]; V[j+(i-l)*nJ=Mat[i] [j];
C} for i:=l tom do c) for (i•1;i<•m;i++)
for j:=l ton do for (j=l;j<=n;j++)
V[i+(j-l)*n] :~Mat[i,j]; V[i+ (j-1) *nl •Mat [i) [j);
d) for i: • l to m do d) for (i•l;i<•m;i++l
for j:•l ton do for (j•1d<=nd++)
V[j+(i-1)*n] :•Mat[j,i); V[j+(i-1l*n]=Mat[i,j];
Subprograme
!
1+ x 2 '
f (x) = X + 1,'
pentru x e (- oo ,-1);
6
pentru x e ( 1, oo ).
1+ X
Se citesc două valori reale a şi b. Să se scrie un program care afişează care dintre
valorile f (a> şi f (b) este cea mai mare.
ln plus, dacă într-un alt program este necesară sortarea altui vector de
~u mere reale, metoda clasică ne permite să alegem din secvenţa de instrucţiuni ce
'ormează programul pe cele ce realizează sortarea, să le copiem Tn noul program
şt să facem eventualele adaptări (numărul de componente şi numele vectorului pot
1 altele). Aceste operaţii sunt destul de greoaie şi necesită multă atenţie. Prin
mplementarea modulară, cu ajutorul subprogramelor, "preluarea" se realizează
mult mai uşor.
-+ Funcţia are variabile proprii - adică variabile care sunt definite în cadrul el. În
exemplu, ele sunt s şi i . Aceste variabile se numesc variabile locale.
var n:integer;
function subp(n:integer)z real;
var szreal;
i:integer;
begin
s:=O;
for i:•1 to n do s:•s+1/i;
subp:•s;
end;
begin
write ('n•'); readln(n);
write(subp(n):5: 2);
end.
var n,i:integer;
rez,prodzreal;
function subp(nzinteger)z real;
var szreal;
i:integer;
begin
s:=O;
for iz•l to n do s:•s+l/i;
subp:•s;
and;
begin
write ('n•'); readln(n);
rez:•subp(n);
prod:•l;
for iz•l to n do prodz•prod*rez;
write(prodz5:2);
end.
La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare
aceştia se numesc parametri efectlvl.
24 Capitolul 2. Subprograme
procedur a nume;
begin
end;
Vanual de informatică pentru clasa a Xl-a 25
----------------~----------------------------------------
+ Apelul unei proceduri se face prin utilizarea numelui ei, sub forma nume 1 •
Mai precis, apelul unei proceduri este instrucţiun~, numită instrucţiunea
de apel.
-+ La apel, controlul programului este transferat la prima instrucţiune a
procedurii - după cum se întâmplă şi la funcţii. După executarea procedurii,
se revine in programul principal/a prima instrucţiune care urmează celei de
apel- în cazul de faţă se întâlneşte o altă instrucţiune de apel.
~ Ca şi funcţiile, procedurile se pot plasa În cadrul programului intre
declaraţiile de variabile şi instrucţiunea compusfJ.
l
•
În acest exemplu, procedurile sunt apelate fără utilizarea parametrilor. În
realitate, procedurile pot avea parametri întocmai ca şi funcţiile.
LISTA
ANTET DE
--FUNCŢIE PARAMETRI
FORMALI
IDENTIFICATOR
DE TIP
Exemplu:
function suma(x,y:int eger):real;
begin
sum.a:=x+y;
end
begin
suma:•x+y;
end
LIST.J.
ANTET IDENTIFICATO R PARAMETRI
PROCEOURE
-PROCEDURĂ FORMALI
Exemplu:
procedura suma(var szreal; x,yzreal);
begin
SI"'X+y;
end;
- blocul este:
begin
SI•X+y;
end;
v,a.,ual de informatică pentru clasa a Xl-a 27
Deşi aparent asemănătoare, cele două noţiun i diferă . Buna înţelegere a lor
-e aj ută să evităm anumite erori. Mai mult, aceste noţiuni sunt utilizate de orice
,...baj de programare, nu numai de Pascal.
begin
x:=3;
t
end.
28 Capitolul 2. Subprowame
Exemple
Exemple
procedura sl;
begin
writeln( 'sl')
end;
procedura s2;
begin
sl;
writeln ( • s2');
end;
begin
sl,;
s2;
end.
• Procedura test conţine definiţia a două proceduri sl şi s2. Nici una din
aceste proceduri nu se consideră declarată pentru programul principal.
Amândouă sunt declarate pentru procedura test. Pentru procedura s2, sl
este declarată, dar pentru sl procedura s2 nu este declarată.
\1anual de informatică pentru clasa a Xl-a
29
end1
begin
test1
end.
proced ura b;
begin
writel n( 'Eu sunt b')
Glldl
begin
&1
end.
var p,x,yainteger;
begin
x:=2;
y:-3;
pa • l+prod(x,y);
writeln(p)
end .
~b Observaţii
-/ În cadrul expresiei, apelul este un operand. El Intră în calcul cu valoarea
returnată de funcţie.
LISTĂ
APEL IDENTIFICATOR PARAMETRI
FUNCŢIE FUNCŢIE
EFECTIV!
Cele câteva exemple date până acum fac inutilă prezentarea unui alt
exemplu. Trebuie să ştim că:
Exemple
type vector=array [1 •• 9] of integer;
LISTĂ
PARAM ETRI
EFECTI V!
EXPRESI E
Figura 2.5.
Sintaxa parametrilor trimişi
ranual de informatică pentru clasa a Xl-a 33
În acest paragraf vom analiza modul prin care sunt memoraţi parametrii
""al1 smişi în momentul lan sării în executare a subprogramului.
stiva~~~--3------4--~---a-d-re_s_a_v_a_ri_a_bi-le_i_s_um____~l
a b s
~a al doilea apel, parametrii sunt: 2, 3, sum.
);> valorile reţinute de variabile - în acest caz, parametrii efectiv! trebuie să fie
numele variabilelor.
Exemplu:
var n:integer;
prooedure test(n:integer);
begin
n:=n+l;
writeln(n)
end;
begin
n:•l;
test (n);
writeln(n);
end.
);> parametrii efectiv! sunt valori sau expresii, care mai întâi se evaluează.
Exemplu:
prooedure test(n:integer);
begin
writeln(n)
end;
begin
test(3);
test(3+4*5);
end.
anual de informatică pentru clasa a Xl- a 35
Exemplu:
program test_param;
var x,y:integer;
function suma (a,b:integer):int eger;
begin
suma:=a+b;
end;
function dif (a,b:integer):int eger;
begin
dif:=a-b;
end;
function prod(a,b:integer ):integer;
begin
prod:=a*b;
end;
begin
write('xa'); readln(x);
write('y='l; readln(y);
writeln(prod(dif (x,y),suma(x,y)) );
end.
? în acest caz, ne putem întreba care este mecanismul prin care, deşi pentru o
• variabilă transmisă se reţine adresa sa, În subprogram putem adresa
variabila normal (nu indirect)? La compilare, orice referinţă la variabila
respectivă, este "tradusă" ca adresare indirectă.
36 Capitolul 2. Subprograme
var x,y:integer;
procedura interschimb(var x,y:integer)l
var man:integer1
begin
man:•x; XI•YI Yl~l
end;
begin
x:•21 yz.,3;
intarschimb(x,y);
writa(x,• •,y);
end.
~'
]l.B
Definiţia 2.7. Variabilele globale sunt variabilele programului principal.
Ele sunt rezervate într-o zonă specială de date, numită segment de date.
În versiunea 7 . o a limbajului Pascal, variabilele numerice sunt
iniţializate cu o.
,
a;
end.
Alt termen des utilizat în practica programării este durata de viaţă a unei
-ariabile. El se referă la perioada de timp în care variabila este alocata în memorie.
!.stfel, avem:
durată statică - variabila are alocat spaţiu pe tot timpul executării programului.
durata locală - variabila are alocat spaţiu doar în timpul cât se execută un
anumit bloc.
durată dinamică - alocarea spaţiului de memorie se face în timpul executarii prin
subprograme speciale sau operatori (în Pascal avem subprograme speciale).
Variabilele cu această durată de viaţă se numesc dinamice şi nu se tratează în
acest manual.
38 Capitolul 2. Subprograme
Reamintim faptul că un tip este standard dacă este cunoscut de limbaj (de
exemplu, integer). În caz contrar tipul este nestandard (de exemplu, tipul care
descrie un vector cu componente de tip real) . lată o procedură scrisă greşit:
procedura er (var Vlarray[1 • • 99) of real);
begin
end;
endt
swna(n,i):=st
end;
IMPLEMEN'l'ATION
[tipuri de date ş i variabile locale (valabile numai pentru unitatea de
program)]
procedurile şi funcţiile utilizate de unitatea de program
(BEGJ:N
.. .. ... o eventuală secvenţă de program care se execută
....... în momentul declarărlî unităţii de program în
....... programul care o utilizează.
END.]
procedura scad(a,brreal)t
begin
cr•a-b;
writoln(crls2);
end;
procedura produs(a,baroal);
bagin
ca•a*b;
writoln(cal:2);
end
procedura impart(a,brREAL);
begin
if b~ o thon writaln('~rtiroa nu se poate face ')
olso
begin
cr•a/b;
writoln(ca3a2);
endt
and;
begin
writo( 1 a• 1 ) 1
roadln(a) ;
wri taln ( 1 b= 1 ) 1
roadln(b);
end.
~"'u al de informatică pentru clasa a Xl-a 43
..;; Funcţia are un anumit tip, care precizează natura rezultatului. În exemplu,
tipul este doub:Le întrucât expresia calculată este de acest t\p.
-+ Funcţia are variabile proprii - adica variabile care sunt definite în cadrul ei. În
exemplu, s şi i. Aceste variabile se numesc variabile locale.
-+ Am vazut întoarce un anumit rezultat - în exemplu, de tip double.
că funcţia
Observaţi mecanismul prin care am obţinut aceasta. Calculez expresia în
mod obişnuit. Rezultatul este reţinut de variabila locală s. Prin instrucţiunea
"return s;", funcţia a primit ca valoare de retur conţinutul variabilei s.
La apel, lucrurile stau altfel: valorile acestora sunt cunoscute. Prin urmare,
aceştia se numesc parametri efectivi.
#include <iostream.h>
void citeac(int vt[lO],int n)
{ int i1
for(i-=O;i<n;i++)
{ cout<<"v["<<i+l<<"l•"l
cin>>vt[i];
}
}
main()
{ int v[lO),n;
cout<<•n=• ;
cin>>n;
citesc(v,n );
sortez(v,n );
scriu(v,n) 1
}
:> Cele trei funcţii au tipul vo:l.d, adică nu au valoare de retur. Ele returneam
rezultatul prin intermediul parametrilor.
tip nume.
E:xemple de antete:
1
•,
Observaţii
test(2-3,2+3),
• clasa de memorare;
• vizibilitate;
• durata de viaţă;
• tipul variabilei, singurul pe care l-am studiat până în prezent.
Astfel avem:
int b;
main()
{ b • 4;
cout<<a<<endl;
t(}J
}
3. Durata de viaţă a variabilelor globale este statică. Ele au spaţiu rezervat în tot
timpul execuţiei programului.
B} Variabile locale
Acestea sunt declarate în corpul funcţiilor. Mai precis, pot fi declarate în orice
bloc (instrucţiune compusă) al acestora.
Exemplu:
void t()
{ int a•3;
}
main()
{ int b•4;
}
Exemplu:
register int b•41
Exemplu:
void t()
{ int b•4t
{ int c • 3;
cout<<b<< " "<<c;
}
}
'Aanual de informatică pentru clasa a Xl-a 49
main()
{ a=S;
t();
cout<<a;
}
f · , Observaţii
•
./ În cazul în care, într-un anumit bloc sunt vizibile (se pot accesa) mai multe
variabile, toate cu acelaşi nume, dar au domenii de vizibilitate diferite, se
accesează variabila cu vizibilitatea cea mai mică. De exemplu, dacă în
programul anterior se tipăreşte variabila a din cadrul subblocului funcţiei, se
tipăreşte 3, pentru că acesta este conţinutul variabilei cu cea mai mică
vizibilitate (cea declarată în subblocul respectiv).
./ _!=xistă posibilitatea ca, un ciclu for să conţin~ declaraţia unei variabile locale.
In secvenţa următoare se calculează suma primelor 4 numere naturale.
Variabila i este declarată (şi în consecinţă vizibilă) doar în blocul for:
3. Durata de viaţă a variabilelor locale este atât timp cât durează execuţia blocului
respectiv.
<dz::·. Priviţi programul următor. Acesta conţine o funcţie care calculează suma
~~ · a două numere naturale.
50 Capitolul 2. Subprograme
lată, de exemplu, cum sunt memoraţi în stivă parametrii în cazul primului apel:
stiva ---+1 2 1 3
a b
L Observaţii
•
/ la revenirea în blocul apelant, conţinutul variabilelor memorate în stivă se
pierde- dupa cum ştim, durata de viaţa a variabilelor locale este locală.
Exemplu:
#include <iostream.h>
void test (int n)
{ n+=l;
cout<<n<<endll
}
main()
{ int n•l1
test (n);
cout<<n<<endl;
}
~ Apelăm funcţia. La apel, se rezervă spaţiu în stivă, spaţiu care are numele
parametrului (deci tot n) şi este initializat cu valoarea memorată de variabila
n a programului principal. in acest 'moment avem două variabile n şi ambele
reţin valoarea 1.
~ La ieşirea din funcţie, variabila n (din stivă) se pierde - adică nu mai are
spaţiu alocat. Prin urmare, valoarea 2 este pierdută.
main()
{ test(3);
test(3+4*5);
}
main()
{ int a[lO];
vector(a)J
for (int i•O;i<lOJi++) cout<<a(i)<<" "1
}
"'anual de informatică pentru clasa a Xl-a 53
#include <iostream.h>
void intersc(int &a,int &b)
{ int man=a;
a=b;
b=man;
}
main()
{ int x=2,:y=3;
intersc(x,y) 1
cout<<x<<" "<<y;
}
Deşi aparent asemă nătoare, cele două noţiuni diferă . Buna înţelegere a lor
-e ajută să evităm anumite erori. Mai mult, aceste noţiuni sunt utilizate de orice
"'lbaj de programare, nu numai în C++.
void s2()
{ s1 (); cout<<"Eu sunt s2"<<endl;
}
main()
{ s1 () 1
s2();
#include <iostream.h>
void s2();
void sl()
{ s2 () 1 cout<<"Eu sunt sl"<<endl;
}
void s2()
{ cout<<"Eu sunt s2•<<endl;
}
main()
{ sl ();
}
f
, (, l
Programatorii în C++ obişnuiesc să scrie mai întâi prototipurile tuturor
• funcţiilorutilizate de program - fără main () - iar după funcţia ma in ( > să le
definească. În acest fel, orice funcţie - mai puţin ma in ( ) - poate fi apelată
din oricare alta:
#include <iostream.h>
void sl(); // prototip sl
void s2(); // prototip s2
main()
{ sl();
}
void al()
{ s2 (); cout<<"Eu sunt sl" <<endl;
}
void s2 ()
{ sl (); cout<<"Eu sunt s2"<<endl;
}
~an ual de informatică pentru clasa a Xl- a ss
::1 Aplicaţia 2.1. Revenim la exemplul de funcţie dat în paragraful 2.1. Acesta va fi
:-ezentat în totalitate. Se consideră funcţia:
x+ 1 , pentru xe [-1,1];
2
f(x)= ~-\Î, pentru xe(-oo,-1};
1 - -,
1 +X
pentru x e ( l , oo ).
~ Rezolvare. Cunoaşteţi deja modul in care se calculeaza cel mai mare divizor
:omun pentru două numere naturale date. Cel mai mic multiplu comun a două
"Umere se poate determina impărţind produsul lor la cel mal mare divizor comun al
or. Prin urmare, scriem o funcţie cmmdc cu doi parametri formali m şi n , care
·.,toarce o valoare intreagă- cel mai mare divizor comun al lor.
56 Capitolul 2. Subprograme
~Exerciţii
1. Găs iţi două motive pentru care parametrii funcţiei cmmdc trebuie să fie transmişi
prin valoare şi nu prin referinţă.
2. Scrieţi
un subprogram cmmmo care să returneze cel mai mic multiplu comun a
două numere naturale. Stabiliţi locul unde trebuie integrat acesta in programul dat
şi modificaţi programul principal astfel fncât să se utilizeze subprogramul cerut.
3. Câte expresii diferite care au ca rezultat cel mai mare divizor comun al
numerelor naturale nenule a, b şi o există? ln orice expresie se utilizează numai
apeluri ale funcţiei ollDl\do şi variabilele a, b şi c. De exemplu, trei expresii sunt:
cmmdo(ommdc(a,b),c),
ommdc ( cmmdc (b, a), o) şi
cmmdc(o,cmmdc(a,b) ).
~ Rezolvare. Dispunem deja de o funcţie care calculează cel mai mare divizor
comun a două numere şi am testat-o în programul anterior. Pentru varietate, de
data aceasta implementăm o funcţie cu algoritmul lui Euclid pentru calculul celui
mai mare divizor comun, algoritm prin împărţiri, nu prin scăderi repetate. Cu
ajutorul ei calculăm cel mai mare divizor comun pentru valorile reţinute de primele
două componente şi memorăm această valoare în variabila o. Apoi, pentru fiecare
dintre componentele următoare, se calculează cel mai mare divizor comun intre
valoare.a curentă memorată in o şi cea reţinută de componenta curentă a
vectorului. Cel mai mare divizor comun va fi reţinut din nou de c.
Manual de informatică pentru clasa a Xl-a 57
~Exerciţiu
In locul secvenţei
c ~ cmmdc(v[ l) ,v[:ll))
pentru i =3, n execută
c ~ cmmdc(c ,v[i))
sfârtit pentru
dorim să utilizăm, mal compact, secvenţa:
Care este valoarea pe care trebuie să o aibă variabila c inaintea acestei secven~:?
1 9
2 3 l :Il
4 5 6 3 4 5
7 8 9 1 6 7 8 9
2 3 4 5 6 1 2 3 4 5
7 8 9 1 2 3 6 7 8 9 1 :Il
3 4 5 6 7 8 9 Junior Division
58 Capitolul 2. Subprograme
Alt aspect al problemei este realizarea tipăririi acestor valori pe m linii, linia 1
având o singură valoare, linia a doua două valori etc. Algoritmul este implementat
în procedura tipar, care are ca parametri formali pe m şi n, transmişi prin valoare.
Valorile lor sunt citite în programul principal.
~ Exerciţii
1. După apelul tipar(mln) din programul principal, dacă se adaugă o instruc-
ţiune care afişează valoarea lui n, ce valoare estimaţi că se va tipări?
2. Cum trebuie să arate definiţia subprogramului suc, dacă în subprogramul
tipar, în loc de n~suc (n), se utilizează instrucţiunea suc (n)?
3. Cum putem defini subprogramul suc astfel încât secvenţa de afişare din
subprogramul tipar să fie:
pentru i=l,m execută
pentru j=1,i execută
scrie suc(n)
sfârşit pentru
scrie EOLN
sfârşit pentru
V anual de informatică pentru clasa a Xl-a 59
:J Aplicaţia 2.5. Se citesc două numere naturale m<n. Se cere să' se tipărească
· ~te
numerele palindrom aflate între m şi n. Un număr este paling;om dacă, citit de
r- stânga la dreapta
şi citit de la dreapta către stânga, rezultatul este acelaşi. De
~em plu, numărull2l este palindrom.
Care este avantajul scrierii fiecărei funcţii? Acesta este dat de faptul că,
s:unci când scriem funcţia, ne concentrăm exclusiv asupra ei, deci posibilitatea de
s g reşi este mai mică . Dacă dispunem de funcţie, algoritmul in continuare devine
1ult mai simplu. În plus, este posibil ca oricare dintre funcţii să poată fi folosită şi în
3 te cazuri, la rezolvarea altor probleme.
f Observaţii
•
•"' Ordinea definirii celor două subprograme devine importantă, deoarece funcţia
in~ers, de care are nevoie funcţia palin, trebuie declarată anterior acesteia.
/ Exerciţii
1. Modificaţi antetul funcţiei invers, transformând parametrul n în parametru
transmis prin referinţă şi urmăriţi efectele modificării efectuate.
.Junior Divlslon
0 Rezolvare. Suma cuburilor cifrelor unui număr natural este calculată de funcţia
swna. Numărul n (citit) va ri memorat de prima compon entă a vectorului seria.
Apoi, suma cuburilor sale, de componenta a doua, suma cuburilor numărului reţinut
de a doua componentă va fi reţinută de a treia componentă, ş.a.m.d. După ce este
memorată o valoare, ea este comparată, pe rând, cu cele obţinute anterior. Dacă
este regăsită, se tipăreşte numărul de termeni ai seriei şi seria propriu-zisă
Funcţia swna calculează suma cuburilor cifrelor unui număr. Funcţia este verifică
dacă valoarea n există deja în şirul s format din ls componente.
l.lanual de informatică pentru clasa a Xl-a 61
3 4
3 1 7 g
1 2 3 4
9 1 3 8
62 Capitolul 2. Subprograme
Probleme propuse
a) G(x) =sin(x)+cos(x)•cos(2•x);
b) H(x) = 10•{x} (am notat prin {x} partea fracţionară a lui x).
'anual de informatică pentru clasa a Xl-a 63
7.Scrieţi o funcţie care returnează prima cifră a unui .,număr natural. De exemplu,
dacă parametrul efectiv este 127, funcţia va returna 1.
11
11. Să se tipărească toate numerele prime aflate între doi întregi citiţi. Programul
va folosi o funcţie care testează dacă un număr este prim sau nu.
12. Scrieţi un program care tipăreşte numerele întregi găsite între două valori citite,
numere. care se divid cu suma cifrelor lor. Programul va utiliza o funcţie care
returnează suma cifrelor unui număr întreg primit ca parametr.u .
13. Să se scrie o procedură care permută două linii date ale unei matrice pătratice.
14. Scrieţ! o procedură care interclasează doi vectori sortaţi ştiind că aceştia sunt
ordonaţi descrescător.
1
232
34543
4567654
567898765
67890109876
7890123210987
Junior Division
_-_a. de informatică pentru clasa a Xl-a 65
~ 6 6; b) 5 6; c) 6 6; d) 6 s.
:~ . Ce afi şează programul următor?
o!j'! ·• '., ' ' 1·"
.~ Varianta Pascal ' Varianta C++'·
function f(x:intege r):integer ; #include <iostream. h>
begin int f(int x)
f:=x+l { return x+1;
and; }
procedura t(a:intege r); void t(int a)
begin { a++; cout<<a;
a:=a+l; writeln(a) ; }
and;
void main()
begin { t(f(f(f(1) )));
t(f(f(f(l) ))) }
end.
a) 3; b) 4; d) eroare de sintaxă.
22. Ştiind că valorile citite ale variabilelor a şi b sunt numere naturale nenule, care
dintre secvenţe utilizează subprogramul increment...pentru a obţine produsul celor
două numere?
writeln(t) cout<<t;
end. }
23. Pentru varianta de limbaj preferată, stabiliţi care dintre următoarele antete de
subprogram sunt corecte:
a) procedura p(n:integer; var void p(int n, int& v[10))
v: array[l. .101 of integer);
b) function p(n:integer;var p(int n, float& v)
v:real);
c) procedura p(n:integer;v:real); void p(int n, float v)
d) functio~ p(n):integer; int p(int& n; float v)
24. Pentru funcţiile definite mai jos, care dintre afirmaţii este falsă?
· varianta Pascal
~ction Cat(n1,n2:in teger): long Cat(int n1,int n2)
longint; { int inv=O;
Tar inv:integer; while (n21a0)
~gin { inv=inv*10+n2 %10;
inv:=O; n2=n2/10;
while n2<>0 do begin }
inv:•inv*10+ n2 mod 10; while (invi=O)
n2:=n2 div 10 { nl=nl*lO+inv% 10;
end; inv=inv/10;
while inv<>O do begin
n1:=n1*10+in v mod 10; return nl;
inv:•inv div 10
end;
Cat:=nl
end;
26. Fiind dată funcţia următoare, care dintre afirmaţii este falsă?
1'',__. ;.,:
;, ,, ··
' "':·\ Varianta Pa9cal
. ·
type vect=array [1 •• 40] of byte; void Concat(int A[20], int 1
8(20], int m, int n, int C[40],
procedura Concat(A,B :vect; int&. p)
m,n:b.yte;v ar C1vect;var p:byte);
void Reun(int A[20], int 8[20],
procedura Reun(A,B:v ect; int m, int n, int C[40], int&
m,n:b.yte;v ar C:vect;var p:b.yte); p)
în care:
Concat(X,Y,a,b, Z , p);
Elimin(Z,p);
Elimin(X,a); Elimin(Y,b);
Concat(X,Y,a,b,Z,p);
Elimin(Concat(X,Y,a,b ,Z,p),p);
Elimin(X,a); Elimin(Y,b);
Reun(X,Y,a,b,Z,p);
• Inters (X,Y,a,b,Z,p)l
Dif(X, Z,a,p,Z,p);
= Inters( X,Y,a,b,Z,p);
Dif(Y,Z,b,p,Z,p)l
: Inters(Y, X,a,b,Z,p);
Dif(X,Z,a,b,Z,p);
~ Dif(X,Y,a,b,Z,p);
C. Dacă n•20, eate spaţii se scriu înaintea primului caracter"*", pe penultimul rând?
A. Care este conţinutul lui v după apel, dacă inainte este V=< 1, 2, 3, 4)?
a) V=(1 1 2,3 1 4); b) V=(4,3,2 1 1);
c) V=(0,1,6,10 ) ; d) V=(0,4 , 5 1 9) .
B. Care trebuie să fie iniţial conţi nutul lui v, dacă după apel este V= ( 1 1 6 1 10, o)?
a) V=(2,4,6,8); b) V=(1,6,10,0) ;
c) V=(0,10,6,1); d) V=(1,9,3,2) .
C. Pentru care dintre exemplele u rmătoare de configu raţii ale lui v la intrarea în
subprogram, conţi n utu l acestuia la i eşire coincide cu cel de la intrare?
a) V=(13,10,5, 1 1); b) V=(2,3 1 9 1 13);
c) V=(0,1,2,12); d) v .. (1,4,9,15 .
'.1anual de informatică pentru clasa a Xl- a 71
a) 3; b) s;
c) nu există o astfel de valoare; d) 2 .
C. Pentru X=< 1, O. O,
s , 7), Y= c1, 2, 7), stabiliţi ce valori pot fi scrise în casete
astfel încât apelul CJl\P ( 4, 4, x, Y) să returneze aceeaşi valoare ca şi apelul
cmp ( 4 , 4 , Y, X) .
a) 2 şi respectiv 3; b) 2 şi respectiv s;
c) nu există astfel de valori; d) 3 şi respectiv 6.
O. Pentru care şir de vectori, funcţia Cmp, apelată pentru oricare doi vectori
consecutivi în şir, returnează aceeaşi valoare?
a) A= ( 1, 2, 3) , B= ( 1, 2, 3), C ( 1, 2, 2);
b) A=(1,2), B=(1,2), C=(1,3);
c) A=(1,3), B=(l,2), C=(1,3);
d) Ac ( 2), B= ( 1), c= (O).
72 Capitolul 2. Subprograme
Răspunsuri
19. d); 20. c); 21. a); 22. b); 23. c); 24. d); 25. b),c); 26.a) ;
29. Indicaţie: fiecare număr este scris in binar pe o linie a matricei. Se afişează
numerele zecimale obţinute din num·erele iri binar de pe fiecare coloană a matricei.
A. c) , B. a) , C. a) .
30. Indicaţie: funcţia realizează compararea lexicografică a doi vectori care reţin
numere naturale. A. a) o; b) -1; c) 1; d) o; B. c); C. b); O. d).
Capitolul 3
Şiruri de caractere
. 1. Generalităţi
-t Cine n-a folosit un editor de texte? Chiar acum, când scriem programele
Pascal sau C++ utilizăm un editor de texte. Luaţi codul sursă al unui program
(fişiere cu extensii .pas sau • cpp). Observaţi că sursa este un fişier text în
care fiecare linie a ei, este o linie a fişierului text. Prin urmare, fiecare linie a
fişierului text conţine un şir de caractere. Ce operaţii putem face cu
editoarele? De exemplu, putem modifica o linie. O astfel de operaţie constă
în includerea sau ştergerea unui subşir (caractere consecutive din Interiorul
unul şir). Astfel de operaţii se fac, şi vom vedea cum, prin prelucrarea
şirurilor de caractere. Alte operaţii: a) Find- este o operaţie de Identificare
a unui subşir în cadrul unui şir de caractere; b) Replace este o operaţie de
înlocuire a unui subşir cu un altul; c) cut este o operaţie prin care, din cadrul
unul şir se extrage un subşir al său şi acesta este memorat în Clipboard.
Prin Paste se inserează un şir de caractere în cadrul altui şir de caractere.
Şirul exemplelor ar putea continua. Puteţi găsi altele?
t[S]
1-----l
- ...- . . ·-·· -..- t[255]
t[O] t[l] t[2] t[3] t[4] t[S] t[6] t[7]
În exemplul dat, şirul 'I epuras • este alcătuit din şapte caractere. Octeţii de
a 11a 7 memoreatil caracterele din care este alcătuit şiru l. Restul octeţilor, de la a
a 255 au un conţinut neprecizat. De altfel, nici nu ne interesează conţinutul lor.
faptul că afişarea s-a realizat, în ansamblu, prin precizarea numelui.
Observaţi
Mai mult, putem modifica conţinutul unui singur octet, aşa cum rezultă din
programul următor.
var t: string;
begin
t 1• ':Iepuras•;
t[6] 1'11 ' i ' l
write(t)J
end.
in urma atribuirii, variabila z reţine cuvântu l" ~epuras" şi acesta este afişat.
76 Capitolul 3 - Şiruri de caractere
Exemplu: v ar t: string[4];
Variabila t, ocupă 5 oc:teţi. Primul, cel de indice o, are rolul de a reţine
lungimea cuvântului memorat. In acest caz, variabila poate reţine cuvinte ce au cel
mult 4 caractere. Programul afişează 'mama'.
var tt string[4 ] ;
begin
t z• 'mama';
write(t);
end.
Exemplu:
var tz string[4];
t:= 'DANSATOR';
Exemplu:
var numet string;
Definiţia 3.2. Concatenarea este operaţia prin care din două şiruri de
caractere se obţine un al treilea, format astfel: p~imul şir (cel aflat în
stânga operatorului), urmat de al doilea şir (cel aflat in dreapta
operatorului).
:.amplu:
program st6;
var t, z: string;
begin
t := •acest';
z := ' exemplu';
t :• t+z;
writeln(t);
end.
J Observaţii
•
1. Dacă am fi scris t :mz+t; programul ar fi afişat • exempluacest 1 • De
aci tragem concluzia că operaţia de concatenare nu este comutativă (contează
:;dlnea în care sunt trecuţi cel doi operanzi).
2. Observăm cât este de important să ţinem cont de poziţia blank-ului (al
::oilea şir este precedat de blank). Observaţi că dacă am făcut concatenarea z+t,
am obţinut şirul 1 exempluacest 1 , care este precedat de blank.
• dacă codul primului caracter al şirului a este mai mare decât codul
primului caracter al ş irului b , atunci a>b.
• dacă codul primului caracter al şirului b este mai mare decât codul
primului caracter al şirului a, atunci a<b (b>a ).
Exemple:
• a=' abc' , b= 'bactr •. Atunci a<b, pentru că a [ 11 este a şi are codul mai
mic decât b [ 1 1 care este b .
• a= 1 abc 1 , b= • aba 1 • Atunci a>b, codul lui a [1] este egal cu codul lui b [1] ,
codul lui a [ 2 J este egal cu codul lui b [ 21 iar codul lui a [ 3 1 este mai mare
1
• a• • abc' 1 b= 1 abea •. Aici m=3, n=4. Atunci a<b, codul lui a [1] este egal cu
codul lui b [11. codul lui a [2 1 este egal cu codul lui b [2], codul lui a [3 ]
este egal cu codul lui b[3] şi n>m (şirul bare mai multe caractere).
Algoritmul de sortare este unul studiat (care?), motiv pentru care nu revenim
asupra lui. Programul este prezentat în continuare:
Exemple:
şiru l •mama • are lungimea 4;
4 Exemple de utilizare
a) var a: string;
c: integer;
2. După
cum am învăţat, octetul de indice o reţine lungimea şirului. Pentru c
obţinefolosim funcţia ord astfel: ord(a [01 >. De ce aşa? Atunci când scne-
a[OJ ne referim la un caracter. Folosind această expresie obţinem caracterul ca
are codul dat de număr (în binar). Deci, pentru a obţine codul său, utiliz~
funcţia ord.
var a: string;
begin
write('a= '); readln(a);
writeln('lungime a sirului a este ' length(a))t
writeln('lungime a sirului a este • ord(a[O)));
end.
Un caz aparte de şir este şirul vid. Prin şir vid Înţelegem un şir f/!1ră nici ...
caracter. Evident, şirul vid are lungimea o.
Definiţia 3.4. Fiind dat un şir de caractere, prin subşir al său se înţelege
un şir de caractere consecutive care se regăsesc în şirul iniţial.
Exemple:
• Şirul • harnic • are ca subşir şirul • mi •. Acesta începe în poziţia a treia din
şirul iniţial (3 caractere);
• Şirul • harnic • nu are ca subşir şirul • rnit •, chiar dacă primele trei
caractere (mi) se regăsesc în şirul iniţial.
'Mual de informatică pentru clasa a Xl-a 81
,. Funcţia copy are rolul de a extrage un subşir din cadrul unui şir dat:
function copy(s:string;inceput,lungime:integer):string;
variabila s (de tip string)- conţine şirul din care se face extragerea;
• inceput - reţine poziţia de început a subşi rului care se extrage;
• lungime - reţi ne numărul de caractere care se extrag.
var a, b: string;
i, j: byte;
begin
write('a= ') ; readln(a);
write('i= '); readln(i);
write('j= '); readln(j);
b := copy(a, i, j);
writeln(b);
end.
)- Funcţia pos are rolul de a verifica dacă un şir este subşir pentru altul:
function pos(subsir,sir:string):byte;
F uncţia returnează:
Exemple: 1. Fie şirul abcde 1 • Se caută subşirul 1 bcd 1 • Acesta este găsit, iar
1
2. Programul următor citeşte două şiruri a şi b şi verifică dacă b este subşir al lui
a. în ambele cazuri se dau mesaje. Dacă b nu a fost identificat ca subşir al lui a,
sau, în caz contrar, se afişează poziţia de început a sa.
var a, b: string;
n: integer1
begin
write('a= '); readln(a);
write('b• ')1 readln(b)J
n := poa(b,a);
if n • O then writeln('b nu este subsir al lui a')
else writeln('b este subsir al lui a si incepe in
pozitia • ,n) 1
end.
Exemplu:
var a, b: string;
begin
write(•a• '); raadln(a)t
write('b• '); readln(b)t
insert(b, a, 3);
writeln(a);
and .
)o> Procedura delete are rolul de a şterge un subşir din cadrul unui şir dat.
Pentru aceasta, ea are ca parametri, în ordine:
procedure delete(var sir: string; indice, nr_car: integer);
unde:
::Xemplu:
Programul următor citeşte un şir de caractere într-o variâbilă de tip string,
- -•ită a. Şirului cititi se şterge subşirul care începe în poziţia 3 şi are lungimea 2
::ouă caractere). De exemplu, dacă variabila a reţine şirul • abcde', se afişează
.aba'.
var a:string1
begin
write('a= ' ); readln(a)J
delete(a,3,2);
writel n(a);
end.
O Aplicaţia 3.2. Ştergerea tuturor apariţiilor unui subşir din cadrul unui şir:
var sir., subsir: stringi
poz, lung: byte1
begin
writeln(•introduceti sirul')l readln(sir);
writeln('introduceti subsirul '); readln(subsir)J
lung:~ length(subsir);
poz :• pos(subsir, sir);
while poz <> O do
begin
delete(sir, poz, lung);
poz := pos(subsir, sir);
end;
writeln(sir)J
end.
84 Capitolul 3 - Şiruri de caractere
O Aplicaţia 3.3. Înlocuirea tuturor apariţiilor unui subşir cu alt subşir. Analizaţi
programul următor pentru a descoperi modul în care se realizează aceasta:
var sir, sir_ sters, sir_adaugat: string;
poz, lungt byte;
begin
writeln( 1 introduceti sirul 1 ) ; readln(sir);
writeln( 1 introduceti sirul care se sterge);
readln(sir_sters);
writeln( 1 introduceti sirul care se adauga)/
readln(sir_ adaugat)J
lung := length(sir_sters);
poz :• pos(sir_sters, sir);
while poz <> O do
begin
delete(sir,poz,lung);
insert(sir_adaugat, sir, poz);
poz t= pos(sir_ sters, sir);
end1
writeln(sir};
end.
Exemplu:
var a: string1
n: integer;
begin
write ( 1 n• '); readln(n);
str(n, a);
writeln(a)
end.
};> Pentru realizarea conversiei utilizăm procedura val. Ea are trei parametri şi
anume:
proc:edu.re val (a: atring1 var variabila...JNIIIB%'ica; var cod._er: integer) ;
unde:
• a - conţine şirul ce urmează a fi convertit;
var as stringi
x, ers integer;
begin
write('Sirul este ')1 readln( a)l
val(a, x, er)1
if er • O then writeln(' conversia a reusit •, x)
el se
begin
writeln ('conversia nu a reusit')/
writeln(x)
end
end.
Observaţii
•
Dacă şirul de caractere cifre este precedat de un număr de blank-uri,
conversia reuşeşte.
Exemplu: şirul 1
123 1 se poate converti către valoarea 123.
Dacă variabila care reţine rezultatul este de tip întreg, iar şirul conţine punctul
zecimal, conversia nu reuşeşte.
Aceste variabile se citesc începând din poziţia curentă a cursorului până este
citit numărul de caractere necesar tipului sau până s-a ajuns la sfârşitul de linie.
Programul de mai jos demonstrează acest fapt (dacă linia 1 a fişierului are 3
caractere, se vor afişa două pe un rând şi unul pe al doilea rând). După citirea unei
astfel de variabile, pointerul se află sau pe caracterul ce urmează după ultimul
caracter citit sau pe CR. În situaţia în care pointerul se află pe CR şi se forţează o
nouă citire de tip String, se returnează şirul vid.
var f: text;
a: string[2];
b: string;
begin
assign(f, 'fl.dat');
reset(f);
read(f, a);
writeln(a);
read(f,b);
writeln(b);
close(f);
end.
3.3.1. Generalităţi
1 c 1 a 1 1 1 c 1u , ........................................................................................, J
O
Exemple:
• char vect(ll]="calculator".
char vect {] •"calculator". În acest caz, compilatorul face calculul
numărului de octeţi necesari.
char vect [100]a"calculator". Am rezervat mai mulţi octeţi decât era
necesar.
#include <iostream.h>
main()
{
char a[20];
cin>>a;
cout<<a;
}
·J~ Observaţii
./ Caracterul nul este adăugat automat.
Exemplu: a [O]= 1 c 1
, a [1) =•a 1
, ş.a.m.d.
Din păcate, prin metoda de mai sus nu poate fi citit un şir care conţine mai
multe cuvinte separate prin spaţii. De exemplu, dacă la rularea programului anterior
tastăm şirul" un om", se va afişa "un". Aceasta înseamnă că citirea se face astfel:
Din acest motiv, pentru citirea şirurilor de caractere vom utiliza o funcţie de
un tip special, pe care o prezentăm în continuare.
)> Funcţia:
Observaţii
sau când
2.. _a fel ca mai sus, dar citirea se întrerupe la întâlnirea caracterului
1
1 g
În C++ pot exista mal multe funcţii cu acelaşi nume, dar care diferă
prin
::.arametrii primiţi. Astfel, există şi funcţia:
ain.ge t()
~ră parametri. Ea are rolul de a citi un caracter (fie că este alb, fie că nu).
cu trei parametri, citirea se face până la Tntâlnirea lui. Tn concluzie, se citeşte şirul
vid. Utilizatorul nu mai apucă să îşi tasteze textul. - Prin utilizarea funcţiei fără
parametri, acel caracter se citeşte şi noua citire se poate efectua fără probleme.
#include <iostream.h>
main()
{
char a[]a"masa";
cout<<a+l<<" "<<a+2<<" "<<a+3;
Din acest motiv, programul ti păreşte pentru a+l şirul "asa" , pentru a+2
şirul "sa", ş.a . m . d . Mai mult, vectorii astfel adresaţi pot fi accesa ţi aşa cum
suntem deja obişnuiţi. Astfel, pentru exemplul anterior, (a+l) [OJ reţine caracterul
'a' , (a+l) [1] reţinecaracterul •s •,etc.
După cum observaţi, a+l, a+2, ... sunt expresii. Orice expresie are un
anumit tip. Care este tipul lor? Tipul acestor expresii este char*. Ce semnificaţie
are? Semnificaţia este cea de adresă.
•!• O variabilă de tipul char* poate reţine adresa unui vector de caractere.
•!• În C++, numele unui vector de caractere este o adresă constantă de vector
şi poate fi atribuit unei variabile de tip char*.
~ _aJ de informatică pentru clasa a Xl- a 93
#include <iostream.h>
main()
( char a[]•"Exemplu", *p;
paa; cout<<p<<endl;
p++; cout<<p<<endl;
p++l cout<<p<<endl;
cout<<p[ll<<endl;
cout<<p-a;
}
~ Funcţia strlen are rolul de a returna lungimea efectivă a unui şir (în calculul
lungimii nu intră caracterul nul). Forma generală este:
size_ t strlen(char*);
unde:
• size_ t este un tip întreg, utilizat în adresarea memoriei, definit în "string.h"
(îl putem privi ca pe tipul unsigned int);
• argumentul este de tip char* (adică o adresă către un şir).
94 Capitolul 3- Şiruri de caractere
#include <iostream.h>
#include <string.h>
main()
{ char a[lOOJ;
cin . get(a,lOO) ;
cout<<"Sirul citit are "<<strlen (a)<<" caractere";
}
Aşa cum ştim din lucrul cu tablouri, atribuirile de forma a•b, unde a şi b sunt
vectori de caractere, nu sunt permise. Tot aşa, o atribuire de forma a:::"un sir"
nu este permisă. Astfel de operaţii ca şi multe altele se fac cu anumite funcţii, puse
la dispoziţie de limbaj. Pentru ca acestea să poată fi folosite, trebuie să fie inclus
fişierul antet "string. h", tot aşa cum includem fişierul "iostream. h". Ordinea
de includere nu are importanţă. fn continuare, vom prezenta cele mai uzuale funcţii
şi modul fn care acestea se folosesc.
şiare rolul de a copia şirul de adresă sursa la adresa dest. Copierea se termină
după ce a fost copiat caracterul nul. Se returnează adresa dest. Analizaţi
codul următor:
#include <iostream.h>
#include <string . h>
main()
{ char a[lOO]="un sir", b[lOO]•"alt sir"t
strcpy (a,b);
cout<<at
}
şi rolul de a adăuga şirului de adresă dest şirul de adresă sursa. Şirul de adresă
sursa rămâne nemodificat. Această operaţie se numeşte concatenare şi nu este
comutativă. Rezultatul este adresa şirului sursa, iar şirul va avea ca lungime,
suma lungimilor celor două şiruri care au fost concatenate.
.,... Jal de informatică pentru clasa a Xl-a 95
r ace)aşl
ro) ca strcat cu deosebirea că adaugă şlru)u'l destmaţ'le prlm'll nr octeţi al
s rului sursă. Adăugarea caracterelor se face Tnaintea caracterului nul. Funcţia
-etu rnează adresa de început a şirului destinaţie.
#include <iostream.h>
#include <string . h>
main()
{
char a[20]•"Acesta este"1
cout<<strchr (a,'t 1 )1
}
Programul de mai jos tipăreşte indicele primei apariţii a caracterului 't', şi anume 4:
#include <iostream.h>
#include <string.h>
main()
{
char a[201="Acesta este";
cout<<strchr (a, •t•)-a;;
}
,Jw Observaţii
../ Variabila t este de tipul char* .
../ Testul de apartenenţă a caracterului la şir s-a făcut prin a vedea dacă
variabila t reţine sau nu o (adică o adresă nulă de şir).
#include <iostream.h>
#include <string.h>
main()
{
char a[lOO], *t,c;
cout<< "introduceti sirul "; cin.get(a, lOO);
cout<< "caracterul cutat "; cin>>c;
t=a-1;
do
(
t++;
t=strchr(t,c); .
if (t) cout<<"Indicele este "<<t-a<<endl;
} while (t);
}
Fiecare adresă de subşir, care are ca prim caracter cel reţinut de c, intră în
calculul indicelui acelui caracter - din ea se scade adresa de început.
97
- 3. 7. Compararea şirurilor
? Dar care este mecanismul prin care se compară două şiruri de caractere?
•
Fie m numărul de caractere al şirului sl şi n numărul de caractere al şirului s2.
5ă presupunem că primele i caractere ale lui sl coincid cu primele i ale lui s2.
:J În cazul în care codul caracterului i+l al şiru l ui sl este mai mare decât codul
caracterului corespunzător şirului s2, avem sl>s2.
:l În cazul' în care codul caracterului i+l al şirului sl este mai mic decât codul
caracterului corespunzător şirului s2, avem sl<s2. ln cazul in care şi la
această comparaţie avem egalitate, avem patru posibilităţi:
• ambele şiruri au un număr strict mai mare de caractere decât i+l, caz în
care se compară ca înainte caracterele de pe poziţia i+2;
• . sl are i+l caractere, iar s2 are un număr de caractere mai mare decât
i+l, în acest caz sl<s2;
• s2 are i+l caractere, iar sl are un număr de caractere mai mare decat
i+l, în acest caz sl>s2;
Pe scurt, un şir sl este mai mic ca altul s2, dacă Tn dicţionar sl ar figura
înaintea lui s2.
Exemple: "soare">s;
"tata">mama;
98 Capitolul 3 -Şiruri de caractere
(;, Funcţia strcmp face distincţie Între literele mari şi miel ale a/fabetului.
•
> Funcţia stricmp are forma generală:
int stricmp(char *s1,char *s2);
şi acelaşi rol ca strcmp. Diferenţa este că nu face distincţie Între literele mari şi
miel.
Vectori de cuvinte. Există aplicaţii in care este necesar să se lucreze cu n
cuvinte - fnţelegând prin cuvânt o succesiune de caractere care nu sunt albe. în
acest caz avem posibilitatea să declarăm vectori de cuvinte. Acestea sunt, de fapt,
matrice cu elemente de bază de tip char.
Fiecare linie din cele 10 ale matricei poate reţine un şir de caractere. Acesta poate
avea cel mult 25 de caractere (inclusiv caracterul nul). Cuvintele pot fi adresate prin
a [O] (primul cuvânt), a [1) cuvântul al doilea, ş . a . m . d.
do
{ gasit=O;
f or (i=O;i<n-l;i++)
if {strcmp(cuvinte[ i],cuvinte[i+l])>O )
{ strcpy(man,cuvin te[i]);
strcpy(cuvinte[i ],cuvinte(i+l]);
strcpy(cuvinte[i+ l],man);
gasit=l;
}
}
while (gasit);
for (i=O;i<n;i++) cout<<cuvinte[i ] <<endl;
Dacă pot compara două cuvinte, atunci pot să le sortez. Am folosit sortarea
nterschimbare. lată că, algoritmii, cu precădere cei fundamentali, pot fi folosiţi
"'tr-un context diferit de cel în care au fost prezentaţi.
3.8. Subşiruri
#include <iostream.h>
#incl ude <string.h>
m.ain()
{
char sir(l000],subsir[ 25], *t;
cout<<"introduce ti textul ";
cin.get(sir,lOOO );
cin.get();
cout<<"introduce ti subsirul cautat ";
cin.get(subsir,2 5);
t=strstr(sir,sub sir);
if (t) cout<<"este subsir si are indicele "<<t-sir;
else cout<<"nu este subsir";
}
100 Capitolul 3- Şiruri de caracterE
O Aplicaţia 3.10. Ştergerea tuturor apariţiilor unui subşir din cadrul unui şir
Imediat ce am identificat adresa de inceput a subşiruloi, restul şirului (fără subşir)
este copiat pe poziţia de inceput a subşirului.
#include <iostream.h>
.# include <string . h>
main()
{ char sir[1000],subsir[ 25],*p;
int lung_subsir;
cout<<"introduce ti textul ";
cin.get(sir,1000 );
cin.get();
cout<<"introduce ti subsirul ";
cin.aetlBUbB~r,~~)i
lung_ subsir=strlen(su bsir);
p•strstr(sir,sub sir);
while (p)
{ strcpy(p,p+lung_ subsir);
p • strstr(p,subsir) ;
)
cout<<sir;
)
O Aplicaţia 3.11. fnlocuirea tuturor apariţiilor unui subşir cu alt subşir. Vă las pe
dvs. să descoperiţi modul in care programul următor realizează aceasta:
#include <iostream.h>
#include <string.h>
main()
( char sir[100], man[100], sterg[25], ada ug[25], *p;
int lung_ sterg, lung_ adaug;
cout<<"introduce ti textul ";
cin.get(sir,lOO) ;
cin.get();
cout<<"inlocuim subsirul ";
cin.get(sterg,25 );
cin . get();
cout<<"cu subsirul "1
cin.get(ad&ug,25 );
lung_ sterg• strlen(sterg);
lung_ adaug•strlen(ada ug);
p•strstr(sir,ste rg);
while (p)
(
man[O] • O;//subsir vid;
strncat(man,sir, p-sir);
strcat(man,adaug );
strcat(man,p+lun g_ sterg);
atrcpy(sir,man);
p•strstr(p+lung_ adaug,sterg);
)
cout<<sir;
. )
a.~ual de Informatică pentru clasa a Xl-a 101
Exemplu: şirul sl. este " mama, tata si bunicul". Şirul s2 este:
" , ". Întrucât caracterele separatoare sunt blank-ul şi virgula, rezultă că
entităţile sunt: ":mama", "tata" "si" "bunicul".
• la prima apelare care trebuie să fie de forma strtok ( sl, s2) 1, funcţia
intoarce adresa primului caracter al primei entităţi (în exemplu "mama"). in
plus, după prima entitate separatorul este înlocuit automat prin caracterul
nul (cod O);
• următoarele apeluri ale funcţiei sunt de forma strtok (NULL, s2);, iar
funcţia intoarce de fiecare dată adresa primului caracter al următoarei entităţi
şi , după ea, este adăugat caracterul nul - aceasta permite ca entitatea să
poată fi extrasă cu uşurinţă.
Caută primul caracter al şirului al în s2. Dacă este găsit, returneaza adresa
sa din cadrul şiru lui sl şi execuţia se termină, altfel trece la pasul următor.
• Caută al doilea caracter al şirului sl în s2. Dacă este găsit, returnează adresa
sa din cadrul şirului sl şi execuţia se termină, altfel trece la pasul următor.
•
• dacă nici un caracter al şirului al m:. aparţine şirului s2, funcţia returnează
adresa nulă.
104 Capitolul 3 - Şiruri de caractef"!
~~ <iostream.h>
~:de <string.h>
~~e <stdlib.h>
IIIC..:::.
:.:.ar sir[lOOO],separator[]=" ",cifre[]="0123456789.+-", *p;
!.cx!b~ e s=O;
~ .get(sir,lOOO);
~st rtok(sir,separator);
~le (p)
i f (strspn(p,cifre)==strlen(p)) s+=atof(p);
p=strtok(NOLL, separator);
:::_... :":'<3 ecvt are rolul de a converti o valoare de tip double către un şir.
:..~e rul nul este adăugat automat şirului obţinut. Forma generală este:
~· ecvt(double valoare, int poz, int* zec, int* semn);
Funcţia nu inserează în şir nici punctul zecimal, nici semnul numărului. Şirul
:oţi nut
începe cu cifra cea mai semnificativă a numărului. Pentru ca şirul obţinut să
re corect, este necesar să fie prelucrat, fn continuare, de către programator. Dacă
- Jmăru l poziţiilor ocupate de şir (poz) este mai mare decât ocupă data, şirul este
completat în stânga cu un număr de o necesar. in cazul în care numărul poziţiilor
~ste mai mic decât cel ocupat de număr, rezultatul este rotunjit.
dacă val reţine 1234, atunci se returnează şirul "123", zec reţine 4 şi
semn reţine o.
dacă val reţine 1239, atunci se returnează şirul "124", zec reţine 4 şi
semn reţine o.
dacă val reţine 1, atunci se returnează şirul "100" , zec reţine 1 şi semn
reţine o.
dacă val reţine -0.001, atunci se returnează şirul "100", zec reţine -3
şi semn reţine 1.
)> Funcţia itoa are rolul de a converti o valoare de tip int într-un şir, a cărui
adresă este memorată in variabila sir. Valoarea baza reţine baza de numeraţie
către care să se facă conversia (de obicei baza este 10). fn cazul bazei 10, şirul
obţinut reţine şi, eventual, semnul"-". Funcţia întoarce adresa şirului obţinut.
)> Funcţia 1 toa are acelaşi efect ca i toa, deosebirea fiind dată de faptul că se
converteşte către şir o valoare de tip long int.
)> Funcţia ultoa are acelaşi efect ca itoa, deosebirea fiind dată de faptul că
se converteşte către şir o valoare de tip unsigned long.
Funcţia
, Funcţia
, Funcţia
Pentru a citi o linie a unui fişier text, se poate folosi funcţia următoare:
Funcţia citeşte un şir de caractere, pân ă când una dintre condiţiile următoare
este îndeplinită:
Evident, în acest fel, la o citire pot fi aduse în memorie cel mult 32766
caractere (vezi limitele tipului int).
l~ Observaţii
•
../ Caracterul care marchează sfârşitul liniei ' \n' nu este inserat în şir, în
schimb este inserat caracterul nul (march ează sfârşitul şiru lui) .
../ Este suficient să apelăm funcţia cu primii doi parametri, ultimul fiind implicit.
../ Dacă se doreşte, ultimul parametru poate fi apelat explicit cu o valoare
convenabilă, caz Tn care citirea se face până la intâlnirea ei sau până când
au fost citite Nr_car-1 caractere.
· ..11. Programulurmător citeşte linie cu linie un fişier text ale cărui linii nu au
~. mai mult de soo de caractere şi afişează liniile pe monitor. Nu se
• cunoaşte lungimea fiecărei linii.
#include <fstream.h>
main()
{ fstream f("f.dat",iosz:in );
char Linie_citita[501 );
while (f.getline(Linie_ ci tita,501))
cout<<Linie_citit a<<endl;
}
Observaţie foarte
(;. efectuează
importantă! Prin f»Linie_citito. , citirea se
• astfel:
a) începând cu poziţia curentă a pointerului se sar toate caracterele albe;
b) se citesc toate caracterele până la întâlnirea unui caracter alb.
De exemplu, dacă o linie a fişierului conţine şirul " Afara ploua", se
citeşte şirul"Afara". Testaţ.i!
iX~ ~al de informatică pentru clasa a Xl-a 1os
#include <fstream.h>
main()
{ fstream f("f.dat",ios::out);
f<<" Afara este"<<endl;
f<<"primavaral";
f . close() 1
}
Un şir x
reţine "1 2 3 4 5". O funcţie specială ( numită constructor)
.i:aşează şirului x , un stream (flux), numit ins. Ea are doi parametri: şirul x şi
.-gimea lui: istrstream ins (X, strlen (X)) 1.
#include <iostream.h>
#include <strstrea.h>
#include <string.h>
main()
{
char X[)="l mama tata 4 bunica";
char cuvant [20);
istrstream ins{X, strlen{X));
while (ins>>cuvant && strlen(cuvant))
cout<<cuvant<<en dl;
}
Probleme propuse
1. Se de la tastatură un text. Cuvintele se
citeşte consideră separate prin virgulă
spaţiu sau punct. eate cuvinte are textul citit?
3. Se citeşte un text. Două cuvinte pot fi separate printr-unul sau mai multe spaţi i
Se cere să se elimine spaţiile inutile.
4. Se un fişier text care conţine o singură propoziţie, pe o linie. Programul
citeşte
rea ranjează literele în fiecare propoziţie, in ordine alfabetică, păstrand locul
cuvintelor. Numai literele de la 'A' la 'Z' sunt afectate. Celelalte caractere rămân
neschimbate. Ieşirea va fi tot un fişier text. Numele fişierelor este ales de dvs.
Exemple:
Junior Divislon
1
::.,ual de informatică pentru clasa a Xl- a
ea micşorată a cuvâ
ntului "MISSISSIPPI",
ve rsi un
:.. Eli mi na re. "MSSSS
PP " es te micşorată şi ea :
uro r lite rel or "1". O frază poate fi
:~n ută prin elimi
na rea tut RSR C FAT", prin
RA TE " are ve rsiunea micşorată ''TRV
~AVERSAREA CA
II FE ne literele dintr-o
"E" . Se ce re ca programul dvs. să elimi se
= 11inarea literelor "A ", "1", ă linie. Literele care
t np ut . tx t" şi scrisă pe o singur
ul "i
-ază citită din fişier
tex t .tx t" .
este în fişierul "o ut pu
:m ină se citesc de
la tastatură, iar ieşirea
Ju nio r Di vls ion
ză lim ba jul
co lec tiv - nu ma i pe ntr u ele vii care studia
în
- Problemă de luc ru
l. Şir uri ge ne ral iza te.
:~asca re
ţum iţi de faptul că,
in Pascal, şirurile cu ca
sun teţ i mul
Presupunem că nu
caractere.
~e poate lucra po t
avea cel mult 25 5 de
caractere.
luc răm cu şiruri care
au cel mu lt 30 00 de
De exemplu , do rim să
iar sfârşitul unui şir
reţ inu t ca un ve cto r de 30 00 de caractere,
Jn astfel de şir va fi
valorii o (in binar).
:a fi marcat prin memorarea
subprogramele următoare:
Scrieţi
şir ;
ină lungimea unui
• subprogram care determ
şiruri ;
ite concatenarea a două
• subprogram ca re perm
şir pentru altul;
şir este sau nu sub
bp rog ram ca re identifică dacă un
• su
teşte un şir către
un int reg;
• subprogram care conver
re un şir;
teşte un intreg căt
• subprogram care conver
teşte un şir către
un număr rea l;
• subprogram care conver
teşte un real către
un şir;
• subprogram care conver
anumită poziţie a
altui şir ;
rog ram ca re ins erează un şir pe o
• subp
aşte poziţia
re şterge un subşir
al unui şi r da t (se cuno
• su bp rog ram ca
;
de inc ep ut a subşirului)
intr-un fişier tex t;
su bp rog ram ca re permite sc rierea unui şir
•
n fişier text.
ite citirea unui şir dintr-u
• subprogram care perm
Capitolul 4
Structuri de date neomogene
f Observaţii
•
v" Pentru a adresa un anumit câmp al variabilei de tip RECORD, se foloseşte
numele ei, urmat de '.', apoi de numele câmpului.
.-·· "
~ual de informatică pentru clasa a Xl-a
115
Aşa cum s-a arătat, elementele unui vector pot fi de orice tip, deci inclusiv
tip RECORD.
Adresarea câmpurilor se face prin numele vectorului, urmat
de perechea de
ranteze drepte între care este trecut indicele compo
nentei, apoi selecţia
~ ri u-zisă se face aşa cum am învăţat.
1• Limbajul permite ca
realizează aceasta?
înregistrările să aibă o structură variabilă. Cum se
f Observaţii
•
/ Pentru fiecare inregistrare de acest tip compilatorul rezervă numărul de
octeţinecesari celei mai lungi variante.
/ Este preferabil ca citirea unei variabile de tip înregistrare cu variante să se
facăprin utilizarea instrucţiunii CASE.
118 Capitolul 4. Structuri de date neomogene
În practică, apar situaţii în care toate tipurile de date învăţate până în prezent
nu ne sunt de mare folos. Pentru a înţelege aceasta, vom porni de la un exemplu .
În C++ există un tip de date, numit atruot, care ne permite acest lucru.
Forma generală este (ce este trecut între paranteze drepte este considerat facultativ):
struct [nume structura]
{
[<tip> <nume variabila[, nume variabila, •• • ]>]
[<tip> <nume variabila[, nume variabila, •• • ]>] 1
} [lista de variabile] 1
şi se numeşte elev.
IJan ual de informatică pentru clasa a Xl-a
119
Exi stă două posibilităţi de dec lara re a vari abil elor care _alc
ătuiesc structura.
1. Aşa cum rezultă din form a generală, scriind la sfârşit numele variabilelor:
stru ct ele v
{ cha r num e[20 ], pren ume [20]
;
floa t nota _ma te,n ota_ info ;
int var sta1
}in r1,i nr2 ;
mai n()
{ ele v inr1
cout <<"N Ume "1 cin> >inr .num
e;
cou t<<• Pren ume "1 cin> >inr .pre
num e1
oou t<< "No ta mat ema tica ";
cin>>inr.nota~te;
cou t<< •No ta info rma tica "1
cin> >in r.no ta_i nfo ;
oou t<< "Va rsta "1
cin> >in r.va rsta 1
cout <<" Am oit it t •<< end l
<<in r.nu me< <" "<< inr. pren ume
<<e ndl
<<inr.nota~te~<endl
<<i nr.n ota_ info <<e ndl
<<i nr . var sta;
}
120 Capitolul 4. Structuri de date neomogene
Între două variabile de acelaşi tip struct se poate folosi atribuirea. Astfel,
dacă inrl, inr2 sunt două variabile de tip elev, prin atribuirea inrl:::inr2,
variabila inrl ia aceeaşi valoare ca variabila inr2. În C++, o astfel de atribuire se
mai numeşte copiere bit cu bit.
struct elev
( char nume(20], prenume[20];
struct
( int clasa;
float note(20] ;
}situatie;
int varsta;
} ;
l't· .,. Fie inr o inregistrare de tipul elev. În aceste condiţii, accesarea
Q %: 1
elementelor situate în interiorul substructurll se face ca mai jos:
struct elevl
( char nume[20], prenume[20);
struct
( int clasa;
float note[20);
}situatie_ l, situatie_2;
int varsta;
};
} [lista de variabile] ;
main()
{ persoana pers;
cout<<"Nume persoana " ;cin.get(pers . nume,30);
cout<<"Studii f-fara g-generala,l-liceu;s-superioare) ";
cin>>pers.studii;
switch (pers.studii)
{
case •g •: cout<<" numar clase" ;
cin>>pers.std . nr_clase;
break;
case '1': cout<<"anul terminarii liceului" ;
cin>>pers.std . liceu.an_t;
cout<<"orasul ";
cin>>pers.std.liceu.oras;
break;
case •s•: cout <<"nwnele facultatii ";cin.get();
cin.get(pers.std.facultate.nume_f,30);
cout<<"nr ani de studiu ";
cin>>pers.std . facultate.nr_ani;
}
~ anual de informatică pentru clasa a Xl-a 123
//afisez inregistrarea
cout<<pers.nume<<endl;
switch (pers . studii)
{
case 'f': cout<<•n-are saracu• studii"; break;
case 'g': cout<<" numar clase "<<pers.std.nr_clase; break;
case '1': cout<<"a terminat liceul in"
<<pers.std.liceu.an_t
<<" in orasul "<<pers . std.liceu.oras; break;
case •s•: cout<<"numele facultatii"
<<pers.std.facultate.nume_f
<<" nr ani de studiu "
<< pers.std.facultate.nr_ani;
}
}
Probleme propuse
1. Citiţi o variabilă cu următoarea structură:
• nwne_elev: 30 caractere;
• data_nasterii:
zi : intreg;
luna : intreg;
an : intreg;
• nota matematica - real;
• nota informatica - real;
• nota engleza - real;
• media - real;
Testaţi dacă datele au fost introduse corect. Citirea se va verifica prin afişarea
rezultatului.
2. Citiţi n înregistrări de tipul celei de mai sus şi afişaţi-le în ordinea alfabetică a
numelui.
• o mulţime de valori;
• o regulă de codificare a acestora; 1
• o mulţime de operaţii definite pe mulţimea datelor.
Prin tipul de mai sus se descrie structura unei variabile capabilă să reţină
numere raţionale. Fie A 1 mulţimea valorilor care pot fi memorate prin utilizarea
tipului întreg. Fie A2 =A1 ··{0}. Atunci, o variabilă de tip ratio nal poate memora
valori care aparţin mulţimii A 1 XA2 • Evident, este sarcina programatorului ca valoarea
reţinută de variabila corespunzătoare lui q să fie diferită de o.
în unele lucrări veţi întâlni definiţii ale tipului de date care exclud regula de codificare. Aici
1
Fie B mu lţimea valorilor care pot fi reţinute de tipul real. Atunci, variabila a
poate reţine la un moment dat un element al mulţimii :
BxBx ... x B.
~
de 11 an'
Practica impune utilizarea unor structuri ale datelor de o mare varietate, care
nu se suprapun întotdeauna peste tipurile care pot fi descrise prin limbaj .
Vom numi nod, o variabilă de un tip oarecare. De obicei, acest tip este
structurat. După caz, termenul nod poate fi înlocuit cu articol, înregistrare sau
entitate.
fn cele mai multe cazuri, "ansamblul de date" care formează structura este
alcătuit dintr-o mu lţime cu un număr variabil de noduri.
Relaţiile existente Tntre noduri şi operaţiile care pot fi efectuate cu ele vor fi
prezentate prin exemple.
IH: De reţinut!
fJÎ
./ ln practică s-au impus anumite structuri. Acest lucru este datorat faptului că
există mulţi algoritmi care le utilizează. Ele vor fi tratate, pe scurt, în
paragrafele următoare.
126 Capitolul 5. Structuri de date
Definiţia 5.2. O listă liniară este o colecţie de n~O noduri, x1, xl, ... , Xn
aflate într-o relaţie de ordine. Astfel, X 1 este primul nod al listei, X 2
este al doilea nod al listei, ..., Xn este ultimul nod.
a) Evidenţa situaţiei şcolare a elevilor unei clase. Fie n numărul elevilor. Aici, un
nod reţine numele unui elev şi notele la diversele materii. Vom avea deci, n noduri.
Nodurile vor fi memorate in ordinea alfabetică a numelor elevilor. În clasa
respectivă pot fi transferaţi elevi din alte clase, caz in care se adaugă noduri. Din
clasă, unii elevi pot pleca în alte clase, caz in care se şterg noduri.
a) Accesul la oricare nod al listei se poate face cu mare uşurinţă . Dacă dorim să
adresăm nodul k, atunci scriem v [kl (presupunand că vectorul care reţine nodul
se numeşte v).
1 71 1 1 12 1 8 1 9 15 1 8 13 12 1 6 +. . . . .f...........
f...........l.......... I........... +. . . . . +. . . J
J......... I..........
1 71 3 1 1 1 2 1 8 19 1 5 18 1 3 1 2 1 6 1
128 Capitolul 5. Structuri de date
111 13 11 12 la 19 15 la 13 12 16 1
Acum se completează valoarea reţinută de nodul 2:
171 5 1 3 11 12 1a 19 15 18 13 12 16 1
Observaţii
adr1
.J.I..:..ad.::.:.r:...dt---~11!
Ll..:.in:.:..
1
adr2
1 in2 1adrd .. nil
• in1, in:l, ... , inn reprezintă informaţiile conţinute de noduri, de altă natură
decât cele de adresă.
"ecare nod reţine adresele predecesorului şi succesorului său, aşa cum se vede i n
"gura următoare:
1 nil 1in 1 1 adr2 1 • • 1 adr1 1 in2 1 adr3 C: ::::J adrn·11 inn 1 nil
adG ad~ adrn
Aşa cum am invăţat, lista liniară este alcătuită din mai multe noduri intre care
există o relaţie de ordine. Tn cazul alocării Tnlănţuite, informaţia memorată de
• ecare nod va cuprinde şi un câmp de adresă -in cazul alocării simplu inlănţuită
sau două câmpuri de adresă -in cazul alocării dublu Tn lănţuită. in acest paragraf
vom studia implementarea alocării simplu in lănţuită.
lată cum se descrie informaţia dintr-un nod, în cazul listelor alocate simplu
înlănţuit, atunci când acesta reţine un nu[llăr intreg.
• Pentru memorarea listei folosim un vector care are componentele de tip Nod,
descris mai jos:
·Varianta C++
Lista=array[l •• lOOO) of Nod; nod L[1000];
var L:lista~
Din descriere rezultă că lista poate avea cel mult 1000 de noduri. Acesta
este spaţiul disponibil.
L ~~~-7~-3--~--~--_.-5~~4--~~--5--~4~--o--~~~~
1 2 3 4 5 6
130 Capitolul 5. Structuri de date
1~~.~ J • I o
.~rJ. Ce observăm?
a) Fiecare nod trebuie să reţină şi adresa nodului următor. Adresa este, de fapt,
indicele componentei din vector care reţine informaţia asociată nodului următor.
Prin urmare, necesarul de memorie este mai mare.
L ----.1 3 15 1 11
4 1 5 14
1 2 3 4 5 6
ocupat-.! o o
1 2 3 4 5 6
L ... 1 7 13 15 14 11 15 4 1o
1 2 3 4 5 6
ocupat---.1 o o
1 2 3 4 5 6
b) Memorăm informaţia: 9.
L~1713 Q 15 14 11 5 14 1 o
1 2 3 4 5 6
ocupat---.1 o
1 2 3 4 5 6
L ... 1 7 1 3 Q !1 5 14 1 1 15 14 1 o
1 2 3 4 5 6
ocupat---.1 o
1 2 3 4 5 6
L ... 1 7 1 3 Q fi 1 5 14 1 1 12 14 1o
1 2 3 4 5 6
ocupat---.1 o
1 2 3 4 5 6
[8] Problema 4. Ştergerea unui nod. sa presupunem că in lista de mai jos dorim
să ştergem al doilea nod.
L ---+1 1 7 3 15 14 11 1 5 14 1o
1 2 3 4 5 6
ocupat--+-1 o o
1 2 3 4 5 6
L •1 7 14 15 1 4 11 1 5 14 1o
1 2 3 4 5 6
ocupat--+-1 o o o
1 2 3 4 5 G
Lista va deveni:
Exemplele sunt date pentru lista liniară simplu înlănţuită, dar bine înţelese,
ne permit să deducem singuri modul de efectuare a operaţiilor respective pentru
liste dublu înlănţuite .
"'an ual de informatică pentru clasa a Xl-a 133
Definiţia 5.3. Stiva este o listă pentru care singurele operaţii permise
sunt:
-+ Stivele se pot aloca secvenţial (ca vectorii). Fie ST [il un vector. ST (11,
ST (2 1, ..., ST (n) pot reţine numai litere sau numai cifre. O variabilă k indică
in permanenţă vârful stivei, adică ultimul element Introdus.
0
D Scoatem din stivă pe B (A nu poate fi scos deocamdată); k=l.
0
D Scoatem din stivă pe A; stiva rămâne vidă k=O.
~ Observaţii
•
./ ln mod practic, la scoaterea unei variabile din stivă, valoarea variabilei ce
indică vârful stivei scade cu 1, iar atunci când scriem ceva în stivă, o
eventuală valoare reziduală se pierde.
134 Capitolul 5. Structuri de date
'
./ Este posibil să vă întrebaţi : de ce nu putem accesa un element al stivei, chiar
dacă nu este ultimul introdus? Nimeni nu ne opreşte~ doar că, în acest caz,
nu respectăm pri'ncipiul stivei.
a
C'X: Exemple
x-1, x~12
F(x) = {
F(F(x + 2)),x < 1.2
Vom incepe prin a studia modul de calcul al funcţiei pentru x=lS şi x=S:
f(15)=14;
f (8 )=f(f(10))=f(f(f(12))) =f(f(ll ))=f(f(f(13)))=f(f(12)) =f(11)
af(f( 1 3))=f(12)=11.
12 13
10 10 11 11
8 '1 8 8 8 8
12 13
8 11 11 12
f=11
~ Se poate demonstra uşor că pentru valori mai mici decat 12, funcţia ia
i -' valoarea 11. Observaţia simplifică mult programul, dar exemplul a fost dat în
alt scop.
2. Fu ncţia lui Ackermann. Se dă funcţia de mai jos, defin ită pe produsul cartezian
NXN. Se citesc m şi n . Să se calculeze Ack (m, n >.
l
n+1, m=0
Ack(m,n)= Ack(m-1 ,1 ), n= O
Ack(m - 1,Ack(m,n -1)),altfel
136 Capitolul 5. Structuri de date
ack(O,,ack(0,3))=ack(0,4 )•5.
Pentru calculul acestei funcţii, folosim o stivă dublă , ST. Iniţial, valorile m şi n
se reţin la nivetul 1. Pe nivelul k al stivei se reţin valorile curente m şi n . ln funcţie de
valorile acestora se procedează astfel:
• pentru cazul n=O, se rămâne pe acelaşi nivel in stivă, punând in locul lui m
valoaream-1, iar în locul lui n, valoarea 1;
1 o o1
2 o 1 1 1 1 1 1
2 1 2 1 2 1 2 1 2 1
1 o
1 1 1 1
o2 1 3 1 2 1 2
g1 1 3 1 2 1 3 1 3
o1
1 1 o2
1 2 1 2 o3
1 3 1 3 1 3 o4 ack(2,1 )=5.
137
lll.anual de Informatică pent ru clasa a Xl-a
Definiţia 5.4. O coadă este o listă pentru care toate inserările sunt făcute
la unul din capete, toate ştergerile (consultările, modificările) la celălalt
capăt.
1 2 3 4
2 3 4 5
3 4 5 6
Probleme propuse
1. Care dintre structurile de mai jos nu este liniară?
a) b) C) d)
cemplu: k=3; V= ( 1, 2, 3); p=2. Numărul citit este 5. După rulare trebuie să
rem:
:4;V=(l,S,2 ,3).
cemplu: k=3; V= ( 1, 2, 3); p=2. După rulare trebuie să avem: k=2; V== ( 1, 3).
Pentru problema anterioară, care dintre afirmaţiile de mai jos este falsă?
Pentru a şterge un nod aflat pe poziţia p sunt necesare k-p deplasări spre
inga ale conţinuturilor celorlalte noduri.
Subprogramul va avea parametrul k transmis prin valoare.
Subprogramul va avea parametrul k transmis prin referinţă.
Dacă k=p, nu se efectuează deplasări către stânga.
1
t
mului nod reţine adresa primului nod, se obţine o listă circulară:
1 ~--1--M~r 1 1 ·1 1 ,. . . . . . . . . . . . . ....... 1 1 1
.. 1
Creaţi o listă circulară in care fiecare nod reţine un număr natural. De
: menea, scrieţisubprograme de inserare şi ştergere a unui nod al listei create.
140 Capitolul 5. Structuri de date
10. În jurul arbitrului sunt aşezaţi N jucători numerotaţi în sens orar. Arbitrul,
începând de la un jucător K num ără până la M. Per.soana la care s-a oprit
numă rătoarea este elimin ată din cerc. Arbitrul repetă procedeul începând cu
persoana următoare celei eliminate. Procedeul se repetă până când rămâne un
jucător L. Să se scrie un program care:
Care din afirmaţiile de mai jos nu este adevărată după executarea secvenţei
de mai sus?
a) Din stivă au fost extrase, in această ordine, valorile: 2, 4, 3;
b) stiva este vidă; c) stiva conţine valoarea 1; d) stiva are un singur nivel.
15. Să se scrie un program care, pentru problema de mai sus, citeşte ca date de
intrare şirul vagoanelor aflate pe linia A şi şirul vagoanelor care trebuie obţinut pe
linia B. Se cere să se afişeze şirul mutărilor de tip Push nr_ vagon şi Pop
nr_vagon (aţi recunoscut, desigur, o structură de tip stivă) prin care se poate
obţine şiru l vagoanelor de pe lina B. Dacă acest şir nu se poate obţine, in momentul
in care se ajunge în situaţia unei mutări imposibile, să se afişeze mesajul
'Imposibil'.
Răspunsuri
1. d) 4. b) 11. b) 14. d)
Capitolul 6
Introducere În recursivitate
5. 1. Prezentare generală
procedure exemplu(n:integer);
begin
if n<>O then
begin
writeln (n) 1
exemplu(n-1);
end
end;
begin
exemplu(?) ;
end.
function suma(n1integer)1integer;
begin
suma:=O;
if n<>O then
suma:=n+suma(n-1);
end;
begin
writeln(suma(7));
end .
i,j?~
.· :~), . Funcţia de mai jos este recursivă. Ea afişează, pe rânduri separate,
~?f.' · numerele 7, 6, ... , 1:
linclude <iostre am.h>
void exernplu(int n)
{ if (ni=O)
{ cout<<n<<endl;
exemplu (n- 1) ;
}
}
main()
( exernplu(7);
}
lanual de informatică pentru clasa a Xl-a 143
main()
{ cout<<suma(7);
}
A) Pentru a scrie o funcţie recursivă care efectuează acelaşi calcul, vom porni de
a o definiţie recursivă a lui n 1. Aceasta este:
1, n= O
n! = fact(n) = { n· fact(n-,•) , altfel cu nE N
3 ! =fact(3)=3Xfact(2)=3X2Xfact(l)=3X2X1Xfact(0)=3X2X1Xl=6.
Funcţia se autoapelează .
Parametrul n ia valoarea
fact=l
o. în stivă se creează un nou nivel, care reţine n
cu valoarea o. Funcţia ia valoarea 1, autoapelul
nu mai are loc. Se revine pe nivelul 3.
-+1
• fact=l
Pe nivelul 3 se efectuează calculul1*1=1.
n .-- Se revine apoi pe nivelul 2.
..J facl=6
Se revine apoi în ma in ( ) .
Il 1 3 Referinţă către p 1
p
val n prod
2 3. Referinţă către p
1 3 Referinţă către p
p
val n prod
3 3 Referinţă către p
2 3 Referinţă către p
1 3 Referinţă către p
p val n prod
Pentru că val este 3- mai mic sau egal cu 3- se efectuează prod-Prod*val, deci p
ia valoarea 6, după care se revine pe nivelul2, apoi 1, apoi în programul principal.
~'
.' ,1' Observaţii
.. Pentru a ne familiariza cu
exemple intuitive.
raţionamentul recursiv, vom porni de la câteva
~e
e
~~ · Observaţii
x -1 , x ;?:12
F(x) ={ F(F(x + 2)),x < 12
0 Rezolvare. Această aplicaţie a fost tratată iterativ, prin utilizarea stivei. În cazul
tratării recursive, nu facem altceva decât să transcriem definiţia recursivă a funcţiei.
n+1, m=O
Ack(m,n)= Ack(m-1,1), n=O
{
Ack(m -1,Ack(m,n -1)), altfel
Varianta .~ascal ·
var m,n:integer; #include <iostream.h>
int m,n;
function
ack(m,n:integer) :integer; int Ack(int m,int n)
begin { if (lm) return n+1;
if m=O el se
then ack:=n+1 if (In)
el se return Ack(m-1, 1);
if n=O then ack:=ack(m-1,1) el se
el se re turn
ack:=ack(m-l,ack {m,n-1)) Ack(m-1,Ack(m,n -1));
end; }
begin main()
write('m='); readln(m); { cout<<"m•"; cin>>m;
write('n='); readln(n); cout<<"n="; cin>>n;
writeln(ack(m,n) ) cout<<Ack(m,n);
end.
0 Rezolvare. Utilizăm o definiţie recursivă a celui mai mare divizor comun pentru
doui:l numere naturale a şi b:
a a =b
cmmdc(a,b) = c~mdc(a - b, b),a > b
{
cmmdc(a,b - a),a < b
Manual de informatică pentru clasa a Xl-a 1 51
O Aplicaţia 6.5. Să se scrie o funcţie recursivă pentru a calcula suma cifrelor unui
număr natural.
0, n=O 0, n=O
S(n) = { S(n) = {
n mod 1O+ S(n div 10), altfel n% 10+S(n 1 10), altfel
Varianta Pascal':·
var n:integer 1 #include <iostream .h>
int n;
function s(n:inte ger):inte ger;
begin int s(int n)
if n=O then s:=O { if (In) return 01
e l :se s:=n mod 10 + s(n div 10) else return n%10 + s(n/10)1
endt }
begin main()
write('n ='}; readln(n }; { cout<<"n ••; cin>>n1
writeln( s(n)) cout<<s (n) 1
end. }
0 Aplicaţia 6.6. Se considera şirurile definite recurent astfel: a 0 ...a; b 0 •b; a,b>O:
main()
begin
{ cout<<"a="; cin>>a;
write('a•'); readln(a);
cout<<"b=•; cin>>b;
writa('b='}; readln(b};
cout<<"n="; cin>>n;
write('n='} ; readln(n);
cout<<an(n}<< ' '<<bn (n} ;
writeln(an(n ):5:10,' '
}
bn(n) : 5:10)
end.
• se citeşte un caracter;
• dacă este diferit de o, se reapelează funcţia;
• se tipăreşte caracterul.
D Aplicaţia 6.9. Se dă mulţimea {1,2, ... ,n} şi se cer toate permutările acesteia.
• din fiecare permutare a mulţimii {1, 2, ••• , n-1} ( ( a1, a:~, ••• , an_1} ), se
obţin următoarele permutări ale mulţimii ( 1, 2, ••• , n):
:a.'lual de informatică pentru clasa a Xl-a 155
Figura 6.1.
Cazul în care n•l
$ '...:
' Fie matricea de mai jos:
o 1 1 o
ooo 1
A=
o 1 1 1
1· o o o
1 1 o
1 1 1
A=
1 1 1 1
1 o o o
A=[t ~ ~ il·
iar în matricea de mai jos este reprezentat un singur obiect:
A=[~ !!Il
Ca şi în problemele anterioare, pentru a evita testul ieşirii din matrice,
aceasta este bordată cu linii şi coloane având valoarea "o". Algoritmul este tot cel
din problema anterioară (FIII), dar aici căutarea se face pe 8 direcţii.
În programul principal se citeşte matricea şi se caută primul element "1"
printre elementele acesteia. Se apelează apoi funcţia compact< > care are rolul de
a marca cu o toate elementele matricei care aparţin acestui prim obiect identificat.
La revenire, se testează dacă mai există elemente cu valoarea "1" în matrice. În
caz afirmativ, se poate trage concluzia că în fotografie aveam Iniţial mal multe
obiecte (altfel, fotografia conţinea un singur obiect) .
, '''ii'
•,,JI, ' '
,". . :yarl~nta Pascal·
j
Z~egin main()
~ite('M='}; readln(m); { cout<<"M=";cin>>m;
~ite('N='}; readln(n); cout<<"N=";cin>>n;
for i:=l to m do for (i=l;i<=m;i++)
for j:=l ton do for (j=l;j< .. n;:i++)
begin { cout<<"a["<<i<<','
wri te ( 'a [ ' 1 i 1 ' , ' 1 j, ' ] =' ) ; <<:i<<"l=";
readln(a[ilj]) cin»a[i] [j];
end; }
for i:=l to n do for (i=l;i<=n;i++)
begin { a(O] [i]=O;
a(O,i]:=O; a(m+ll [i]=O;
a(m+l,il :=O; }
end; for (i=l ; i<w.m;i++)
for i:=l to m do { a[i] [0]=0;
begin a[i] (n+ll=O;
a(i,O]:=O; }
a(i,n+l] :•0 x=O ;
end; do
x:sO; { X++;
repeat y=O;
x:=x+l; do
y:=O; { y++;
repeat while (y 1=n &:&: a [x] [y] 1=1) ;
y:=y+l }
until (y=n) or (a[x,y]=l) while ((xl.,m) &:&:a[x][y]l=l);
until (x=m) or (a[x,y]•l); compact(x,y,a);
compact(x,y,a); gasit=01
gasit:=false; for (i=l;i<=m;i++)
for i:=l tom do for (j=l;:i<=n;:i++)
for j :=l ton do if (a[i] [j]==l) gasit=l;
if a[i,j]=l then if (ga sit)
gasit: .. true; cout<<"mai multe obiecte" ;
if gasit else cout<<"un obiect";
then wri teln ( • mai mul t .e }
obiecte•)
else writeln( • un obiect')
end .
Probleme propuse
7. Scrieţi un subprogram recursiv care cal culează câte cuvinte distincte cu 2r.
caractere se pot forma cu n caractere A şi n caractere B.
V(J], Il = 1;
max(V[l],V[2], ... V[n]) =
· { max(max(VP ], V[2l, ... vrn - 1]), Y[nl) altfel.
10. Scrieţi o funcţie recursivă care testează dacă un număr natural n>l este prirr
11. Scrieţi o funcţie recursivă care returnează suma elementelor pare ale ur-
vector citit.
Exemplu: Pentru n•4 şi V= ( 2 1 2 1 s 1 6) , se returnează 1 o.
12. Scrieţi o funcţie recursivă prin care se testează dacă un număr natural x s:c
regăseşte între componentele unui vector v cu n numere naturale.
13. Scrieţi o funcţie recu rsivă care primeşte ca parametri două numere natura:
i<j şi un număr real xe [ i1jl şi returnează [xJ (parte întreagă din x). Nu s;
vor folosi funcţiile specializate ale limbajului.
::e informatică ntru clasa a Xl-a 161
:..: 1eţio funcţie recursivă care returnează numărul cifrelor pe care le are un
..:. 'latural primit ca parametru.
O, k>n
S(n,k)== 1, kE {l,n}
{S(n -1 , k - 1) + kS(n - 1, k) 1< k< n
26. Calculaţi iterativ şi recursiv cel mai mare divizor comun pentru două numere
naturale m şi n, utilizând algoritmul lui Euclid:
a) 12;
b) 21;
c) eroare de executare;
d) o.
28. Ce calculează funcţia următoare?
Varianta Pasc~l
fl,lnction
begin
if n<>O then return (n%2=•0)*n +t(n-1);
t:•ord(n mod 2=0)*n+t(n-1) elae return O;
else t: • O; }
end;
~ Pentru care dintre numerele de mai jos, care sunt parametri de intrare pentru
:cţia următoare, ultimele 2 numere afişate vor fi o?
~} 295;
~) 1024;
:. ) 1000;
:. ) 10000.
şi v2 .. (4,5,1) ce se afişează la
30. Dacă n este egal cu 3, Vl:o(l, 2,3)
apelul t (n, 1, 1)?
a) 1 2 3;
b) 1 4 2 5 3 1;
c) cerinţa nu este corectă;
d) 4 5 1.
164 Capitolul 6. Introducer e în recursivitate
31. Care dintre afirmaţiile de mai jos sunt corecte dacă n este 3 şi apelul este
t(n,1,1) ?
a)
•
întotdeauna se vor afişa cel mult 6 numere;
b) întotdeauna se vor afişa cel puţin 3 numere;
c) întotdeauna se vor afi şa cel mult 3 numere;
d) întotdeauna se vor afişa cel puţin 6 numere.
32. Dacă n este 3, pentru care din datele de mai jos se afişează un număr maxirr
de valori distincte, dacă apelul este t ( n, 1, 1)?
a) 1 2 3; b) 1 2 3 4 5 6;
c) 4 5 6; d) nici o valoare.
. Dacă n=4, pentru care dintre valorile de mai jos ale lui m se afişează două
ori?
b) 3; c) 2; d) 1.
37. În funcţia de mai jos înlocuiţi linia cu una dintre instrucţiunile următoare,
11
•••
11
astfel încât funcţia să-şi încheie execuţia fără eroare pentru orice valoare admisibilă
a argumentului:
Varianta Pascal
x(n:inte ger):inte gerl int x(int n)
begin {
if n<>O then if (n)
begin (
writeln( n); cout<<n1
end }
end; }
38. Dacă funcţia este apelată prin an< 4), de câte ori se autoapelează?
39. Pentru care dintre valorile de rnai jos, care sunt parametri de intrare pentru
funcţia an, executarea funcţiei se termină cu eroare?
40. Pentru programul de mai jos, de câte ori se autoapelează funcţia an?
.. •
'!<
;pf Varianta
. .r.
~
Pascal
. . . ~1;· 1 :
- • o
' - ti
" ~<' .
~··: •,:. ;·.1~"'·
h• ~~·. ' ··~' .~:·~,,,; V~rianta:.~t:+ ~!:: ,,,!;~ .,..
functio n an(n:in teger):i nteger; #includ e <iostrea m.h>
begin int an( int n)
i f n=O then an:=2 { if (n==O) re turn 2;
el se el se
if n=l then an:=-1 if (n••1) re turn 1;
el se an:=an( n-1)-an (n-2)+1 el se
end; re turn an(n-1) -an(n-2 )+1;
}
begin
writeln (an(4)) ; main()
end. { cout<<a n(4); }
Indicaţii / Rezolvări
Sn = {0, dacan = O
Sn_1 +n, altfel
(2n) =C"
n:n.
' ' 211
8.
,,. .
·ifil~:' ··::~~~
.... ,::~.
1 1• -::-
Varianta Pascal V~r,lanta C++ ' -, c ;
' ' ',
1 then Prim:=fals e
else Prim:•Prim (n,i+l);
end;
1
11.
12.
function
Palindrom(i,j:integer):boolean;
begin (i>=:ll roturn 1;
if i>=j eloo
then Palindrom:=true if (V[i] I=V[j]) return O;
el se else return
if V[i] <>V[j] Palindrom(i+1,j-1);
then Palindrom:=false }
else Palindrom:=
Palindrom(i+1,j-1);
end;
15.
1 ~· 1·
Varianta Pascal ,
'.
, '''· '· ·· .. ,. · Varlanta ·C++ ··•il
funotio n int Distinc te(int i,int n)
Distinc te(i,nzi nteger) zboolea n; { int gasit,j ;
var gasit:bo olean; if (i•=n) return 1;
j:integ er; el se
begin { gasit=O ;
if i=n for (j•i+1;j <=nJj++ )
then Distinc tez•true if (V[il ==V[j)) gasit=l ;
el se if (gasit) return O;
begin e lse return
gasitz• false; Distinc te(i+1, n);
for jz•i+1 ton do )
i f V[i] =V[j] }
then gasit:= true;
if gasit
then Distinc te:=fals e
else Distinc te:=
Distinc te(i+1,n );
end
end;
170 ' Capitolul 6. Introducere în recursivita te:
27. a); 28. d); 29. b); 30. a); 31. a), b); 32. a); 33. d);
38. a) ; 39. b) ;
40. a) Autoapelurile se efectueazâ după schema de mai jos:
Acum, vedeţi "pe viu" motivul pentru care, în cazul unor astfel de formule de
recurenţă, în care, în expresie, intervin mal mulţi operanzi ce se calculeazâ
.
recursiv, este de preferat metoda iterativă.
Capitolul 7
Metoda DIVIDE ET IMPERA
7.2. Aplicaţii
:;' Rezolvare. Trebuie tipărită valoarea maximă dintre numerele reţinute în vector de
~:.. la j (iniţial i=l şi j =n).
---
---
-----~
1.4anual de informatică pentru clasa a Xl-a 175
-
- . ~~~~~~
176 Capitolul 7. Metoda D IVIDE fT IMPERJ.
Avem:
T(n) = T(2k) = 2(T(2k-l) + 2k-l ) = 2T(2k-l) + 2k =2T(2k- 2 + 2k-l ) + 2k =
2
2T(2k- )+2k +2k =...2k +2k + ... +2k =n+n+ ... +n =n · k =n ·log 2n
'------v--'
dekori de kori
O Problema 7.3. Fie vectorul a cun componente numere întregi (sau reale). Se
cere ca vectorul să fie sortat crescător.
0 Rezolvare. Este necesară o funcţie POZ care tratează o porţiune din vector
cuprinsă între indicii daţi de l i (limita inferioară) şi ls (limita superioară) . Rolt.
acestei funcţii este de a poziţiona prima componentă a [li] pe o poziţie k cuprins.1
între l i şi ls, astfel încât toate componentele vectorului cuprinse între l i şi k-l
să fie mai mici sau egale decât a [kl şi toate componentele vectorului cuprinse
între k+1 şi ls să fie mai mari sau egale d~cât a [k).
• i=l, j=S;
• a[1 J >a [S], deci se inversează elementele aflate pe poziţiile 1 şi 5,
deci a= ( 2, 9, 3, 1, 6) şi programul trece la modul de lucru b) ;
• i =2 , j=5;
• a [21 >a [51, deci a= (2,6 ,3, 1,9) şi se revine la modul de lucru a);
• i=2, j=4;
• a [ 2 1 >a ( 4], deci a= ( 2, 1, 3, 6, 9); se trece la modul de lucru b );
• ic:3, j=4;
• funcţia se încheie, elementul aflat iniţial pe poziţia 1 se găseşte
acum pe poziţia 4, toate elementele din stânga lui fiind mai mici
decât el, totodată toate elementele din dreapta lui fiind mai mari
decât el (k=4).
f După aplicarea funcţiei POZ, este evident că elementul care se află iniţial în
• poziţia l i va ajunge pe o poziţie k şi va rămâne pe acea poziţie în cadru l
vectorului deja sortat, fapt care reprezintă esenţa algoritmului.
• se apelează Poz ;
• se apelează QUICK pentru l i şi k-1 ;
• se ape l ează QUICK pentru k+l şi ls.
l'
Varianta Pascal
type vector=array [1 .. 100] of #include <iostream.h>
integer; int a[100],n,k;
void poz (int li,int ls,int&
var i,n,k:into ger;
k,int a[100])
a :veotor;
{ int i=li,:l=ls,c,i1=0,~1=-1;
procedura poz (li,ls:integer; while (i<:l)
var k:integ er; { if (a[i]>a(j])
va.r a:vector); { c=a (j]; a[j]=a[i];
a[il=c; c=il;
var i,j,c,i1,j1:integ er; i1=-:11; :11=-c;
begin }
i=i+il;
i1:=0; :1=:1+:11;
jl:=-1; }
i:=li; k=i;
j:=ls; }
178 Capitolul 7. Metoda DIVIDE ET IMPERA
while i<j do
void quick (int li,int ls)
begin { if (li<ls)
i f a[i] >a[j]
{ poz(li,ls,k,a);
then
quick(li,k-1);
begin
quick(k+l,ls);
c:=a[j]; }
a [ j] : •a [ i] ; }
a [il :=c;
CJ•il; main()
il:=-jl; { int i;
jlJ•-c cout<<"n="; ein>>n;
end~
for (i•l;i<•n;i++)
i:=i+il;
{ eout<<"a["<<i<<"l•";
j:•j+jl
cin»a[i];
end; }
k:=i
quick(l,n);
end;
for (i•l;i<•n;i++)
procedura quick(li,ls:integer); cout<<a[i)<<endl;
begin }
if li<ls
then
begin
poz(li,ls,k,a);
quick(li,k-1);
quick(k+l,ls)
end
end;
bagin
write( 'n•');
readln(n) 1
for i:•l to n do
bagin
write(•a[•,i,•]•');
readln(a[i])
end;
quick(l,n); ..,.
for i:•l to n do
writeln(a[i])
end.
~ Rezolvare.
Dacă n=1, se face mutarea ab, adică se mută discul de pe tija a pe tija b.
ab, n= 1
H(n,a,b,c) ={ H(n - 1,a,c,b),ab,H(n - 1, c, b, a), n >1
h 1 •xv(i),yv(i)
x,y
Pentru a se afla în interiorul dreptunghiului, gaura trebuie să îndeplinească
simultan cond iţi ile:
1) xv(i) >x;
2) xv(i) <x+l;
3) yv(i) >y;
4) yv(i)<y+h.
Dacă facem o tăietură verticală prin această gaură, obţinem două dreptunghiuri:
1) x, y, xv(i) -x, h;
2) xv(i), y, l+x-xv(i), h.
1) X, y , l , yv ( i) -y;
2) x, yv(i), 1, h+y-yv(i ).
if. gasit el se
then if (l*h>lf*hf)
begin { xf=x;
dimp(x,y,xv[i]-x , yf..y;
h,xf,yf,lf,hf,xv, yv)l lf•l;
dimp(XY[i],y,l+x -xv[i], hf•h;
h,xf.,yf,lf,hf.,xv ,yv); }
dimp(x,y,l,yv[i] -y, }
xf.,yf,lf,hf,xv,y v)l
dimp(x,yv[i],l,h +y-yv[i], main ()
xf.,yf,lf,hf,xv,yv ) { cout<<"n•"1 cin>>n1
end for (int i•l;i<•n1i++)
el se { cout<<"x["<<i<<" ]c•;
i f (l*h)>(lf*ht) cin»xv[i];
then cout<<"Y["<<i<<" l•"1
begin cin»yv [il 1
Xfi•XI )
yfi•YI oout<<"1•"1 cin>>l1
lf.a•l1 cout<<"h•"; cin>>h1
hfl•h dimp(O,O,l,h,xf ,yf,lf,
end hf,xv,yv);
cout<<"x•"<<xf<< " y•"<<yf
<<" l•"<<lf<<" h • "<<hf1
begin )
write ( 'n•') ;
readln(n);
for ia•l to n do
begin
write ( 'x [ •, i, • l • • ) 1
readln(xv[i]);
~1ri te ( •y [ ' , i, • l • • ) 1
readln(yv[i])
end;
write( '1•');
readln(l)l
write( 'h• •) 1
readln(h) 1
lf :•O;
h.f :•01
dimp(O,O,l,h,xf, yf,
lf,hf,xv,yv) 1
writeln( 'x•' ,xf, • Y•' ,yf., •
1•' ,lf,. h•',hf)
end.
Manual de informatică pentru clasa a Xl-a 183
7.3. Fractali
initgraph(gdriver,gmode,'cale');.
2) prin indicarea cu ajutorul primilor doi parametri a unui driver şi a unui mod
de lucru solicitate de programator (în acest caz, nu se poate executa programul pe
un calculator ce nu este dotat cu placa grafică specificată):
gdriver := VGA;
gmode :"' VGAHI;
initgraph(gdriver,gmode,'cs\tp\bgi');
if graphresult<>O then
begin
writeln("Tentativa esuata!");
halt
end;
Tentativa de iniţializare grafică poate eşua din diverse motive, cum ar fi: lipsa
unităţii
GRAPH, calea indicată greşit, etc. Testarea se realizează cu funcţia tntreag ă
graphresult care returnează o în caz afirmativ şi o valoare diferită de o, în
caz contrar.
Limbajul C++ (în varianta Borland), conţine o serie de funcţii care permit
realizarea unor apli caţii grafice. Acestea sunt reunite in fişierul GRAPHJ:CS. H, ce se
găseşte in folderul :INCLUDE.
initgraph(&gdriver,&gm ode,"oale"); .
2) prin indicarea cu ajutorul primilor doi parametri a unui driver şi a unui mod
de lucru solicitate de programator (în acest caz, nu se poate executa programul pe
un calculator ce nu este dotat cu placa grafică specificată):
Tentativa de iniţializare grafică poate eşua din diverse motive, cum ar fi: lipsa
un ităţii GRAPHICS , ca lea i ndicată greşit, etc. Testarea se realizează cu funcţia
,
întreagă graphre sul t ( ) care returnează o în caz afirmativ şi o valoare diferită
de o, în caz contrar.
Odată intraţiîn modul grafic, nu se mai poate scrie pe monitor ca până acum
(de exemplu, cu cout). Ieşirea din modul grafic se face prin utilizarea
• procedurii closegra ph ( ) .
Atenţiei Pentru a putea scrie şi rula programe C++ ce utilizează modul grafic al
limbajului, trebuie bifată următoarea opţiune , din meniu:
f Aceste culori sunt cele implicite. Pentru a utiliza mai multe culori (dar nu în
J,jitl acelaşi timp), se poate schimba setul (paleta) de culori. Întrucât în acest
moment nu sunt necesare o multitudine de culori, nu vom prezenta în detaliu
acest aspect.
..,a., ual de Informatică pentru clasa a Xl-a 187
setbkcolor(c uloare);.
~ Observaţii
•
Schimbarea culorii nu afectează ce am desenat anterior, ci doar ce este scris
după apelul acestei rutine.
Operaţia de desenare
Varlanta·P~scal
begin main ()
initg; { init() 1
setcolor(red ); ••tcolor(RED ) 1
moveto(O,O); moveto(O,O);
lineto(getmax x,getmaxy); lineto(getma xx(),getmaxy ());
readln1 getch() 1
end. }
_/\_
Figura 7.1. Exemplu de transformare
Fiecare latură a acestui poligon se transformă din nou, după aceeaşi regulă.
Să se vizualizeze figura obţinută după ls paşi {n um ăr citit de la tastatură).
Y1 - k · Y2
1-k
Demonstraţi singuri aceste formule!
k = DA =-2·
DB '
x = x 1 +2·x 2
1' 3 ' Y,, = Y1 +2·
3 -
)'?
begin if (n<ls)
rotplan((2*xl+x2) div 3, {generator(x1,y1,div((2*xl+x2),
(2*yl+y2) div 3, (x1+2*x2) div 3).quot,div{(2*yl+y2),
3, (y1+2*y2) div 3,x,y,pi/3); 3).quot,n+l,ls);
if n<ls then generator(div((2*xl+x2),
begin 3).quot,div((2*yl+y2),
generator(xl,yl, (2*xl+x2) 3),quot,x,y,n+l,ls);
div 3,(2*y1+y2) div 3, generator(x,y,div((x1+2*x2),
n+l, ls); 3).quot,div((y1+2*y2),
generator{{2*xl+x2) div 3, 3).quot,n+l,ls);
(2*yl+y2) div 3, generator(div((x1+2*x2),
x,y,n+l,ls); 3).quot,div((y1+2*y2),
generator(x,y, (x1+2*x2) div 3).quot,x2,y2,n+l,ls);
3,(y1+2*y2) div 3,n+l,ls); }
generator({x1+2*x2) div 3, else desenez(xl,yl,x2,y2,x,y);
(yl+2*y2) div 3, }
x2, y2, n+l, ls);
main()
end
{ cout<<"ls= "; cin>>ls;
else desenez{xl,yl,x2,y2,x,y);
init ();
end;
setcolor(6);
begin L = getmaxx()-320;
write('ls= '); readln(ls); generator(160,getmaxy()-150,
initg; 160+L,getmaxy()-150, 1,ls) ;
setcolor(red); generator(160+L,getmaxy()-
L:=getmaxx-320; 150,160+div(L,2).quot,
generator(l60,getmaxy-150, getmaxy() -150-
160+L,getmaxy-1SO,l,ls)/ ceil(L*(sqrt(3)/2)),l,ls);
generator(160+L,getrnaxy-150, generator(160+div(L,2) ,quot,
160+L div 2,getmaxy-150 - getrnaxy() -1SO-
L*round(sqrt (3)/2) , 1,ls) ; ceil(L*{sqrt(3)/2)),160,
generator(160+L div 2,getmaxy- getmaxy()-lSO,l,ls);
150-L*round(sqrt(3)/2),160, setfillstyle(1,4);
getmaxy- lSO,l , ls)/ floodfill(div(getmaxx(),2)
setfillstyle(l,blue); .quot,div(getmaxx(),
floodfill(getmaxx div 2, 2).quot,6);
getmaxy div 2, red); getoh()/
readln closegraph();
end . }
Priviţi mai jos rezultatele obţinute pentru diferite valori ale lui la:
la = 2 ls ::: 3 ls =4
Figura 7.2. Exemple de fractali formaţi cu ajutorul curbei lui Koch (triunghi echilateral)
"'.anual de informatică pentru clasa a Xl-a 191
Fiecare segment al liniei frânte astfel formate se transformă din nou după
aceeaşi regulă. Se cere să se vizualizeze curba după ls transformări (valoare
citită de la tastatură).
procedura desen(xl,yl,x 2,
y2,n,ls:inte ger); void rotplan(int xc,int yc,
var x3,x4,x5,x6, x7,x8,xc, int xl,int yl,int &x,int &y,
y3,y4,y5,y6, y7,y8,yc:inte ger; float unghi)
{
begin
}
if n<=ls then
begin void desen(int xl,int yl,int
x3:=(3*xl+x2 ) div 4; x2,int y2,int n,int ls)
y3:=(3*yl+y2 ) div 4; { int x3,x4,x5,x6, x7,x8,
rotplan(x3,y 3,xl,yl,x4,y4 , xc,y3, y4,y5,y6,y7, y8,yc;
-pi/2); if (n<=ls)
xc:=(xl+x2) div 2; { x3=div(3*xl+ x2,4) .quot;
yo:=(yl+y2) div 2; y3=div(3*yl+ y2, 4).quot;
rotplan(xc,yo ,x3,y3,x5,y5 , rotplan(x3,y 3,xl,yl,x4,y4 ,
-pi/2); -M_PX/2);
rotplan(xc,y c,x3,y3, xc=div(xl+x2 ,2) .quot;
yc=div(yl+y2 ,2).quot;
x6,y6,pi/2);
rotplan(xc,y c,x3,y3,x5,y 5,
x8:=(x1+3*x2 ) div 4;
-M_PI/2);
y8:=(y1+3*y2 ) div 4;
rotplan(xc,y c,x3,y3,x6,y 6,
rotplan(x8,y 8,xc,yc,x7,y 7,
M_PJ:/2);
pi/2); x8=div(x1+3* x2, 4).quot;
desen(xl,yl, x3,y3,n+l,ls ); y8=div(yl+3* y2, 4) . ·q uot;
desen(x3,y3 ,x4,y4,n+l,ls ); rotplan(x8,y 8,xc,yc,x7,y 7,
desen(x4,y4, x5,y5,n+l,ls) ; M_ PJ:/2);
desen(xS,yS ,xc,yc,n+l,ls ); desen(xl,yl, x3,y3,n+l,ls );
desen(xc,yc, x6,y6,n+l,ls) ; desen(x3,y3 ,x4,y4,n+l,ls );
desen(x6,y6, x7,y7,n+l,ls) ; desen(x4,y4, x5,y5,n+l,ls) ;
desen(x7,y7 ,x8,y8,n+l,ls ); d e sen(xS,yS , xc,yc,n+l,ls );
desen(x8,y8 ,x2,y2,n+l,ls ); desen(xc,yc, x6,y6,n+l,ls );
if n = ls then begin desen(x6,y6 ,x7,y7,n+l,ls );
moveto(xl,yl ); desen(x7,y7 ,x8,y8,n+l,ls );
lineto(x3,y3 ); desen(x8,y8, x2,y2,n+l,ls) ;
lineto(x4,y4 ); if (n == ls)
lineto(xS,yS ); { moveto(xl,yl );
lineto(x6,y6 ); lineto (x3 , y3) ;
lineto(x7,y7 ); lineto(x4 , y4);
lineto(x8,y8 ); lineto(xS,yS );
lineto(x2,y2 ); lineto(x6,y6 );
lineto(x7,y7 );
end
lineto(x8,y8 );
end
lineto(x2,y2 ); }
end;
}
begin }
write('ls= '); readln(ls); main()
initg; setcolor(red ); ( cout<<"ls= "; oin>>ls;
desen(100,10 0,300,100,1, ls); init(); setcolor{6);
desen(300,10 0,300,300,1,1 s); desen(100,10 0,300,100,1, ls);
desen(300,30 0,100,300,1, ls); desen(300,10 0,300,300,1, ls);
desen(100,30 0,100,100,1,1 s); desen(300,30 0,100,300,1, ls);
setfillstyle( l,blue); desen(100,30 0,100,100,1, ls);
floodfill(getm axx div 2, setfillstyle( 1,3);
getmaxy div 2, red); floodfill(div {getmaxx(),2 )
readln .quot,div(ge tmaxy(),2).q uot,6);
end. getch(); closegraph() ;
•.ţanual de informatică pentru clasa a Xl- a 193
Sunt prezentate mai jos imaginile obţinute în urma rularii programului, pentru
4
:: erite valori ale lui ls:
ls==l ls=2
Figura 7.4. Exemple de fractali formaţi cu ajutorul curbei lui Koch (pătrat)
7.3.4. Arborele
Pentru diverse valori ale parametrului de intrare ls, vom obţine arborii:
ls =3 ls =5 ls =7
Figura 7.6. Exemple de fractali de tip arbore
~ Observaţii
•
~ Exemplele grafice prezentate au fost generate pentru valori mici ale lui ls
deoarece la tipărire, detaliile sunt greu de observat peste o anumită limită .
Probleme propuse
1. Se citeşte a~1. număr real. Se cere să se scrie o funcţie care calculează ln(a)
cu 3 zecimale exacte. Nu este permisă utilizarea funcţiei logaritmice a limbajului.
2. Scrieţi o funcţie care calculează prin metoda DIVIDE ET IMPERA suma numerelor
reţinute dintr-un vector.
5. Se ştie că ecuaţia x 3 +x-1=0 are o singură rădăcină reală Tn intervalul <o, 1).
Scrieţi un program, care o afişează cu 4 zecimale exacte.
196 Capitolul 7. Metoda DIVIDE ET IMPERA
Răspunsuri
1. ln (a) =x (::> a=e>C (::> ex-a=O. Dacă notăm cu f (X) =ex-a, atunci trebuie
rezo lvată ecuaţia f(x)•O. Avem f(O)=e 0 -a==1-a<O şi f(a)=e 4 -a>O. De
aici,
rezultă că f(x) are o rădăcină în intervalul (O,a). Cum f(x) este
strict
crescătoa re (ca diferenţă între funcţia strict crescătoare e" şi o constantă ),
rădăcina este unică . Algoritmul pe care îl folosim se numeşte în matematică
"metoda Tnjum~t~ţirii intervalului', dar, din punct de vedere informatic, corespund e
metodei DIVIDE ET IMPERA.
Fie liaO şi ls•a, m=(a+b) /2. Dacă f(li)Xf(m )<O, rădăcina se găseşte în
(li,m) , altfel rădăcina este în [m,ls) . Condiţia de terminare este ca
jli - lsj < 0.0001, pentru că trebuie să avem 3 zecimale exacte.
begin main()
write {'a=' ) ; readln(a); { cout<<"a="; cin>>a;
writeln(' rezultat cout<<"rezultat calculat "
calculat:',LogN(a,O,a):3 :3); <<LogN(a,O,a)<<endl;
writeln(' rezultat preluat • cout<<"rezultat preluat "
ln(a):3:3); <<log(a)<<endl;
end. }
5. Vedeţi problema 1.
6. Funcţia Poz returnează poziţi a k pe care se va găsi, după rularea ei, primul
element al vectorului. în plus, toate elementele de indice mai mic decât k sunt mai
mici sau egale decât A [kl şi toate elementele de indice mai mare decât k sunt mai
mari sau egale decât A [kl . Altfel spus: elementul A [ 11 , care se află după rularea
funcţiei pe poziţia k, este al k-lea cel mai mic element din vectorul A. Atunci, în
cazul în care k=t , problema este rezolvata. Dacă t<k, elementul căutat are
indicele cuprins între l i şi k-1 şi reluăm rularea funcţiei Poz între aceste limite, iar
dacă t>k, elementul căutat are indicele între k+l şi ls şi rel uăm rularea fu ncţiei
Poz între aceste limite. Datorită faptului că, la fiecare pas, se restrânge numărul
valorilor de căutare, se ajunge în situaţia în care t=k.
Secvenţa este:
lil=1; li=l;
ls:=n; ls=n;
repeat do
poz(li,ls,k,a); { poz(li,ls,k,a);
if t<k then lsJ=k-1; i f (t<k) ls=k-1;
if t>k then li:=k+l; i f (t>k) lia k+1;
until t=k; }while ( t 1=k) ;
writeln('Elementul cautat • cout<<"elementul cautat "
a [t]) 1 «a[t] 1
• soluţia lor poate fi pusă sub forma unui vector S=xl,x::~, .•. ,x0 , cu
X1EA1 , X 2 EA::~, . .. , XnEAo;
{1,2,3}X(1,2 ,3}X{1,2,3} :{11, 12, 13, 21, 22, 23, 31, 32, 33}
X{1,2,3)= {111, 112, 113, 121, 122, 123, 131, 132, 133, 211,
2 12, 213, 221, 222, 223, 231, 232, 233, 311, 312, 313, 321,
322, 323, 331, 332, 333}.
200 Capitolul 8. Metoda backtracking
Principiut metodei
j,f, 1 1 ••
rl::,,. ' Varianta C++ ...•r,,,,. "'..":; .
,"·'" v~~la"'ta ~~scai .. l",. : ·!:r 1 '/: lr, · .
Pentru permutări, vom avea o soluţie când s-a generat o secvenţă alcătuită din n
numere distincte. Cum subprogramul este recursiv, acest fapt se intâmplă atunc1
când s-a ajuns pe nivelul n+l.
De exemplu, dacă n=4, o soluţie este reprezentată în figura 8.1., a). Modul de
obţinere al soluţie i este prezentat în figurile urm ătoare, de la b) la i):
~ .:
\lW 1·· "
~
' '
,.... " .. ·'· '·· !1: i.:,"·
l .r. ,,, •.·..
·" li '
a) b) c)
.-!.;·:·,~.
~
~-\
~
1'11 1'
1 ~·· ·~
:
',. ~ ...
~ 'i:::;jl:,
!" :r;;-!:- .1•1:
1;: ti,..: '
1·· '
d) e) f)
,..,
~ ~
li:;. :;ii'' ' ;1 1!•
·-
1. :.:'
1
\liV \lW
~ \}JV
'::' ~
g) h) i)
lsol(i) -sol(j)l=li-jl
(diferenţa, în modul, dintre linii şi coloane este aceeaşi).
Exemple:
a)
sol(l) = 1 i • 1
sol(3) = 3 j = 3
lsol(l) - sol(3) 1 = 11 - 31 a 2
l i - jl = 11 - 31 = 2
Agura 8.2.
206 Capitolul 8. Metoda backtracking
b)
sol(l) = 3 i 1 =
sol(3) = 1 j =3
lsol(i) - sol(j) 1 = 13 - 11 = 2
li- jl = 11- 31 = 2
Figura 8.3.
Exerciţii
? Este Tntotdeauna necesar să-I folosim pe acesta sau putem reţine numai
• ideea şi, după caz, să scriem mai puţin?
! .,. (, ,..,,..
Varianta Pascal .;, : ..'' Varianta C++
var sol:array[1 •• 9] of integer; #include <iostream.h>
n:integer1 #include <math.h>
int n, sol[lO];
function
valid(k:integer):boolean l int :valid(int k)
{ for (int i=l;i<k;i++)
var i :integer; if {sol [k] ==sol [il 11
begin abs(sol[k]-sol[i])
valid:•true; ==abs(k-i))
for i:=l to k-1 do return O;
if (sol[k]=sol[i]) or return 1;
(abs(sol(k]-sol[i])=abs( k-i)) }
then void back ( int k)
valid:=false { if (k==n+l) // solutie
end; //tipar
{ for (int i=l;i<=n;i++)
procedura back(k:integer); cout<<sol[i];
cout<<endl;
var i:.integer; }
begin el se
if k•n+l {solutie} { sol[k]cO;
then while(sol[k]<n)
begin 11 succesor
{tipar} { sol[k]++i
for i:=l to n do if (valid(k))back(k+l);
write(sol[i));
writeln; }
end
main()
el se
begin { cout<<"n'""l cin>>n;
sol[k] :=O; {init} back(l);
while sol[k]<n do }
{succesor}
begin
sol[k]: .. sol[k]+l;
if valid(k)
then
back(k+l)
end
end
end1
begin
write( 'n=');
readln(n);
back(l)
end.
~ Exerciţii
1. Testaţi subprogramuf anterior pentru problema generării permutărilor.
~ Este demonstrat faptul că sunt suficiente numai 4 culori pentru ca orice hartă
• .~ să poată fi colorată.
Pentru exemplificare, vom considera harta din figura 8.4., unde ţările sunt
numerotate cu cifre cuprinse între 1 şi 5 .
• ţara 1 - culoarea 1;
• ţara 2 -culoarea 2;
• ţara 3 -culoarea 1;
• ţara 4 -culoarea 3;
Figura 8.4.
• ţara 5 - culoarea 4 .
Manual de info rmati că pentru clasa a Xl-a 211
Exerciţii
E,x: Exemple
O Enunţ. Se dau n mulţimi: A1, A 2 , ... A", unde A1 =U1 2 1 ... 1 k 1 }, pentru
k==1, 2, ••• 1 n. Se cere produsul cartezian al celor n mu lţimi.
J~· Observaţii
1. Avem k1Xk:.~x... xk,. elemente ale produsului cartezian. De aici rezultă că
algoritmul este exponenţial.
A... produsul cartezian al lor A1XA:.~x ••• XAz. se mai numeşte spaţiul soluţiilor. În
acest context, metoda backtracking caută una sau toate soluţiile, care sunt
elemente ale produsului cartezian şi care indeplinesc anumite condiţii. Astfel, se
poate justifica faptul că, în generarea produsului cartezian, nu este necesar
subprogramul valid pentru că se generează toate elementele produsului
cartezian, fără a verifica anumite condiţii.
Manual de informatică pentru clasa a Xl-a 2 ,-
.~
Deş i algoritmul este exponenţia l , există aplicaţii utile, evident, atunci când
fiecare mulţime A1 poate lua numai câteva valori şi unde n este suficient de mic.
~ Exerciţii
1. Tabelarea anumitor funcţii. Se dă funcţia
unde fiecare mulţime A1 este dată de numerele întregi din intervalul [a 1 ,bd şi
2. Scrieţi programul care generează toate "cuvintele" cu patru litere care au pdma
şi ultima literă vocale, litera a doua consoană din mulţimea {P, R, s, T} , iar a treia
1teră consoană din mulţimea {B, M, R, T, V}.
3. Scrieţi programul care generează şi numără eate cuvinte de cinci litere ale
alfabetului englez se pot forma, cu condiţia să nu existe două consoane al ăturate
şi nici două vocale alăturate .
::J Enunţ. Fiind dată mulţimea A={1 1 2, ••• ,n}, se cere să se afişeze toate
SJbm ulţimile ei.
~ Exerciţii
valor.:
1. Problema nu este rezolvată in totalitate. Programul afişează numai toate
program ul s.:
pe care le poate lua vectorul caracteristic. Completaţi-! astfel incat
afişeze ţoate submulţimile mulţimii <1, 2 ••• n} 1
in baza ;.
3. Să se afişeze toate numerele scrise in baza 10 a căror reprezentare
cu 1. Valorile n şi k se citesc de ..i
are n cifre, dintre care exact k sunt egale
tastatură (n<12, k<n). De exemplu, pentru n:c3 şi k•2, se obţin valorile: s şi 6.
,
1
Observaţii
Fiind dată o mulţime
cu n elemente, avem 2n submulţimi ale ei. Mulţimea
dat~ şi submulţimea vidă sunt submulţimi ale mulţimii datei De ce? Fiecare
componentă a vectorului caracteristic poate reţine două valori. Prin urmare,
numărul de submulţimi este
2·2·2
~
...2=2" .
uenori
CP = n!
n (n - p)!p!
Rezolvare. O soluţie este de forma x 1, x 2, ••• 1 :xp, unde x 1, x:~. ..., :xpe A.
•lus, x1, x2, ... , xp trebuie să fie distincte. Cum la o mulţime ordinea elementelor
prezintă importanţă, putem genera elementele ei in ordine strict crescătoare .
~stă observaţie ne ajută foarte mult în elaborarea algoritmului.
~---- -r~=~- -
218 Capitolul 8. Metoda backtracking
sol[n-1]<sol(n]~-p+p=n.
Relaţiile de mai sus simplifică mult algoritmul, pentru că ţinând cont de ele, nu mai
este necesar să se testeze nici o condiţie de continuare.
.".fi Exerciţii
· Se dau coordonatele din plan a n puncte. Afişaţi coordonatele vârfurilor tuturor
::c:ratelor care au ca vârfuri puncte din mulţimea considerată.
; . Se dau n substanţe chimice. Se ştie că, în anumite condiţii, unele substanţe intră
,. ·eacţii chimice cu altele. Fiind date p perechi de forma ( i, j) cu semnificaţia că
s..~stanţa i intră în reacţie cu substanţa j, se cer toate grupurile de s<n substanţe
:sfel încât oricare două substanţe din grup nu intră în reacţie.
Se dau două mulţimi A={l,2, ••• ,p} şi B={1,2, •• • ,n}. Se cer toate
·~ncţiileinjective definite pe A cu valori în B. O astfel de problemă este una de
;-enerare a aranjamentelor de n luate câte p (A~ ).
: xemplu: p=2, n=3. Avem: 12, 21, 13, 31, 23, 32. De exemplu, 21 este funcţia
: :A-4B dată astfel: f (1) =2; f (2) =1. Avem relaţiile:
ni
A~ = · = n(n-1) ... (n-p+1).
(n - p)!
Pe de altă parte, se poate lucra mult mai eficient. O soluţie este de forma:
x1x2 ••• xp. unde x1, x:~, ... , XpEB. În plus, x 1, x:~, ... , Xp trebuie să fie distincte.
Spre deosebire de algoritmul de generare a combinărilor, aici ne interesează toate
permutările unei soluţii (acestea sunt, la rândullor, alte soluţii). Aceasta înseamnă
că nu mai putem pune în soluţie elementele în ordine crescătoare. Să recapitulăm:
.•••_ d·
Varianta C++
~ Exerciţii
care se pot forma
1. Se citesc n, p şi apoi n litere distincte. Afişaţi toate cuvintele
cu p dintre ele.
numele care se
2. Se citesc n şi apoi: numele mici a n persoane. Ştiind că toate
nume de băieţi, să se afişeze
termină cu a reprezintă nume de fată, celelalte fiind
Două mulţimi sunt distincte
toate mulţimile de perechi fată-băiat care se pot forma.
lu, pentru n=S, Maria , Ana,
dacă cel puţin una dintre perechi diferă. De exemp
a-Dor u, Ana-C osmin },
Doina , Doru, Cosmi n, se afişează mulţimile: {Mari
{Doin a-Dor u,
{Ana- Cosmi n,Mar ia-Dor u}, {Mari a-Dor u,Doin a-Cos rnin},
-Cosm in}.
Maria -Cosm in}, {Ana- Doru,D oina-C osmin }, {Doin a-Dor u,Ana
Manual de informatică pentru clasa a Xl-a 221
0 Rezolvare. Chiar dacă ştim să generăm toate submulţimile unei mulţimi, tot nu ne
ajută să generăm toate partiţiile.
1 • Pentru a putea genera toate partiţiile, trebuie să găsim o metodă prin care să
putem reţine o partiţie. O primă idee ne conduce la folosirea unui vector, sol, astfel:
dacă sol [il •k, atunci elementul i se găseşte în mulţimea k a partiţiei. Totuşi, nu
ştim câte mulţimi sunt in partiţia respectivă . Există o partiţie care conţine n mulţimi
atunci când fiecare element este într-o mulţime şi una care conţine toate mulţimile,
adică tocmai mulţimea A. Cu alte cuvinte, numărul mulţimilor dintr-o partiţie este
între 1 şi n.
Prin această condiţie se evită situaţia in care, de exemplu, vectorul sol reţine
<1, 3, 1). Aceasta ar avea semnificaţia că elementele 1 şi 3 se găsesc in
submulţimea 1 a partiţiei, iar elementul 2 se găseşte in submulţimea 3 a partiţiei. ln
acest caz, lipseşte submulţimea 2 a partiţiei.
- sol=(l,1,l) - A1 =(1,2,3);
begin
write('n='); readln(n);
back(l);
end.
Toate problemele pe care le-am întâlnit până acum admit soluţi i care
îndeplinesc următoarele caracteristici:
-+ soluţiile sunt sub formă de vector;
-+ toate soluţiile unei probleme au aceeaşi lungime, unde prin lungime
înţelegem numărul de componente ale vectorului soluţie.
224 Capitolul 8. Metoda backtracking
c > Toate soluţiile sub formă de vector ale problemei generării tuturor partiţii lor
mulţimii A au lungimea n.
f Ordinea numerelor din sumă este importantă . Astfel, se tipăreşte 11.2 dar
J;. şi 211, 121.
~~ie
[lŢo 1o o J1l1lo o 11111110
s=O,I<=l s=l,k =2 s=2,k::=3
~
s=3,k=4
'
Observaţimodul in care ca lculăm suma la fiecare pas. De câte
ori se trece
• la componenta următoare (k+l) , las se adună sol
[kJ, de câte ori se face
pasul înapoi (se trece la componenta k-1), din s se
scade sol [kl.
Programul este prezentat în continuare:
Varia nta· Pasca l ' ' .., ·. .,. Vari a ni~ C++
var sol: array [1 .• 100] of integ er; #incl ude <iost ream. h>
n,i,s :inte ger; int sol[lO O], n,i,s ;
proce dura back (k:in teger ); void back (int k)
begin
{ if {s===n )
if s=n then begin { for (i=l;i <==k -l;i++ )
for i:=l to k-1 do cout< <sol CiJ;
write (sol[ iJ); cout< <endl ;
write ln; }
end el se
else begin { sol[k ]=O;
sol[k ]:=O; while (sol[ k]+s <n)
while sol[k ]+s<n do ( sol[k ]++;
begin s+=s ol[k] ;
sol[k ] :=sol [kl+l ; back( k+l);
s:=s+ sol[k ]; back( k+l); s-=so l[k];
s: =s-so l[k]
end; }
end }
end;
main( )
begin
{ cout< <"n=" ; cin>> n;
write {'n= ') ; readl n{n);
back (l);
back{ l) }
end.
226 Capitolul 8. Metoda backtracking
~Exerciţii
1. Cum trebuie procedat în cazul în care se cere ca soluţiile să fie afişate o singură
dată? Spre exemplu, dacă s-a afişat descompunerea 1,1, 2 să nu se mai afişeze
2 , 1,1sau1, 2,1?
Indicaţie: procedeul a mai fost întâlnit, de exemplu la generarea combinărilor.
Soluţiile se vor genera în ordine crescătoare. Modificaţi programul în acest sens.
2. Adaptaţi metoda de rezolvare astfel încât să se genereze numai partiţiile formate
din numere naturale distincte.
3. Adaptaţi metoda de rezolvare astfel încât să se genereze numai partiţiile formate
din cel puţin p numere naturale distincte (n şi p citite de la tastatură).
4. Adaptaţi metoda de rezolvare astfel încât să se genereze numai partiţiile formate
din numere naturale aflate în intervalul [a, bl (n, a şi b citite de la tastatură).
5. Rezolvaţi problema scrierii numărului natural n ca sumă de numere naturale
alese dintr-o mulţime formată din k valori date {v1, v2, ... , vk}. Astfel, 10 se
poate scrie ca sumă de numere alese din mulţimea {2,3,6} în felul următor:
10=2+2+2+2+2, 10=2+2+3+3,10=2+2+6.
O En unţ. Se dau suma s şi n tipuri de monede având valori de a 1 ,a2 , • •• ,a0 lei. Se
cer toate modalităţile de plată a sumei s utilizând aceste monede. Se presupune
că se dispune de un număr nelimitat de exemplare din fiecare tip de monedă.
1) 1 de 2, 1 de 3; 2) 1 de 1, 2 de 2 ; 3) 2 de 1, 1 de 3;
4) 3 de 1, 1 de 2; 5) 5 de 1;
.1•·1..~· Ce observăm?
22 /
,,.anual de informatică pentru clasa a Xl-a
ă situaţie corespunde
torului sol care reţin o. Aceast
1. Există componente ale vec ul. Din ace st motiv, fiecare
vă nu este luată fn calc
:az ulu i în care mo ned a respecti are aflată înaintea tuturor celo
r
componentă a vectorului
sol va fi iniţializată cu o valo
oosibile, adică cu -1.
de tipuri de monede).
componente (n este numărul
2. Orice soluţie are exa ct n t luate în calcul.
edele, chiar şi cele care nu sun
Acest număr include toate mon
manenţă sum a obţinută
la un
rioară, vom reţine în per
3. Ca şi la pro blem a ante
, avem la dispoziţie suma:
moment dat. Astfel, la pasul k
l[k -1]
ol[ 2] + • • • + a[k -l] *so
s • a(l ]*s ol[ l] + a(2 ]*s
0 Rezol vare
2. Nu toate soluţi ile au aceeaşi lungime, întrucât există trasee de lungime d iferită.
Se obţine o soluţie atunci când coordonatele camerei unde s-a intrat sunt în afara
matricei (nu au linia între 1 şi m şi nu au coloana intre 1 şi n). Evident, atunci când
s-a găsit o situaţie, aceasta se afi şează.
3• Spunem că o cameră este accesi bilă dacă există intrare din camera curentă
către ea. Atenţie la modul (vedeţi programul) Tn care testăm dacă o cameră este
accesibilă sau nu. Este o operaţie in care se testează conţin u tul unui anumit bit.
Acesta se obţine efectuâ nd un ŞI logic intre dou ă valori. De exemplu, dacă testăm
i eş irea spre sud , atunci efectuăm ŞI logic între 0010( 21=2<lo> şi valoarea reţinută
în matrice pentru camera curentă. Dacă valoarea obţinută este diferită de o, atunci
avem ieşire din camera cu rentă către sud.
4 . Înainte de a intra într-o cameră accesibilă se testează dacă respectiva cameră
a mai fost vizitată sau nu. Pentru aceasta utilizăm funcţia vizitat. ln caz că a
fost vizitată, se face pasul inapoi.
Analizaţi programul:
Varianta Pa~cal
var sol : arr ay [1 •• 100,1 •. 2] of # include <iostream.h>
integer; int sol [100] [ 2] , 1 [10] [10],
l:array [0 .• 10,0 . • 10] of m,n, i,j,lin,col;
integer; i nt vizitat ( int k, int lin,
m,n,i , j,lin,col:intego r; int col)
function vizitat (k,lin, [ int v • O;
col:integer):boo lean; for (i.,l;i<=k;i++)
begin if (sol [i] [O]==lin &&
vizitat: = false; sol [i] [l]a=col) val;
for i: =l to k-1 do 1 return v;
if (sol[i,l]=lin) and }
(sol[i,2]=col)
void tipar (int k,i nt lin,
then vizitat:=true; int col)
end; { cout <<" Solutie "<<end l. ;
procedura for (i.,1 ; i<=k-1;i++)
tipar(k,lin,col:i nteger); cout<<sol[i] [0] <<" "
begin <<sol [i] [1] <<e ndl;
writeln('Solutie '); if ( lino:n•O)
for i: =1 to k-1 do cout<<"iesire prin nord"
writeln(sol [i , 1],' •, <<endl ;
sol[i,2 ]); el se
if lin.. o then i f (lin==m+l)
writeln('ie sire prin nord ' ) cout<<"iesire prin sud"
el se <<endl;
if lin=m+l then el se
wri teln ( • iesire pri n sud' ) if (col==O)
el se cout<< "iesire prin vest"
if col= O t:hen <<endl ;
writeln(' l esire prin vest') el se
el se cout<< "iesire prin est"
writeln( • iesire prin est '); <<endl;
readln; }
end;
230 Capitolul 8. Metoda backtracking
~ Exerciţii
1. Adaptaţi rezolvarea pentru un labirint Tn care fiecare căsuţă reţine valoarea 1
sau o (1 semnificând căsuţă plină , prin care nu se poate trece, iar o căsuţă liberă ,
pe unde se poate trece). Ca şi in problema prezentată , deplasarea se poate face
dintr-o căsuţă in orice altă căsuţă alăturată, orizontal sau vertical , cu condiţia ca ea
să existe şi să fie l iberă. Val idaţi poziţia iniţială a omului (lin, col), astfel încât
aceasta să coresp undă unei căsuţe libere. Esti maţi spaţi u l de memorie utilizat
in această vari a ntă.
Varianta Pascal . · ·
• l' • 1
.. ~·, · · :.. ' · ...;·~ Varianta C+;+- , , .' ·, i, 1,.. :.!··
var sol:array [1 •• 100,1 •• 3] #include <iostream .h>
of integer1
t:array [0 •• 10,0 •• 10] int sol[100] [3],t[10] [10],
of integer; m,n,i,j,l in,col1
m,n,i,j,l in,col:in teger;
procedur a t ipar(k:in teger); void tipar(in t k)
begi n { cout<<"S olutie "<<endl;
writeln( 'Solutie •); for(i=l;i< =k-1;i++ )
for i:=1 to k-1 do cout<<so l [i] [1] <<" "
writeln( sol [i, 2],' ', <<sol[i] [2]<<end l;
sol[i,J] )I
end; void b a ck(int k, i n t lin, int col)
procedur a { if (linu=O 1 1 lin==m+1 11
back(k,l in,col:in teger); col==O 1 1 col==n+1 )
begin tipar(k) l
if (lin=O) or (lin•m+1 ) or el se
(col=O) or (col•n+1) { sol[k] [0 ]=0;
then tipar(k) sol [k) [1] =lin;
olse begin sol[k] [2) r:ocol;
sol[k,1]: =0; while (sol[k] [0)<4)
sol [k,2] :=lin; (
sol[k,J) :=col1 sol[k) [0]++;
while sol[k,1]< 4 do switch(s ol [k] [0])
begin {
sol[k,1J: =sol(k,1 ]+11 case 1:
case sol[k,l] of if(t[lin- 1] [col]<t[ lin] [col])
1:if t[lin-1,c oll< back(k+ l,lin-l,co l); break;
t[lin,co l] then case 2:
back(k+ 1,lin-1,c ol); i f(t[lin) [col+l]< t[lin] [col])
2:if t[lin,col +1]< back(k+ l,lin,col +l); break;
t[lin,co l] then case 3:
back(k+1 ,lin,col+ 1) J if(t[lin +l l [col)<t[l in] [col])
3:if t[lin+1,c ol]< back(k+1 ,lin+1,co l ); break;
t[lin,co l) then case 4:
back(k+ l,lin+1,c ol)J if (t [lin] [col -1] <t [lin] [col])
4:if t[lin,col -1]< back(k+ l,lin,col -1); break;
t[lin,co l) then )
_j
back(k+1 ,lin,col- 1); }
end1 {case} }
end end end; }
begin main ( )
write('M =')1 readln(m ); { cout<<"m ="; cin>>m;
write('N =')1 readln(n );
~~ cout<<"n ="; cin>>n;
~
Vanual de informatică pentru clasa a Xl-a 233
begin if (k=-n*n)
if k=n*n { for (i=l;i<=k-l;i++)
then cout<<sol[i] [0]<<" "
begin <<sol[i] [l]<<endl;
for i:=1 to k-1 do cout<<lin<<" "<<col;
writeln(st[i,1], ' ' exit(EXIT_SUCCES S);
st[i,2]); }
writeln(lin,' •,col); el se
halt; { sol[k] [O]=lin;
end sol[k] [l]=col;
el se for (i=O;i<=7;i++)
begin { linie=lin+x[i];
st[k,1] :=lin; coloana=col+y[i] ;
st[k,2] :=col; if (linie<=n && linie>=1
for i:=1 to 8 do
&& coloana<=n &&
begin
coloana>=l &&
linie:=lin+x[i];
t[linie] [coloana]==Ol
coloana:=col+y[i ];
{
if (linie<=nl and
t[linie] [coloana)=l;
(linie>=l) and
back(k+l,linie,co loana);
(coloana<=n) and
(coloana>=1) and t[linie] [coloana]=O;
}
(t[linie,coloana]g O)
}
then
}
begin
}
t[linie,coloana] :=1;
back(k+l,linie,
main()
coloana) 1
t [linie,coloana]:a O; { cout<<"n=";
end; cin>>n;
end back(1,1,1);
e .n d
end;
begin
write ('n=');
readln(n);
back(1,1,l);
end.
Vanual de informatică pentru clasa a Xl-a 235
Probleme propuse
10. Fiind dat un num~r natural pozitiv n, se cere s~ se producă la ieşire toate
descompunerile sale ca sumă de numere prime.
11. "AttUa şi regele". Un cal şi un rege se află pe o tablă de şah. Unele câmpuri
sunt "arse", poziţiile lor fiind cunoscute. Calul nu poate călca pe câmpuri "arse",
iar orice mişcare a calului face ca respectivul câmp să devină "ars" . Să se afle
dacă exist~ o succesiune de mutări permise (cu restricţiile de mai sus), prin
care calul să poată ajunge la rege şi să revină la poziţia iniţială. Poziţia iniţială
a calului, precum şi pozi ţi a regelui sunt considerate "nearse".
12. Se dau n puncte în plan prin coordonatele lor. Se cer toate soluţiile de unire a
acestor puncte prin exact p drepte, astfel încât mulţimea punctelor de
intersecţie ale acestor drepte să fie inclusă în mulţimea celor n puncte.
17. Se dau N puncte albe şi N puncte negre în plan, de coordonate intregi. Fiecare
punct alb se uneşte cu câte un punct negru, astfel încât din fiecare punct, fie el
alb sau negru, pleac~ exact un segment. S~ se determine o astfel de
configuraţie de segmente astfel încât oricare două segmente să nu se
intersecteze. Se citesc N perechi de coordonate corespunzând punctelor albe
şi N perechi de coordonate corespunzând punctelor negre.
' 9. O trupă cuN actori işi propune să joace o piesă cu A acte astfel încât:
20. Fiind dat un număr natural N şi un vector v cuN componente întregi, se cere:
24. Fiind date numele a n soldaţi , ce algoritm vom utiliza pentru a lista toate
grupele de câte k soldaţi? Se ştie că într-o grupă, ordinea prezintă importanţă .
25. Fiind date n numere naturale, ce algoritm vom utiliza pentru a determina
eficient o submulţime maximală de numere naturale distincte?
Indicaţii
6. Deşi
algoritmul este asemănător, nu este acelaşi, trebuie pusă o condiţie
suplimentară. De exemplu, in cuvântul "mama" nu se poate inversa a de pe poziţia
2 cu a de pe poziţia 4.
23. b)
24. a)
25. d)
Explicaţie: primele două variante prezintă soluţii exponenţiale, a treia este în
o (nl >. Dar dacă sortăm numerele, atunci le putem afişa pe cele distincte dintr-o
singură parcurgere. Sortarea se poate efectua in o (nXlog (n) ), iar parcurgerea
în O(n). Prin urmare, complexitatea este O(nXlog(n)).
26.d)
1. Se dau n oraşe. Unele dintre ele sunt unite prin şosele directe (care nu mai
trec prin alt oraş).
2. Se cunosc relaţiile de prietenie dintre n persoane.
3. Se dau n ţări şi se cunoaşte relaţia de vecinătate între ele.
4. Se dau n triunghiuri, iar unele dintre ele sunt asemenea.
V= {1,2 1 3 ,4,5,6};
E = {(1,2), (1,3), (1,5), (2,3), (3,4),
(4,5)}
Observaţii
./ Două noduri distincte pot fi unite prin cel mult o muchie. În exemplul de
mai sus, <1., 2) este muchia care uneşte nodul 1 cu nodul 2. Dacă scriem
(2,1.), ne referim la aceeaşi muchie (perechea este neordonată) .
Definiţia este restrictivă, în unele lucrări veţi întâlni definiţii mai puţin restrictive, de
1
Definiţia 9.3. Într-un graf neorientat, prin gradul unui nod v se înţelege
numărul muchiilor incidente cu nodul v şi se notează cu d(v). Un nod
cu gradul o se numeşte nod izolat, iar unul cu gradul 1 se numeşte nod
terminal.
O relaţie utilă: fie un graf neorientat cun noduri şi m muchii. Dacă notăm cu d1,
dl .... , a., gradele celor n nodu,·i, atunci avem relaţia:-
" d1 +d 2 +d 3 +.~d-:-=2m.l
~ Demonstraţie: fiecare muchie face să crească gradele celor două noduri la
care este incidentă cu câte o unitate. Prin urmare, se obţine re l aţia anterioară.
Pentru a înţe l ege bine noţiunile prezentate în acest paragraf, ne vom referi la
exemplele din 9 .1.1:
- fie afirmaţia: nodul i este izolat. Pentru exemplul 1., înseamnă că nu există nici
o şosea care leagă oraşul i cu alt oraş, pentru exemplul 2 ., înseamnă că
persoana i nu are nici un prieten, pentru exemplul 3 ., înseamnă că ţara i nu se
învecinează cu nici o ţară (este situată pe o in su lă), pentru exemplul 4., înseamnă
că nu există nici un triunghi dintre celelalte n-1 triunghiuri care să fie asemenea cu
triunghiul i.
~ Exerciţiu
Daţi un exemplu inspirat din viaţa reală, pentru care să găsiţi graful asociat.
Astfel, veţi răspunde la întrebările: ce semnificaţie a~ nodurile sau muchiile şi ce
înseamnă gradul unui nod.
242 Capitolul 9. Introducere în teoria grafurilor
În acest paragraf, prezentăm principalele structuri de date prin care grafurile pot
fi memorate în vederea prelucrării lor. De la început, precizăm faptul că vom alege o
structură sau alta în funcţie de2 :
a) algoritmul care prelucrează datele referitoare la graf;
Pentru fiecare structură de date pe care o vom folosi, vom avea câte o
procedură (funcţie) care citeşte datele respective. Toate aceste subprograme se
găsesc grupate în unitatea de program grafuri .pas (pentru Pascal) şi în
grafuri. cpp (pentru C++). Vom fi astfel scutiţi ca, pentru fiecare program pe care îl
realizăm, să fim nevoiţi să adăugăm liniile de cod necesare citirii ş i ne permite să ne
concentrăm exclusiv asupra algoritmului.
0 Fişierul text:
1
1
1
3
5
2
2 3
3 4
Figura 9.3.
4 5
Exemplu de graf neorientat
a .. =
I,J
{1,O, pentru {i, j) e E
pentru (i, j) ~ E
2
Modul de alegere a structurii il veţi inţelege pe parcursul studiului acestui capitol.
~ianual de informatică pentru clasa a Xl-a 243
o o 1
1 1 o
1 o 1 o o o
1 1 o 1 o o
A6.6 =
o o 1 o 1 o
1 o o 1 o o
o o o o o o
(:1, Observaţii
•
1 . Întrucât, din modul în care a fost definit graful, rezultă că nu există muchii de la un
nod la el însuşi, rezultă că elementele de pe diagonala principală reţin o:
6 . Dacă graful citit are un număr mic de muchii, atunci matricea de adiacenţă este o
formă ineficientă de memorare a lui, pentru că ea va reţine o mulţime de o.
#include •grafuri.cpp"
int A[50] [50],n;
n,i , j:integer; main()
begin {
CitireN( • Graf. txt • ,A, n); CitireN("Graf . txt",A,n);
for i:=1 to n do for (int i=1;i<-n;i++)
begin { for (int ja1;j<• n;j++)
for j:=1 ton do cout<<A[i] [j]<<• •;
write (A[i,j],• ') ; cout<<endl;
writeln; }
end; }
end.
0 1 -> 2,3,5
2 -> 1 , 3
3 -> 1,2,4
4 - ~ 3,5
5 -> 1,4
6 ->
Figura 9.4.
Manual de informatică pentru clasa a Xl-a ~45
Start 15 17 19 l11l12l O 1
1 2 3 4 5 6 7 8 9 10 11 12
T[O] 2 1 3 1 5 1 3 2 4 3 5 4
T [1] o o 1 o 3 o 2 4 8 o 10 6
4 Exemplu de utilizare
Dorim să vedem care este lista nodurilor adiacente cu nodul 3. Start [3] =9,
adică lista începe în coloana 9 a matricei T. Primul nod adiacent cu nodul 3 este 4.
Următorul se gc':!lseşte la indicele a. Următorul nod adiacent cu nodul 3 este nodul 2.
Următorul se găseşte la indicele 4. Acesta este nodul 1 . El este ultimul din listă,
pentruT(1,4)=0 (T[l] [4)).
Con siderăm primul caz, în care vom pune pe j, ca prim element în lista
nodurilor adiacente cu i. Variabila k, care are iniţial valoarea o, va reţine indicele
ultimei coloane din T completată. O astfel de operaţie se realizează în patru paşi:
.~ -
!
':- . ~~·
Programul următor citeşte datele despre un graf şi afişează, pentru fiecare
..... . nod, lista nodurilor adiacente:
Mai jos, puteţi observa cum se descrie un vector (v) care reţine muchiile
unui graf:
Să considerăm mulţimea elevilor unei clase. Teoretic, oricare doi elevi din
clasă se cunosc. Pentru a transpune în limbaj specific teoriei grafurilor această
situaţie, vom considera că fiecare elev este un nod al grafului. Pentru că oricare doi
elevi se cunosc, înseamnă că oricare două noduri sunt unite printr-o muchie.
Astfel, am obţinut un graf aparte, pe care-I vom numi graf complet.
Definiţia 9.4. Prin graf complet vom înţelege un graf neorientat în care
oricare două noduri sunt adiacente. Vom nota un graf complet prin K", unde
n este numărul de noduri ale grafului.
248 Capitolul 9. Introducere în teoria grafurilor
Figura 9.5.
Exemplu de graf complet
Relaţii utile:
1. Într-un graf complet, gradul oricărui nod este n-1. Evident, din fiecare nod,
pleacă (sosesc) n-1 muchii.
n(n -1)
2. Într-un graf complet, avem relaţia: m = , unde m este numărul de
2
muchii, iar n, numărul de noduri.
··· )!. Demonstraţie: am văzut că numărul maxim de muchii pe care le poate avea
~ un graf neorientat este:
n(n - 1)
., 2
.r
şi corespunde unui graf complet. Se ştie că, fiind dată o mu~ime A cun elemente,
avem 2n submulţimi disjuncte ale acesteia (aici este inclusă şi submulţimea vidă
şi A). Prin urmare, avem:
n(n - 1)
2- 2-
submulţimi ale numărului maxim de muchii. Ori, fiecărei submulţimi de muchii îi
corespunde un graf nemientat, pentru că nodurile sunt aceleaşi.
f, Un graf parţial al unui graf dat, este el însuşi sau se obţine din G prin
• suprimarea anumitor muchii. Priviţi exemplul de mai jos:
Figura 9.6.
Obţinerea unui
graf parţial
--->
rezultă
G={V,E)
2. Fiind date n oraşe, unele dintre ele sunt unite printr-o şosea directă (care nu mai
trece prin alte oraşe). Asociem situaţiei date un graf G. Datorită precipitaţiilor, anumite
şosele se inundă şi nu mai pot fi utilizate. Aceasta înseamnă că 1'n G se suprimă
anumite muchii şi se obţine un graf parţial G •.
lli· Definiţia 9.6. Un subgraf al unui graf neorientat G.., .<v, E) este un graf
:.I!.) G1 .. (V11 E1), unde v1cv. E1c::E, iar muchiile din E 1 sunt toate muchiile din
' E care sunt incidente numai la noduri din mulţimea v 1 .
( ., Un s~bgraf al unui graf G este el însuşi sau se obţine din G prin suprimarea
• anumttor noduri şi a tuturor muchiilor incidente cu acestea. Priviţi exemplul de
mai jos:
Figura 9.7.
Obţinerea unui
subgraf
--->
rezultă
G= (V,E)
250 Capitolul 9. Introducere în teoria grafurilor
1. Se dau n firme. între unele din acestea se stabilesc relaţii de colaborare. Asociem
situaţiei date un graf G. intre timp, anumite firme se desfiinţează . Aceasta inseamna
că în G vom elimina anum ite noduri şi muchiile incidente lor, obţinând un subgraf al
luiG, G1.
2 • Mai multe calculatoare (n) sunt legate în reţea cu ajutorul unor cabluri. Asociem
situaţiei date un graf G. Între timp, anumite calculatoare se defectează. Astfel, se
obţine un subgraf al lui G, G1 .
-+ Vizităm apoi toate nodurile adiacente cu el • fie ele j 1, j 2, ... jk, vizitate în
această ordine.
-+ Parcurgerea continuă în acest mod până când au fost vizitate toate nodurile
accesibile.
3
În acest paragraf vom exemplifica parcurgerile doar in cazul grafurilor conexe. Cum
noţiuneanu a fost prezentată până în acest moment. precizăm doar că vom exemplifica
parcurgerea grafurilor în care oricare două noduri sunt "legate• printr-o succesiune
de muchii.
Manual de informatică pentru clasa a Xl-a 251
Nod pornire 1: 1 3 6 2 7 5 4
Nod pornire 3: 3761254
Nod pornire 6: 6 3 1 7 2 5 4
Figura 9.8.
bag in
CitireN('Graf.txt' , A, n);
bf(l);
end.
1
Parcurgerea continuă în acest mod până când au fost vizitate toate nodurile
accesibile.
Figura 9.9.
254 Capitolul 9. Introducere în teoria grafurilor
9.1. 7. Lanţuri
Definiţia 9.7. Pentru graful neorientat G= (V, E), un lanţ L=[v1 ,v2 ...vp]
este o succesiune de noduri cu proprietatea că oricare două noduri vecine
sunt adiacente, adică (v1 ,va)EE, (v;r,v3)EE, ... , (vp_1 ,vp)EE. De
altfel, un lanţ poate fi definit prin succesiunea de muchii (v1 , va) EE, (v2 , v 3 ) EE, ... ,
(Vp-ltVp)EJ!!.
Definiţia 9.8. Se numeşte lanţ elementar un lanţ care conţine numai noduri
distincte.
Figura 9.1 O.
O Problema 9.1. Fiind dat un graf şi două noduri ale sale a şi b, să se scrie un
program care decide dacă între ele există un lanţ sau nu, iar în caz că acest lanţ
există, se cere să se afişeze lanţul.
. {j,
T[1] =
dacă i este descendent al lui j
O, dacă i nu a fost selectat
Să
mai observăm că un nod este selectat o singură dată, deci, în final, T va
reţine, pentru fiecare nod i, nodul j de la care a fost selectat. Pentru nodul de la care
a pornit parcurgerea (a) vom avea T (a) = O, pentru că acest nod nu a fost selectat de
algoritm. De aici, rezultă că drumul poate fi reconstituit, pornind de la T, astfel: se
afişează b, apoi T [b) , apoi T [T [b) ) ... până când se obţin e valoarea o. Pentru ca
drumul să nu fie afişat în ordine inve rsă faţă de modul în care a fost obţinut ,
subprogramul refac care îl reconstituie şi îl afişează este recursiv. Programul de mai
jos afişează drumul, pornind de la matricea de adiacenţă a grafului:
,
if (T[b]<>O) then refac(b); if (T[b]taO) refac(b);
end. }
•
1. Să observăm că vectorul T poate fi folosit pentru a obţine lanţuri de la nodul a la
oricare alt nod al grafului.
2• Dacă refacem rezolvarea prin utilizarea parcurgerii în lăţime, vom observa că
lanţu l obţinutare lungimea minimă . Prin natura ei, parcurgerea BF selectează nodurile
în ordinea "depăl1ării" lor faţă de nodul de la care a început parcurgerea. Astfel, la
inceput se vizitează primul nod (a), apoi nodurile pentru care lungimea lanţului de la a
la ele este 1, apoi nodurile pentru care lungimea lanţului de la a la ele este 2, ş.a.m.d.
a) pentru exemplul 1, întrebarea este: cum putem afla, pentru fiecare oraş în parte,
oraşele în care putem ajunge cu maşina?
b) pentru exemplul 4, întrebarea este: cum putem afla, pentru fiecare triunghi în
parte, care sunt triunghiurile asemenea cu el?
{~·.
dacă există lanţ de la i la j
L(i,j) = 'in caz contrar
IAanual de informatică pentru clasa a Xl-a 259
:J Problema 9.2. Fiind dat un graf G, cum putem obţine matricea lanţurilor?
~ Răspunsul este uşor de dat. Parcurgem graful începând cu nodul1. Pentru toate
-odurile j vizitate, vom avea L <1, j ) =1, completând astfel prima linie a matricei.
;poi, vom parcurge din nou, graful, pornind de la nodul 2. Pentru toate nodurile j,
:izitate, vom avea L(2, j) =1, apoi parcurgem graful începând cu nodul 3 .... ş.a.m.d.
O anumită îmbunătăţire a algoritmului se obţine dacă ţinem cont de faptul că matricea
~ţurilor este simetrică (de ce?). Lăsăm ca exerciţiu scrierea acestui program.
1trebare: care este complexitatea acestui algoritm?
Definiţia 9.9. Un graf neorientat G= (V, E) este conex, dacă pentru orice
pereche de noduri x, yeV, există un lanţ în care extremitatea iniţială este x
şi extremitatea finală este y.
1,~,
,~j Un graf cu un singur nod este, prin definit,ie, conex. Aceasta pentru că nu există
• două noduri diferite pentru care să se pună problema existenţei unui lanţ.
260 Capitolul 9. Introducere în teoria grafurilo·
O Problema 9.3. Fiind dat un graf Go: (V, E >, să se scrie un program care să decidă
dacă graful dat este sau nu conex.
0 Rezolvare. Ţinând cont de cele învăţate, problema nu este grea. Putem utiliza
una din metodele de parcurgere învăţate, DF sau BF. Ideea este următoarea: dacă ,
pornind de la un nod, printr-una din metodele de parcurgere, ajungem să vizităm toate
celelalte noduri, atunci graful dat este conex. Cum putem şti dacă am vizitat toate
nodurile? Simplu, după parcurgere, toate componentele vectorului s reţin 1. Puteţ1
scrie acest program?
Fie graful asociat unuia dintre cazurile prezentate. În termeni din teoria
grafurilor, problema se reduce la determinarea nodurilor unei componente conexe.
$i': Exemple
Figura 9.14.
2. Graful din figura 9.14. conţine 3 componente
conexe. Aşa cum un graf, cu un singur nod, este
conex, tot aşa un nod izolat alcătuieşte el singur o
G
componentă conexă.
0
Manual de informatică pentru clasa a Xl - a 261
.~ Observaţii
'")
'r>
1 . Câte componente conexe poate avea un graf neorientat cun noduri? Numărul
lor este cuprins între 1, pentru un graf conex şi n corespunzător unui graf cu toate
nodurile izolate.
0 Rezolvare. După cum uşor vă puteţi da seama, o parcurgere a grafului (DF sau
BF) pornind de la un anumit nod, vizitează toate nodurile componentei conexe care
îl conţin e . Pentru fiecare nod vizitat, s [il reţine 1. Dacă, după o parcurgere, mai
rămân noduri nevizitate, parcurgerea se reia începând de la primul nod nevizitat.
Evident, numărul componentelor conexe este egal cu numărul de parcurgeri
necesare pentru a fi vizitate toate nodurile.
O Problema 9.5. Fiind dat un graf conex, G= (V, E >. să se scrie un program care
decide dacă graful conţine cel puţin un ciclu.
0 Rezolvare. Începem prin a observa că dacă graful nu este conex, putem rezolva
problema verificând dacă există un ciclu într-o componentă conexă a sa. Pentru
simplitate, am preferat să considerăm că graful este conex. Şi aici, problema se poate
rezolva pornind de la o parcurgere DF. Graful conţine cel puţin un ciclu dacă, în
timpul parcurgerii, algoritmul va ajunge în situaţia de a vizita un nod de două ori
(tentativă oricum respinsă, pentru că algoritmul testează acest lucru, vedeţi rolul
vectorului s). Vom da un exemplu, cu graful de mai jos, pe care îl parcurgem DF.
f: Observaţie
•
Deşi parcurgerea se face în timp polinomial şi cu toate că programul este
simplu, se putea proceda într·un mod cu mult mai inteligent. Mai mult, aproape că nu
este cazul să facem un program. Graful fiind conex, este suficient să verificăm relaţia
m=n-1,
unde m este numărul de muchii, iar n este numărul de noduri. Dacă relaţia este
verificată, înseamnă că graful nu conţine cicluri, altfel, dacă m>n-1 înseamnă că
graful conţine cel puţin un ciclu, iar dacă m<n-1 înseamnă că nu este conex, şi ar
contrazice cerinţa.
9.1.11. Arbori
begin main()
CitireN( 'Graf.txt• ,A,n); { CitireN("Gra f.txt",A,n);
df(l); df(l);
suma:=O; suma= O;
for i:=l to n do for (i=l;i<=nJi++ )
suma:=suma+ s[i]; suma+=s[i];
if suma<>n if (sumal =n)
then writeln('Nu este conex') cout<<"Nu este conex";
el se el se
if gasit if (gasit)
then writeln('Are ciclu') cout<<"Are ciclu";
else writeln('Arb ore') ; else cout<<"Arbor e"t
end. }
~ Demonstratie .
~ Fie G un arbore (graf neorientat, conex şi fără cicluri). Trebuie să demonstrăm
că are n-1 muchii. Vom demonstra prin inducţie. Dacă n=l, numărul muchiilor
este o (se verifică, are n-1 muchii). Vom presupune proprietatea adevărată
pentru arbori cun noduri (adică au n-1 muchii). FJe un arbore cu n+l noduri.
Există cel puţin un nod terminal (nod care are o sfngură muchie incidentă).
Dacă nu ar exista un astfel de nod, să considerăm un lanţ care porneşte
dintr-un nod oarecare. La fiecare pas, vom selecta o muchie. Până la urmă,
pentru că mulţimea nodurilor este finită şi pentru că nu există nod terminal,
lanţul va trece de două ori printr-un acelaşi nod. Asta înseamnă că arborele ar
conţine cicluri (absurd, se contrazice definiţia). Eliminăm nodul terminal şi
muchia care îi este incidenta. Obţinem un arbore cu n noduri. Conform ipotezei
făcute, acesta va avea n-1 muchii. Înseamnă că arborele cu n+1 noduri va
avea n muchii (n-1+1).
ţ::: Fie G un graf cu n-1 muchii, care nu conţine cicluri. Rămâne de dovedit că G
este conex. Vom demonstra prin reducere la absurd. Presupunem că G
nu este conex. Fie G~. G2, ... , Gp componentele conexe ale grafului. Fiecare
dintre ele îndeplineşte condiţiile:
a) este conexă (aşa a fost aleasă);
~ unde:
-+ V={v1 , v 2 , ... , vn} este o m ulţime fin ită de elemente numite vârfuri sau
noduri.
-+ A este o mu lţi me de arce. Vom nota un arc prin perechea ordonată
(vi, Vj) cu i:;>~:j .
268 Capitolul 9. Introducere în teoria grafurilor
...li Observatii.
1. În cazul grafurilor orientate. dacă există arcul (vi, v:1 > nu înseamnă că există
automat şi arcul (v:~, vd. Din acest motiv, în definiţie, s-a precizat că un arc este o
pereche ordonată de forma (v1 ,v:~>·
2. Din definiţie , rezultă că nu există arce de la un nod la el însuşi. Astfel, un arc a
fost definit (v11 v:1) cu i;t:j.
3. Să observăm că mulţimea arcelor A, respectă relaţia Ac.vxv, unde vxv este
produsul cartezian al mulţimii v cu ea însăşi.
4. Grafurile neorientate sunt cazuri particulare
de grafuri orientate, mai precis acele grafuri
orientate în care pentru orice arc (vi, v:1) există
arcul (v:~,vd. Alăturat , puteţi observa un graf
neorientat (stânga) reprezentat ca un graf orientat
(dreapta).
Figura 9.20.
5. Grafurile orientate se mai numesc şi
dlgrafuri.
Definiţia 9.14. În graful orientat G= (V, A), vârfurile distincte v1 ,v:~e G sunt
adiacente dacă există cel puţin un arc care le uneşte.
Astfel, avem următoarele cazuri:
a) Există numai arcul (v11 v:~)EA- în acest caz spunem că arcul {v 1 , v:~ ) E A
este incident spre exterior cu v.1 şi spre interior cu v :1.
b) Există numai arcul <v:~ , vd e A- în acest caz spunem că arcul (v:~ , vt)eA
este incident spre interior cu v 1 şi spre exterior cu v :1.
c) Există arcul (v1 , v:~) E A şi arcul (v:~ ,vt> e A.
Definiţia 9.15. Într-un graf orientat, prin gradul exterior al unui vârf v vom
.~·
;;.,t:_;) înţelege numărul arcelor Incidente spre exterior cu v. Gradul exterior al
unui nod va fi notat cu d+ (v) .
Definiţia 9.16. Într-un graf orientat, prin gradul interior al unui nod v vom
înţelege numărul arcelor incidente spre interior cu v.
Gradul interior al unui nod va fi notat cu d - (v) .
e.
C ·x : Pentru vârful i din figura alăturată, avem:
d+(i)=3 şi
d-(i) =2. Figura 9.21,
\1anual de informatică pentru clasa a Xl-a 269
":!. Demonstraţie. Relaţia este adevărată, pentru că fiecare arc este incident spre
exterior cu un vârf şi fiecare arc este incident spre interior cu un vârf.
11 ( 11 - 1)
":!. Demonstraţia se face prin Inducţie. Dacă n=l, avem 1 graf orientat. Dacă
n ..2, cele două noduri pot să nu fie sau să fie adiacente. În acest din urmă caz,
putem avea arcul (v1 ,v2 ) sau arcul (v2 ,vd sau putem avea ambele arce
(v11 v 2 ) şi (v2 , vd. În total, avem 4 grafuri orientate, valoare care rezultă şi din
formulă, dacă înlocuim n cu 1.
grafuri orientate. Adăugăm vârful n+l. Acest vârf poate fi adiacent cu fiecare
dintre celelalte n vârfuri în exact 3 moduri (vedeţi adiacenţa) sau poate să nu fie
adiacent. Atunci, numărul de grafuri orientate cu n+l noduri este
11(11- 1) 11(11- 1) +11 11(11+1)
4 2 x4'1 =4 2 =4 2 .
Definiţia 9.17. Un graf orientat este complet dacă oricare două vârfuri i
şi j (i;t:j sunt adiacente.
)
270 Capitolul 9. Introducere în teoria grafurilor
~
n(n-1)
Pentru fiecare structură de date pe care o vom folosi, vom avea câte o
procedură (funcţie)care citeşte datele respective. Toate aceste subprograme se
găsesc grupate în unitatea de program grafuri.pas {pentru Pascal) şi în
grafuri.cpp (pentru C++).
Toate subprogramele pe care le utilizăm citesc datele dintr-un fişier text, în care
pe prima linie vom scrie număru l de noduri (n), iar pe următoarele linii câte o muchie
( i, j) ca în exemplul următor, în care este prezentat un graf şi liniile fişierului text
care este citit pentru el:
Fişierul 6
0 text:
1 2
1 3
1 5
2 3
3 4
4 5
Figura 9.22.
a .. =
•.J
{1,O, pentru (i, j) e A
pentru (i, j) li!: A
o o 1 o
gx:· Pentru graful din figura 9.22., matricea de
este prezentată alăturat.
adiacenţă
o o 1 o o o
o o o o o
•
l Observaţii
o o o o 1 o
1. Întrucât, dir. modul în care a fost definit graful, rezultă că nu o o o o o o
există arce de la un nod la el însuşi, rezultă că elementele de o o o o o o
Manual de informatică pentru clasa a Xl-a 271
~ Definiţia 9.18. Un graf parţial al unui graf orientat dat G=(V,A) este un
2:.J graf Gt= (V, A 1 ) • unde A10\.·
Un graf parţial al unui graf dat, este el însuşi, sau se obţine din G prin
suprimarea anumitor arce.
--->
rezulta 0
Figura 9.23.
Obţinerea unui
graf parţial G=(V,A)
Referitor la exemplul 1 din 9. 2 .1. unele persoane îşi şterg din agendă
numerele altor persoane din grup. Aceasta înseamnă că noul graf nu va mai avea
anumite arce, deci va deveni un graf parţial al grafului iniţial.
Un subgraf al unui graf G este graful G sau se obţine din G prin suprimarea
anumitor vârfuri şi a tuturor arcelor incidente cu acestea.
("] 1
cx:
--->
rezultă
Figura 9.24.
Obţinerea unui
subgraf G=(V,A)
Pentru exemplul 2: dacă graful are un circuit înseamnă că există cel puţin o
noţiune care nu poate fi explicată decât prin
intermediul altora care, la rândul lor, ar trebui
explicate exact prin noţiunea care nu poate fi
explicată fără ele. Se mai întâmplă şi aşa. Un
exemplu de limbaj care nu poate fi predat în mod
clasic este Java. De exemplu, cel mai simplu
program utilizeaz~ din plin programarea orientată
pe obiecte, care se studiază după ce am învăţat să
scriem programe simple.
Pentru exemplul 3: dacă după execuţia
instrucţiunii i,pentru cel puţin un set de date de
intrare, se ajunge să se execute instrucţiunea j,
înseamnă că există un lanţ de la i la j. De
asemenea, dacă după ce se execută instrucţiunea
i, se ajunge să se execute din nou instrucţiunea i,
atunci programul conţine structuri repetitive, iar
graful asociat conţine circuite.
Aşa cum am definit pentru grafuri neorientate
matricea lanţurilor, similar, se poate forma pentru Figura 9.25.
grafuri orientate matricea drumurilor:
{~'.
dacă există drum de la i la j
DQ,j) = în caz contrar
Definiţia 9.20. Graful orientat G= (V, A) este tare conex dacă \/x,yev,
3 drum de la x la y şi drum de la y la x.
&%: ·
. !\:
~
Figura 9.26.
O Problema 9.8. Fie un graf orientat G= (V, A), memorat prin intermediul matricei de
adiacenţă . Se cere să se determine vârfurile fiecărei componente tare conexă.
0 Rezolvare
a) Vom numi succesori ai vârfului i, toate nodurile j, pentru care există drum de la
i la j, la care se adaugă i. De exemplu, pentru graful dat., succesorii vârfului 1 sunt
vârfurile 1, 2, 3 şi 4. Pentru a determina toţi succesorii vârfului i, vom efectua o
parcurgere DF a grafului pornind de la acest vârf. Succesorii nodului i vor fi reţinuţi în
vectorul suc.
276 Capitolul 9. Introducere în teoria grafurilc·
c) Dacă un vârf este simultan succesor şi predecesor al lui i, atunci el va face parte
din componenta tare conexă a vârfului i. Mulţimea nodurilor cu această proprietate va
fi o componentă tare conexă a grafului. De ce? Pentru că între două vârfuri k şi 1
există atât drum de la k la 1 (de la k lai şi de lai la 1) cât şi drum de la 11a k (de la
1 la i şi de la i la k). Mulţimea nodurilor cu această proprietate este maximală î~
rap.ort cu relaţia de incluziune. Dacă, prin absurd, ar mai exista un vârf cu această
proprietate, care nu aparţine acestei mulţimi, atunci ar trebui să existe drum de lai la
el, şi de la el la i, caz în care acesta ar fi fost găsit prin procedeul dat.
1234567 1234567
suc 1 1 1 1 o o o suc 1 1 1 o o o o
pred 1 o o o o pred
1 1 1 1 1 o o o o
1234567 1234567
suc 1 1 1 2 o o o suc 1 1 1 2 o o o
pred 2 2 o pred 1
1 1 1 2 1 1 2 o o o
1234567 1234567
suc l. 1 1 2 3 o 3 suc 1 1 1 2 3 4 3
pred 1 1 1 2 3 o 3 pred 1 1 1 2 3 4 3
Manual de informatică pentru clasa a Xl- a
Probleme propuse )
'-....
1. O cunoştinţă mi-a zis: la mine în birou suntem s persoane. Fiecare dintre noi
colaborează cu exact 3 persoane. A zis adevărul?
2. Demonstraţi că într-un graf neorientat numărul nodurilor de grad impar este par.
3. Fiind date n persoane şi :m relaţii de prietenie între ele de forma: persoana i este
prietenă cu persoana j, se cere să se stabilească corespondenţele între afirmaţiile
din stânga şi cele din dreapta.
6. La un ştrand există 6 bazine. Unele dintre ele sunt unite printr-o ţeavă prin care
poate circula apa. Astfel, bazinul 1 este unit cu bazinul 2, bazinul 4 cu bazinul 5 şi
bazinul 2 cu bazinul 3.
6.1. Ştiind că fiecare bazin poate fi dotat cu un robinet, se cere num ăru l minim de
robinete care asigură umplerea tuturor bazinelor.
6.2. Care este numărul minim de ţevi prin care se pot uni două bazine, astfel încât să
se poată umple toate bazinele cu un singur robinet. Daţi exemple de bazlne unite care
asigură cerinţa problemei.
7. Fiind dat un grup de n persoane, în care dintre situaţiile de mai jos se poate
folosi pentru modelare un graf neorientat?
a) Unele persoane din grup cunosc alte persoane din grup;
b) Unele persoane din grup simpatizează alte persoane din grup;
o) În cazul în care toate persoanele lucrează într-o firmă, unei~ persoane din grup
sunt şefi pentru alte persoane din grup;
d) Unele persoane din grup sunt prietene cu
alte persoane din grup.
1 1 1 1 o 1 o o 1 1 1o 1 o o 1 1 1o 1 o· o 1 1 1 o 1 o
1 1 ooo oo 1oo oo oo 1o o oo o o 1 ooo o oo
1 o 1 1 o oo 1 o o 1 o oo 1 o o l o o o 1 oo 1 o oo
1 o 1 1 o o 1 1 o 1 oo o 1 1 o 1 o o o 1 1 o 1 ooo 1
oo oo 1 oo ooo oo oo oo ooo 1 o 1 1 1 1 1 1 1
1 o ooo 1 1 l o o oo o 1 1 o oo o o 1 1 o
o o 1 oo
a) b) c} d}
280 Capitolul 9. Introducere în teoria grafurilor
9. Care este valoarea de adev~r a afirmaţiilor de mai jos (A, adev~rat, iar F, fals):
o 1 o o o 1 o1o o 1 ooo
1 o o 1 o 1
1 o 1 o o 1 o 1 o o 1 o 1 o o 1 o 1 o
o1 o 1 o 1 o1 1 o 1o o o 1 o 1 1
1 o o 1 1o oo 1o1 1 oo o 1
oo o oo oo ooo o o o Figura 9.30.
a) b) c) d)
11. Care dintre matricele de mai jos poate fi matricea de ad iacenţă a unui graf
neorientat?
o 1 o 1o o ooo
1 o 1 o 1o
1 o l oo 1 o 1 o o l o 1 oo
o o o 1 o l o 1 o 1
1 o 1 1 o o 1 1o o 1
oo o oo o oo o
a) b) c) d)
Manual de i n formatică pentru clasa a Xl-a 281
o o o
o o o
o o o
o
o
o
o
1
0000
1 o OI
o o o li
ro 1
1000
o
o o o
1
o
o
o
l
:l d 0
o o o o 0001 0000 o) Figura 9.31.
a) b) c) d)
15. Care este numărul minim şi care este numărul maxim de componente conexe
pe care le poate avea un graf neorientat cu 8 noduri şi 6 muchii?
16. Care este numărul de cifre o pe care îl reţine matricea de adiacenţă a unul graf
neorientat cu n noduri şi m muchii?
17. Care este numărul minim şi numărul maxim de noduri izolate pe care il poa.te
avea un graf neorientat cu 10 noduri şi 10 muctlii?
18. Care este num ă rul de grafuri neorientate cu 5 noduri?
19. Precizaţi care dintre afirmaţi ile urmă
toare sunt adevărate ş i care sunt false.
Toate afirm aţiile se referă la graful din
figura 9.32.
19.3. Există două noduri din graf pentru care nu există un lanţ care le uneşte.
19.4. "6 1 2 3 5 4 7" este un lanţ în graful dat.
19.5. "3 2 5 1 4 6 7" este un lanţ în graful dat.
19.6. Numărul minim de muchii care trebuie eliminate pentru a obţine un arbore
parţial este 2.
19.7. Numă rul maxim de muchii care pot fi eliminate astfel încât graful să rămână
conex este 3 .
19.8. Numărul minim de muchii care pot fi eliminate pentru ca graful să nu conţină
cicluri este 3 .
19.9. Un arbore parţial al grafului dat are 7 muchii.
282 Capitolul 9. Introducere în teoria grafurilor
20. Precizaţi dacă afirmaţiile de mai jos sunt adevărate sau false.
20.3. Cu ajutorul parcurgerii în lăţime se poate determina dacă un graf este conex.
20.6. Un graf este alcătuit din două componente conexe. Pentru ca graful să devină
conex, este suficient să eliminăm o anumită muchie.
20.7. Un graf este alcătuit din două componente conexe. Fiecare dintre ele
alcătuieşte un graf parţial al grafului dat.
20.8. Un graf este alcătuit din două componente conexe. Fiecare dintre ele
alcătuieşte un subgraf al grafului dat.
20.9. Cu ajutorul parcurgerii în lăţime se poate determina, dacă există, un lanţ între
două noduri ale grafului.
20.12. Orice graf complet este alcătuit dintr-o singură componentă conexă.
20.13. Din orice graf complet, prin eliminarea anumitor muchii se poate obţine un
arbore.
20.14. Orice graf complet are un subgraf care este arbore.
28. Fiind dată matricea drumurilor unui graf, se cere să se scrie programul care
afişează componentele conexe.
30. Se dau n puncte distincte în plan: Pdx1 ,ytl cu OSxt,Yi~200, pentru orice
i=1, 2, ... , n. Considerăm că fiecare punct este unit cu cel mai apropiat punct
diferit de el (dacă există mai multe puncte la distanţă minimă, se uneşte cu fiecare
dintre acestea). Numim regiune o mulţime maximală de puncte cu proprietatea că
oricare dintre ele sunt unite printr-un lanţ. Să se determine numărul de regiuni şi să
se vizuallzeze regiunile (punctele şi legăturile dintre ele).
31. Se dă matricea de adiacenţă a unui graf neorientat. Se cere să se afişeze toate
ciclurile de lungime k. Un ciclu se va afişa o singură dată.
32. Se dă matricea de adiacenţă a unui graf neorientat. Se cere să se afişeze
toate ciclurile de lungime 4 . Se cere un algoritm eficient.
33. Într-un grup de n persoane, anumite persoane, împrumută altor persoane diverse
sume de bani! Modelând problema cu ajutorul grafurilor orientate, se cere să stabiliţi
corespondenţa dintre afirmaţiile din stânga şi cele din dreapta.
34. Se dau n mulţimi de numere naturale: A 1 , A2 ... A". Acestor mulţimi li se asociază
un graf orientat astfel: dacă mulţimea A 1 este inclusă în mulţimea A:~, în graful asociat
vom avea arcul (A1 , A:~). Nu vom considera cazul de incluziune a unei mulţimi în ea
lnsăşi. Stabiliţi corespondenţa dintre operaţiile din stânga şi cele din dreapta.
a) 1 1; b) 1 3; c) 1 o; d) o o.
Figura 9.33.
37. În graful din figura 9.34, care este lungimea celui mai
lung lanţ elementar şi care este lungimea celui mai lung
drum elementar?
a) 3 2; b) 2 2; c) 2 3; d) l 2.
Figura 9.34.
41. Care este numărul minim de arce care trebuie adăugate pentru ca graful să
devină
tare conex?
a) 1 ; b) 2; c) 3; d) 4.
42. Se dă un graf orientat. Se cere să se afişeze, pentru fiecare vârf în parte, gradul
interior şi gradul exterior. Problema se va rezolva în cazul în care graful este dat prin
matricea de ad iacenţă şi în cazul în care el este dat prin liste de adiacenţă.
43. Fiind date un graf orientat şi o succesiune de vârfuri să se decidă dacă
succesiunea este drum, iar în caz afirmativ se va preciza dacă este sau nu un drum
elementar. Problema se va rezolva în cazul în care graful este dat prin mat.ricea de
ad iacenţă şi în cazul în care el este dat prin liste de adiacenţă .
44. La fel ca mai sus, dar se cere să se determine dacă succesiunea respectivă este
sau nu lanţ (lanţ elementar).
45. Se dă un graf prin lista muchiilor. Programul va decide dacă graful este
neorlentat.
46. Se dau listele de adi acenţe ale unui graf orientat. Programul va afişa matricea de
adiacenţă.
vor afişa indicii componentelor care se inversează, iar dacă sortarea nu este posibilă,
se afişează Nu. Datele de intrare se gc':isesc în fişierul text date. in astfel:
Linia 1 n
Linia 2 1, ... , n într-o ordine oarecare;
Linia 3 m
următoarele m linii conţin fiecare câte o pereche de indici i, j.
Exemplu:
3 Programul va afişa:
3 1 2 1 2
2 2 3
2 3
1 2
Răspunsuri
7. Pentru a putea modela anumite relaţii cu ajutorul unui graf neorientat trebuie ca
relaţia existentă între i şi j să fie reciprocă, pentru că muchia (i, j) presupune căi
este in relaţie cu j şi j este în relaţie cu i. Dacă i cunoaşte pe j, nu este obligatoriu
ca j să cunoască pe i, dacă i simpatizează pe j, nu este obligatoriu ca j să
simpatizeze pe i , dacă i este şeful lui j, j nu poate fi şeful lui i. În concluzie,
răspunsul este d) pentru că relaţia de prietenie este reciprocă.
8. b).
9. 9.1. A; 9.2. F; 9.3. F; 9.4. Ft 9.5. F; 9.6. A; 9.7. F; 9.8. Al 9.9. A;
9.10. A.
10. b) Dacă matricea este de adiacenţă, atunci vă puteţi orienta după gradele
vârfurilor. Evident, graful reprezentat de matricea de adiacenţă trebuie să aibă
vârfurile cu aceleaşi grade cu vârfurile grafului reprezentat în desen.
11. d) Desigur, puteţi desena graful, dar, mai uşor, elim inaţi variantele în care
aveţi 1 pe doagonala principală, sau acelea în care matricea nu este simetrică.
12. 8. Dacă matricea este dată corect, nu este nevoie să desenaţi graful pentru
ca, apoi, să-i număraţi muchiile. Se ştie că suma gradelor tuturor nodurilor este
egală cu dublul numărului de muchii. Prin urmare, este suficient să însumaţi
elementele reţinute de matrice si să împărţiţi rezultatul la 2 .
13. 2.
14. a) Dacă matricea are 4 linii şi 4 coloane, este clar că subgraful ar rezulta prin
eliminarea unui singur nod şi a muchiilor incidente lui. Dacă eliminăm nodul din
centru, se obţin 4 noduri izolate. Oricare alt nod am elimina, rămân 1 nod cu
gradul 3 şi 3 noduri cu gradul 1.
15. 2 componente conexe şi 5 componente conexe.
3
16. n -2m. Matricea de adiacenţă are n 3 elemente. Am văzut faptul că suma
tuturor cifrelor de 1 (adică a gradelor vârfurilor) este 2m (unde m este număru l de
muchii).
17. o şi 5.
10
18. 2 •
38. c).
39. b).
40. c).
41. a).
50. Se poate lucra direct pe matricea L. Idee: pentru camera iniţială vom avea
L(i,j)=l. Apoi, pentru toate camerele accesibile vecine cu ea vom avea
L(i ,j)=2, apoi pentru toate camerele accesibile cu ele vom avea L(i,j)=3 ...
ş.a.m.d. Pentru a obţine această marcare vom parcurge în lăţime graful asociat.
Putem evita memorarea acestuia. Vom introduce în coadă coordonatele camerei
iniţiale. Vom încărca în coadă coordonatele tuturor camerelor vecine pentru care
L ( i, j) =1. Pentru fiecare astfel de cameră, pentru care, iniţial , L <i, j) =O, vom avea
L(i, j )=2. Se trece apoi la următorul element din coadă cu care se procedează
asemănător. Se ştie că, prin parcurgerea în lăţime, se vizitează nodurile în
ordinea lungimii drumului, de la ele la nodul iniţial. Deducen:!, astfel, că marcarea
este corectă. Algoritmul se termină când coada este vidă. In final, se afişează
matricea L.
53. Asociem problemei un graf neorientat. Nodurile sunt indicii elementelor vectorului,
de la 1 la n. Când conţinuturile a două elemente se pot inversa, nodurile
corespunzătoare sunt unite printr-o muchie. Dacă nodurile i1, i 2, ... , ik sunt unite
printr-un drum: atunci intersch imbărlle (i1, i2), (i:~, i3), ... , (ik_1 , ik),
( ik-1• ik-2), ... , ( i:~, i 1 > inversează conţinuturi le elementelor de indice i 1 şi ik,
lăsând conţinuturile celorlalte elemente de indici i 2 , ... , ik-l nemodificate. O
parcurgere în lăţime determină distanţa minimă între două noduri.
Anexa 1
Memento
A) Tipuri întregi
' .. , . '' . ~ .,. " . ' . . ocupă · • .:::.!; \.•' ; •, ' .~! + ,,\:'~::l:·'·"'l~dfl.;
Numetlp
. ' · J· ·, ~.emnlflcaţle ·,. ·;?;:;Valori admlse '·;;·..··ifir' ·'i
., ;:. ' (blti) ' ' ,, '!* ;:; !;t• '•:: ' '.. + .... :·:·.~>::;;· l
l.ongint de la -2147483648 la
întreg lung 32
2147483647
byte număr natural scurt 8 de la o la 255
word cuvânt 16 de la o la 65535
c) Tipuri reale
.
1 :~ v~torl aâ.mis~ (în·:m~dy;).'Hi!l
' ' · ocupă
., ·Nume. tip · :S~innlfi~atle.... i : •: (biti) ' • • 11 , ~ .. 'h ,11 t:.; ~~~:·,,,
' ' !'
D) Tipul logic - boolean- poate reţi ne doar două valori true şi false.
290 Anexa 1. Memento
A.l.3 . Operatori
A.l.3.1. Prioritatea operatorilor
lată cele 4 grupe de prioritate.
• operatori unari (+ şi - );
• operatori binarl ( +, -, •, /, DIV, MOD).
Operatorul •. Are semn ificaţia de înmulţire. Operanzii sunt de tip intreg sau
real. Dacă cel puţin unul din operanzi esti de tip real, rezultatul este de tip
real, altfel rezultatul este de tip întreg.
·'~·'
Operatorul DJ:V furnizează rezultat corect numai dacă ambele valori sunt
• numere întregi pozitive .
-+ Operatorul MOD. Are semnificaţia de rest al împărţi rii pentru numere întregi.
Operanzii sunt în mod obligatoriu de tip întreg, iar rezultatul va fi întotdeauna
de tip întreg. Operanzii trebuie separaţi de operator prin cel puţin un spaţiu.
~;.. Ca şi în cazul operatorului DJ:V, rezultatul este corect numai dacă ambii
~~· operanzi sunt pozitivi. Fie a MOD b. Rezultatul se obţine astfel:
a - a DIV b (R=D-ÎxC).
-+ Operatorul < (mai mic). Fiind daţi doi operanzi a ş i b, operatorul < arată
dacă este adevărată sau nu rel aţia a<b. Dacă relaţia este adevărată
rezultatul va fi TRUE, altfel rezultatul va fi FALSE.
-+ Operatorul <= (mai mic sau egal). Fiind daţi doi operanzi a şi b, operatorul
<= arată dacă este adevărată sau nu relaţia a<=b. Dacă relaţia este
adevărată rezultatul va fi TRUE, altfel rezultatul va fi FALSE.
-+ Operatorul > (mai mare). Fiind daţi doi operanzi a şi b, operatorul > arată
dacă este adevărată sau nu relaţia a>b. Dacă relaţia este adevărată
rezultatul va fi TRUE, altfel rezultatul va fi FALSE.
-+ Operatorul >=(mai mare sau egal). Fiind daţi doi operanzi a şi b, operatorul
>= arată dacă este adevă rată sau nu relaţia a>=b. Dacă relaţia este
adevărată rezultatul va fi TRUE, altfel rezultatul va fi FALSE.
-+ Operatorul OR (sau). Regula este s impl ă : dacă unul dintre operanzi este
TRUE, rezultatul este TRUE, altfel rezultatul este FALSE.
-+ Operatorul XOR (sau exclusiv). Ş i aici, regula este foarte simplă: dacă
argumentele sunt diferite rezultatul este TRUE, contrar el este FALSE.
Manual de informati că pentru clasa a Xl- a
----------------------------~
-+ Operatoru l xoR (sAu EXCLUSIV ) este binar. Se face XOR pentru toate
perechile de biţi aflaţi pe aceeaşi poziţie a celor doi operatori. Dacă biţii sunt
diferiţi rezultatul este 1, altfel, rezultatul este o.
• se evaluează expresia;
• variabila v ia această valoare.
Forma 1.
Forma 2.
Aici, c1, ... ,cnl•····znp reprezintă constante de acelaşi tip ca şi expresia ordinală.
REPEAT
Îti
Î2i
In
UNTIL expresie logică
Forma 1.
FOR variabilă := expresie 1 TO expresle2 DO instrucţiune
unde:
- variabila poate fi de orice tip ordinal (de exemplu, de tip integer, char
sau boolean, dar în nici un caz de tipul real);
- expresie1 , expresie2 sunt expresii de acelaşi tip cu variabila.
Pasu/2.3.
• Dacă valoarea reţinută de variabila de ciclare este strict mai mică
decât valoarea obţinută în urma evaluării expresiei 2 (evaluare
efectuată la început) se adună 1 variabilei de ciclare şi se trece
la2.2.
• Dacă valoarea reţinută de variabila de ciclare este egală cu valoarea
obţinută în urma evaluării expresiei 2, executarea instrucţiu nii FOR
se încheie.
Forma 2.
)> Funcţia logaritmică f:9t+~9t, unde f(x)=ln (x) este funcţia inversă funcţiei
exponenţiale şi are forma generală:
xY =eln(~Y) =eY·In(x}.
Aceasta înseamnă că putem calcula xY - pentru că funcţi a putere nu există
în Pascal: exp(y*ln(x) ).
2
)> Funcţia pătratică f:9t~9t+, unde f(x)=x :
)> Funcţia radical f:9t+~9t+, unde: f(x) =./X, are forma generală:
~ Atenţie: dacă
x este negativ, rezultatul este eronat.
• Exemple: int ( 2. 75) returnează 2 . o, int ( -2.75) returnează -2. o.
returnează 1-tl.
298 Anexa 1. Memento
A) Tipuri întregi
'" ' ':fi': ..•• ,. ,..• ·'
~:i;Fl, 1 · ·· ·l'fl'" ",'1;! rl• · ~~;:!.~!:J •. ;:!!;· i :.J \~~JJ:!~:Jj . ;.;:;l: ~·~ i!,j.:t~. ~t~i!.,:~~~~-,·'
s;ffiriWibaţ~e ·
:t·1.!J•tr-l·,''
·. Qcup~ : !''P
'· •Nu.pe·tlp 1
1.
,.1
• ' . '• ;., ' '4 ' (biţi)
' '":'''•Valori admise
-!.: ;," .., :,., '
.t;:~
.
.
unsigned
char caracter fără semn 8 de la o la 255
char caracter 8 dela -128 la 121
unsigned
int întreg fără semn 16 dela o la 65535
int întreg 16 de la -32768 la 32767
unsigned Tntreg lung fără
long 32 dela o la4.294.967.295
semn
long de la -2.147.483.648 la
întreg lung cu semn 32
2 . 147.483.647
B) Tipuri reale
'.
~~me tip
'
l;l' , Ocupă '~
Se~nlflcaţle 'j'.!;(biţi).. ' ' Valori adml~e (in modul) ".
"'':·· !.!:!•!i.,,, " ,;: •' 1;11 'ii.:l··· ·;.,
A.2.2. Constante
1. Constante întregi. Acestea se clasifică astfel:
• zecimale (în baza 10). Exemple: 23, 1239, 56.
• octale (în baza 8). O constantă în baza 8 se declară precedată de un o
nesemnificativ. Exemplu: 0123 . Se reţine numărul intreg 123(8) .
• hexazecimale (în baza 16). Acestea sunt precedate de ox sau ox.
Exemplu: pentru OX1A2 adică 1A2 116> sau Ox1a2, adică 1A2 1161 •
Manual de informatică pentru clasa a Xl-a 299
Printr-o secvenţă escape, constanta se introduce prin codul său într-una din bazele
8 sau 16. De exemplu, constanta a poate fi scrisă (echivalent) astfel: \141'
1 1 1
sau · \x61 În cazul când se foloseşte codul scris în baza 16, acesta este
1
•
• blank ( • • );
• tab orizontal ( • \ t • );
• newline ( • \n • );
• tab vertical ( • \ v •);
• cr (• \r•).
5. Constante reale
• tip- reprezintă tipul constantei (dacă este absent, tipul este int);
• nume - reprezintă numele constantei;
• valoare - reprezintă valoarea constantei.
300 Anexa 1 . Memento
A.2.3. Operatori
1 ()[] - >::. s ~ d
2 !- +- + +- - * ( typecast ) sizeof new de/ere d ~ s
3 . *- > * s ~ d
4 */% s ~ d
5 +- ,\' ~ d
6 << >> s ~ d
7 <<= > >= s ~ d
8 = != s ~ d
9 & s ~ d
1o 1\
s ~ d
Il s ~ d
12 & & s - ) d
13 11 s ~ d
14 ? : d ~ s
15 = * = 1 = + = - = & = 1\ = 1= <<= >>= d ~ s
16 s -~ d
~ Observaţii
•
1. Operatorul "/" (împărţire) acţionează în mod diferit in funcţie de operanzi:
b) dacă cel puţin un operand este de unul din tipurile reale, rezultatul este
real (se efectuează împărţirea obişnuită).
2. Operatorul "%" acţionează numai asupra operanzilor de tip întreg. Rezultatul
obţinut este corect din punct de vedere matematic numai dacă ambii
operanzi sunt numere naturale.
3. În cazul în care se împart două valori intregi, se procedează astfel:
a) se face împărţirea intreagă a celor două valori care sunt considerate in
modul;
b) semnul câtului se stabileşte după regula semnelor (+ cu + rezultat +,
+cu-, rezultat-}, etc.
• <(mai mic);
• <=(mai mic sau egal);
• >(mai mare);
• >=(mai mare sau egal).
Rezultatul unei operaţii logice este 1, în cazul în care inegalitatea este
respectată şio, în caz contrar.
Aceştia sunt:
• == pentru egalitate;
• 1 = pentru inegalitate.
Operatorii pot fi prefixaţi (aplicaţi Tn faţa operandului) sau postflxaţi (aplicaţi după
operand).
• 1 - negare logică ;
• && - şi logic;
• 11 - sau logic.
Operatorul şi logic (binar) acţionează astfel: dacă ambii operanzi sunt diferiţ i
de o, rezultatul este 1, altfel el este o.
Operatorul sau logic (binar) acţionează astfel: dacă cel puţin unul din
operanzi este o valoare diferită de o, rezultatul este 1, altfel rezultatul este o.
Operatorul "<<' este binar. El are rolul de a deplasa către s~-,ga ::::....-:--...-:..
tuturor biţilor operandului din stanga sa, cu un număr de pozi~t ega cu :a :;a:;.:
reţinută de al doilea operand. Poziţiile rămase libere (în dreapta) vor reţine va10area o
Operatorul ">> " este binar. El are rolul de a deplasa către dreapta con~nutu
tuturor biţilor operandului din stanga cu un număr de poziţii egal cu valoarea reţ inută
de al doilea operand. Dacă operandul din stânga este de un tip întreg fără semn,
poziţiile rămase libere (în stanga) vor reţine valoarea o. Dacă al doilea operand
reţine valoarea m, o astfel de deplasare este echivalentă cu împărţirea întreagă cu
2"'. În cazul în care primul operand este un întreg cu semn, fiecare poziţie din
stânga rămasă liberă se completează cu valoarea reţinută de bitul de semn.
În cazul operatorilor binari "& ", "1", """, rezultatul se obţine aplicând pentru
fiecare pereche de biţi aflaţi pe aceeaşi poziţie regulile din tabelul următor. Atunci
când cei doi operanzi nu au aceeaşi lungime (dar numai atunci - de exemplu, dacă
ambii operanzi sunt de tip char şi rezultatul este de tip char), se aplică regulile de
conversie pentru expresii aritmetice.
"· of'.· 1
,.,OPz . OP',1&OP''::
.2 ,
. 0PtAOP2 , 11 • :;t:of.IOPz
.... '
1
. il, '' ;oljij
o o o o o
1 o o 1 1
o 1 o 1 1
1 1 1 o 1
Operatorul "-" (negare pe biţi) are rolul de a inversa conţinutul biţilor (dacă
un bit conţine o, va conţine 1 şi invers).
În C++ atribuirea este operator. În plus, în C++ avem mai mulţi operatori de
atribuire. Operatorul "=" se foloseşte intr-o expresie de forma:
v•expresie
Aici, v este o variabilă.
• se evaluează expresia;
• se evaluează expresia;
·• valoarea obţinută este atribu ită variabilei vn (eventual convertită -dacă
este cazul);
• conţinutul variabilei vn este atribuit variabilei V 0 _1 (eventual, se
efectuează conversia necesară);
•
• conţinutul variabilei v 1 este atribuit variabilei v (eventual, se efectuează
conversia necesară).
Pentru atribuiri se mai pot utiliza şi operatorii: "*=", "!=", "%=", "+=", "-="
"<<=", ">>=", "&>", ""="sau "1=n.
În ansamblu, expresia este de tipul lui exp 2 sau exp3 şi produce valoarea
exp2 sau exp3 (în funcţie de cea care se eva lu ează).
Manual de informatică pentru clasa a Xl-a 305
De multe ori, dorim ca unul sau mai mulţi operanzi să intre în calcul convertiţi
aşa cum dorim (nu implicit). Pentru aceasta, înaintea operandului se trece între
paranteze tipul său.
Exemplu: fie declaraţia: float x= -1.9;. Atunci: ( int )x•-1 (se face
conversia din float în int prin trunchiere).
A.2.4. Instrucţiuni
Forma 1.
i f (expresie) instrucţiune 1 el se instrucţlune2
• se evaluează
expresia;
• dacă valoarea produsă de aceasta este diferită de o, se execută
instrucţiune1;
• dacă valoarea produsă este o se execută lnstrucţiune2•
Forma 2.
if (expresie) instrucţiune
• se evaluează expresia;
• dacă valoarea produsă de aceasta este diferită de o, se execută
instrucţiunea subordonată.
306 Anexa 1. Memento
Principiul de executare:
• se evaluează expresia;
• dacă aceasta produce o valoare egală cu cea produsă de exp1, se
execută, în ordine, instrucţiuni, şi se trece la instrucţiunea următoare,
altfel se execută numai secvenţa instrucţlunim. t·
5. Instrucţiunea "while"
do
instrucţiune
while(expresie);
Principiul de executare:
~ Funcţia abs are forma generală : int abs ( int x) ; Rolul ei este de a
întoarce lx 1 (modulul lui x).
~ Funcţia fabs are forma generală double fabs(double x) ; are acelaşi
rol cu abs, numai că întoarce valoarea unui număr real (chiar double).
308 Anexa 1. Memento
-+ Funcţia labs are forma generală long int labs <long int x) ; şi
acelaşi rol cu abs, numai că întoarce valoarea unui întreg lung.
~ Funcţia acos are forma generală: double acos(double x); şi
calculează valoarea funcţiei arccos(x): [-1,1] -7 [O,n].
Switch 1 Switch 2
Subreteaua 1 Subreteaua 2
Figura A.1 . Exemplu de reţea de calculatoare legată la Internet
310 Anexa 2 -Aplicaţii practice ale grafuril or
~~ Observaţii
•
de
Structura anterioară este de tip arbore. Pe fiecare nivel însă, protocoalele
rea transmi siei
comunicaţie efectuează operaţii specifice pentru asigura
bidirecţionale între fiecare dispozitiv terminal (calculator).
pe
Router- ul este un dispozitiv electronic care decide calea (drumul optim)
eaua către un
care vor fi trimise informaţii l e de la un calculator din Subreţ 1,
la n~ndul său, în
altul din Subrete aua 2. La nivel local, Switch-ul decide
Control , identific ator unic pe glob) a
functie de adresa MAC (Media Access
fiedrci plăci de reţea, cărui destinatar îi este dedicat blocul de date. Pentru
a se conecta la reţeaua Internet, Router-ul are o legătură cu un
ISP
(Internet Service Provider).
L1 l2
-în serie: o activitate nu poate începe până când alta nu a fost terminată;
-în parale!: mai multe activităţi desfăşurate fn acelaşi timp.
:•. ,1.·1
. . . .''
Având cunoscut drumul critic pentru un graf asociat unui proiect, se pot
analiza în detaliu anumite aspecte particulare ale fiecărui eveniment sau activitate.
Dorim să cunoaştem cum se pot derula celelalte activităţi, care nu sunt critice, in
funcţie de durata drumului critic. Astfel, au fost introduse câteva noţiuni teoretice,
ce vor fi prezentate în continuare.
Se consideră un graf de activităţi, pentru care notăm cu v~. (vârfurile)
evenimentele şi cu A[i, j J (arcul de la v~. la V:~) activităţile. Vom defini:
t~.• - data limită a unui eveniment v 1 ca fiind diferenţa între t., (data
aşteptată a lui Va) şi drumul maxim de la v~. la Va·
Sărevenim la exemplul din figura A.3. Pentru evenimentul 4, vom avea data
aşteptată egală cu 10 (5+2+3) unităţi, iar data limită, egală cu 16 (21-5) unităţi.
Putem astfel considera că evenimentul 4 trebuie să fie atins după 10 unităţi
temporale, iar ln cazul unei întârzieri, atingerea sa nu poate să dureze cu mai mult
de 6 (16-10) unităţi faţă de data sa aşteptată de terminare.
r
ML i, j) - marginea fiberă a unei activităţi, ca fiind t~- t 1 -d (A [ i, j J ) , ce
semnifică durata cu care se poate intârzia începerea activităţii A [i, j J. fără a
modifica data de aşteptare a evenimentului v;~;
Arcele ce formează drumul critic au aceste două valori nule (nu le este
permisă nici o întârziere).
314 Anexa 2 - Aplicaţii practice ale grafurilor
Pentru graful neorientat prezentat anterior, se pot asocia următoarele trei matrice:
315
Manual de informatică pentru clasa a Xl-a
o1 o1 1 oo o1 2 1 1 2 2 o3 2 3 1 2 2
1 o 1 o o o o 1 o1 2 2 3 3 3 o3 2 4 5 5
2 1 o1 2 3 o 3 3 4 4
o1 o1 ooo 3 4 4
2 1 o 2 3 3 2 3 o4 5 5
1 o1 ooo o 1 3
1 o ooo 1 1 1 2 3 2 o1 1 1 4 3 4 o1 1
3 4 3 1 o2 2 5 4 5 1 o2
oooo1 oo 2
oooo1 oo 2 3 4 3 1 2 o 2 5 4 5 1 2 o
it în
l , Observăm faptul că acest graf asociat conţine ciclur i, lucru obişnu
sunt determinate, cu
totuşi
• rile moleculare. Drumurile maxime
structu
precizarea că in programele specializate se evită ciclarea algoritmului prin
utilizarea unei condiţii de stop.
teristi ci
După ce au fost determinate aceste matrice, mai multe carac
două dintre ele:
topolo gice importante pot fi obţinute direct. Prezentăm doar
rilor maxime:
- indice le de drum (Deto ur)- se obţine din matricea drumu
1 Il 11
IN FOProfilul
RIVIATlCA
real
PASCAL & C+ +
o INJ@[Ji]{]ll@0@ ~®0&1[7@ @[plf®llil@~@ !Nlrn©~g ®rnO®riJ®!f~ @J@ lJl!f®lliJO®!ftiD@g
®@OM (Q]@ !J@llil®lf~®!f51 ©!ID®g [ft)OO[Jl~~c~"'n[Ji]il®!lilil@\k!f®
. COMPETENTE
'
DIGITALE
- - - - ·- -
următoarele 1
Pentru a efectua o comandă, utilizaţi
date de contact:
http://www.ls-infomat.ro (