Documente Academic
Documente Profesional
Documente Cultură
4. Metode de programare
(partea a III-a)
#include <stdio.h>
#include <conio.h>
void main()
{ int i,n;
double *v, max;
printf("\nDimensiunea vectorului:");
scanf("%i",&n);
v=new double[n];
printf("Elementele vectorului\n");
for(i=0;i<n;i++)
scanf("%lf",&v[i]);
max=max1(v,0,n-1);
printf("\nElementul maxim:%8.3f",max);
max=max2(v,n);
printf("\nElementul maxim:%8.3f",max);
delete v;
getch();
}
4 Metode de programare
Pe baza acestei proprietăţi, dacă 𝑐 este mijlocul intervalului (𝑎, 𝑏), atunci
este îndeplinită una şi numai una dintre relaţiile 𝑓(𝑎) × 𝑓(𝑐) < 0, 𝑓(𝑐) = 0,
𝑓(𝑏) × 𝑓(𝑐) < 0:
𝑏−𝑎 𝑏−𝑎
𝑁
< 𝜀 ⇒ 𝑁 = [log 2 ( )] + 1
2 𝜀
float f(float x)
{ return (2*pow(x,3)-pow(x,2)+x-2);
}
{ *x2=(x0+x1)/2;
if((*f)(*x2)==0)
return 1;
if(fabs(*x2-x1)>eps)
if((*f)(*x2)*(*f)(x0)<0)
return bisectie(x0,*x2,n-1,eps,f,x2);
else
return bisectie (*x2,x1,n-1,eps,f,x2);
else
return 2;
}
}
void main()
{ float eps,x0,x1,x2;
int n;
printf("x0= ");
scanf("%f",&x0);
printf("x1= ");
scanf("%f",&x1);
printf("n= ");
scanf("%d",&n);
printf("eps= ");
scanf("%f",&eps);
switch (bisectie(x0,x1,n,eps,f,&x2))
{ case 0:{ printf("Nu s-a gasit nici o solutie !"); break; }
case 1:{ printf("Solutia exacta: %f",x2); break; }
case 2:{ printf("Solutia aproximativa: %f",x2); break; }
}
getch();
}
Exemplu. Problema turnurilor din Hanoi ilustrează foarte bine avantajele metodei
divide et impera. Problema poate fi enunţată astfel: se presupune că există trei tije
a, b, c. Pe tija a sînt plasate n discuri de diametre diferite în ordinea descrescătoare
a acestora (de la bază spre vîrf). Se cere ca cele n discuri de pe tija a să fie
deplasate pe tija c astfel respectînd următoarele restricții:
la fiecare mutare este deplasat un singur disc, aflat pe poziţia superioară pe una
din tije;
oricare din discuri poate fi aşezat numai pe un disc de diametru mai mare, cu
excepția primului disc amplasat pe o tijă (la bază), care nu are un alt disc sub el;
tija b poate fi folosită pentru deplasări intermediare.
#include <stdio.h>
#include <conio.h>
void main()
{
unsigned n,a,b,c;
a=1;b=2;c=3;
printf("Numarul de discuri");
Algoritmi și tehnici de programare 7
scanf("%d",&n);
hanoi(n,a,b,c);
getch();
}
Metoda optimului local (Greedy) este o metodă rapidă (cu consum mic de
resurse) folosită în multe probleme de optimizare pentru obținerea unei soluții bune
(acceptabile), posibil chiar soluția optimă.
Numele metodei provine de la faptul că la fiecare pas se face cea mai bună
alegere în contextul local (se alege optimul local), deși aceasta nu garantează o
soluție optimă la nivel global și nici măcar găsirea unei soluții (greedy – lacomul,
care se repede la ce are mai bun în față, ignorînd contextul mai larg). O soluție
8 Metode de programare
acceptabilă găsită prin această metodă poate fi folosită ca bază de pornire pentru
aplicare unui alt algoritm, în vederea găsirii soluției optime.
Numărul de pași (𝑝) poate fi mai mic decît numărul de elemente ale
mulțimii inițiale (𝑛). 𝑝 poate să fie cunoscut de la început sau nu; în ultimul caz,
verificarea făcută la fiecare pas poate determina și oprirea algoritmului.
Algoritmul anterior este prezentat în forma cea mai generală, fără a preciza
exact cum se alege un element sau cum se verifică dacă elementul ales este
acceptabil. Aceste aspecte depind de problema concretă care se rezolvă și se
implementează ca atare. De obicei se poate asocia o valoare numerică fiecărui
element al mulțimii 𝐴 și, în funcție de criteriul de optimizare, se alege cel cu
valoarea cea mai mare sau cea mai mică.
există o mulțime inițială 𝐴 din care se aleg elementele care vor compune soluția
(𝐴 este mulțimea muchiilor grafului; fie 𝑛 numărul de muchii și 𝑚 numărul de
vîrfuri ale grafului);
fiecărui element al mulțimii 𝐴 îi este asociată o valoare numerică (ponderea
muchiei);
10 Metode de programare
dacă problema e continuă, se ia din obiectul curent atît cît încape (adăugare);
dacă problema e întreagă, se respinge obiectul curent.
Fiind valori reale, elementele mulțimii 𝐴 sînt pozitive, nule sau negative,
fiecare avînd un efect specific asupra sumei. În spiritul cerinței, trebuie evitate
elementele negative și trebuie alese cele pozitive. Elementele nule nu afectează
12 Metode de programare
suma și pot fi alese sau nu (de exemplu, dacă se cere să găsim o submulțime cu
număr cît mai mic de elemente, vom evita și elementele nule).
Adesea soluția unei probleme este formată din mai multe elemente
distincte și poate fi prezentată ca un vector de lungime 𝑛: 𝑆𝑜𝑙 = (𝑥1 , 𝑥2 , … , 𝑥𝑛 ),
ale cărui elemente satisfac anumite condiții. Fiecare dintre elementele componente
ale soluției (𝑥𝑖 ) este ales dintr-o mulțime ordonată și finită 𝑆𝑖 , care are 𝑠𝑖 elemente
(𝑥𝑖 ∈ 𝑆𝑖 ), deci soluția aparține spațiului cu 𝑛 dimensiuni 𝑆 = 𝑆1 × 𝑆2 × … × 𝑆𝑛
(𝑆𝑜𝑙 ∈ 𝑆). Spațiul 𝑆 este numit spațiul soluțiilor pentru problema dată. Numărul de
elemente ale acestui spațiu este
𝑛
|𝑆| = ∏ 𝑠𝑖
𝑖=1
Algoritmi și tehnici de programare 13
Exemple
3. Fie un labirint cu una sau mai multe ieșiri. Problema este să se găsească un
drum dintr-un punct dat (care poate fi oricare din camerele labirintului, inclusiv cea
14 Metode de programare
de intrare) pînă la una dintre ieșiri (sau o anumită ieșire). La fiecare pas trebuie
aleasă o opțiune de continuare a drumului. Dacă opțiunea aleasă conduce la o
cameră fără altă ieșire („capcană”), atunci se revine la pasul anterior și se alege altă
opțiune de continuare a drumului.
Soluția unei probleme poate fi găsită în două feluri: prin calcule sau prin
căutarea în spațiul soluțiilor, cu reținerea acelor elemente care satisfac condițiile
problemei. Este preferabilă soluționarea prin calcule1 (datorită consumului mic de
resurse), dar nu întotdeauna e disponibil un astfel de algoritm. Una din metodele de
căutare în spațiul soluțiilor este metoda backtracking. Ea implică o verificare a
tuturor elementelor din spațiul soluțiilor (parcurgerea întregului spațiu). Problema
labirintului constituie un exemplu tipic de aplicare a metodei backtracking.
Metoda este formalizată astfel: soluția este exprimată sub forma unui
vector 𝑋 = (𝑥1 , 𝑥2 , … , 𝑥𝑛 ). Pentru fiecare element al soluției este definită
mulțimea valorilor posibile (𝑥𝑖 ∈ 𝑆𝑖 ), definind astfel spațiul soluțiilor problemei
𝑋 ∈ 𝑆 = 𝑆1 × 𝑆2 × … × 𝑆𝑛 . Elementele care compun soluția trebuie să
îndeplinească anumite condiții, numite condiții interne. Condițiile interne pot fi
aplicate asupra unui element, independent, sau pot exprima relații între unele
1
Exemple:
a) Rezolvarea ecuației de gradul 1 (𝑎 ∙ 𝑥 + 𝑏 = 0 unde 𝑎, 𝑏 ∈ ℝ) se poate face prin calcule
(𝑥 = −𝑏 ∕ 𝑎) sau prin verificarea tuturor elementelor din spațiul soluțiilor (mulțimea ℝ).
b) Rezolvarea ecuației de gradul 2 (𝑎 ⋅ 𝑥 2 + 𝑏 ⋅ 𝑥 + 𝑐 = 0 unde 𝑎, 𝑏, 𝑐 ∈ ℝ) se poate face prin
calcule sau prin verificare tuturor elementelor din spațiul soluțiilor (mulțimea ℂ2 ).
În ambele exemple este evident preferabilă utilizarea formulelor, a doua variantă fiind practic
imposibilă (spațiul soluțiilor este infinit).
Algoritmi și tehnici de programare 15
elemente ale soluției (posibil toate). Elementele din spațiul soluțiilor care
îndeplinesc aceste condiții se numesc soluții rezultat. Condițiile de continuare
constituie restricția condițiilor interne la primele 𝑖 elemente vectorului 𝑋. Atunci
cînd 𝑖 este egal cu 𝑛 condițiile de continuare reprezintă chiar condițiile interne.
Atunci cînd se încearcă alegerea unei valori noi pentru elementul 𝑥𝑖 trebuie
precizate următoarele: valorile deja atribuite pentru elementele 𝑥1 , 𝑥2 , … , 𝑥𝑖−1
(fie acestea 𝑣1 , 𝑣2 , … , 𝑣𝑖−1 ), și mulțimile de valori consumate pentru elementele
𝑥1 , 𝑥2 , … , 𝑥𝑖 (fie acestea 𝐶1 , 𝐶2 , … , 𝐶𝑖 ) – pentru elementele 𝑥𝑖+1 , 𝑥𝑖+2 , … , 𝑥𝑛
16 Metode de programare
nu s-au consumat încă valori, deci mulțimile 𝐶𝑖+1 , 𝐶𝑖+2 , … , 𝐶𝑛 sînt vide. Toate
aceste date pot fi reprezentate sub forma unui tabel, numit configurație:
𝑣1 … 𝑣𝑖−1 𝑥𝑖 … 𝑥𝑛
(𝐶 … 𝐶𝑖−1 |𝐶𝑖 ∅ ∅)
1
1) Atribuie și avansează. Are loc atunci cînd există valori neconsumate pentru
𝑥𝑖 , iar valoarea aleasă 𝑣𝑖 ∈ 𝑆𝑖 − 𝐶𝑖 are proprietatea că soluția parțială (𝑣1 , 𝑣2 , … ,
𝑣𝑖−1 , 𝑣𝑖 ) îndeplineşte condiţiile de continuare. În acest caz 𝑣𝑖 se atribuie lui 𝑥𝑖 şi
se adaugă la 𝐶𝑖 după care se avansează la componenta 𝑥𝑖+1 . Operaţia este notată
astfel:
… 𝑣𝑖−1 𝑥𝑖 𝑥𝑖+1 … … 𝑣𝑖−1 𝑣𝑖 𝑥𝑖+1 …
(… 𝐶 |𝐶 ∅ …) → (… 𝐶𝑖−1 𝐶𝑖 ∪ {𝑣𝑖 }| ∅ )
𝑖−1 𝑖 …
3) Revenire. Operaţia are loc atunci cînd toate valorile pentru 𝑥𝑖 au fost
consumate (𝐶𝑖 = 𝑆𝑖 ), deci este imposibilă alegerea unei valori noi. Se revine la
componenta 𝑥𝑖−1 încercînd atribuirea unei noi valori, neconsumate, pentru ea.
Pentru această nouă valoare a lui 𝑥𝑖−1 se vor încerca ulterior toate valorile posibile
pentru 𝑥𝑖 , deci are loc o reconsiderare a valorilor consumate pentru 𝑥𝑖 , 𝐶𝑖 devenind
mulţimea vidă. Operaţia este notată astfel:
… 𝑣𝑖−1 𝑥𝑖 𝑥𝑖+1 … … 𝑣𝑖−2 𝑥𝑖−1 𝑥𝑖 …
(… 𝐶𝑖−1 |𝐶𝑖 ∅ …) ← (… 𝐶𝑖−2 |𝐶𝑖−1 ∅ …)
inițializare 𝑆1 , 𝑆2 , … , 𝑆𝑛
𝐶𝑖 = ∅, 𝑖 = 1, 𝑛 //construire configurație inițială
𝑖=1
cît timp 𝑖 > 0 //cît timp configurația nu e finală
o dacă 𝑖 == 𝑛 + 1 //configurație de tip soluție?
reține soluția 𝑆𝑜𝑙 = (𝑥1 , 𝑥2 , … , 𝑥𝑛 )
𝑖 =𝑖−1 //revenire după găsirea unei soluții
o altfel
dacă 𝐶𝑖 ≠ 𝑆𝑖 //mai sînt valori neconsumate
alege o valoare 𝑣𝑖 ∈ 𝑆𝑖 − 𝐶𝑖
𝐶𝑖 = 𝐶𝑖 ∪ {𝑣𝑖 }
dacă (𝑣1 , 𝑣2 , … , 𝑣𝑖−1 , 𝑣𝑖 ) satisfac condițiile de continuare
o 𝑥𝑖 = 𝑣𝑖 //atribuie și avansează
o 𝑖 = 𝑖+1
altfel //revenire
𝐶𝑖 = ∅
𝑖 =𝑖−1
𝑖=1
𝑥𝑖 = 𝑎𝑖 − 𝑟𝑖 //primul element minus rația, de multe ori 0=1-1
cît timp 𝑖 > 0
o 𝑣𝑏 = 0 //variabila de impas
o cît timp 𝑥𝑖 < 𝑠𝑖 și 𝑣𝑏 == 0 //alegerea unei noi valori pentru 𝑥𝑖
𝑥𝑖 = 𝑥𝑖 + 𝑟𝑖 //următorul element din 𝑆𝑖
posibil(𝑥𝑖 ,vb) //sînt îndeplinite condițiile de continuare
o dacă 𝑣𝑏 == 0 //impas => revenire
𝑖 =𝑖−1
o altfel
dacă 𝑖 == 𝑛
dacă condiții_finale(x) //configurație soluție?
o reține_soluția 𝑆𝑜𝑙 = (𝑥1 , 𝑥2 , … , 𝑥𝑛 )
altfel //avans
𝑖 =𝑖+1
𝑥𝑖 = 𝑎𝑖 − 𝑟𝑖 //primul element din 𝑆𝑖 minus rația
backtracking(i)
{ dacă (i==n+1)
retine_solutia();
altfel
x[i]=init(i);
cît timp ( următor(i) )
dacă ( posibil(i) )
backtracking(i+1);
}
backtracking(i)
{ dacă (i==n+1)
retine_solutia();
altfel
pentru (j=a[i]; j<=s[i]; j+=r[i])
Algoritmi și tehnici de programare 21
{ x[i]=j;
dacă ( posibil(i) )
backtracking(i+1);
}
}
Pentru a evita calcularea acestei sume la fiecare pas, se poate păstra într-o
variabilă suma curentă plătită, care se ajustează de fiecare dată cînd se atribuie o
valoare nouă unui element al soluției. Inițial aceasta este zero.
La apelul inițial suma curentă are valoarea zero iar pasul curent este 1
(configurație inițială).
Algoritmi și tehnici de programare 23
if(r=='n')
{ printf("\n\nUrmatoarea (n) sau Ultima (l)?");
r=_getch();
}
}
if( i==n)
retine_solutia(++nr,n,x);
else
for(j=1; j<=n; j++ )
{ x[i]=j;
if( posibil(x,i) )
nr=permutari_r(n,i+1,x,nr);
}
return nr;
}
Editura ASE,
Bucureşti 2007
2 Metode de programare
1. Introducere_______________________________________________3
2. Grafuri 3
2.1. Definiţii şi reprezentări ale grafurilor 3
2.1.1 Moduri de reprezentare a grafurilor
2.1.2. Reprezentarea matriceală
2.1.3. Reprezentarea tabelară
2.1.4. Reprezentarea prin intermediul listelor
2.2. Modalităţi de parcurgere a grafurilor 7
1.2.1. Metoda de parcurgere BF (Breadth First)
1.2.2. Metoda de parcurgere DF (Depth First)
1.2.3. Parcurgerea în adîncime în varianta generalizată – DFG
2.3. Drumuri în grafuri. Conexitate 21
2.3.1 Drumuri; definiţii
2.3.2. Matricea existenţei drumurilor; algoritmul Roy-Warshall
2.3.3. Componente conexe ale unui graf
2.3.4. Drumuri de cost minim
2.4. Circuite şi cicluri în grafuri şi în digrafuri 31
3. Structuri arborescente 37
3.1. Grafuri de tip arbore 37
3.1.1. Definiţii şi caracterizări ale grafurilor arbori
3.1.2. Reprezentări şi parcurgeri ale arborilor orientaţi
3.1.3. Arbori parţiali. Algoritmul Kruskal
3.2. Arbori binari 49
3.2.1. Reprezentarea arborilor binari. Modalităţi de parcurgere
3.2.2. Arbori de sortare
3.2.3. Arbori de structură
Bibliografie _62
2
Algoritmi și tehnici de programare 3
1. Introducere
Grafurile sînt structuri de date cu aplicaţii în multe domenii ale informaticii, algoritmii
pentru reprezentarea şi prelucrarea grafurilor fiind consideraţi fundamentali în acest domeniu. În
subcapitolul 2.1 sînt prezentate principalele noţiuni ale domeniului, precum şi modalităţile uzuale
de reprezentare a structurii de graf. În continuare sînt descrise tehnicile de parcurgere a grafurilor
în lăţime şi în adîncime. Traversarea în adîncime a grafurilor determină obţinerea unei clasificări
a muchiilor, în funcţie de care pot fi derivate diferite proprietăţi ale grafurilor. Verificarea
conexităţii şi calculul drumurilor în grafuri sînt tratate în subcapitolul 2.3. În finalul capitolului
este studiată problema determinării circuitelor şi ciclurilor în grafuri şi digrafuri.
2. Grafuri
Definiţia 2.1.8. Fie G=(V,E) un graf. Elementul vV se numeşte vîrf izolat dacă,
Cea mai simplă reprezentare a unui graf este cea intuitivă, grafică; fiecare vîrf este
figurat printr-un punct, respectiv muchiile sînt reprezentate prin segmentele de dreaptă, orientate
(în cazul digrafurilor) sau nu şi etichetate (în cazul grafurilor ponderate) sau nu, avînd ca
extremităţi punctele corespunzătoare vîrfurilor care o determină
Exemple
2.1.1. Fie G=(V,E) graf, cu V={1,2,3,4,5,6}, E={(1,2),(1,3),(2,5),(3,5),(5,6)}. O posibilă
reprezentare grafică este,
2
4
6
5
3
2.1.2. Fie D=(V,E) digraf, V={1,…,5}, E={(1,2), (1,3), (1,5), (2,5), (3,5), (4,1), (5,4)}.
Digraful poate fi reprezentat grafic astfel,
1
4
2
3
5
2.1.3. Fie D=(V,E) graf direcţionat, V={1,2,3,4,5}, E={(1,2), (1,3), (1,5) (2,5), (3,5),
(4,4)}. Reprezentarea grafică este,
4
Algoritmi și tehnici de programare 5
4
2
3
5
2.1.4. Fie G=(V,E,W) graf ponderat, V={1,2,3,4}, E={(1,2), (1,3), (1,4), (2,3), (2,4)},
W((1,2))=5, W((1,3))=1, W((1,4))=7, W((2,3))=4, W((2,4))=2. O posibilă reprezentare grafică
este:
1
5 1
2 3
4
2
7
Exemplu
2.1.5. Graful din exemplul 2.1.1, digraful din exemplul 2.1.2 şi graful direcţionat din
exemplul 2.1.3 sînt reprezentate prin matricele de adiacenţă,
0
1 1 0 0 0
0 1 1 0 1
0 1
1 1 0
1 0 0 0 1 0
1 0 0 0 0 1 0 0 0 0 1
0
(2.1.1), A 0
0 0 0 1
A 0 0 0 1 (2.1.2), A 0 0 0 0 1 (2.1.3)
0 0 0 0 0 0
1 0 0 0 0 0 0 0 1 0
0 1 1 0 0 1
0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 1
Exemplu
2.1.6. Presupunînd că ponderile reprezintă costuri, matricea de reprezentare a grafului
5 1 7
5 4 2
din exemplul 2.1.4. este W .
1 4
7 2
Exemple
2.1.7. Graful din exemplul 2.1.1 poate fi reprezentat astfel, VS=(4),
1 2
1 3
A 2 5
3 5
5 6
1 2
1 3
1 5
2.1.8. Digraful din exemplul 2.1.2 este reprezentat prin A 2 5 .
3 5
4 1
5 4
6
Algoritmi și tehnici de programare 7
1 2
1 3
1 5
2.1.9. Graful direcţionat din 2.1.3. este reprezentat prin A .
2 5
3 5
4 4
2.1.10. Graful ponderat din exemplul 2.1.4. nu are vîrfuri izolate, deci este reprezentat
1 2 5
1 3 1
prin intermediul matricei A 2 3 4 .
1 4 7
2 4 2
orice vîrf al grafului conectat de vîrful iniţial şi vîrful iniţial este prezentat în cazul grafurilor
oarecare.
Parcurgerea DFG presupune vizitarea tuturor vîrfurilor unui graf sau graf direcţionat
prin aplicarea metodei DF tuturor vîrfurilor care, după ultima traversare DF, nu au fost încă
vizitate.
Exemple
2.2.1. Fie graful,
1
2 3
6
4
7
5
vîrf 1 2 3 4 5 6 7
d
0 0
1 0 1 1 1 1
2 0 1 1 1 2 2 1
0 1 1 1 2 2 1
8
Algoritmi și tehnici de programare 9
1 8
3
2
6
4 9 10
11
5 7
1 2 3 4 5 6 7 8 9 10 11
vîrf
d
0 0
1 0 1 1 1 1
2 0 1 1 2 1 2 1
0 1 1 2 1 2 1
Exemplu
2.2.3. Pentru graful din exemplul 2.2.1., aplicarea metodei de traversare BF
c
t 1 2 3 4 5 6 7
t=1 1 0 0 0 0 0 0
t=2 1 1 1 1 0 0 1
t=3 1 1 1 1 1 0 1
t=4 1 1 1 1 1 1 1
t=5 1 1 1 1 1 1 1
t=6 1 1 1 1 1 1 1
t=7 1 1 1 1 1 1 1
t=8 1 1 1 1 1 1 1
C
t
t=1 1
t=2 2 3 4 7
t=3 3 4 7 5
t=4 4 7 5 6
t=5 7 5 6
t=6 5 6
t=7 6
t=8
Observaţie Deoarece graful din exemplul 2.2.1. este conex, traversarea BF realizează
vizitarea tuturor vîrfurilor grafului. Aplicarea metodei BF grafului din exemplul 2.2.2. nu
determină vizitarea vîrfurilor 8,9, 10 şi 11, deoarece acestea sînt vîrfuri neconectate cu vîrful
iniţial . Cu alte cuvinte, metoda BF aplicată unui graf determină vizitarea tuturor vîrfurilor
care sînt conectate cu vîrful iniţial selectat.
typedef struct nn
{ int inf;
struct nn *leg;
} nod,* pnod;
10
Algoritmi și tehnici de programare 11
nou->inf=info;
nou->leg=NULL;
if(*head==NULL) *head=nou;
else (*tail)->leg=nou;
*tail=nou;
return 1;
}
else return 0;
}
void main()
{
int n,v0,a[10][10];
clrscr();
printf("Numarul de varfuri:");
scanf("%i",&n);
printf("\nMatricea de adiacenta\n");
for(int i=0;i<n;i++)
for(int j=0;j<i;j++){
scanf("%i",&v0);
a[j][i]=a[i][j]=v0;
}
for(i=0;i<n;i++)a[i][i]=0;
printf("\nVarful initial ");
scanf("%i",&v0);
printf("\nParcurgerea BF a grafului este");
breadth_first(v0,a,n);
}
12 Metode de programare
În continuare sînt prezentate o serie de rezultate prin care este demonstrată proprietatea
parcurgerii BF de a calcula distanţa minimă de la orice vîrf v conectat de vîrful iniţial v0 la v0.
Lema 2.2.1. Fie G=(V,E) un graf oarecare şi v0 V arbitrar. Atunci, pentru orice
muchie u ,v E , v0 ,v v0 ,u 1 .
Demonstraţie Dacă u este conectat de v0 în G, atunci, evident, şi v este conectat de v0 în
G. În acest caz, cel mai scurt drum de la v0 la v nu poate fi mai lung decît cel mai scurt drum de la
v0 la u prelungit cu muchia (u,v), deci afirmaţia este demonstrată. În situaţia în care u nu este
conectat de v0 în G, atunci, evident, rezultă inegalitatea v0 ,v v0 ,u 1 .
Lema 2.2.2 Fie G=(V,E) un graf neorientat sau graf direcţionat şi v0 V vîrf iniţial al
procedurii de traversare BF. Atunci orice v V vizitat, are loc inegalitatea d v v0 ,v .
Demonstraţie Afirmaţia este demonstrată prin inducţie după ordinea vizitării BF a
elementelor v V conectate cu v0 în G.
Dacă v v0 , rezultă d v 0 şi, pentru orice u V \ v, d u u ,v , deci
afirmaţia este adevărată.
Fie v vîrful vizitat ca rezultat al procesării vîrfului u. Prin aplicarea ipotezei inductive,
d u v0 ,u , a rezultatului lemei 2.2.1 şi a procedurii de parcurgere BF obţinem,
d v d u 1 v0 ,u 1 v0 ,v .
Deoarece vîrful v nu a fost anterior găsit în lista vecinilor nici unui nod studiat înaintea
vîrfului u, v este inserat în C.
Lema 2.2.3 Fie G=(V,E) un graf neorientat sau graf direcţionat şi C v1 ,v2 ,...,v p
coada calculată la un moment al aplicării procedurii de parcurgere BF. Atunci următoarele
inegalităţile sînt verificate, [Cor,Lei şa]
d v p d v1 1
d vi d vi 1 , i 1,..., p 1 .
12
Algoritmi și tehnici de programare 13
capitolul 9) Gp, numit subgraful predecesorilor definit de BF pe G, unde G p V p , E p şi
Exemplu
2
3 4 7
5 6
14 Metode de programare
Exemple
2.2.5. Pentru graful,
1
2 3
6
4
7
5
c
1 2 3 4 5 6 7
t
t=1 1 0 0 0 0 0 0
t=2 1 1 1 1 0 0 1
t=3 1 1 1 1 0 1 1
t=4 1 1 1 1 0 1 1
14
Algoritmi și tehnici de programare 15
t=5 1 1 1 1 1 1 1
t=6 1 1 1 1 1 1 1
t=7 1 1 1 1 1 1 1
t=8 1 1 1 1 1 1 1
t=1 1
t=2 7 4 3 2
t=3 6 4 3 2
t=4 4 3 2
t=5 5 3 2
t=6 3 2
t=7 2
t=8
2.2.6. Pentru graful din exemplul 2.2.2 vîrfurile 8,9,10 care nu sînt conectate cu vîrful
iniţial nu vor fi vizitate nici prin aplicarea metodei DF. Ordinea în care sînt vizitate vîrfurilor
corespunzător acestei variante este: 1, 2, 3, 4, 6, 7, 5.
O variantă de implementare a metodei DF rezultă prin gestionarea stivei S în modul
următor. Iniţial vîrful v0 este unicul component al lui S. La fiecare etapă se preia, fără
ştergere, ca vîrf curent vîrful stivei. Se introduce în stivă unul dintre vecinii vîrfului curent
încă nevizitat. Vizitarea unui vîrf revine la introducerea lui în S. Dacă vîrful curent nu are
vecini încă nevizitaţi, atunci el este eliminat din stivă şi este efectuat un nou acces de preluare
a noului vîrf al stivei ca vîrf curent. Calculul se încheie în momentul în care este efectuat un
acces de preluare a vîrfului stivei ca vîrf curent şi se constată că S este vidă. Evident, nici în
cazul acestei variante nu vor fi vizitate vîrfurile care nu sînt conectate cu vîrful iniţial ales.
16 Metode de programare
Exemplu
2.2.7. Pentru graful,
1
2 3
6
4
7
5
c 1 2 3 4 5 6 7
t=1 1 0 0 0 0 0 0
t=2 1 1 0 0 0 0 0
t=3 1 1 0 1 0 0 0
t=4 1 1 1 1 0 0 0
t=5 1 1 1 1 0 1 0
t=6 1 1 1 1 0 1 1
t=7 1 1 1 1 0 1 1
t=8 1 1 1 1 0 1 1
t=9 1 1 1 1 0 1 1
t=10 1 1 1 1 1 1 1
t=11 1 1 1 1 1 1 1
t=12 1 1 1 1 1 1 1
t=13 1 1 1 1 1 1 1
t=14 1 1 1 1 1 1 1
t=1 1
t=2 2 1
t=3 4 2 1
t=4 3 4 2 1
t=5 6 3 4 2 1
t=6 7 6 3 4 2 1
t=7 6 3 4 2 1
t=8 3 4 2 1
t=9 4 2 1
t=10 5 4 2 1
t=11 4 2 1
16
Algoritmi și tehnici de programare 17
t=12 2 1
t=13 1
t=14
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
typedef struct nn{
int inf;
struct nn *leg;
}nod,* pnod;
void main()
{
int n,v0,a[10][10];
clrscr();
18 Metode de programare
printf("Numarul de varfuri:");scanf("%i",&n);
printf("\nMatricea de adiacenta\n");
for(int i=0;i<n;i++)
for(int j=0;j<i;j++){
scanf("%i",&v0); a[j][i]=a[i][j]=v0;
}
for(i=0;i<n;i++)a[i][i]=0;
printf("\nVarful initial ");scanf("%i",&v0);
printf("\nParcurgerea DF a grafului este");
depth_first(v0,a,n);
}
void DFG(graf G)
{
for( u V ){
mark[u]=0;
p[u]=0;
}
t=0;
for( u V )
if(!mark[u])DF_Visit(u);
}
void DF_Visit(varf u)
{
mark[u]=1;
d[u]=t++;
for( v V :A[u][v]==1)
if(!mark[v]){
p[v]=u;
DF_Visit(v);
}
mark[u]=2;
f[u]=t++;
}
18
Algoritmi și tehnici de programare 19
Observaţie Fie G=(V,E) un graf sau un graf direcţionat. Pe baza procedurii DFG poate fi
realizată următoarea clasificare a elementelor e u ,v E ,
1) Muchii de tip arbore în DF- graful pădure G p , etichetate cu T: u ,v are eticheta T
dacă procesarea vîrfului v a fost decisă ca rezultat al testării existenţei muchiei e;
2) Muchii de tip înapoi, cu etichetă B: u ,v este muchie B dacă v este ancestorul lui u
într-o componentă conexă a DF- grafului pădure G p ;
3) Muchii de tip înainte, notate cu F: acele muchii u ,v , neetichetate cu T şi în care v
este descendent al lui u într-o componentă conexă a DF- grafului pădure G p ;
4) Muchii de tip trecere, etichetate cu C: toate muchiile u ,v rămase neetichetate după
încheierea etichetării cu T, B şi F.
Teorema 2.2.3.
Fie G=(V,E) un graf neorientat. Orice element e E este fie de tip T, fie de tip B.
[Cor,Lei şa]
Exemple
2.2.8. Pentru graful
1 8
3
2
6
4 9 10
5 7
obţinem,
1) ordinea de parcurgere DFG a vîrfurilor: 1,2,3,4,6,7,5,8,9,10
2) graful pădure G p ,
8
1
2 9
3
10
4
6 5
5 8 4 3
20
Algoritmi și tehnici de programare 21
1 2
4 3
7
6 8
Una dintre cele mai importante proprietăţi ale grafurilor o constituie posibilitatea de
accesare, prin intermediul unei secvenţe de muchii (arce), dintr-un vîrf dat a oricărui alt vîrf al
grafului, proprietate cunoscută sub numele de conexitate sau conexiune. Aşa după cum a rezultat
în §2.2., dacă G=(V,E) este un graf conex, atunci pentru orice vîrf iniţial v0 considerat metodele
BF şi DF permit vizitarea tuturor vîrfurilor din V.
Definiţia 2.3.1. Fie G=(V,E) un graf, u,vV. Secvenţa de vîrfuri : u0, u1,..,un este un u-v
drum dacă u0=u, un=v, uiui+1E pentru toţi i, 0 i n . Lungimea drumului, notată l() este
Definiţia 2.3.2. Fie : u0, u1,..,un un drum în graful G=(V,E). este un drum închis dacă
u0=un; în caz contrar, se numeşte drum deschis. Drumul este elementar dacă oricare două
vîrfuri din sînt distincte, cu excepţia, eventual, a extremităţilor. Drumul este proces dacă,
pentru orice 0 i j n 1 uiui+1 ujuj+1.
Evident, orice drum elementar este un proces.
22 Metode de programare
Exemplu
2.3.1. Pentru graful,
v2
v4
v5
v1 v3
1: v1, v2, v3, v2, v5, v3, v4 este un v1- v4 drum care nu este proces;
2: v1, v2, v5, v1, v3, v4 este un v1- v4 proces care nu este drum elementar;
3: v1, v3, v4 este un v1- v4 drum elementar.
Definiţia 2.3.3. Fie : u0, u1,..,un un drum în graful G=(V,E). ’: v0, v1,..,vm este un
subdrum al lui dacă ’ este un drum şi pentru orice j, 0 j m , există i, 0 i n astfel
încît ui=vj.
Observaţie Orice drum cu lungime cel puţin 1 conţine cel puţin un drum elementar cu
aceleaşi extremităţi.
Într-adevăr, dacă : u0, u1,..,un nu este elementar, atunci există 0 i j n şi i 0 sau
j n astfel încît ui=uj. Atunci drumul
u j u j 1 ...u n , dacă i 0
: u0 u1 ...u i , dacă j 0
'
Exemplu
2.3.2. În graful,
v2 v6 v7
v1 v4 v5 v8 v10
v3 v9
dacă : v1, v2, v4, v5, v3, v1, v2, v5, v6, v7, v8, v9, v5, v9, v8, v10, atunci 1: v1, v2, v5, v9, v8, v10,
2: v1, v2, v4, v5, v9, v8, v10 sînt v1-v10 subdrumuri elementare.
22
Algoritmi și tehnici de programare 23
Lema 2.3.1. Fie G=(V,E) un graf, V n . Dacă A este matricea de adiacenţă asociată
grafului, atunci, pentru orice p1, a ij( p ) este numărul vi-vj drumurilor distincte de lungime p din
graful G, unde A p aij( p ) .
Demonstraţie
Demonstrarea acestei afirmaţii este realizată prin inducţie după p
Pentru p=1, deoarece pentru orice 1 i , j n există cel mult un vi-vj drum de lungime 1
şi dacă există, fie acesta Г: vi, vj. Rezultă că numărul vi-vj drumurilor de lungime 1 este egal cu
aij1 .
Presupunem că Ap-1 = aij p 1 are proprietatea că pentru toţi 1 i , j n , aij p 1 este
egal cu numărul vi-vj drumurilor de lungime p-1 în G.
p
Cum Ap=Ap-1A = aij p , rezultă că, 1 i , j n , a ij( p ) a
k 1
( p 1 )
ik a kj . Orice vi-vj drum
prin:
1 k ( k 1 )
A A, A A A
, k 2 .
Dacă A este matricea de adiacenţă a unui graf G=(V,E), atunci pentru fiecare k,
(k ) 1, dacă există drum de la i la j de lungime k
1 k n 1 , a ij
0 , altfel
(1) (2) ( n 1 )
Matricea M A A A se numeşte matricea existenţei drumurilor în
graful G. Semnificaţia componentelor matricei M este:
0 , dacă nu există vi v j drum în G
1 i , j n , mij
1, altfel
24 Metode de programare
Exemplu
2.3.3. Pentru graful,
2
4
0 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
1 0 0 0 2 0 1 1 1 3 1 0 1 1 1 1 1 1
A , A , A , M
1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 1 1 1 1 1 1
0 1 1 1 1 1 1
Observaţie Calculul matricei existenţei drumurilor permite verificarea dacă un graf dat
este conex. Graful este conex dacă şi numai dacă toate componentele matricei M sînt egale cu 1.
Algoritmul Roy-Warshall calculează matricea existenţei drumurilor într-un graf G cu n
vîrfuri.
void Roy_Warshall (unsigned char a[10][10],unsigned n,unsigned char m[10][10])
{int i,j,k;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
m[i][j]=a[i][j];
for (j=0;j<n;j++)
for (i=0;i<n;i++)
if(m[i][j])
for (k=0;k<n;k++)
if (m[i][k]<m[k][j]) m[i][k]=m[k][j];}
Datele de intrare sînt: n, numărul de noduri şi A, matricea de adiacenţă corespunzătoare
grafului. Matricea M calculată de algoritm constituie ieşirea şi este matricea existenţei drumurilor
în graful G.
Definiţia 2.3.5. Fie G=(V,E) graf netrivial. Vîrfurile u,v V sînt conectate dacă există un
u-v drum în G.
Definiţia 2.3.6. Dacă G este un graf, atunci o componentă conexă a lui G este un subgraf
conex al lui G, maximal în raport cu proprietatea de conexitate.
24
Algoritmi și tehnici de programare 25
Exemplu
2.3.4. Componentele conexe ale grafului
1
5
2
6
4
3
Observaţii
1) Un graf este conex dacă şi numai dacă numărul componentelor sale conexe este
1.
2) Mulţimile de vîrfuri corespunzătoare oricăror două componente conexe distincte
sînt disjuncte. Rezultă că mulţimile de vîrfuri corespunzătoare componentelor conexe ale
unui graf formează o partiţie a mulţimii vîrfurilor grafului.
Exemplu
2.3.5. Pentru graful,
1 7 3
2
4 5 8 9 6
Definiţia 2.3.7. Fie G=(V,E,w) un graf ponderat. Costul drumului : u1,u2,..,un, notat
L(), este definit prin:
n 1
L wu i ,u i 1 .
i 1
Pentru orice u şi v vîrfuri conectate în G, u v, w-distanţa între u şi v, notată D(u,v), este
definită prin,
Du ,v minL , Duv , unde Duv desemnează mulţimea tuturor u-v drumurilor
elementare din G. Dacă Duv este astfel încît D(u,v)=L(), drumul se numeşte drum de cost
minim.
Algoritmul Dijkstra
Următorul algoritm a fost propus de către E. W. Dijkstra pentru determinarea w-
distanţelor D(u0,v) şi a cîte unui u0-v drum de cost minim pentru fiecare vîrf vu0 într-un graf
ponderat, unde u0 este prestabilit.
Fie G=(V,E,w) un graf conex ponderat, u0V, SV, u0S. Se notează S V \ S şi
D u0 , S min Du0 , x ; x S . Fie v S astfel încît D(u0,v)=D(u0, S ), : u0, u1,…,upv un u0-
v drum de cost minim. Evident, 0ip uiS şi ’: u0, u1,…,up un u0- up drum de cost minim.
De asemenea,
D u0 , S min Du0 ,u w( uv ); u S ,v S ,uv E .
Dacă xS, y S astfel încît D u0 , S Du0 , x w( xy ) , rezultă
Du0 , y Du0 , x w( xy ) .
Pentru determinarea a cîte unui cel mai ieftin u0-v drum, algoritmul consideră o etichetare
dinamică a vîrfurilor grafului.Eticheta vîrfului v este (L(v),u), unde L(v) este lungimea unui cel
mai ieftin u0-v drum determinat pînă la momentul respectiv şi u este predecesorul lui v pe un
astfel de drum.
Pentru (V,E,w) graf conex ponderat, V n şi u0V, calculul implicat de algoritmul
Dijkstra poate fi descris astfel:
Pas 1: i=0; S0={u0}; L(u0)=0, L(v)= pentru toţi v V, v≠u0. Dacă n=1 atunci stop
Pas 2: Pentru toţi v S i , dacă L(v)>L(ui)+w(uiv), atunci L(v)=L(ui)+w(uiv) şi etiche-
tează v cu (L(v),ui).
Pas 3: Se determină d=min{L(v), v S i } şi se alege ui+1 S i astfel încît L(ui+1)=d.
Pas 4: Si+1=Si {ui+1}
Pas 5: i=i+1. Dacă i=n-1, atunci stop. Altfel, reia Pas 2.
Observaţie Dacă (V,E,w) graf ponderat neconex, atunci, pentru u0V, algoritmul lui
Dijkstra permite determinarea w-distanţelor D(u0,v) şi a cîte unui u0-v drum de cost minim pentru
toate vîrfurile v din componenta conexă căreia îi aparţine u0.
26
Algoritmi și tehnici de programare 27
Exemplu
2.3.6. Fie graful ponderat,
1
5 1
2 9
3
16
2
5 5
4
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
typedef struct{
int predv;
float L;
} eticheta;
28
Algoritmi și tehnici de programare 29
modifica(s,sb,ui,&ns,&nb);
}
return r;
}
void main()
{
int n,i,j;
clrscr();
printf("Numarul de varfuri");
scanf("%i",&n);
printf("Matricea ponderilor:\n");
float w[50][50];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%f",&w[i][j]);
int u0;
printf("\nVarful initial:");
scanf("%i",&u0);
u0--;
eticheta *rez=Dijkstra(w,n,u0);
for(i=0;i<n;i++){
printf("Distanta de la vf. %i la vf. %i este %7.2f\n",u0+1,i+1,rez[i].L);
printf("Un drum de cost minim este:");
printf("%i, ",i+1);
j=rez[i].predv;
while(j-u0){
printf("%i, ", j+1);
j=rez[j].predv;
}
printf("%i\n\n",u0+1);
}
free(rez);
getch();
}
În anumite aplicaţii este necesară exclusiv determinarea w-distanţelor D(v0,v), pentru toţi
vV. În acest caz algoritmul Roy-Floyd permite o rezolvare a acestei probleme mai simplu de
implementat decît algoritmul Dijkstra.
Algoritmul Roy-Floyd
Pentru (V,E,w) graf ponderat, V n şi W matricea ponderilor, sistemul de w-distanţe
D(v0,v), vV, poate fi calculat pe baza următoarei funcţii (similară algoritmului Roy-Warshall),
Algoritmul Yen
Algoritmul propus de Yen pentru calculul tuturor w-distanţelor într-un graf ponderat este
mai eficient din punctul de vedere al volumului de operaţii decît algoritmul Roy-Floyd. Fie
(V,E,w) un graf ponderat şi W matricea ponderilor. Pentru determinarea w-distanţelor de la vîrful
vk fixat la celelalte vîrfuri ale grafului, algoritmul Yen iniţiază următoarele operaţii,
Pas 1: D=W
Pas 2: i=1; λ(k)=0, b(k)=0; λ(j)=0, pentru toţi 1 j n , j k
Pas 3: Calculează min{dkj; 1 j n , λ(j)=1};
Determină j0 astfel încît λ(j0)=1 şi d kj0 = min{dkj; 1 j n , λ(j)=1}
B(j0)= d kj0 , λ(j0)=0
d[k,j] =min{d[k,j],d[k,j0]+d[j0,j]}, pentru toţi j, 1 j n
i=i+1
Pas 4: Dacă i<n, reia Pas 3, altfel stop.
Exemplu
2.3.7. Fie graful
1
4
3
5 7
2
2
1
5
4 3
4
30
Algoritmi și tehnici de programare 31
Se consideră vk=1.
3 2 7 4
3 5
Pas 1: D 2 5 4 1
7 4
4
1
Exemple
2.4.1. În graful,
v1
v4
v2
v3
v5 v6
1: v1, v2, v3, v6, v5 este un proces;
2: v1, v2, v3, v6, v5, v3, v4, v1 este un circuit şi nu este ciclu;
3: v1, v3, v5, v4, v1 este un ciclu.
v3 v4
2.4.3. Digraful,
V1 V2
V3 V4
nu conţine cicluri.
Definiţia 2.4.5. Fie D=(V,E) un digraf. Funcţiile grad exterior, odD, respectiv grad
interior, idD, sînt definite prin, od D : V N ; id D : V N ,
u V , od D u v / v V , uv E , u V , id D u v / v V , vu E
Funcţia grad, notată degD, este definită astfel,
deg D : V N, u V, deg D u id D u od D u .
Algoritmul Marimont
Procedura Marimont verifică dacă un digraf D=(V,E), V n , este sau nu aciclic. La
terminarea calculului este afişat mesajul “DA”, dacă digraful D este aciclic, respectiv “NU”, în
caz contrar. Descrierea pe paşi a algoritmului Marimont este,
Pas 1: V0=V, E0=E, D0=(V0,E0)
Pas 2: Dacă od D0 v 1 pentru toţi vV0, scrie “NU”, stop (dacă toate vîrfurile sînt
extremităţi iniţiale ale măcar unui arc, atunci există cicluri în D0); altfel, continuă.
Pas 3: Selectează vV0 cu od D0 v 0 ;V0=V0\{v}; E0=E0-{e/ eE0, e incidentă cu v în
D0}; D0=(V0,E0)
Pas 4: Dacă V0Ø, atunci reia pasul 2; altfel scrie “DA”, stop.
Exemple
2.4.4 Pentru digraful,
32
Algoritmi și tehnici de programare 33
1
e1 e2
2
4 e3
e4
3 e5
5
evoluţia algoritmului Marimont este,
Pas 1: V0={1,2,3,4,5}, E0={e1,e2,e3,e4,e5}
Pas 2: od D0 5 0 , continuă
1
e1 e2
2
4 e3
e4
3
Pas 3: Selectează vîrful 5, elimină 5 din V0, elimină arcul e5 E0
Pas 4: reia de la pasul 2
Pas 2: od D0 i 1 pentru toţi i din V0 ={1,2,3,4}, scrie “NU”, stop.
2.4.5. Pentru digraful D:
1
6
e7 e4 e1
5 4 e5
e9 e6 2
e8 e3 e2
7 3
algoritmul Marimont determină următoarea secvenţă de operaţii:
Pas 1: V0={1,2,3,4,5,6,7}, E0={e1,e2,e3,e4,e5,e6,e7,e8,e9}
Pas 2: od D0 7 0 , continuă
Pas 3: Selectează vîrful 7, elimină 7 din V0, elimină arcele e8 şi e9 din E0
D0:
1
6
e7 e4 e1
5 4 e5
e6 2
e3 e2
3
Pas 4: reia de la pasul 2
D0: • 1
Pas 4: reia de la pasul 2
Pas 2: od D0 1 0 , continuă
Pas 3: Selectează vîrful 1, elimină 1 din V0
V0=Ø
Pas 4: scrie “DA”, stop.
Algoritmul Marimont poate fi descris în C astfel,
#include<stdio.h>
#include<conio.h>
typedef struct{
int vi,vf;} arc;
int grad_exterior(arc *arce,int na,int v)
{
int od=0;
for(int i=0;i<na;i++)
34
Algoritmi și tehnici de programare 35
if(arce[i].vi==v) od++;
return od;
}
void main()
{
int n,nv, na;
int vf[20],i,j,a[20][20];
arc arce[100];
clrscr();
36 Metode de programare
printf("Numarul de varfuri");
scanf("%i",&n);
for(i=0;i<n;i++)
vf[i]=i+1;
nv=n;na=0;
printf("Matricea de adiacenta:\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++){
scanf("%i",&a[i][j]);
if(a[i][j]){
arce[na].vi=i+1;
arce[na].vf=j+1;
na++;
}
}
if(Marimont(vf,arce,nv,na))
printf("\n\nDigraful este aciclic");
else printf("\n\nDigraful este ciclic");
getch();
}
36
Algoritmi și tehnici de programare 37
3. Structuri arborescente
Una dintre cele mai studiate clase de grafuri sînt cele de tip arbore. În acest capitol sînt
prezentate principalele caracteristici ale arborilor, algoritmi pentru calculul arborelui parţial de
cost minim, arbori direcţionaţi, arbori cu rădăcină şi arbori binari. Pe lîngă operaţiile primitive
asupra arborilor – căutarea unei informaţii, inserarea unui nod, extragerea unui nod şi metode de
parcurgere, sînt prezentate două clase importante de arbori binari: arbori de sortare şi arbori de
structură.
Structurile cele mai simple şi care apar cel mai frecvent în aplicaţii sînt cele arborescente
(arbori). Grafurile arbori constituie o subclasă a grafurilor conexe.
Definiţia 3.1.1 Graful G este arbore dacă G este aciclic şi conex.
Definiţia 3.1.2. Fie G=(V,E) graf arbore. Subgraful H=(V1,E1) al lui G este subarbore al
lui G dacă H este graf arbore.
Exemple
3.1.1. Graful
1
2
3 4
5 6
7
este arbore, deoarece, orice (i,j) E , i≠j, există un i-j drum şi graful nu conţine cicluri.
38 Metode de programare
3.1.2. Graful
1 3
4 2 7
5
7
nu este arbore, deoarece drumul :1,4,6,2,1 este un ciclu.
3.1.3. Graful
1 3 7
4 2
5
9
6
8
nu este arbore, deoarece conţine trei componente conexe: {1,2,3,4,6}, {3} şi {7,8}.
Verificarea proprietăţii unui graf de a fi arbore poate fi realizată prin intermediul unor
algoritmi care să verifice calităţile de conexitate şi respectiv aciclicitate. De asemenea, verificarea
proprietăţii unui graf de a fi arbore poate fi realizată astfel.
Proprietatea 1. Un graf G=(V,E), cu V n , E m este graf arbore dacă şi numai dacă
G este aciclic şi n=m+1.
Exemple
3.1.4. Graful din 3.1.1 este arbore, pentru că este aciclic şi n=7, m=6.
3.1.5. Graful din 3.1.2. nu este arbore pentru că este ciclic.
3.1.6. Graful din exemplul 3.1.3. nu este arbore deoarece este aciclic, dar n=9, m=6.
Proprietatea 2 Un graf G=(V,E), cu V n , E m este graf arbore dacă şi numai dacă
G este conex şi n=m+1.
Exemple
3.1.7. Graful din 3.1.1. este arbore deoarece este conex şi n=m+1.
3.1.8. Graful conex din exemplul 3.1.2. nu este arbore pentru că n=6 şi m=8.
3.1.9. Graful din 3.1.3. nu este conex, deci nu este graf arbore.
Observaţie
Fie G=(V,E) un graf. Următoarele afirmaţii sînt echivalente,
1. G este graf arbore;
2. G este graf conex minimal: oricare ar fi eE, prin eliminarea muchiei e din E, graful
rezultat nu este conex;
3. G este graf aciclic maximal: prin adăugarea unei noi muchii în graf rezultă cel puţin
un ciclu.
38
Algoritmi și tehnici de programare 39
Observaţie Graful suport al unui arbore direcţionat este aciclic, deci, pentru orice uV,
u r, r-u drumul din T este unic. De asemenea, un arbore direcţionat are cel mult o rădăcină.
Rezultă că, pentru orice uV, u r, distanţa de la rădăcină la vîrful u este egală cu numărul de
muchii ale r-u drumului în T.
Exemple
3.1.10. Arborele direcţionat
1
3 4
6
5
2
7 8 9 10
este arbore cu rădăcină 1.
3 7
5 6
nu are rădăcină.
3.1.12. Arborele
40 Metode de programare
1
4
6
5
2
8 10
este un subarbore cu rădăcină 1 al arborelui din 3.1.10.
situat pe nivelul i al arborelui T, dacă distanţa de la vîrf la rădăcină este egală cu i. Rădăcina
Deoarece orice arbore orientat este în particular digraf, reprezentarea arborilor orientaţi
poate fi realizată prin utilizarea oricăreia dintre modalităţile prezentate în §8.1. Datorită
caracteristicilor arborilor orientaţi pot fi însă obţinute reprezentări mai eficiente din punct de
vedere al spaţiului de memorie solicitat.
Una dintre modalităţi este reprezentarea de tip FIU-FRATE, care constă în numerotarea
convenţională a vîrfurilor grafului şi memorarea, pentru fiecare vîrf i al arborelui, a următoarelor
informaţii,
- FIU(i): numărul ataşat primului descendent al vîrfului i;
- FRATE(i): numărul ataşat vîrfului descendent al tatălui vîrfului i şi care urmează
imediat lui i;
- INF(i): informaţia ataşată vîrfului i (de obicei valoarea i).
Pentru reprezentarea arborelui sînt reţinute rădăcina şi numărul nodurilor. Absenţa
„fiului”, respectiv a :fratelui” unui vîrf este marcată printr-o valoare din afara mulţimii de numere
ataşate vîrfurilor (de obicei valoarea 0).
Exemplu
3.1.13. Arborele orientat
40
Algoritmi și tehnici de programare 41
2 3 4
5 6 7 8
9 10 11 12 13 14 15 16
vîrf
adresă fiu 1 … adresă fiu n
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
void A_preordine(arbore r)
{
if(r){
printf("%i ",r->inf);
for(int i=0;i<4;i++)
A_preordine(r->fiu[i]);
}
}
void main(){
clrscr();
int n,j,info;
arbore radacina=NULL;
printf("Introduceti informatiile pe niveluri\n");
printf("Introduceti radacina\n");
scanf("%i",&info);
radacina=(arbore)malloc(sizeof(arb));
radacina->inf=info;
for(int i=0;i<4;i++)radacina->fiu[i]=NULL;
printf("Numarul de fii ai nodului %i",radacina->inf);
scanf("%i",&j);
for(int k=0;k<j;k++){
scanf("%i",&info);
inserare_tata(&radacina,k,info);
}
arbore ppred=radacina;
inserare(&ppred);
printf("Parcurgerea A-preordine a arborelui : \n");
A_preordine(radacina);
getch();}
Parcurgerea în A-preordine
Modalitatea de vizitare a vîrfurilor în parcurgerea în A-preordine poate fi descrisă
astfel. Iniţial, rădăcina arborelui este selectată drept vîrf curent. Este vizitat vîrful curent şi
sînt identificaţi descendenţii lui. Se aplică aceeaşi regulă de vizitare pentru arborii avînd ca
rădăcini descendenţii vîrfului curent, arborii fiind vizitaţi în ordinea precizată prin numerele
ataşate vîrfurilor rădăcină corespunzătoare.
42
Algoritmi și tehnici de programare 43
Exemplu
3.1.14. Pentru arborele orientat din exemplul 3.1.13., prin aplicarea parcurgerii în A-
preordine, rezultă: 1,2,5,6,9,10,11,12,13,7,3,4,8,14,15,16.
Parcurgerea A-postordine
Regula de parcurgerea în A-postordine este asemănătoare traversării A-preordine,
singura diferenţă fiind aceea că, în acest tip de traversare, rădăcina fiecărui arbore este
vizitată după ce au fost vizitate toate celelalte vîrfuri ale arborelui.
Exemplu
3.1.15. Pentru arborele orientat din exemplul 3.1.13. ordinea de vizitare a vîrfurilor
este: 5,9,10,11,12,13,6,7,2,3,14,15,16,8,4,1.
Pentru arbori reprezentaţi prin structuri dinamice de date, implementarea parcurgerii
în A-postordine poate fi obţinută pe baza următoarei funcţii recursive. Parametrul de intrare
al funcţiei A_postordine reprezintă rădăcina arborelui curent în momentul apelului.
Exemplu
3.1.16. Pentru arborele definit în exemplul 3.1.13., prin aplicarea parcurgerii pe
niveluri, rezultă următoarea ordine de vizitare a nodurilor, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16.
Atîta timp cît timp coada este nevidă, este preluat cu ştergere un vîrf din C, este vizitat şi sînt
introduşi în coadă descendenţii săi. Calculul este încheiat cînd C=Ø.
În cazul reprezentării FIU-FRATE a arborelui de traversat, parcurgerea pe niveluri
poate fi implementată prin următoarea funcţie.
Exemplu
3.1.17. Pentru arborele de la exemplul 3.1.13., evoluţia algoritmului este,
t=1 1 8
t=2 2 3 4
t=3 3 4 5 6 7
t=4 4 5 6 7
t=5 5 6 7 8
t=6 6 7 8
t=7 7 8 9 1 1 1 1
0 1 2 3
t=8 8 9 1 1 1 1
0 1 2 3
44
Algoritmi și tehnici de programare 45
t=9 9 1 1 1 1 1 1 1
0 1 2 3 4 5 6
t=10 1 1 1 1 1 1 1
0 1 2 3 4 5 6
t=11 1 1 1 1 1 1
1 2 3 4 5 6
t=12 1 1 1 1 1
2 3 4 5 6
t=13 1 1 1 1
3 4 5 6
t=14 1 1 1
4 5 6
t=15 1 1
5 6
t=16 1
t=17
void frati(v)
{if (v){push(C,v);
fraţi(FRATE[v]);
}
}
void parc()
{if (C){pop(C,v);VIZIT(v);
frati(FIU[v]); parc();
}
}
46 Metode de programare
Definiţia 3.1.10. Fie G un graf. Subgraful parţial H este un arbore parţial al lui G
dacă H este graf arbore.
Definiţia 3.1.11. Fie G=(V,E,w) un graf ponderat conex.Dacă T=(V,E0) este un arbore
parţial al grafului G’=(V,E), ponderea arborelui T, notată W(T), este definită prin
W(T)=
eE0
w( e ) .
Exemplu
3.1.18. Pentru graful ponderat
1
4 3
2
2 6 8 5
2 9
1 12
4 3
4 2 3
2 6 5
8 9
4 3
Definiţia 3.1.12. Arborele parţial T0T(G) este arbore parţial minim pentru G dacă
W(T0)=min{W(T); TT(G)}, unde T(G) este mulţimea arborilor parţiali corespunzători
grafului G.
Observaţie Dacă G este graf finit, atunci T(G) este o mulţime finită, deci orice graf
finit ponderat şi conex are cel puţin un arbore parţial minim.
În continuare este prezentat algoritmul Kruskal pentru determinarea unui arbore
parţial minim al unui graf ponderat conex G=(V,E,w).
Pas 1: i=1; E0=
Pas 2: Determină R={e/eE \ Ei-1 astfel încît graful (V,Ei-1 {e}) este aciclic}
Dacă R=, atunci stop; altfel, selectează eiR cu w(ei)=min{w(e), eR}; Ei=Ei-
1 {e i}
46
Algoritmi și tehnici de programare 47
#include<stdio.h>
#include<conio.h>
int radacina(int v,int *tata)
{ int u=v;
while(tata[u]>=0) u=tata[u];
return u; }
void main()
{
clrscr();
48 Metode de programare
este:
i, j după cea de-a t-a iteraţie muchia selectată TATA Costul
t=0 (-1,-1,-1,-1,-1,-1)
t=5,i=4,j=4 (-3,-3,2,2,1,1)
12
48
Algoritmi și tehnici de programare 49
Exemplu
3.2.1. Pentru arborele binar,
1
2 3
4 5 6 7
8 9 10
subarborii rădăcinii sînt:
2 3
6 7
4 5
8 9 10
Subarbore stîng Subarbore drept
În plus faţă de metodele A-preordine, A-postordine şi pe niveluri, parcurgerile în
preordine (RSD), inordine (SRD) şi respectiv postordine (SDR) sînt special considerate pentru
arbori binari şi au multiple aplicaţii. Regula de vizitare pentru aceste tipuri de parcurgere revine la
parcurgerea subarborelui stîng şi parcurgerea subarborelui drept corespunzători vîrfului curent.
La momentul iniţial vîrful curent este rădăcina arborelui. Diferenţa dintre cele trei tipuri de
parcurgere este dată de momentul în care devine vizitat fiecare vîrf al arborelui. În parcurgerea
RSD (rădăcină-subarbore stîng-subarbore drept), fiecare vîrf al arborelui este vizitat în momentul
în care este vîrf curent; în parcurgerea SRD, vizitarea vîrfului curent R este efectuată după ce a
fost parcurs subarborele stîng al lui R, respectiv în parcurgerea SDR vizitarea fiecărui vîrf este
efectuată după ce au fost parcurşi subarborii aferenţi lui.
50 Metode de programare
Exemplu
3.2.2. Pentru arborele de la exemplul 3.2.1., secvenţele de vîrfuri rezultate prin
aplicarea parcurgerilor RSD, SRD, SDR sînt:
- preordine: 1,2,4,8,5,3,6,9,10,7
- inordine: 4,8,2,5,1,9,6,10,3,7
- postordine: 8,4,5,2,9,10,6,7,3,1.
30 70
10 40 90
20 80
50
Algoritmi și tehnici de programare 51
Exemplu
3.2.4. Aplicarea algoritmul descris pentru inserarea informaţiei 55 în arborele de sortare
din exemplul 3.2.3. determină următoarele operaţii,
INF(v)=50; 50<55, inserează în subarborele cu rădăcina avînd informaţia ataşată 70.
INF(v)=70; 70>55, inserează în subarborele stîng cu rădăcina NULL.
Este creat nodul cu informaţie 55, fiu stîng al nodului de informaţie 70.
Arborele rezultat este
50
30 70
10 40 55 90
20 80
Exemplu
3.2.5. Ştergerea informaţiei 70 din arborele de sortare din exemplul 3.2.4. este realizată
astfel:
70>50, decide ştergerea din subarborele drept
70=70, decide ştergerea din arborele curent: rădăcina etichetată cu 70; există subarbore
stîng iar acesta nu are subarbore drept- nodul cu informaţie 70 este etichetat cu 55, iar p este
înlocuit cu subarborele său stîng (vid). Arborele rezultat
52 Metode de programare
50
30 55
10 40 90
20 80
este arbore de sortare.
Observaţie
Punctul c) de la pasul 2 al algoritmului de eliminare a unei informaţii dintr-un arbore de
sortare poate fi înlocuit cu:
c) dacă INF(v)=nr atunci:
c1) dacă subarborele drept este vid, atunci adresa vîrfului v este memorată într-o celulă
suplimentară aux, v devine fiul stînga al lui v, iar celula aux este eliberată din memorie;
c2) dacă subarborele drept este nevid atunci se determină cel mai mic element din
subarborele drept, altfel
c2.1.) dacă fiul dreapta al lui v nu are subarbore stîng, atunci informaţia ataşată fiului
dreapta este transferată în vîrful curent, iar fiul dreapta este înlocuit cu fiul său
dreapta şi este eliberată memoria corespunzătoare celulei v->fiud.
c2.2) altfel, se transferă în rădăcină informaţia ataşată ultimului nod p determinat la
c2), nodul p este înlocuit cu fiul său dreapta şi celula corespunzătoare lui p este
eliberată din memorie.
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
52
Algoritmi și tehnici de programare 53
if(*radacina==NULL) return 0;
else if((*radacina)->inf>info)
return extragere(&((*radacina)->l),info);
else if((*radacina)->inf<info)
return extragere(&((*radacina)->r),info);
else{
if((*radacina)->l==NULL){
arbore aux=*radacina;
*radacina=(*radacina)->r;
free(aux);
}
else{
arbore p,p1;
for(p=(*radacina)->l;p->r;p1=p,p=p->r);
if(((*radacina)->l)->r==NULL){
(*radacina)->inf=p->inf;
(*radacina)->l=p->l;
free(p);
}
else{
(*radacina)->inf=p->inf;
arbore aux=p;
p1->r=p->l;
free(aux);
}
}
return 1;
}
}
void main()
{
clrscr();
int n,info;
arbore radacina=NULL;
printf("Numarul de noduri:");
scanf("%i",&n);
printf("Introduceti informatiile\n");
for(int i=0;i<n;i++){
scanf("%i",&info);
inserare(&radacina,info);
}
printf("Parcurgerea SRD a arborelui de sortare: \n");
srd(radacina);
printf("\nInformatia nodului de extras:");
scanf("%i",&info);
if(extragere(&radacina,info)){
printf("\nArborele rezultat in parcurgere SRD\n");
srd(radacina);
}
else printf("\nInformatia nu este in arbore");
getch();
}
54 Metode de programare
Expresiile aritmetice în care intervin numai operatori binari pot fi reprezentate prin
intermediul arborilor binari în care fiecare nod neterminal are doi fii.
Definiţia 3.2.5. Un arbore de structură are vîrfurile etichetate astfel:
- fiecare nod neterminal este etichetat cu un simbol corespunzător unuia dintre operatori;
- fiecare nod terminal este etichetat cu un operand.
Construcţia arborelui de structură corespunzător unei expresii aritmetice date se
realizează pe baza parantezării existente în expresie şi a priorităţilor convenţional asociate
operatorilor (ordinea operaţiilor) astfel încît rădăcina fiecărui subarbore este etichetată cu
operatorul care se execută ultimul în evaluarea subexpresiei corespunzătoare acelui subarbore.
Exemplu
3.2.6. Pentru expresia matematică (a+b)*(c-d)+e/g, arborele de structură corespunzător
este
+
* /
+ - e g
a b c d
54
Algoritmi și tehnici de programare 55
+
* în construcţie
+ +
în construcţie * în construcţie
*
+ în construcţie + în construcţie
+ +
* în construcţie * în construcţie
+ în construcţie + -
a b a b în construcţie în construcţie
+ +
* în construcţie * în construcţie
+ - + -
a b c în construcţie a b c d
* /
+ - în construcţie în construcţie
a b c d
* /
+ - e în construcţie
a b c d
56
Algoritmi și tehnici de programare 57
* /
+ - e g
a b c d
Definiţia 3.2.6. Se numeşte forma poloneză directă a unei expresii, expresia rezultată în
urma parcurgerii RSD a arborelui de structură. Se numeşte forma poloneză inversă a unei
expresii, expresia rezultată în urma parcurgerii SDR a arborelui de structură.
Exemplu
3.2.8. Pentru expresia considerată la exemplul 3.2.7., forma poloneză directă este +*+ab-
cd/eg. Forma poloneză inversă a expresiei date este ab+cd-*eg/+.
Observaţie Parcurgerea arborelui în inordine determină secvenţa de simboluri rezultată
prin eliminarea parantezelor din expresia dată. Restaurarea unei forme parantezate poate fi
realizată printr-o parcurgere SRD şi anume în modul următor. La momentul iniţial vîrful curent
este rădăcina arborelui de structură. Dacă vîrful curent v nu este vîrf terminal, atunci se generează
(s1) eticheta(v)(s2), unde eticheta(v) este operatorul etichetă a vîrfului, s1 este secvenţa rezultată
prin traversarea SRD a subarborelui stîng, s2 este secvenţa rezultată prin traversarea SRD a
subarborelui drept. Dacă v este vîrf terminal atunci este generată secvenţa eticheta(v).
Exemplu 3.2.9. Prin aplicarea metodei de evaluare descrise pentru a=3, b=2, c=5, d=2,
e=6 şi g=2, obţinem:
58 Metode de programare
18
15 3
5 3 6 2
3 2 5 2
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
#include<values.h>
#include<string.h>
#include<math.h>
58
Algoritmi și tehnici de programare 59
cr_arb_str(&((*rad)->l),p,poz-1,s,pri);
cr_arb_str(&((*rad)->r),poz+1,u,s,pri);
}
}
void forma_poloneza(arbore rad)
{
if(rad){
printf("%c",rad->inf);
forma_poloneza(rad->l);
forma_poloneza(rad->r);
}
}
void main()
{
clrscr();
char s[100];
int p[100];
arbore radacina=NULL;
printf("Expresia:");
scanf("%s",&s);
prioritati(s,p);
int n=strlen(s);
cr_arb_str(&radacina,0,n-1,s,p);
printf("\nForma poloneza inversa ");
forma_poloneza(radacina);
printf("\n Valori pentru varabile\n");
atribuie_arbore(radacina);
printf("\nEvaluarea: %7.3f",eval(radacina));
getch();
}
60 Metode de programare
Bibliografie
1. [Aho, Hop şa] Aho A., Hopcroft J., Ullman J., Data Structures and Algorithms,
Addison-Wesley, 1983
2. [Bras, Brat] Brassard G., Bratley P., Algoritmics: Theory and Practice, Prentice-Hall,
1988
3. [Cor, Lei şa] Cormen T., Leiserson C., Rivest R., Introduction to Algorithms, MIT
Press, sixteenth printing, 1996
4. [Gon] Gonnet G.H., Handbook of Algorithms and Date Structures, Addison-Wesley,
1984
5. [Hor] Horowitz E., Sahni S., Fundamentals of Computer Algorithms, Computer
Science Press, 1978
6. [Knu] Knuth D., Fundamental Algorithms, vol 1 of The Art of Computer
Programming, Addison-Wesley, 1973
7. [Knu] Knuth D., Sorting and Searching, vol 3 of The Art of Computer Programming,
Addison-Wesley, 1973
8. [Man] Manmber U., Introduction to Algorithms: A Creative Approach, Addison-
Wesley, 1989
9. [Pop, Geo şa] Popovici Ct., Georgescu H., State L., Bazele informaticii, vol 1, Tip.
Universităţii din Bucureşti, 1990
10. [Tom] Tomescu I.., Probleme de combinatorică şi teoria grafurilor, Editura
Didactică şi Pedagogică, Bucureşti, 1981
11. [Tud] Tudor S., Tehnici de programare, Ed. Teora, 1994
12. [Wil] Wilf H., Algorithms and Complexity, Prentice-Hall, 1986
13. [Negrescu, 1994] Liviu Negrescu, Limbajele C şi C++ pentru începători, Editura
Microinfomatica, Cluj-Napoca, 1994
14. [Smeureanu, 1995] Ion Smeureanu, Ion Ivan, Marian Dârdală, Limbajul C/C++ prin
exemple, Editura Cison, Bucureşti 1995
15. [Ghilic, 2003] Bogdan Ghilic-Micu, Ion Gh. Roşca, Constantin Apostol, Marian
Stoica, Cătălina Lucia Cocianu, Algoritmi în programare, Editura ASE,
Bucureşti 2003
60
lOMoARcPSD|5932583
int main()
{ float x0,x1,eps,sol;
int cod;
unsigned n;
float (*functie)(float);
cod=bisectie(x0,x1,n,eps,functie,&sol);
if(cod==0) printf("nu s-a gasit sol");
else if(cod==1) printf("s-a obtinut solutia exacta:%5.2f", sol);
else if(cod==2) printf("s-a obtinut o sol aproximativa:%5.2f", sol);
else if(cod==3) printf("intervalul dat nu are nici o sol");
return 0;}
2. Divide et imprea maxim
#include<stdio.h>
int main()
{ int i,n;
float v[100],m;
printf("nr elemente\n");
scanf("%d", &n);
printf("elemente: \n");
for(i=0;i<n;i++)
scanf("%f ", &v[i]);
m= max(v,0,n-1);
printf("nr maxim este=%5.2f", m);
}
3. Graf Dijkstra
#include <stdio.h>
l[i] = a[x0][i];
s[i] = 0;
if (a[x0][i] != 1000)
pred[i] = x0;
else pred[i] = -1;
}
g = 0;
s[x0] = 1;
pred[x0] = 0;
r = 1;
do
{
m = 1000;
for (i = 0; i<n; i++)
if ((s[i] == 0) && (l[i]<m))
{
m = l[i]; k = i;
}
r = r + 1;
if ((l[k] == 1000) || (r>n - 1))g = 1;
else
{
s[k] = 1;
for (i = 0; i<n; i++)
if ((s[i] == 0) && (l[i]>l[k] + a[i][k]))
{
l[i] = l[k] + a[i][k]; pred[i] = k;
}
}
} while (g != 1);
}
void afisare(int a[30][30], int n)
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%5d ", a[i][j]);
printf("\n");
}
}
void main()
{
int c[30][30], n, l[30], pred[30], x,i ;
preluare(&n, c);
afisare(c, n);
printf("\nVarful selectat este:");
scanf("%d", &x);
dijkstra(c, n, l, pred, x);
for (i = 0; i < n; i++)
if((i+1)!=x) printf("\nCosturile minime de la %d la %d este: %d",
x,i+1,l[i]);
for (i = 0; i < n; i++) if ((i + 1) != x) printf("\nParintele nodului
%d este: %d", i + 1, pred[i] + 1);
}
4. Graf parcurgere BF
#include<stdio.h>
FILE *f;
int i, j;
int x, y;
f = fopen("lista.txt", "r");
fscanf(f, "%d", nv);
fscanf(f, "%d", nm);
for (i = 0; i<*nv; i++)
for (j = 0; j<*nv; j++)
a[i][j] = a[j][i] = 0;
for (i = 0; i<*nm; i++) {
fscanf(f, "%d", &x);
fscanf(f, "%d", &y);
a[x - 1][y - 1] = a[y - 1][x - 1] = 1;
}
fclose(f);
}
void BF(int a[20][20], int n, int c[20], int vo, int *u, int parinte[20], int
m[20])
{
int i, k, p;
m[k] = 1;
}
p = p + 1;
}
}
int main() {
int a[20][20], c[20], u, n, nm, vo, i, j, parinte[20], m[20];
citire(&n, &nm, a);
for (i = 0; i<n; i++)
{
for (j = 0; j<n; j++)
printf("%d ", a[i][j]);
printf("\n");
}
printf("vo= ");
scanf("%d", &vo);
for (i = 0; i<n; i++)
m[i] = 0;
for (i = 0; i<n; i++)
c[i] = -1;
BF(a, n, c, vo, &u, parinte, m);
printf("\n nr. varfurilor vizitate=%d", u);
printf("\n varfurile vizitate: ");
for (i = 0; i <= u; i++)
printf("%d ", c[i] + 1);
printf("\nparintii: ");
for (i = 0; i <= u; i++)
if (i != vo - 1) printf("\nparintele lui %d este %d ", i + 1,
parinte[i] + 1);
//for (i = 0; i <= u; i++)
// printf("\nm[%d]=%d", i + 1, m[i]);
int nr = 1;
if (f)
{
printf("\n");
RF(n, c);
afisare(c, n);
}
1. Recursivitate Ackermann
#include<stdio.h>
#include<conio.h>
#include<math.h>
printf("Cititi m si n: ");
scanf("%d ", &m);
scanf("%d", &n);
a=ack(m,n);
printf("Ackerman pentru m=%d si n=%d este =%d", m,n,a);
return 0;
}
2. Recursivitate combinari
#include<stdio.h>
#include<stdio.h>
#include<conio.h>
#include<math.h>
comb(int n, int k)
{ int c;
if(n<k) c=0;
else if(k==0||k==n) c=1;
else c=comb(n-1,k-1) + comb(n-1,k);
return c;}
int main()
{
int n,c,k;
3. Recursivitate Fibonacci
#include<stdio.h>
#include<conio.h>
#include<math.h>
int fib(int n)
{
int f;
if(n==0||n==1) return 1;
else if(n>1) return fib(n-1)+fib(n-2);
}
int main()
{
int n,f;
printf("Cititi n: ");
scanf("%d", &n);
f=fib(n-1);
printf("Termenul %d din sirul lui Fibonaci este %d",n,f);
return 0;
}
4. Recursivitate Hermite
#include "stdio.h"
using namespace std;
//Subprogram pentru calcularea functiei HEMITE
long Hemite(int n,int x)
{
if(n==0) return 1;
else if(n==1) return 2*x;
else if(n>1) return 2*n* Hemite(n-1,x) - 2*(n-1)* Hemite(n-2,x);
}
int main()
{
int n,x;
long h;
printf("x="); scanf("%d", &x);
printf("n="); scanf("%d", &n);
h=Hemite(n,x);
printf("%ld",h);
return 0;
}
#include<stdio.h>
#include<conio.h>
#include<math.h>
int a[100],n,i;
int max(int a,int b)
{
if(a>b) return a;
else return b;
}
int maxim(int a[],int n)
{
if(n==1) return a[0];
else return max(a[n],maxim(a,n-1));
}
int main()
{
int m;
printf("cititi dimensiunea vectorului: ");
scanf("%d",&n);
printf("Elementele vectorului sunt:");
for(i=0;i<n;i++)
{ printf("a[%d]= ", i);
scanf("%d", &a[i]);
}
m=maxim(a,n);
printf("%d", m);
}
{
int i, j;
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%5d ", a[i][j]);
printf("\n");
}
}
void RW(int n,int m[100][100])
{
for (int k = 0; k < n;k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (m[i][j] == 0)
m[i][j] = m[i][k] * m[k][j];
}
int main()
{
int a[100][100], n, m[100][100];
preluare(a,&n);
afisare(a, n);
printf("\n");
RW(n, a);
afisare(a, n);
}
2. Interclasare vectori
#include<conio.h>
#include<stdio.h>
#include<malloc.h>
int main()
{ int m,n,*px,*py,i,j,k;
{ printf("v1[%d]=", i+1);
scanf("%d",px+i);
}
sortare(px,m);
sortare(py,n);
int *pi=(int*)malloc((m+n)*sizeof(int));
k=0;
i=0;
j=0;
}
k=k+1;
}
if(i<m)
for(int ii=i;ii<m;ii++)
{ *(pi+k)=*(px+ii);
k=k+1;
}
else
for(int jj=j;jj<n;jj++)
{ *(pi+k)=*(py+jj);
k=k+1;
}
printf("\n");
for(i=0;i<k;i++)
printf(" %d ", *(pi+i));
free(px);
free(py);
free(pi);
getch();
return 0;
}
3. Recursivitate: Permutari
#include<stdio.h>
#include<stdio.h>
#include<conio.h>
#include<math.h>
permutari(int n)
{ int p;
if(n==0||n==1) p=1;
else p= n* permutari(n-1);
return p;}
int main()
{
int n,p;
#include<stdio.h>
#include<stdio.h>
#include<conio.h>
#include<math.h>
aranj(int n, int k)
{ int a;
if(n<k) a=0;
else if(k==0) a=1;
else a= n* aranj(n-1,k-1);
return a;}
int main()
{
int n,a,k;
int main ()
{
unsigned n1,n2,div;
printf("dati cele doua numere\n");
scanf("%d %d", &n1, &n2);
div=cmmdc(n1,n2);
printf("cel mai mare divizor comun este: %d", div);
return 0;
}
BACKTRACKING
1. Scrieti un program care sa calculeze aranjamente de n folosind metoda backtracking
#include<stdio.h> // PERMUTĂRI
int maxim=20;
int n,v[20] ; //n-nr. de elemente, v[20]-vectorul în care construim soluţia
int max;
int valid(int k) //verificăm condiţiile de continuare
{int i;
for (i=1;i<=k-1;i++) //comparăm fiecare element din vectorul v cu ultimul element
selectat
if (v[i]==v[k])
return 0;
return 1;
}
int solutie(int k) //verificăm dacă am obţinut o soluţie
{if (k==max)
return 1;
return 0;
}
void afisare(int k) //afişează conţinutul vectorului v
{int i;
for (i=1;i<=k;i++)
printf("%d ",v[i]);
printf("\n");
}
void BK(int k)
{int i;
for (i=1;i<=n;i++)
{v[k]=i; //selectăm un element din mulţimea Sk
if (valid(k)) //verificăm dacă eelementul ales îndeplineşte condiiile de continuare
{if (solutie(k)) //verificăm dacă am obţinut o soluţie
afisare(k);
else
BK(k+1); //reapelmăm funcţia pentru poziţia k+1 din vectorul v
}
}
int main()
{ printf("aranjamente de n luate cate k \n");
printf("dati n-ul:"); scanf("%d" ,&n);
printf("\ndati k-ul:"); scanf("%d" ,&max);
BK(1);
return 0;
}
2. Scrieti un program care sa calculeze combinari de n luate cate k folosind metoda
backtracking
#include<stdio.h> // PERMUTĂRI
int maxim=20;
int n,v[20] ; //n-nr. de elemente, v[20]-vectorul în care construim soluţia
int max;
int valid(int k) //verificăm condiţiile de continuare
{int i;
for (i=1;i<=k-1;i++) //comparăm fiecare element din vectorul v cu ultimul element
selectat
if (v[i]==v[k]||v[i]>v[k])
return 0;
return 1;
}
int solutie(int k) //verificăm dacă am obţinut o soluţie
{if (k==max)
return 1;
return 0;
}
void afisare(int k) //afişează conţinutul vectorului v
{int i;
for (i=1;i<=k;i++)
printf("%d ",v[i]);
printf("\n");
}
void BK(int k)
{int i;
for (i=1;i<=n;i++)
{v[k]=i; //selectăm un element din mulţimea Sk
int main()
{ printf("combinari de n luate cate k \n");
printf("dati n-ul:"); scanf("%d" ,&n);
printf("\ndati k-ul:"); scanf("%d" ,&max);
BK(1);
return 0;
}
3. Scrieti un program care sa calculeze problema damelor folosind metoda backtracking
#include<stdio.h> // PERMUTÃRI
#include<math.h>
int maxim=20;
int n,sol,v[20] ; //n-nr. de elemente, v[20]-vectorul în care construim soluþia
{int i,j,x;
sol++; printf("\n Solutia: \n", sol);
for (i=1;i<=n;i++)
{for (j=1;j<=n;j++)
if (v[i]==j) printf("D ");
else printf("_ ");
printf("\n");
}
}
void BK(int k)
{int i;
for (i=1;i<=n;i++)
{v[k]=i; //selectãm un element din mulþimea Sk
if (valid(k)) //verificãm dacã eelementul ales îndeplineºte condiiile de continuare
{if (solutie(k)) //verificãm dacã am obþinut o solutie
afisare(k);
else
BK(k+1); //reapelmãm funcþia pentru poziþia k+1 din vectorul v
}
}
}
int main()
{ printf("n= ");scanf("%d",&n);
BK(1);
return 0;
}
4. Scrieti un program care sa calculeze permutari de k folosind metoda backtracking
#include<stdio.h> // PERMUTÃRI
int maxim=20;
int n,v[20] ; //n-nr. de elemente, v[20]-vectorul în care construim soluþia
}
int solutie(int k) //verificãm dacã am obþinut o soluþie
{if (k==n)
return 1;
return 0;
}
void afisare(int k) //afiºeazã conþinutul vectorului v
{int i;
for (i=1;i<=k;i++)
printf("%d ",v[i]);
printf("\n");
}
void BK(int k)
{int i;
for (i=1;i<=n;i++)
{v[k]=i; //selectãm un element din mulþimea Sk
if (valid(k)) //verificãm dacã eelementul ales îndeplineºte condiiile de continuare
{if (solutie(k)) //verificãm dacã am obþinut o soluþie
afisare(k);
else
BK(k+1); //reapelmãm funcþia pentru poziþia k+1 din vectorul v
}
}
}
int main()
{ printf("n= ");scanf("%d",&n);
BK(1);
return 0;
}
5. Scrieti un program care sa calculeze problema suma folosind metoda backtracking
#include <stdio.h> // PLATA SUMEI
#define MAX 20
int n=0,x,v[MAX],w[MAX],z[MAX],S,Suma,sol;
//v-vectorul soluþie,w-valoarea monedelor,z-nr.maxim de monede de un anumit tip
void citire();
int valid(int k);
int solutie();
void afisare(int k);
void BK(int k);
int main()
{citire();
BK(1);
return 0;
}
void BK(int k)
{int i;
for (i=0;i<=z[k];i++)
{v[k]=i;
if (valid(k)==1)
{if (solutie()==1)
afisare(k);
else
BK(k+1);
}
}
}
void citire()
{int i;
printf("suma este: "); scanf("%d",&S);
printf("nr de monede este: "); scanf("%d",&n); //se citeºte suma S ºi numãrul de
monede
printf("valoarea monedelor este:\n");
for(i=0;i<n;i++)
{scanf("%d",&w[i]); //se citesc valorile monedelor
z[i]=S/w[i];} //z-memorezã numãrul maxim de monede de un anumit tip, penru a plati
suma S
}
int valid(int k)
{int i;
Suma=0;
for (i=0;i<k;i++)
Suma=Suma+v[i]*w[i];
if ((Suma<=S)&&(k<=n))
return 1;
return 0;}
int solutie()
{if (Suma==S)
return 1;
return 0;}
void afisare(int k)
{int i;
sol++;printf("solutia: %d", sol);
for (i=0;i<k;i++)
if (v[i]) {printf(" \n%d monede de valoarea %d", v[i],w[i]); printf("\n");}
printf("\n");}
#include <stdio.h>
#define MAX 20
int n,v[MAX],sol_max[MAX],g[MAX],c[MAX],s,s_max,G,gr,nr_sol;
char nume[MAX][MAX];
void back(int k);
int valid(int k);
void optim();
void citire();
void afisare();
main()
{citire();
back(1);
afisare(); //afisam solutia optima
}
void back(int k)
{ int i;
for(i=0;i<=1;i++)
{v[k]=i; //0-obiectul k sete NEselectat, 1-obiectul k este selectat
if (valid(k))
if (k==n) optim(); //din multimea solutiilor vom retine doar solutia optima
else back(k+1); }
}
int valid(int k)
{ gr=0;
for(int j=0;j<k;j++)
gr=gr+v[j]*g[j]; //-insumam greutatile obiectelor selectate pana la pasul k
if(gr<=G) return 1; //verificam daca greutatea cumulata nu depaseste greutatea maxima
G
else return 0;
}
void optim()
{int s=0,j; nr_sol++;
for(int j=0;j<n;j++)
s=s+v[j]*c[j]; //s-calculam suma câºtigurilor obiectelor selectate
if((nr_sol==0)||(s>s_max)) //daca s>suma maxima, solutia este mai buna
{s_max=s; //retinem solutia in sol_max
for(j=0;j<n;j++)
sol_max[j]=v[j];
}
}
void citire()
{ int i;
1. Sortare numarare
#include <stdio.h>
#include <malloc.h>
void sort_numarare(int v[] ,int l)
{int i,j,*num;
int *temp;
temp=(int*)malloc(l*sizeof(int));
num=(int*)malloc(l*sizeof(int));
for(i=0;i<l;i++)
num[i]=0;
for(i=0;i<l-1;i++)
for(j=i+1;j<l;j++)
if(v[j]<v[i])
num[i]++;
else
num[j]++;
for(i=0;i<l;i++)
temp[num[i]]=v[i];
for(i=0;i<l;i++)
v[i]=temp[i];
free(temp);
free(num);
}
int main()
{
int v[20];
int n,i;
printf("nr elem vector: ");
scanf("%d", &n);
printf("elem vector: \n");
for (i=0;i<n;i++)
scanf("%d", &v[i]);
sort_numarare(v,n);
printf("vector sortat\n");
for (i=0;i<n;i++)
printf("%d ", v[i]);
return 0;}
2. Sortare bule
#include <stdio.h>
void sort_bule(int v[],int l)
{int i,gata;
int a;
gata=0;
while(!gata)
{gata=1;
for(i=0;i<l-1;i++)
if(v[i]>v[i+1])
{gata=0;
a=v[i];
v[i]=v[i+1];
v[i+1]=a;
}}}
int main()
{
int v[20];
int n,i;
printf("nr elem vector: ");
scanf("%d", &n);
printf("elem vector: \n");
for (i=0;i<n;i++)
scanf("%d", &v[i]);
sort_bule(v,n);
printf("vector sortat\n");
for (i=0;i<n;i++)
printf("%d ", v[i]);
return 0;}
3. Sortare insertie
#include<stdio.h>
for(i=0;i<n;i++)
printf("%d ", a[i]);
}
4. Sortare prin interclasare
#include<conio.h>
#include<stdio.h>
#include<malloc.h>
int main()
{ int i,n;
float v[100];
printf("nr elemente\n");
scanf("%d", &n);
printf("elemente: \n");
for(i=0;i<n;i++)
{
printf("v[%d]=", i+1);
scanf("%f", &v[i]);}
sortare(v,0,n-1);
for(i=0;i<n;i++)
printf("%5.2f", v[i]);
}
5. Sortare prin selectie
#include <stdio.h>
a=v[i];
v[i]=v[j];
v[j]=a;}}
int main()
{
int v[20];
int n,i;
printf("nr elem vector: ");
scanf("%d", &n);
{ i=poz(x,p,u);
quick(x,p,i-1);
quick(x,i+1,u);
}
}
int main()
{ int n,i;
float v[1000];
printf("Dimensiunea vectorului:");
scanf("%i",&n);
printf("Elementele vectorului\n");
for(unsigned i=0;i<n;i++)
scanf("%f",&v[i]);
quick(v,0,n-1);
printf("Vectorul sortat\n");
for(i=0;i<n;i++)
printf("%8.4f ",v[i]);
getch();
}
7. Sortare shell
#include <stdio.h>
void sort_shell(int v[], int l)
{int i,j,inc;
int a;
for(inc/2;inc>0;inc=inc/2)
for(i=inc;i<l;i++)
for(j=i-inc;(j>=0)&&(v[j]>v[j+inc]);j=j-inc)
{a=v[j];
v[j]=v[j+inc];
v[j+inc]=a;
}}
int main()
{
int v[20];
int n,i;
printf("nr elem vector: ");
scanf("%d", &n);
printf("elem vector: \n");
for (i=0;i<n;i++)
scanf("%d", &v[i]);
sort_shell(v,n);
printf("vector sortat\n");
for (i=0;i<n;i++)
printf("%d ", v[i]);
return 0;}
int main()
{ float x,y;
unsigned n;
printf("Cititi n- rangul termenului: "); scanf("%d", &n);
printf("Cititi a0: "); scanf("%f", &a0);
printf("Cititi b0: "); scanf("%f", &b0);
printf("Cititi alfa: "); scanf("%f", &alfa);
printf("Cititi beta: ");scanf("%f", &beta);
printf("Cititi gama: ");scanf("%f", &gama);
printf("Cititi delta: ");scanf("%f", &delta);
x= A(n);
y=B(n);
printf("an=%5.2f, bn=%5.2f",x,y);
{ float p;
if(n==0) p=1;
else p= x*putere(x,n-1);
return p;
//P(x)= a[n]*putere(x,n)+a[n-1]*putere(x,n-1)+...+a[o]
int main()
float x, a[100];
double p;
int n,i;
for(i=0;i<n+1;i++)
printf("a[%d]=",i);
scanf("%f", &a[i]);
p=polinom(a,n,x);
printf ("\n");
return 0;
4.Bisectie
#include<stdio.h>
#include<conio.h>
#include<math.h>
float fct(float);
/* functia principala*/
int main()
{ float a,b,eps,x;
int cod;
long n;
float (*functie)(float);
scanf("%f",&eps);
functie=fct;
bisectie(a,b,functie,eps,n,&cod,&x);
return 0;}
for(c=0;(c<n)&&!gata;c++)
*cod=gata;}
5.Cautare binara
#include<stdio.h>
#include<conio.h>
#include<math.h>
int mij;
mij=(ld+ls)/2;
int main()
{ int i,n,p;
float v[100],k;
printf("nr elemente\n");
scanf("%d", &n);
printf("elemente: \n");
for(i=0;i<n;i++)
scanf("%f", &k);
p= caut_bin(v,0,n-1,k);
else
6.Problema paznic
#include<stdio.h>
#include<math.h>
{ int r;
while (b!=0)
{r=a%b;
a=b;
b=r;
if (a==1)
return 1;
else
return 0;
int i,j,nr;
nr=0;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
nr=nr+ (cmmdc((fabs(x-i)),(fabs(y-j)))==1);
int main()
int m,n,x,y,nr;
printf("m=");scanf("%d",&m);
printf("n=");scanf("%d",&n);
printf("x=");scanf("%d",&x);
printf("y=");scanf("%d",&y);
nr= pomi(m-1,n-1,x-1,y-1);
int sol[100];
int i, sr;
sr=s;
for(i=0;i<n;i++)
sol[i]=sr/t[i];
sr=sr%t[i];
int main()
for(i=0;i<n;i++)
{ printf("tipul %d:",i+1);
plata_unitate(S, t, n, sol);
for(i=0;i<n;i++)
2. Alg. Dijkstra :
R: calculeaza distantele si drumurile minime de la un nod al unui graf la toate
celelalte noduri din graf
3. Fie functia :
int calc (int n) calc(3)
{ rez=2*calc(2)+calc(1)=7
int rez ; =3 =1
if (n==0 || n==1)
rez=1; calc(2)
else rez=2*calc(1)+calc(0)=3
rez=2* calc(n-1)+calc(n-2); =1 =1
return rez;
}
R: 4,1,2,7,8,5
R: 1342
calculeaza:
R: ultima aparitie a unei valori date (val) intr-un vector
13. Care dintre urm. afirmatii referitoare la arborele orientat sunt adevarate?
R: -graful suport este conex
- graful suport este aciclic
- este graf asimetric
- este arbore directionat cu radacina
R: * * * * * + + + + +
19. Care dintre afirmatiile urmatoare NU este valabila pt. Alg. lui Kruskal :
F – dintre arcele disponibile se allege arcul cu ponderea cea mai mica si care
formeaza un ciclu prin adaugarea la arbore
A- determina arborele partial de cost min
A- dintre arcele disponibile care nu au fost analizate inca se allege arcul cu
ponderea cea mai mica si care nu formeaza un ciclu prin adaugarea la arbore
A – mult. muchiilor selectate E0 se initializeaza la inceput cu mult. vida
21. Fie mult. de litere {a,b,c,d} . Se genereaza permutarile acestei mult. Precizati
care sunt solutiile anterioara si urmatoare solutiei cabd
R: bdca si cadb
23. Care dintre urm. afirm. referitoare la metoda Divide et Impera sunt
adevarate?
A – este utilizata in rezolvarea unor problem complexe
A – implementarea este realizata de obicei prin subprogram recursive
A – se aplica pt problem care pot fi descompuse in problem cu complexitate
mai mica
A – rezolvarea problemelor rezultate in urma descompunerii este mai usoara
decat rezolvarea intregii problem initiale
F – pt fiecare dintre problemele rezultate in urma descompunerii se aplica un
procedeu diferit de descompunere
R: atribuie si avanseaza
30. Un graf reprezentat prin matrice de adiacenta poate fi verificat daca este
conex prin urm. metode:
R: - folosind parcurgerea in adancime
-folosind parcurgerea in latime
31. Secventa:
for (inc=n/2;inc>0;inc=inc/2)
for(i=inc;i<n;i++)
for(j=i-inc;;(j>=0)&&(v[j]>v[j+inc]);j=j-inc)
{
a=v[j]
v[j]=v[j+inc];
v[j+inc]=a;
}
34. Care dintre urm. afirm. legate de subprograme recursive NU este adevarata:
R: pot fi folosite numai pt. implementarea unui alg. recursive
36. Intr-un graf neorientat G notam cu n nr. de vf. si cu m nr. de muchii. Daca
graful este arbore, atunci intre n si m exista urm. relatie matematica:
R: n=m+1
37. Care dintre urm. operatii NU fac parte din operatiile specific metodei
optimului local:
R: -construirea unui element candidat x
- eliminarea elem. x selectat din Solutia problemei
39. Fie multimea de litere {a, b, c, d}. Se genereaza permutarile acestei multimi,
Precizati care sunt solutiile anterioara si urmatoare solutiei cabd.
R:bdca sic dab
40. Fie graful G=(V,E) cu V={1,…,7} , E+{(1,4);(1,5);(2,4);(3,6);(4,7)} si v_0=2 .
Ordinea in care sunt vizitate varfurile corespunzator parcurgerii in latime BF
este:
R: 2, 4, 1, 7, 5
R: atribuie si avanseaza
53. In configuratia urmatoare (specifica metodei backtracking) este prezentata
operatia de:
R: revenire dupa
construirea unei
solutii
54. Care din urmatoarele afirmatii referitoare la implementarea recursiva este
adevarata:
consum mic de resurse de memorie
timp de executie mic
usurinta in proiectare/programare (lungimea mica a codului sursa)
scaderea numarului de operatii
se poate aplica numai pentru rezolvarea unor probleme complexe, care nu
pot fi rezolvate prin implementare iterativa
55. Fie functia:
int f (int n)
{ int rez;
if (n == 0) rez = 0;
else if (n % 2) rez = n + f (n – 1);
else rez =n / … 1);
return rez; }
Ce va returna apelul f(4)?
R:7
56. Fie functia:
int s(int n)
{ int rez;
if (n == 0) rez = 0;
else rez = n + s(n – 1); return rez; }.
In cazul apelului s(3), functia va returna valorea:
R:6
57. Care din urmatoarele afirmatii referitoare la metoda Divide et Impera sunt
adevarate?
este utilizata in rezolvarea unor probleme complexe
implementarea este realizata de obicei prin subprograme recursive
R: [2,4,5,5,5,3,0,4]
59. Fie graful G=(V,E), V={1,2..7}, E={(1,2,3), (1,4,3), (1,7,4), (2,3,4), (2,5,5),
(2,6,6), (2,7,3) (3,4,4),(3,5,5), (4,5,7), (5,6,3), (6,7,5), }. Aplicand algoritmul
lui Prim, care va fi rezultatul obtinut plecand de la varful 2?
R: 22
60. Fie graful G=(V,E), V=(A,B,C,D,E,F), SI E={ (A,B), (B.E), (B,F), (C,E), (C,D)}. Care
este nodul ce poate fi ales ca radacina a arborelui astfel incat fiecare nod
care nu este de tip frunza sa aiba un numar impar de descendenti directi
(fii)?
R: B
61. Fie graful G=(V,E), V=(A,B,C,D,E,F), SI E={ (A,E), (B.D), (B,E), (C,D), (E,F)}. Care
este nodul ce poate fi ales ca radacina a arborelui astfel incat fiecare nod
care nu este de tip frunza sa aiba un numar impar de descendenti directi
(fii)?
R: E
62. Daca in cadrul unui arbore se elimina o muchie atunci se obtine:
R: un graf neconex
63. Ce reprezinta un graf partial al unui graf neorientat?
R: un graf din care se elimina anumite muchii
64. Fie urmatoarea functie:
Int f (int n)
{ if (n==0)
Return 0;
Else return f(n-1)+2*n;}
Care va fi rezultatul pt apelul functiei f(5) si f(4)
R: 30-f(5)
20-f(4)
65. Ce reprezinta un subgraf al unui graf orientat?
R: un graf din care se elimina noduri si muchii adiacente
66. Utilizandu-se metoda backtracking pentru a genera toate permutarile de 5
obiecte, dupa identificarea solutiei 2-4-5-3-1 care va fi urmatoarea solutie
identificata:
R: 2-5-1-3-4