Curs Algoritmica Grafurilor PDF
Curs Algoritmica Grafurilor PDF
Curs Algoritmica Grafurilor PDF
ALGORITMICA GRAFURILOR
- sinteze de curs şi aplicaţii -
Arad, Autorii
23 noiembrie 2007
3
Cuprins
Prefaţă 3
1 Noţiuni introductive 7
1.1 Reprezentarea grafurilor orientate . . . . . . . . . . . . . . . . 7
1.2 Grafuri neorientate . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Operaţii cu grafuri . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4 Grafuri valorizate . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.5 Drumuri, circuite şi lanţuri . . . . . . . . . . . . . . . . . . . . 16
1.6 Componente conexe şi tare conexe . . . . . . . . . . . . . . . . 18
1.7 Arbori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.8 Grafuri bipartite . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.9 Reţele de transport . . . . . . . . . . . . . . . . . . . . . . . . 24
1.9.1 Problema fluxului maxim . . . . . . . . . . . . . . . . . 25
1.9.2 Probleme de transport . . . . . . . . . . . . . . . . . . 27
1.9.3 Probleme de afectare . . . . . . . . . . . . . . . . . . . 29
1.10 Exerciţii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4
CUPRINS 5
3 Aplicaţii 106
3.1 Reprezentarea grafurilor . . . . . . . . . . . . . . . . . . . . . 106
3.2 Parcurgerea unui graf . . . . . . . . . . . . . . . . . . . . . . . 120
3.2.1 Introducere . . . . . . . . . . . . . . . . . . . . . . . . 120
3.2.2 Parcurgerea ı̂n lăţime . . . . . . . . . . . . . . . . . . . 120
3.2.3 Parcurgerea ı̂n adâncime . . . . . . . . . . . . . . . . . 122
3.2.4 Sortarea topologică a unui graf . . . . . . . . . . . . . 124
3.3 Operaţii cu grafuri . . . . . . . . . . . . . . . . . . . . . . . . 136
3.4 Lanţuri şi cicluri . . . . . . . . . . . . . . . . . . . . . . . . . 153
3.5 Arbori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
3.6 Matricea drumurilor . . . . . . . . . . . . . . . . . . . . . . . 168
6 CUPRINS
Bibliografie 265
Capitolul 1
Noţiuni introductive
Observaţia 1.1.3 Remarcăm că s-a făcut convenţia ca arcul (x3 , x1 ) să fie
notat (3, 1) ş.a.m.d.
7
8 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
Observaţia 1.1.8 Pentru graful din exemplul 1.1.2 remarcăm că (x4 , x4 )
este o buclă. Mai notăm că
Observaţia 1.2.5 Multe definiţii pentru grafuri orientate şi neorientate sunt
aceleaşi, deşi anumiţi termeni pot avea semnificaţii diferite ı̂n cele două con-
texte. Remarcăm că dacă avem un graf neorientat acesta poate fi transformat
ı̂ntr-un graf orientat ı̂nlocuind fiecare muchie (x, y) prin două arce (x, y) şi
(y, x). Reciproc, dacă avem un graf orientat versiunea neorientată se obţine
eliminı̂nd buclele şi direcţiile. Prin urmare, ı̂n continuare atunci când nicio
precizare nu este făcută ne referim la grafuri orientate.
Observaţia 1.3.2 În general, nu facem deosebire ı̂ntre două grafuri izomorfe.
Astfel, vom scrie G = G0 ı̂n loc de G ' G0 .
G ∪ G0 := (X ∪ Y, U ∪ V ).
12 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
G ∩ G0 := (X ∩ Y, U ∩ V ).
Atunci G ∪ G0 este
şi G ∩ G0 este
1.3. OPERAŢII CU GRAFURI 13
G ⊕ G0 := (X, U ∪ V ) .
G ⊗ G0 := (X, W ) ,
Atunci G ⊕ G0 este
G ⊗ G0 este
14 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
Gt este
1. G ⊕ G0 are matricea A + A0 ;
2. G ⊗ G0 are matricea A · A0 ;
3. Gt are matricea At .
Observaţia 1.3.10 Evident G[Y ] este un subgraf al lui G dar nu orice sub-
graf este generat de o submulţime de vârfuri aşa cum arată exemplul următor.
1.4. GRAFURI VALORIZATE 15
Observaţia 1.4.2 Un graf valorizat poate fi reprezentat sagital ca şi ı̂n figura
1.1, trecând ı̂nsă deasupra fiecărui arc valoarea acestuia. In general ı̂nsă
preferăm ca un graf valorizat să fie reprezentat printr-un tabel de forma:
arcele (xi , xj )
.
valorile arcelor vij
ij 12 14 15
.
vij 7 8 9
Soluţie.
Exemplul 1.5.2 Exemple de drumuri ı̂n graful din exemplul 1.1.2 ar fi:
µ3 = {(1, 2), (2, 4), (4, 5), (5, 3), (3, 1)} , l(µ3 ) = 5 .
Convenim ca drumul µ1 să fie notat (1, 2, 4), drumul µ2 să fie notat (3, 2, 4, 5),
iar drumul µ3 să fie scris (1, 2, 4, 5, 3, 1). Precizăm că µ3 este un circuit.
1.5. DRUMURI, CIRCUITE ŞI LANŢURI 17
Definiţia 1.5.3 Un drum se numeşte simplu, dacă arcele din care este for-
mat drumul sunt distincte.
Un drum se numeşte elementar dacă toate vârfurile din el sunt distincte.
Un drum care trece o dată şi o singură dată prin fiecare vârf al grafului se
numeşte drum hamiltonian. Prin urmare aceste drumuri au lungimea
n − 1 (unde n reprezintă numărul de vârfuri).
Prin circuit hamiltonian ı̂nţelegem acele circuite ce conţin toate vârfurile
grafului o dată şi o singură dată, cu excepţia vârfului iniţial care coincide cu
cel final. Prin urmare au lungimea n.
Prin circuit eulerian al unui graf ı̂nţelegem un circuit simplu care foloseşte
toate arcele grafului.
Un graf care conţine un circuit hamiltonian se numeşte graf hamiltonian.
Un graf care conţine un circuit eulerian se numeşte graf eulerian.
Observaţia 1.5.6 Pentru graful din exemplul 1.1.2 matricea drumurilor este
1 1 1 1 1
1 1 1 1 1
D= 1 1 1 1 1 .
1 1 1 1 1
1 1 1 1 1
În capitolul următor vom vedea diverşi algoritmi pentru determinarea acestei
matrici.
Definiţia 1.5.7 Puterea de atingere a unui vârf x ∈ X ı̂n graful
G = (X, U ) reprezintă numărul de vârfuri la care se poate ajunge printr-
un drum ce pleacă din x şi notează p(x).
Exemplul 1.5.10 În graful din exemplul 1.1.2 avem lanţul L = (1, 2, 3, 5).
Observaţia 1.6.2 Componentele conexe ale unui graf sunt clasele de echiva-
lenţă ale vârfurilor ı̂n raport cu relaţia de ”accesibil”.
Observaţia 1.6.5 Componentele tare conexe ale unui graf orientat sunt
clasele de echivalenţă ale vârfurilor ı̂n raport cu relaţia de ”reciproc acce-
sibile”.
1.7 Arbori
Definiţia 1.7.1 Se numeşte arbore un graf neorientat fără cicluri şi conex.
Exemplul 1.7.2
1. G este un arbore;
4. G este un graf aciclic maximal, adică G este fără cicluri dar G + (x, y)
are cicluri pentru orice două vârfuri neadiacente x, y ∈ X;
Pentru arborele de mai sus, nodul x3 este rădăcină, un nod tată ar putea fi
nodul x2 care are noduri fii pe x5 , x6 , x9 , prin urmare aceştia sunt fraţi.
22 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
Exemplul 1.7.11
4. Fiecare vârf poate fi atins plecând din r, dar renenţând la un arc dis-
trugem această proprietate.
(b) Ai 6= ∅, (∀)i = 1, r;
(c) Ai ∩ Aj = ∅, (∀)i, j = 1, r, i 6= j.
2. orice muchie u ∈ U ı̂şi are extremităţile ı̂n clase diferite, adică două
vârfuri din aceeaşi clasă nu pot fi adiacente.
În cazul ı̂n care r = 2 vom folosii termenul de graf bipartit.
Definiţia 1.8.2 Un graf r-partit pentru care orice două vârfuri din clase
diferite sunt adiacente se numeşte complet.
Teorema 1.8.3 Un graf este bipartit dacă şi numai dacă nu conţine cicluri
de lungime impară.
24 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
Exemplul 1.8.4
Exemplul 1.8.5
3. G este conex (ı̂ntre oricare două vârfuri există cel puţin un lanţ) şi
există drumuri de la x0 la xn ı̂n G;
1. ”condiţia de conservare”:
(b) X X
f (x0 , y) = f (x, xn ) = f ;
y∈X x∈X
Observaţia 1.9.4 Vom rezolva această problemă doar ı̂n ipoteza că funcţia
capacitate ia doar valori numere raţionale. In capitolul următor vom prezenta
algoritmul Ford-Fulkerson care rezolvă această problemă. Ideea acestui algo-
ritm este ca plecând de la un flux să-l mărim până când atinge cea mai mare
valoare posibilă.
26 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
2. f (x, y) < 0. În acest caz spunem că avem un flux virtul de la x la y.
În această situaţie f (y, x) > 0 (din condiţia de simetrie) şi prin urmare
(y, x) ∈ U ;
X
f − (x) = f (y, x) .
(y,x)∈U,f (y,x)>0
Problema revine la a găsi un flux f care să satureze arcele iniţiale şi terminale
P
m P n
şi pentru care cantitatea cij xij este minimă.
i=1 j=1
Un cuplaj ar putea fi
1.10. EXERCIŢII 31
1.10 Exerciţii
Exerciţiul 1.10.1 Se consideră graful orientat G = (X, U ) având reprezentarea
sagitală
1, 1, 1, 3, 3, 4, 5, 7 ?
32 CAPITOLUL 1. NOŢIUNI INTRODUCTIVE
Să se determine
1. G ∪ G0 ;
2. G ∩ G0 ;
3. Gt ;
4. G ⊗ G;
6. G.
Exerciţiul 1.10.4 Fie G = (X, U ) un graf neorientat. Să se arate că fie G
fie complementarul său G este conex.
Exerciţiul 1.10.6 Să se arate că mulţimea componentelor conexe ale unui
graf neorientat G = (X, U ) formează o partiţie a lui X.
33
34 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Figura 2.1:
Soluţie.
0 0 1 0 1 0 0 0 1 0 1 0
1 0 0 1 0 0 1 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0
A=
; A := T1 (A) =
0 0 0 0 0 1 0 0 0 0 0 1
0 0 1 0 0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 1 0 0 0 0
0 0 1 0 1 0 0 0 1 0 1 0
1 0 1 1 1 0 1 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0
A := T2 (A) =
; A := T3 (A) =
0 0 0 0 0 1 0 0 0 0 0 1
0 0 1 0 0 0 0 0 1 0 0 0
1 1 1 1 1 0 1 1 1 1 1 0
0 0 1 0 1 0 0 0 1 0 1 0
1 0 1 1 1 1 1 0 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0
A := T4 (A) =
; A := T5 (A) =
0 0 0 0 0 1 0 0 0 0 0 1
0 0 1 0 0 0 0 0 1 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1
2.1. MATRICEA DRUMURILOR 35
0 0 1 0 1 0
1 1 1 1 1 1
0 0 0 0 0 0
A := T6 (A) =
1 1 1 1 1 1
0 0 1 0 0 0
1 1 1 1 1 1
0 ⊕ 0 = 0; 0 ⊕ 1 = 1; 1 ⊕ 0 = 1; 1 ⊕ 1 = 1 ;
0 ⊗ 0 = 0; 0 ⊗ 1 = 0; 1 ⊗ 0 = 0; 1 ⊗ 1 = 1 .
Aceste operaţii se pot extinde la matrici cu coeficienţi din mulţimea {0, 1}
obţinând ”adunarea booleană” a matricilor care acţionează la fel ca şi ı̂n cal-
culul matricial clasic ”termen cu termen” şi ”ı̂nmulţirea booleană” a matri-
cilor care acţionează la fel ca şi ı̂n calculul matricial clasic ”linie per coloană”.
Aceste operaţii vor fi notate tot cu ⊕ şi ⊗, sperând că nu este posibilă nicio
confuzie.
Vom defini
(k)
A(k) := A ⊗ A ⊗ · · · ⊗ A = (aij ) .
Teorema 2.1.3 Fie A = (aij )ni,j=1 matricea de adiacenţă a grafului
G = (X, U ). Atunci
1. Matricea A(k) este matricea drumurilor (elementare sau nu) de lungime
(k)
k, adică, dacă aij = 1 atunci ı̂ntre xi şi xj există un drum de lungime
(k)
k, iar dacă aij = 0 atunci ı̂ntre xi şi xj nu există drum de lungime k;
D = A ⊕ A(2) ⊕ . . . ⊕ A(n−1) .
36 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Soluţie.
0 0 1 0 1 0 0 0 1 0 0 0
1 0 0 1 0 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0
A=
; A =
(2)
0 0 0 0 0 1 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 1 0 0 1 0 0
0 0 0 0 0 0
0 1 1 0 0 0
0 0 0 0 0 0
A(3) =A ⊗A=
(2)
1 0 0 1 0 0
0 0 0 0 0 0
0 0 1 0 1 1
0 0 0 0 0 0
1 0 0 1 0 0
0 0 0 0 0 0
A(4) =A ×A=
(3)
0 0 1 0 1 1
0 0 0 0 0 0
0 1 1 0 0 0
0 0 0 0 0 0
0 0 1 0 1 1
0 0 0 0 0 0
A(5) =A ⊗A=
(4)
0 1 1 0 0 0
0 0 0 0 0 0
1 0 0 1 0 0
2.1. MATRICEA DRUMURILOR 37
În final
0 0 1 0 1 0
1 1 1 1 1 1
0 0 0 0 0 0
D = A ⊕ A(2) ⊕ A(3) ⊕ A(4) ⊕ A(5) =
1 1 1 1 1 1
0 0 1 0 0 0
1 1 1 1 1 1
Observaţia 2.1.5 Pentru a face economie de timp este suficient să ob-
servăm că:
1. D = A ⊗ (A ⊕ I)(n−2) , unde I este matricea unitate;
2. A ⊗ (A ⊕ I)(n−2+k) = A ⊗ (A ⊕ I)(n−2) , (∀)k ≥ 0.
Prin urmare vom calcula
r)
(A ⊕ I)(2) , (A ⊕ I)(4) , . . . , (A ⊕ I)(2
1 0 1 0 1 0 1 0 1 0 1 0
1 1 1 1 1 1 1 1 1 1 1 1
0 0 1 0 0 0 0 0 1 0 0 0
(A ⊕ I)(2) =
; (A ⊕ I) =
(4)
0 1 0 1 0 1 1 1 1 1 1 1
0 0 1 0 1 0 0 0 1 0 1 0
1 1 0 1 0 1 1 1 1 1 1 1
38 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
0 0 1 0 1 0
1 1 1 1 1 1
0 0 0 0 0 0
D = A ⊗ (A ⊕ I)(4) =
1 1 1 1 1 1
0 0 1 0 0 0
1 1 1 1 1 1
Soluţie.
0 0 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
A=
0 0 0 0 0 1
0 0 1 0 0 0
0 1 0 0 0 0
Etapa 1. La linia 1 adunăm boolean liniile 3 şi 5.
0 0 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
A= 0 0 0 0 0
1
0 0 1 0 0 0
0 1 0 0 0 0
Pe linia 1 nu s-au obţinut noi elemente egale cu 1 şi prin urmare trecem la
etapa 2.
2.1. MATRICEA DRUMURILOR 39
Observaţia 2.1.12 În cazul ı̂n care avem un graf G = (X, U ) alfabetul va
fi mulţimea vârfurilor grafului.
U = {(1, 2), (1, 4), (1, 5), (2, 4), (3, 1), (3, 2), (3, 5), (4, 4), (4, 5), (5, 3)} .
AB AD AE B D E
BD D
L1 = CA CB CE ; LR = A B E
DE E
EC C
Etapa 2.
Etapa 3.
AECB ADEC ABDE
BDEC
L3 = CABD CADE, CBDE
DECA DECB
ECAB ECAD, ECBD
Etapa 4.
ADECB ABDEC AECBD
BDCEA
L4 = CABDE
DECAB
ECABD
şi
U = {(x0 , x1 ), (x0 , x5 ), (x1 , x3 ), (x2 , x6 ), (x3 , x5 ), (x4 , x5 )} .
Să se determine arborele maximal ce conţine x0 .
Observaţia 2.2.4 Graful din exemplul 2.2.1 are două componente conexe:
C(x0 ) = {x0 , x1 , x5 , x3 , x4 }, C(x2 ) = {x2 , x6 }.
Figura 2.2:
Prin urmare
b− (1) = {1, 2, 5} .
Γ
(B)
Γ+2 (1) = Γ+ (Γ+ (1)) = Γ+ (2) = {3, 5, 6} ;
Γ+3 (1) = Γ+ (Γ+2 (1)) = Γ+ ({3, 5, 6}) = {4, 7, 1, 6} ;
Γ+4 (1) = Γ+ (Γ+3 (1)) = Γ+ ({4, 7, 1, 6}) = {3, 8, 6, 2, 7} .
Astfel
b+ (1) = {1, 2, 3, 4, 5, 6, 7, 8} şi C(1) = Γ
Γ b− (1) ∩ Γ
b+ (1) = {1, 2, 5} .
Etapa 3. Alegem vârful x3 .
(A)
Γ−2 (3) = Γ− (Γ− (3)) = Γ− ({2, 4}) = {1, 3} ;
Γ−3 (3) = Γ− (Γ−2 (3)) = Γ− ({1, 3}) = {5, 2, 4} ;
Γ−4 (3) = Γ− (Γ−3 (3)) = Γ− ({5, 2, 4}) = {2, 1, 3} .
Deci
b− (3) = {1, 2, 3, 4, 5} .
Γ
(B)
Γ+2 (3) = Γ+ (Γ+ (3)) = Γ+ ({4, 7}) = {3, 8, 6} ;
Γ+3 (3) = Γ+ (Γ+2 (3)) = Γ+ ({3, 8, 6}) = {4, 7, 8} .
Astfel
b+ (3) = {3, 4, 6, 7, 8} şi C(3) = Γ
Γ b− (3) ∩ Γ
b+ (3) = {3, 4} .
Etapa 4. Alegem vârful x6 .
(A)
Γ−2 (6) = Γ− (Γ− (6)) = Γ− ({2, 5, 7}) = {1, 2, 3, 6} ;
Γ−3 (6) = Γ− (Γ−2 (6)) = Γ− ({1, 2, 3, 6}) = {5, 1, 2, 4, 7} ;
Γ−4 (6) = Γ− (Γ−3 (6)) = Γ− ({5, 1, 2, 4, 7}) = {2, 5, 1, 3, 6} .
Deci
b− (6) = {1, 2, 3, 4, 5, 6, 7} .
Γ
(B)
Γ+2 (6) = Γ+ (Γ+ (6)) = Γ+ (7) = {6, 8} ;
Γ+3 (6) = Γ+ (Γ+2 (6)) = Γ+ ({6, 8}) = {7, 8} .
Astfel
b+ (6) = {6, 7, 8} şi C(6) = Γ
Γ b− (6) ∩ Γ
b+ (6) = {6, 7} .
2.3. DETERMINAREA COMPONENTELOR TARE CONEXE 47
În final
b+ (xk ) ∩ Γ
C(xk ) = Γ b− (xk ) .
Soluţie.
1 2 3 4 5 6 7 8
1 0 1 0 0 0 0 0 0
2 0 0 1 0 1 1 0 0
3 0 0 0 1 0 0 1 0
A= 4 0 0 1 0 0 0 0 1 .
5 1 0 0 0 0 1 0 0
6 0 0 0 0 0 0 1 0
7 0 0 0 0 0 1 0 1
8 0 0 0 0 0 0 0 1
Alegem mai ı̂ntâi vârful x8 pentru că observăm că pe linia 8 toate elementele
sunt 0 (excepţie ultimul). Prin urmare Γ b+ (x8 ) = {x8 } şi astfel C(x8 ) = {x8 }.
48 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
1 2 3 4 5 6 7
1 0 1 0 0 0 0 0
2 0 0 1 0 1 1 0
3 0 0 0 1 0 0 1
A1 = .
4 0 0 1 0 0 0 0
5 1 0 0 0 0 1 0
6 0 0 0 0 0 0 1
7 0 0 0 0 0 1 0
1 2 3 4 5 6 7
1 0 1 1 0 1 1 0
2 0 0 1 0 1 1 0
3 0 0 0 1 0 0 1
A2 = .
4 0 0 1 0 0 0 0
5 1 0 0 0 0 1 0
6 0 0 0 0 0 0 1
7 0 0 0 0 0 1 0
1 2 3 4 5 6 7
1 1 1 1 1 1 1 1
2 0 0 1 0 1 1 0
3 0 0 0 1 0 0 1
A3 = .
4 0 0 1 0 0 0 0
5 1 0 0 0 0 1 0
6 0 0 0 0 0 0 1
7 0 0 0 0 0 1 0
2.3. DETERMINAREA COMPONENTELOR TARE CONEXE 49
1 2 3 4 5 6 7
1 0 1 0 0 0 0 0
2 1 0 1 0 1 1 0
3 0 0 0 1 0 0 1
A4 = .
4 0 0 1 0 0 0 0
5 1 0 0 0 0 1 0
6 0 0 0 0 0 0 1
7 0 0 0 0 0 1 0
1 2 3 4 5 6 7
1 1 1 0 0 0 0 0
2 1 0 1 0 1 1 0
3 0 0 0 1 0 0 1
A5 = .
4 0 0 1 0 0 0 0
5 1 0 0 0 0 1 0
6 0 0 0 0 0 0 1
7 0 0 0 0 0 1 0
3 4 6 7
3 0 1 0 1
A6 = 4 1 0 0 0 .
6 0 0 0 1
7 0 0 1 0
50 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
3 4 6 7
3 1 1 1 1
A7 = 4 1 0 0 0 .
6 0 0 0 1
7 0 0 1 0
3 4 6 7
3 1 1 0 1
A8 = 4 1 0 0 0 .
6 0 0 0 1
7 0 0 1 0
Atunci Γ b− (x3 ) = {x3 , x4 } şi deci C(x3 ) = Γb+ (x3 ) ∩ Γb− (x3 ) = {x3 , x4 }.
Eliminăm din matricea A6 liniile 3, 4 şi coloanele 3, 4.
6 7
Obţinem A9 = 6 0 1 .
7 1 0
Alegem vârful x6 . Adunăm boolean linia 7 la linia 6.
6 7
Obţinem A10 = 6 1 1 .
7 1 0
Deci Γb (x6 ) = {x6 , x7 }. Revenim la matricea A9 şi adunăm boolean coloana
+
7 la coloana 6.
6 7
Obţinem A11 = 6 1 1 .
7 1 0
b −
Avem Γ (x6 ) = {x6 , x7 }. Atunci C(x6 ) = Γ b+ (x6 ) ∩ Γ
b− (x6 ) = {x6 , x7 }.
2.3. DETERMINAREA COMPONENTELOR TARE CONEXE 51
Soluţie.
1 2 3 4 5 6 7 8
1 0 1 0 0 0 0 0 0
2 0 0 1 0 1 1 0 0
3 0 0 0 1 0 0 1 0
A= 4 0 0 1 0 0 0 0 1
5 1 0 0 0 0 1 0 0
6 0 0 0 0 0 0 1 0
7 0 0 0 0 0 1 0 1
8 0 0 0 0 0 0 0 1
1 2 3 4 5 6 7 8
1 1 1 0 0 0 0 0 0
2 0 1 1 0 1 1 0 0
3 0 0 1 1 0 0 1 0
A⊕I = 4 0 0 1 1 0 0 0 1
5 1 0 0 0 1 1 0 0
6 0 0 0 0 0 1 1 0
7 0 0 0 0 0 1 1 1
8 0 0 0 0 0 0 0 1
52 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
1 2 3 4 5 6 7 8
1 1 1 1 0 1 1 0 0
2 1 1 1 1 1 1 1 0
3 0 0 1 1 0 1 1 1
(A ⊕ I)2 = 4 0 0 1 1 0 0 1 1
5 1 1 0 0 1 1 1 0
6 0 0 0 0 0 1 1 1
7 0 0 0 0 0 1 1 1
8 0 0 0 0 0 0 0 1
1 2 3 4 5 6 7 8
1 1 1 1 1 1 1 1 0
2 1 1 1 1 1 1 1 1
3 0 0 1 1 0 1 1 1
3
(A ⊕ I) = 4 0 0 1 1 0 1 1 1
5 1 1 1 0 1 1 1 1
6 0 0 0 0 0 1 1 1
7 0 0 0 0 0 1 1 1
8 0 0 0 0 0 0 0 1
1 2 3 4 5 6 7 8
1 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1
3 0 0 1 1 0 1 1 1
4
(A ⊕ I) = 4 0 0 1 1 0 1 1 1
5 1 1 1 1 1 1 1 1
6 0 0 0 0 0 1 1 1
7 0 0 0 0 0 1 1 1
8 0 0 0 0 0 0 0 1
Obţinem
3 4 6 7 8
3 1 1 1 1 1
4 1 1 1 1 1
B= .
6 0 0 1 1 1
7 0 0 1 1 1
8 0 0 0 0 1
3 4 6 7 8
3 1 1 1 1 1
4 1 1 1 1 1
Atunci B (2) =
6 0 0 1 1 1
7 0 0 1 1 1
8 0 0 0 0 1
L = x1 , x2 , x3 , L10 , x9 , x8 , L7 , x3 , x4 , x5 , x6 , x3 , x1
adică
L∗n = Ln−1 ⊗L LR ,
operaţia de multiplicare latină fiind puţin modificată, ı̂n sensul că acum vom
păstra acele cuvinte ce au un simbol comun cu condiţia ca ele să se găsească
pe diagonala princilală.
56 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
U = {(1, 2), (1, 4), (1, 5), (2, 4), (3, 1), (3, 2), (3, 5), (4, 4), (4, 5), (5, 3)} .
Soluţie. Etapele 1,2,3,4 au fost făcute ı̂n soluţia exemplului 2.1.13. Precizăm
că ı̂n etapa 4 au fost găsite tocmai drumurile hamiltoniene.
Etapa 5.
ABDECA
BDCEAB
L∗5 = CABDEC
DECABD
ECABDE
Soluţie.
2.5. DRUMURI ŞI CIRCUITE HAMILTONIENE 57
1 1 0 0 1 0 1 1 1 0 1 1
0 1 1 0 0 0 1 1 1 0 1 0
1 0 1 0 1 0 1 1 1 0 1 1
A⊕I = , (A ⊕ I)(2) =
0 1 1 1 0 1 1 1 1 1 1 1
0 0 0 0 1 1 0 0 0 0 1 1
0 0 0 0 1 1 0 0 0 0 1 1
1 1 1 0 1 1
1 1 1 0 1 1
1 1 1 0 1 1
(A ⊕ I)(3) = , C(x4 ) = {x4 }
1 1 1 1 1 1
0 0 0 0 1 1
0 0 0 0 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
B= 1 1 1 1 1 , B (2) = 1 1 1 1 1
0 0 0 1 1 0 0 0 1 1
0 0 0 1 1 0 0 0 1 1
Se găsesc componentele tare conexe C(x1 ) = {x1 , x2 , x3 } şi C(x5 ) = {x5 , x6 }.
Drumul hamiltonian este x4 , x2 , x3 , x1 , x5 , x6 .
Teorema 2.5.5 Dacă ı̂ntr-un graf orientat fără circuite există un drum
hamiltonian atunci acesta este unic.
58 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Soluţie. Etapa 1.
0 1 0 1 0 1 1 0 1 0
0 0 1 1 1 0 1 1 1 1
A= 0 0 0 0 0 , A⊕I = 0 0 1 0 0
0 0 0 0 1 0 0 0 1 1
0 0 1 0 0 0 0 1 0 1
1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 0 1 1 1 1
(A ⊕ I)(2) = 0 0 1 0 0 , (A ⊕ I)(4) = 0 0 1 0 0
0 0 1 1 1 0 0 1 1 1
0 0 1 0 1 0 0 1 0 1
2.6. DRUMURI DE VALOARE OPTIMĂ 59
0 1 1 1 1
0 0 1 1 1
D = A ⊗ (A ⊕ I)(4) = 0 0 0 0 0
0 0 1 0 1
0 0 1 0 0
Etapa 2. Observăm că ı̂n matricea D toate elementele de pe diagonala
principală sunt zero. Prin urmare graful nu are circuite şi algoritmul lui
Chen poate fi aplicat.
Etapa 3. Remarcăm că p(x1 ) = 4; p(x2 ) = 3; p(x3 ) = 0; p(x4 ) = 2;
P5
p(x5 ) = 1. Atunci p(xi ) = 10. Dar n(n−1)
2
= 5·4
2
= 10. Algoritmul lui Chen
i=1
ne spune că există un drum hamiltonian care se obţine ordonând vârfurile ı̂n
ordine descrescătoare a puterii lor de atingere: x1 , x2 , x4 , x5 , x3 .
Figura 2.3:
Soluţie.
ij 12 13 14 24 25 31 32 34 35 36 37
vij 14 10 12 8 8 7 5 4 12 2 15
tij 14 10 12 -2 8 -10 4 2 12 2 15
tij 14 10 12 -2 8 -10 4 2 12 2 15
tij 14 10 12 -2 8 -10 4 2 12 2 15
ij 41 46 56 57 58 68 78 79 87 89 93
vij 5 10 6 15 4 12 9 20 6 16 12
tij -12 0 -10 3 4 14 1 17 -1 16 -32
tij -12 0 -10 3 2 12 -1 17 1 18 -32
tij -12 0 -10 3 2 12 -1 15 1 16 -30
Tabelul marcajelor este
x1 x2 x3 x4 x5 x6 x7 x8 x9
λi 0 14 10 12 22 12 25 26 42
,
λi 0 14 10 12 22 12 25 24 42
λi 0 14 10 12 22 12 25 24 40
2.6. DRUMURI DE VALOARE OPTIMĂ 61
(m) (m−1)
Algoritmul se ı̂ncheie dacă ai = ai . In această situaţie drumurile
de valoare optimă sunt formate din acele arce (xi , xj ) ∈ U pentru care
(m) (m−1)
ai = vij + aj .
(m) (m−1)
Dacă există i astfel ı̂ncât ai 6= ai se trece la etapa m+1.
Exemplul 2.6.3 Să se determine drumurile de valoare minimă de la xi ,
(i = 1, 8), la x9 ı̂n graful valorizat din figura 2.3.
62 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Soluţie.
V 1 2 3 4 5 6 7 8 9
1 0 14 10 12 ∞ ∞ ∞ ∞ ∞
2 ∞ 0 ∞ 8 8 ∞ ∞ ∞ ∞
3 7 5 0 4 12 2 15 ∞ ∞
4 5 ∞ ∞ 0 ∞ 10 ∞ ∞ ∞
5 ∞ ∞ ∞ ∞ 0 6 15 4 ∞
6 ∞ ∞ ∞ ∞ ∞ 0 ∞ 12 ∞
7 ∞ ∞ ∞ ∞ ∞ ∞ 0 9 20
8 ∞ ∞ ∞ ∞ ∞ ∞ 6 0 16
9 ∞ ∞ 12 ∞ ∞ ∞ ∞ ∞ 0
(1)
ai ∞ ∞ ∞ ∞ ∞ ∞ 20 16 0
(2)
ai ∞ ∞ 35 ∞ 20 28 20 16 0
(3)
ai 45 28 30 38 20 28 20 16 0
(4)
ai 40 28 30 38 20 28 20 16 0
(5)
ai 40 28 30 38 20 28 20 16 0
In concluzie:
µ(x1 , x9 ) = (1, 3, 6, 8, 9) , v(µ(x1 , x9 )) = 40;
µ(x2 , x9 ) = (2, 5, 8, 9) , v(µ(x2 , x9 )) = 28;
µ(x3 , x9 ) = (3, 6, 8, 9) , v(µ(x3 , x9 )) = 30;
µ(x4 , x9 ) = (4, 6, 8, 9) , v(µ(x4 , x9 )) = 38;
µ(x5 , x9 ) = (5, 8, 9) , v(µ(x5 , x9 )) = 20;
µ(x6 , x9 ) = (6, 8, 9) , v(µ(x6 , x9 )) = 28;
µ(x7 , x9 ) = (7, 9) , v(µ(x7 , x9 )) = 20;
µ(x8 , x9 ) = (8, 9) , v(µ(x8 , x9 )) = 16.
Etapa 2. R := R ∪ {x} .
Etapa 3. Pentru fiecare y ∈ X \ R cu proprietatea (x, y) ∈ U executăm:
Dacă d(y) > d(x) + v(x, y) atunci punem d(y) := d(x) + v(x, y) şi P (y) = x.
În caz contrar d(y) şi P (y) rămân neschimbate.
Etapa 4. Dacă R 6= X se trece la etapa 1. Dacă R = X algoritmul s-a
ı̂ncheiat.
Figura 2.4:
64 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Soluţie.
Iteraţia 0 1 2 3 4 5 6
R := R ∪ {x} ∅ {x1 } {x2 } {x5 } {x3 } {x6 } {x4 }
d(x2 )/P (x2 ) ∞/− 3/x1 3/x1 3/x1 3/x1 3/x1 3/x1
d(x3 )/P (x3 ) ∞/− ∞/− 14/x2 12/x5 12/x5 12/x5 12/x5
d(x4 )/P (x4 ) ∞/− ∞/− ∞/− 23/x5 23/x5 23/x5 23/x5
d(x5 )/P (x5 ) ∞/− ∞/− 8/x2 8/x2 8/x2 8/x2 8/x2
d(x6 )/P (x6 ) ∞/− 28/x1 23/x2 23/x2 18/x3 18/x3 18/x3
R = R ∪ {x3 } = {x1 , x2 , x5 , x3 } .
2.6. DRUMURI DE VALOARE OPTIMĂ 65
Cum
23 = d(x4 ) < d(x3 ) + v(x3 , x4 ) = 12 + 15 = 27 ,
d(x4 ) şi P (x4 ) rămân neschimbate. Dar
0 3 14 29 8 20 ∅ 1 2 3 2 3
∞ 0 11 26 5 17 ∅ ∅ 2 3 2 3
∞ 6 0 15 11 6 ∅ 3 ∅ 3 2 3
V = T4 (V ) =
, P =
∞ 9 3 0 8 9 ∅ 3 4 ∅ 4 3
∞ 10 4 15 0 10 ∅ 3 5 5 ∅ 3
∞ ∞ ∞ ∞ ∞ 0 ∅ ∅ ∅ ∅ ∅ ∅
0 3 12 23 8 18 ∅ 1 5 5 2 3
∞ 0 9 20 5 15 ∅ ∅ 5 5 2 3
∞ 6 0 15 11 6 ∅ 3 ∅ 3 2 3
V = T5 (V ) =
, P =
∞ 9 3 0 8 9 ∅ 3 4 ∅ 4 3
∞ 10 4 15 0 10 ∅ 3 5 5 ∅ 3
∞ ∞ ∞ ∞ ∞ 0 ∅ ∅ ∅ ∅ ∅ ∅
0 3 12 23 8 18 ∅ 1 5 5 2 3
∞ 0 9 20 5 15 ∅ ∅ 5 5 2 3
∞ 6 0 15 11 6 ∅ 3 ∅ 3 2 3
V = T6 (V ) =
, P =
∞ 9 3 0 8 9 ∅ 3 4 ∅ 4 3
∞ 10 4 15 0 10 ∅ 3 5 5 ∅ 3
∞ ∞ ∞ ∞ ∞ 0 ∅ ∅ ∅ ∅ ∅ ∅
În concluzie: cum p41 = ∅ ı̂nseamnă că nu există drum din x4 ı̂n x1 .
Dacă suntem interesaţi de un drum de valoare minimă din x1 ı̂n x6 , cum
v16 = 18 avem că valoarea acestuia este 18. Apoi p16 = 3 ı̂nseamnă că
predecesorul lui x6 este x3 . Cum p13 = 5 avem că predecesorul lui x3 este
x5 . Dar p15 = 2 şi deci predecesorul lui x5 este x2 . Apoi p12 = 1 ne spune că
predecesorul lui x2 este x1 . Prin urmare drumul este µ = (x1 , x2 , x5 , x3 , x6 ).
Apoi v42 = 9 ne spune că valoarea minimă a unui drum din x4 ı̂n x2 este
9. Pentru a găsi acest drum observăm că p42 = 3, adică predecesorul lui x2
este x3 . Cum p43 = 4 avem că predecesorul lui x3 este x4 . Deci drumul este
µ = (x4 , x3 , x2 ).
Alegem muchia (x3 , x6 ). Cum vârfurile terminale ale acestei muchii aparţin
aceluiaşi arbore se trece la muchia următoare (x1 , x3 ) care va fi adăugată la
A. Deci
Alegem muchia (x2 , x4 ). Vârfurile terminale ale acestei muchii aparţin aceluiaşi
arbore. Trecem la următoarea muchie. Alegem muchia (x7 , x9 ). Vârfurile
terminale ale acestei muchii aparţin la arbori diferiţi. Se adaugă această
muchie la A. Obţinem
Figura 2.5:
70 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Exemplul 2.8.1 În figura 2.6 este considerată o reţea de transport. Vârful
x0 este intrarea reţelei iar vârful x10 este ieşirea reţelei. Capacitatea fiecărui
arc este trecută ı̂n chenar. Să se determine fluxul maxim aplicând algoritmul
Ford-Fulkerson.
Soluţie. A) Presupunem mai ı̂ntâi că f (x, y) = 0, (∀)x, y ∈ X. În această
situaţie reţeaua reziduală Gf coincide cu reţeaua iniţială.
B) Căutăm un drum rezidual ı̂n Gf . Marcăm intrarea reţelei cu +.
Atunci vârful x1 va putea fi marcat cu +0 . Plecând de la vârful x1 , vârful
x2 va putea fi marcat cu +1 . Apoi x5 va fi marcat cu +2 , vârful x8
va fi marcat cu +5 şi vârful x10 va fi marcat cu +8 . Obţinem drumul
rezidual µ1 = (x0 , x1 , x2 , x5 , x8 , x10 ) care are capacitatea reziduală
cf (µ1 ) = min{12, 8, 14, 13, 12} = 8. Prin urmare mărim fluxul cu 8
unităţi pe arcele din care este format acest drum şi ı̂l lăsăm neschimbat ı̂n
rest.
C) În mod similar găsim drumul rezidual µ2 = (x0 , x1 , x4 , x5 , x7 , x10 ) care
72 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Figura 2.6:
1.2. Se scade din fiecare coloană cel mai mic element. Mai precis, pentru
j = 1, n, se scade din elementele coloanei ”j” elementul
4.2. Se determină
θkl = max{θij } .
4.3. Se asociază lui E două noduri: Ekl şi E kl . Vom pune
Etapa 5. Dacă s-a obţinut o matrice de tipul (1, 1) algoritmul s-a ı̂ncheiat.
În caz contrar ramificarea se continuă din acel nod cu marginea cea mai mică.
În cazul mai multor noduri se alege un nod de tip Ekl .
Dacă s-a ales un nod de tip Ekl se trece la etapa 4.
Dacă s-a ales un nod de tip E kl atunci pentru a evita afectarea (k, l) se pune
ı̂n matricea nodului precedent tkl = ∞ şi se trece la etapa 4.
2.9. PROBLEME DE AFECTARE 75
Exemplul 2.9.1 Să se rezolve problema de afectare (minim) ı̂n care ma-
tricea timpilor este:
1 2 3 4 5 6 7
1 10 1 3 1 5 1 1
2 ∞ 2 5 3 0 ∞ 8
3 11 8 ∞ ∞ 5 9 5
T =
4 5 11 3 3 6 9 ∞
5 ∞ 7 4 9 ∞ 4 4
6 11 8 7 ∞ ∞ 3 2
7 9 ∞ 12 9 5 10 8
Soluţie. Precizăm mai ı̂ntâi că anumite elemente ale matricei T sunt egale
cu ∞, ceea ce ı̂nseamnă că pe o anumită maşină nu poate fi executată o
anumită lucrare. De exemplu t21 = ∞ ne spune că maşina M2 nu poate
executa lucrarea L1 .
Scădem din fiecare linie cel mai mic element. Acestea sunt ı̂n ordine 1, 0, 5, 3,
4, 2, 5. Obţinem
1 2 3 4 5 6 7
1 9 0 2 0 4 0 0
2 ∞ 2 5 3 0 ∞ 8
3 6 3 ∞ ∞ 0 4 0
T =
4 2 8 0 0 3 6 ∞
5 ∞ 3 0 5 ∞ 0 0
6 9 6 5 ∞ ∞ 1 0
7 4 ∞ 7 4 0 5 4
Scădem din fiecare coloană cel mai mic element. Prin urmare din coloana
ı̂ntâi va trebui să scădem 2
1 2 3 4 5 6 7
1 7 0 2 0 4 0 0
2 ∞ 2 5 3 0 ∞ 8
3 4 3 ∞ ∞ 0 4 0
TR =
4 0 8 0 0 3 6 ∞
5 ∞ 3 0 5 ∞ 0 0
6 7 6 5 ∞ ∞ 1 0
7 2 ∞ 7 4 0 5 4
76 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
h = 1 + 5 + 3 + 4 + 2 + 5 + 2 = 22 .
1 3 4 5 6 7
2 ∞ 5 3 0 ∞ 8
3 4 ∞ ∞ 0 4 0
T (E12 ) = 4 0 0 0 3 6 ∞
5 ∞ 0 5 ∞ 0 0
6 7 5 ∞ ∞ 1 0
7 2 7 4 0 5 4
Scădem din fiecare linie cel mai mic element şi apoi din fiecare coloană
cel mai mic element. Observăm că TR (E12 ) = T (E12 ) şi h12 = 0. Deci
ω(E12 ) = ω(E) + h12 = 22 + 0 = 22. Continuăm ramificarea din nodul E12 .
θ25 = 3, θ35 = 0, θ37 = 0, θ41 = 2, θ42 = 0, θ43 = 3, θ53 = 0, θ56 = 1,
θ57 = 0, θ67 = 1, θ75 = 2. Fie θ25 = max{θij }. Alegem afectarea (2, 5).
Avem ω(E 25 ) = ω(E12 ) + θ25 = 22 + 3 = 25. Tăiem linia 2 şi coloana 5.
Obţinem:
1 3 4 6 7
3 4 ∞ ∞ 4 0
4 0 0 0 6 ∞
T (E25 ) =
5 ∞ 0 5 0 0
6 7 5 ∞ 1 0
7 2 7 4 5 4
2.9. PROBLEME DE AFECTARE 77
1 3 4 6 7
3 4 ∞ ∞ 4 0
4 0 0 0 6 ∞
TR (E25 ) =
5 ∞ 0 5 0 0
6 7 5 ∞ 1 0
7 0 5 2 3 2
Prin urmare trebuie să continuăm din nodul E 12 . Atunci pentru a nu alege
afectarea (1, 2) revenim la matricea TR şi elementul t12 = 0 ı̂l punem t12 = ∞.
Obţinem şi matricea redusă scăzând 2 din coloana a doua.
1 2 3 4 5 6 7
1 7 ∞ 2 0 4 0 0
2 ∞ 0 5 3 0 ∞ 8
3 4 1 ∞ ∞ 0 4 0
TR =
4 0 6 0 0 3 6 ∞
5 ∞ 1 0 5 ∞ 0 0
6 7 4 5 ∞ ∞ 1 0
7 2 ∞ 7 4 0 5 4
2 3 4 6 7
1 ∞ 2 0 0 0
2 0 5 3 ∞ 8
T (E75 ) =
3 1 ∞ ∞ 4 0
5 1 0 5 0 0
6 4 5 ∞ 1 0
3 4 6 7
1 2 0 0 0
T (E22 ) = 3 ∞ ∞ 4 0
5 0 5 0 0
6 5 ∞ 1 0
Exemplul 2.9.3 Să se rezolve problema de afectare (maxim) ı̂n care ma-
tricea timpilor este:
1 2 3 4 5
1 16 50 20 25 35
2 26 20 35 50 5
T =
3 30 50 5 0 25
4 16 10 45 10 35
5 6 35 30 50 5
Soluţie. Maximul fiecărei coloane este: 30, 50, 45, 50, 35. Scădem elementele
fiecărei coloane din maximul lor. Obţinem:
1 2 3 4 5
1 14 0 25 25 0
2 4 30 10 0 30
T =
3 0 0 40 50 10
4 14 40 0 40 0
5 24 15 15 0 30
2.9. PROBLEME DE AFECTARE 83
1 2 3 5
1 14 0 25 0
T (E54 ) = 2 4 30 10 30
3 0 0 40 10
4 14 40 0 0
Continuăm ramificarea din nodul E43 . Avem θ12 = 0, θ15 = 10, θ32 = 10.
Alegem θ15 = max{θij }. Astfel avem afectarea (1, 5) şi
max{tij } + 1.
D1 D2 D3 D4
B1 3 1 5 7
B2 1 4 2 6
B3 2 3 3 1
Să se determine afectarea optimă astfel ı̂ncât costul total de transport să fie
minim.
1 2 3 4
1 3 1 5 7
T = 2 1 4 2 6
3 2 3 3 1
4 8 8 8 8
Avem h = 11 şi
1 2 3 4
1 2 0 4 6
TR = 2 0 3 1 5
3 1 2 2 0
4 0 0 0 0
86 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
1 3 4
2 0 1 5
T (E12 ) =
3 1 2 0
4 0 0 0
3 4
TR (E21 ) = 3 2 0
4 0 0
2.9. PROBLEME DE AFECTARE 87
Observăm că θ34 = 2, θ43 = 2, θ44 = 0. Alegem θ34 = max{θij }. Deci avem
afectarea (3, 4).
ω(E 34 ) = ω(E21 ) + θ34 = 11 + 2 = 13 .
Tăiem linia 3 şi coloana 4. Obţinem
3
TR (E34 ) =
4 0
Deci h34 = 0 şi ω(E34 ) = ω(E21 ) + h34 = 11 + 0 = 11. Am ajuns la o matrice
1 × 1. Alegem afectarea (4, 3) şi algoritmul s-a ı̂ncheiat.
Observaţia 2.9.6 Algoritmul lui Little poate fi folosit pentru determinarea
circuitelor hamiltoniene de valoare optimă. Dacă se doreşte aflarea cir-
cuitelor hamiltoniene de valoare minimă se scrie matricea timpilor T = (tij )
punând ½
vij , dacă (xi , xj ) ∈ U şi i 6= j
tij = .
∞, ı̂n rest
Dacă s-a stabilit afectarea (i, j) ı̂n iteraţia următoare se pune tji = ∞ pentru
a evita circuitul (xi , xj , xi ).
Exemplul 2.9.7 Să se determine circuitul hamiltonian de valoare minimă
ı̂n următorul graf valorizat:
ij 12 13 14 21 23 24 31 32 34 41 42 43
vij 9 10 4 6 1 6 7 4 1 5 4 6
Soluţie. Avem matricea
1 2 3 4
1 ∞ 9 10 4 4
T = 2 6 ∞ 1 6 1
3 7 4 ∞ 1 1
4 5 4 6 ∞ 4
Din fiecare linie vom scădea cantitatea pe care am trecut-o ı̂n marginea
dreaptă a tabelului.
1 2 3 4
1 ∞ 5 6 0
T = 2 5 ∞ 0 5
3 6 3 ∞ 0
4 1 0 2 ∞
88 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
1 2 3 4
1 ∞ 5 6 0
TR = 2 4 ∞ 0 5 .
3 5 3 ∞ 0
4 0 0 2 ∞
1 2 4
1 ∞ 5 0
T (E23 ) =
3 5 3 0
4 0 0 ∞
1 2
T (E14 ) = 3 5 ∞
4 ∞ 0
1 2
TR (E14 ) = 3 0 ∞ .
4 ∞ 0
Observăm că θ31 = ∞, θ42 = ∞. Alegem θ31 = max{θij }. Prin urmare avem
afectarea (3, 1) şi
ω(E 31 ) = ω(E14 ) + θ31 = ∞ .
Tăiem linia 3 şi coloana 1. Obţinem
2
T (E31 ) =
4 0
şi h31 = 0. Deci ω(E31 ) = 16. S-a ajuns la o matrice 1 × 1. Alegem afectarea
(4, 2) şi algoritmul s-a ı̂ncheiat.
Prin urmare afectarea optimă este {(2, 3), (1, 4), (3, 1), (4, 2)} şi circuitul hamil-
tonian de valoare minimă este (2, 3, 1, 4, 2), valoarea acestuia fiind 16.
Etapa 1.
1.1. Se ı̂ncadrează un zero de pe o linie cu cele mai puţine zerouri.
1.2. Se taie celelalte zerouri de pe linia şi coloana zeroului ı̂ncadrat.
1.3. Repetăm operaţia până când toate zerourile au fost ı̂ncadrate sau tăiate.
1.4. Dacă se obţine câte un zero ı̂ncadrat pe fiecare linie şi pe fiecare coloană
atunci am obţinut soluţia optimă. În caz contrar se trece la etapa următoare.
Etapa 2.
2.1. Marcăm liniile care nu conţin zerouri ı̂ncadrate şi coloanele care au
zerouri tăiate pe liniile marcate.
2.2. Marcăm liniile cu zero ı̂ncadrat pe coloanele marcate.
2.3. Tăiem liniile nemarcate şi coloanele marcate.
2.4. Fie θ cel mai mic element netăiat. Adunăm θ la elementle dublu tăite şi
ı̂l scădem din elementele netăite lăsând elementele simplu tăiate neschimbate.
Cu matricea obţinută se reia etapa 1.
Soluţie. Aşa cum am văzut ı̂n soluţia exemplului 2.9.1. matricea redusă este
2.9. PROBLEME DE AFECTARE 91
Apoi
sau
t−
i - momentul cel mai devreme al ı̂nceperii activităţii
t+
i - momentul cel mai devreme al terminării activităţii
Ti− - momentul cel mai târziu al ı̂nceperii activităţii
Ti+ - momentul cel mai târziu al terminării activităţii
Aceste date se pun sub forma
2.10. PROBLEME DE ORDONANŢARE 93
t−
i Ai t+
i
Ti− di Ti+
Evident t+ − + −
i = ti + di , Ti = Ti + di . Pentru activitatea iniţială se consideră
t−
0 = 0. Apoi
t−
j = max (t+ +
i + tij ) ; Ti = min (Tj− − tij ) .
j|(Ai ,Aj )∈U j|(Ai ,Aj )∈U
+
Pentru activitatea finală se consideră Tn+1 = t+
n+1 . Pentru fiecare activitate
se defineşte rezerva de timp a acesteia
Ri = Ti− − t−
i .
Pentru proiectul din exemplul precedent, diagrama Gantt ı̂n care activităţile
ı̂ncep la momentele cele mai devreme este:
Pentru proiectul din exemplul precedent, diagrama Gantt ı̂n care activităţile
ı̂ncep la momentele cele mai târzii este:
0 1 2 3 4 5 6
0 0 0 −∞ 0 −∞ −∞ −∞
1 −∞ 0 −∞ −∞ 5 −∞ −∞
2 −∞ −∞ 0 −∞ 2 2 −∞
Soluţie. A =
3 −∞ −∞ 4 0 −∞ 4 −∞
4 −∞ −∞ −∞ −∞ 0 −∞ 3
5 −∞ −∞ −∞ −∞ −∞ 0 6
6 −∞ −∞ −∞ −∞ −∞ −∞ 0
T0 = [0, −∞, −∞, −∞, −∞, −∞, −∞]
T2 = T1 ⊗ A = [0, 0, 4, 0, 5, 4, −∞]
T3 = T2 ⊗ A = [0, 0, 4, 0, 6, 6, 10]
T4 = T3 ⊗ A = [0, 0, 4, 0, 6, 6, 12]
T5 = T4 ⊗ A = [0, 0, 4, 0, 6, 6, 12]
În concluzie t− − − − −
1 = 0, t2 = 4, t3 = 0, t4 = 6, t5 = 6.
2.11. EXERCIŢII 97
2.11 Exerciţii
Exerciţiul 2.11.1 Se consideră graful orientat G = (X, U ) unde
X = {1, 2, 3, 4, 5, 6} şi U = {(1, 2), (1, 4), (2, 1), (2, 3), (2, 4), (3, 2), (3, 4),
(3, 6), (4, 1), (4, 3), (4, 5), (5, 3), (5, 4), (5, 6), (6, 3), (6, 5)}.
Determinaţi matricea drumurilor aplicând:
a) algoritmul lui Roy-Warshall;
b) metoda compunerii booleene;
c) algoritmul lui Chen.
(3, 6), (4, 1), (4, 5), (4, 7), (5, 7), (6, 3), (6, 2), (7, 5)} aplicând:
a) Algoritmul lui Malgrange;
b) Algoritmul lui Chen;
c) Algoritmul lui Foulkes.
Exerciţiul 2.11.7 Să se precizeze dacă graful din exerciţiul 2.11.2 este
eulerian.
Exerciţiul 2.11.8 Să se determine un ciclu eulerian pentru graful din figura
de mai jos
b)
ij 12 13 14 23 25 28 31 34 36 41 45 47
vij 8 9 7 4 6 4 6 3 2 5 5 5
ij 52 57 59 64 67 68 74 78 79 86 87 89
vij 3 10 8 7 6 5 8 7 4 9 8 9
a) Aplicând algoritmul Ford să se determine drumurile de valoare minimă de
la x1 la xi (i = 2, 9);
b) Aplicând algoritmul Bellman-Kalaba să se determine drumurile de va-
loare minimă de la xi la x9 (i = 1, 8);
c) Aplicând algoritmul lui Dijkstra să se determine drumurile de valoare
minimă de la x1 la xi (i = 2, 9);
d) Aplicând algoritmul Floyd-Warshall să se determine drumurile de va-
loare minimă ı̂ntre toate perechile de vârfuri precum şi valorile acestora.
100 CAPITOLUL 2. ALGORITMI PENTRU GRAFURI
Exerciţiul 2.11.15 În figura de mai jos este considerată o reţea de trans-
port. Să se determine fluxul maxim aplicând algoritmul Ford-Fulkerson.
Exerciţiul 2.11.16 Să se rezolve problema de afectare (minim) ı̂n care ma-
tricea timpilor este
4 9 64 169 225
361 400 1 36 64
T = 225 256 441 4 16
484 529 16 81 121
196 225 500 1 9
Exerciţiul 2.11.17 Să se rezolve problema de afectare (minim) ı̂n care ma-
tricea timpilor este
ij 12 13 14 15 21 23 24 25 31 32 34 35
vij 2 5 6 4 3 7 6 1 5 4 3 6
ij 41 42 43 45 51 52 53 54
vij 2 5 7 1 6 3 2 5
Exerciţiul 2.11.19 Se consideră proiectul
ij 12 16 23 25 32 34 36 43 45 53 54 56 26
.
vij 4 20 10 5 2 22 6 2 8 4 15 12 16
ij 12 14 21 23 24 32 34 36
vij 3 5 2 4 1 2 1 1
ij 41 43 45 53 54 56 63 65
vij 1 2 2 1 3 2 2 3
a) Aplicând algoritmul Ford să se determine drumurile de valoare minimă de
la x1 la xi (i = 2, 6);
2.11. EXERCIŢII 105
Aplicaţii
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,a[20][20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++)
a[v[i].x][v[i].y]=1;
cout<<”Matricea de adiacenţă”<<endl;
106
3.1. REPREZENTAREA GRAFURILOR 107
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,k,a[20][20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
k=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]==1) {
k++;
v[k].x=i;
v[k].y=j;
}
cout<<”Graful are ”<<n<<” vârfuri”<<endl;
cout<<”Mulţimea arcelor ”;
for(i=1;i<=k;i++)
cout<<”(”<<v[i].x<<”,”<<v[i].y<<”) ”;
getch();
}
108 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,a[20][20],e,k,p[20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++)
a[v[i].x][v[i].y]=1;
cout<<endl;
for(i=1;i<=n;i++) {
cout<<”Nodul ”<<i<<endl;
e=0;
k=0;
for(j=1;j<=n;j++)
if(a[j][i]==1) {
e=1;
k++;
p[k]=j; }
if(e==0) cout<<”Nu are predecesori”<<endl;
else {
cout<<”Predecesorii sunt ”;
for(j=1;j<=k;j++)
cout<<p[j]<<” ”;
cout<<endl;
3.1. REPREZENTAREA GRAFURILOR 109
}
e=0;k=0;
for(j=1;j<=n;j++)
if(a[i][j]==1) {
e=1; k++;
p[k]=j; }
if(e==0) cout<<”Nu are succesori”<<endl;
else {
cout<<”Succesorii sunt ”;
for(j=1;j<=k;j++)
cout<<p[j]<<” ”;
cout<<endl; }
}
getch();
}
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,x,a[20][20],d1,d2;
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
cout<<”Daţi nodul x ”; cin>>x;
d1=d2=0;
for(i=1;i<=n;i++) {
if(a[i][x]==1) d1++;
if(a[x][i]==1) d2++; }
cout<<”Gradul nodului ”<<x<<” este ”<<d1+d2;
110 CAPITOLUL 3. APLICAŢII
getch();
}
Problema 3.1.5 Să se determine mulţimea vârfurilor izolate pentru un graf
orientat, reprezentat prin matricea sa de adiacenţă.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,a[20][20],d1,d2,e;
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
cout<<”Mulţimea vârfurilor izolate este ”;
e=0;
for(j=1;j<=n;j++) {
d1=d2=0;
for(i=1;i<=n;i++) {
if(a[i][j]==1)
d1++;
if(a[j][i]==1)
d2++; }
if(d1+d2==0) {
e=1;
cout<<j<<” ”;
}
}
if(e==0) cout<<”vidă”;
getch();
}
Problema 3.1.6 Fiind date numărul n de vârfuri şi mulţimea arcelor pentru
un graf orientat, se cere să se scrie un program care construieşte matricea
”arce-vârfuri” asociată grafului.
3.1. REPREZENTAREA GRAFURILOR 111
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,a[20][20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
a[i][j]=0;
for(i=1;i<=m;i++) {
a[v[i].x][i]=1;
a[v[i].y][i]=-1; }
cout<<”Matricea arce-vârfuri”<<endl;
for(i=1;i<=n;i++) {
for(j=1;j<=m;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int n,m,i,j,a[20][20];
112 CAPITOLUL 3. APLICAŢII
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de muchii ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile muchiei ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++) {
a[v[i].x][v[i].y]=1;
a[v[i].y][v[i].x]=1; }
cout<<”Matricea de adiacenţă”<<endl;
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
Problema 3.1.8 Fiind dată o matrice binară de dimensiune n × n, cu ele-
mente din mulţimea {0, 1}, se cere să se determine, cu ajutorul unui program,
dacă ea reprezintă matricea de adiacenţă asociată unui graf orientat sau ne-
orientat.
#include <iostream.h>
#include <conio.h>
void main( ) {
int n,i,j,k,a[20][20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
do {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
}while((a[i][j]!=0)&&(a[i][j]!=1));
k=0;
for(i=1;i<n;i++)
3.1. REPREZENTAREA GRAFURILOR 113
for(j=i+1;j<=n;j++)
if(a[i][j]!=a[j][i]) k=1;
if(k==0) cout<<”Reprezintă un graf neorientat”;
else cout<<”Reprezintă un graf orientat”;
getch();
}
Problema 3.1.9 Pentru un graf orientat cunoaştem numărul de vârfuri,
numărul de arce şi pentru fiecare arc o valoare. Să se scrie un program care
determină matricea asociată grafului valorizat dat.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
float v;
}v[20];
int n,m,i,j,a[20][20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y;
cout<<”Valoarea arcului ”<<i<<” ”;
cin>>v[i].v; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++)
a[v[i].x][v[i].y]=v[i].v;
cout<<”Reprezentarea grafului valorizat”<<endl;
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
114 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
float v;
}v[20];
int n,m,i,j,a[20][20];
clrscr();
cout<<”Numar de varfuri ”; cin>>n;
cout<<”Numar de muchii ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremitatile muchiei ”<<i<<” ”;
cin>>v[i].x>>v[i].y;
cout<<”Valoarea muchiei ”<<i<<” ”;
cin>>v[i].v; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++) {
a[v[i].x][v[i].y]=v[i].v;
a[v[i].y][v[i].x]=v[i],v; }
cout<<”Reprezentarea grafului valorizat”<<endl;
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
scrie un program care permite adăugarea şi ştergerea muchiilor ı̂ntr-un graf
neorientat. Memorarea grafului se va realiza cu ajutorul listelor de adiacenţă.
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
struct nodlvadiac {
int nr;
nodlvadiac *urm; };
struct nodlladiac {
int vf;
nodlvadiac *prim;
nodlladiac *urm; };
nodlladiac *cap=NULL;
void insert(int i,int j) {
nodlladiac *p;
nodlvadiac *q;
for(p=cap;p;p=p->urm)
if(p->vf==i) {
q=new nodlvadiac;
q->urm=p->prim;
q->nr=j;
p->prim=q;
return; }
p=cap;
cap=new nodlladiac;
cap->urm=p;
cap->vf=i;
cap->prim=NULL;
insert(i,j);
}
int sterge(int i,int j) {
nodlladiac *p;
nodlvadiac *q,*s;
for(p=cap;p;p=p->urm)
if(p->vf==i) {
if(p->prim->nr==j) {
q=p->prim->urm;
116 CAPITOLUL 3. APLICAŢII
delete p->prim;
p->prim=q;
return 0; }
else for(q=p->prim;s=q->urm;q=q->urm)
if(s->nr==j) {
q->urm=q->urm->urm;
delete s;
return 0; }
return -1; }
return -1;
}
void listare() {
nodlladiac *p;
nodlvadiac *q;
for(p=cap;p;p=p->urm) {
cout<<endl<<p->vf<<”:”;
for(q=p->prim;q;q=q->urm) cout<<q->nr<<” ”; }
}
void main() {
int i,j;
char c;
clrscr();
do{ cout<<”\n[I]ntroducere muchie || [S]tergere muchie || [E]xit ”;
cin>>c;
switch(c|32) {
case ’i’:cout<<”Introduceţi capetele muchiei inserate: ”;
cin>>i>>j;
insert(i,j);
insert(j,i);
break;
case ’s’:cout<<”Introduceţi capetele muchiei şterse: ”;
cin>>i>>j;
if(sterge(i,j)==-1) cout<<”\n Nu s-a putut face ştergerea”<<endl;
sterge(j,i); }
listare();
}while(c-’e’);
getch();
}
3.1. REPREZENTAREA GRAFURILOR 117
#include <stdio.h>
#include <conio.h>
int r[30][30],n,i,j,b;
void main() {
clrscr();
printf(”Daţi numărul de persoane ”); scanf(”%d”,&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
printf(”Relaţia dintre %d şi %d ”,i,j);
scanf(”%d”,&r[i][j]); }
i=1;
for(j=1;j<=n;j++)
if(r[j][i]==0) i=j;
b=1;
for(j=1;j<=n;j++)
if((r[j][i]==0) || r[i][j]==1)&& i!=j) b=0;
if(b) printf(”Persoana %d e celebritate ”,i);
else printf(”Nu există celebritate”);
getch();
}
Problema 3.1.13 Fiind dat un număr natural n, scrieţi un program care
să genereze toate grafurile neorientate cu n vârfuri. Să se afişeze şi numărul
de soluţii obţinut.
#include <iostream.h>
#include <conio.h>
118 CAPITOLUL 3. APLICAŢII
int st[20],a[20][20],n,nrsol=0;
int tipar() {
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
nrsol++;
k=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
k++;
a[i][j]=st[k];
a[j][i]=a[i][j]; }
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
cout<<endl;
return n; }
void back(int p) {
int i;
for(i=0;i<=1;i++) {
st[p]=i;
if(p==(n*(n-1))/2) tipar();
else back(p+1); }
}
void main() {
clrscr();
cout<<”Număr de vârfuri=”; cin>>n;
back(1);
cout<<nrsol;
getch();
}
Problema 3.1.14 În fişierul text graf.txt este scrisă o matrice, astfel: pe
primul rând două numere naturale separate prin spaţiu, care reprezintă
numărul de linii şi numărul de coloane ale matricei, şi, pe următoarele rânduri
valori numerice despărţite prin spaţiu, care reprezintă elementele de pe câte
3.1. REPREZENTAREA GRAFURILOR 119
o linie a matricei. Scrieţi un program care să verifice dacă această matrice
poate fi matricea de adiacenţă a unui graf neorientat.
#include <fstream.h>
#include <stdio.h>
void main() {
int a[20][20],n,m,i,j,k,s,ok,ok1,ok2;
fstream f(”graf.txt”,ios::in);
f>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
f>>a[i][j];
clrscr();
ok=1;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if ((a[i][j]!=0)||(a[i][j]!=1)) ok=0;
ok1=1;
for(j=1;j<=m;j++) {
s=0;
for(i=1;i<=n;i++)
s=s+a[i][j];
if (s!=2) ok1=0; }
ok2=1;
for(j=1;j<m;j++)
for(k=j+1;k<=m;k++)
for(i=1;i<=n;i++)
if(a[i][j]==a[i][k]) ok2=0;
if (ok && ok1 && ok2) cout<<”Matricea de adiacenţă a unui graf neorien-
tat”;
else cout<<”Matricea nu poate fi asociată unui graf neorientat”;
f.close();
getch();
}
120 CAPITOLUL 3. APLICAŢII
Figura 3.1:
#include <iostream.h>
#include <conio.h>
void main() {
int a[20][20],c[20],v[20],i,j,k,p,u,n,z,x;
clrscr();
cout<<”Număr de vârfuri ”;
cin>>n;
for(i=1;i<=n;i++)
122 CAPITOLUL 3. APLICAŢII
a[i][i]=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
cout<<”Primul nod ”; cin>>x;
for(k=1;k<=n;k++) {
c[k]=0;
v[k]=0; }
p=u=1;
c[p]=x;
v[x]=1;
while(p<=u) {
z=c[p];
for(k=1;k<=n;k++)
if((a[z][k]==1)&&(v[k]==0)) {
u++;
c[u]=k;
v[k]=1; }
p++; }
for(k=1;k<p;k++)
cout<<c[k]<<” ”;
getch();
}
Figura 3.2:
a[i][j]=0;
for(k=1;k<=m;k++) {
cout<<”Extremităţi ”;
cin>>x>>y;
a[x][y]=1;
a[y][x]=1; }
for(i=1;i<=n;i++) {
v[i]=0;
urm[i]=0; }
cout<<”Vârf iniţial ”;
cin>>x;
cout<<”Parcurgere ı̂n adâncime ”<<endl;
cout<<x<<” ”;
v[x]=1;
p=1;
st[p]=x;
while (p>0) {
t=st[p];
k=urm[t]+1;
while ((k<=n)&& ((a[t][k]==0) || ((a[t][k]==1)&& (v[k]==1))))
k++;
urm[t]=k;
if (k==n+1) p- -;
else {
cout<<k<<” ”;
v[k]=1;
p++;
st[p]=k;
}
}
getch();
}
ı̂n aşa fel ı̂ncât, pentru orice elemente x, y cu proprietatea că xRy, elementul
x să apară afişat ı̂naintea lui y.
Exemplul 3.2.3 Pentru fişierul de intrare
56
121314242343
se va afişa
Există posibilitatea sortării topologice
12435
Redefinim problema ı̂n termeni din teoria grafurilor. Dacă elementele mulţimii
sunt considerate drept vârfuri şi relaţiile de precedenţă drept arce, se formează
ı̂n acest mod un graf orientat. Problema are soluţii numai dacă graful nu
are circuite (ı̂n caz contrar un vârf ar trebui afişat ı̂naintea lui ı̂nsuşi), ceea
ce ı̂nseamnă că există cel puţin un vârf ı̂n care nu ajunge niciun arc, deci
ı̂naintea căruia nu se află niciun alt vârf. Acest vârf va fi afişat primul iar
apoi va fi ”şters” din graf, reducând problema la n − 1 vârfuri. Ştergerea
se face prin marcarea vârfului găsit ca inexistent şi decrementarea gradelor
tuturor vârfurilor care trebuie afişate după el.
#include <stdio.h>
#include <mem.h>
#include <conio.h>
int sortare(void);
int solutii(void);
int i,j,a[30][30],l[30][30],m,n,k,ind[20];
void main(void) {
clrscr();
FILE*f;
f=fopen(”toposort.in”,”r”);
fscanf(f,”%d%d”,&n,&m);
memset(a,0,sizeof(a));
for(i=1;i<=m;i++) {
fscanf(f,”%d%d”,&j,&k);
a[j][k]=1; }
fclose(f);
for(i=1;i<=n;i++) ind[i]=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
126 CAPITOLUL 3. APLICAŢII
l[i][j]=a[i][j];
for(i=1;i<=n;i++)
for(k=1;k<=n;k++)
if(l[i][k]) for(j=1;j<=n;j++)
if(l[k][j]) l[i][j]=1;
solutii();
}
void solutii(void) {
int di[30];
for(i=1;i<=n;i++) di[i]=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]) ++di[j];
for(k=0,i=1;i<=n;i++)
if((di[i]==0) && (ind[i]==0)) {
for(j=1;j<=n;j++)
if(a[i][j]) di[j]–;
ind[i]=++k; i=1; }
if(k!=n)
{ puts(”Nu există posibilitatea sortării topologice”);
return;}
puts(”Există posibilitatea sortării topologice”);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(ind[j]==i){
printf(”%d”,j);
break; }
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],c[20],v[20],n,i,j,x,z;
int nevizitat() {
3.2. PARCURGEREA UNUI GRAF 127
int j,primn;
primn=-1;
j=1;
while((j<=n) && (primn==-1)) {
if(v[j]==0) primn=j;
j++; }
return primn;
}
int conex() {
int k,u,p;
cout<<”Primul nod ”; cin>>x;
for(k=1;k<=n;k++) {
c[k]=0;
v[k]=0; }
p=u=1;
c[p]=x;
v[x]=1;
while(p<=u) {
z=c[p];
for(k=1;k<=n;k++)
if((a[z][k]==1) && (v[k]==0)) {
u++;
c[u]=k;
v[k]=1; }
p++; }
if(nevizitat()==-1) return 1;
else return 0;
}
void main() {
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”j<<”]=”;
cin>>a[i][j];
128 CAPITOLUL 3. APLICAŢII
a[j][i]=a[i][j]; }
if(conex()==1) cout<<”Conex ”;
else cout<<”Nu este conex”;
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],c[20],v[20],n,i,j,x,z,nc;
int nevizitat() {
int j,primn;
primn=-1;
j=1;
while((j<=n) && (primn==-1)) {
if(v[j]==0) primn=j;
j++; }
return primn;
}
void parcurg(int x) {
int k,u,p;
for(k=1;k<=n;k++)
c[k]=0;
p=u=1;
c[p]=x;
v[x]=1;
while(p<=u) {
z=c[p];
for(k=1;k<=n;k++)
if((a[z][k]==1) && (v[k]==0)) {
u++;
c[u]=k;
v[k]=1; }
p++; }
for(k=1;k<p;k++)
3.2. PARCURGEREA UNUI GRAF 129
cout<<c[k]<<” ”;
cout<<endl; }
void main() {
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
for(i=1;i<=n;i++) v[i]=0;
cout<<”Vârf de plecare ”; cin>>x;
nc=0;
while(x!=-1) {
nc++;
parcurg(x);
x=nevizitat(); }
cout<<”Număr de componente conexe ”<<nc<<endl;
if(na==1) cout<<”Graf conex”;
else cout<<”Graful nu este conex”;
getch();
}
Problema 3.2.6 Fiind dat un graf, ale cărui date se citesc din fişierul
”bipartit.in”, să se verifice dacă acesta este bipartit. Fişierul este struc-
turat astfel: pe primul rând se găsesc două numere naturale, n şi m, care
reprezintă numărul de noduri şi numărul de muchii din graf; pe următoarele
m linii găsim perechi de numere naturale ce reprezintă extremităţile unei
muchii.
#include <stdio.h>
#include <conio.h>
int i,j,k,n,m,sel,gasit,i1,a[10][10],ind[10];
void intro(void) {
FILE*f;
f=fopen(”bipartit.in”,”r”);
130 CAPITOLUL 3. APLICAŢII
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=m;i++) {
fscanf(f,”%d%d”,&j,&k);
a[j][k]=a[k][j]=1; }
fclose(f); }
void main() {
clrscr();
intro();
sel=1;
for(i1=1;i1<=n;i1++)
if(ind[i1]==0) {
ind[i1]=1;
do{
gasit=0;
for(i=i1;i<=n;i++)
if(ind[i]==sel)
for(j=i1+1;j<=n;j++) {
if((a[i][j]==1) && (ind[j]==sel))
{ printf(”Nu este bipartit”); return;}
if((a[i][j]==1) && (ind[j]==0)) {
ind[j]=3-sel;
gasit=1;
for(k=1;k<=n;k++)
if((ind[k]==3-sel) && )a[j][k]==1))
{ printf(”Nu este bipartit”); return;}
} }
sel=3-sel;}while(gasit);
}
puts(”\n Prima submulţime: ”);
for(i=1;i<=n;i++)
if(ind[i]==1) printf(”%d ”,i);
puts(”\n A doua submulţime: ”);
for(i=1;i<=n;i++)
if(ind[i]==2) printf(”%d ”,i);
getch();
}
ı̂ntr-o limbă neobişnuită, care foloseşte aceleaşi litere ca şi alfabetul englez.
Cartea conţine un index, dar ordinea cuvintelor ı̂n index este diferită de cea
din alfabetul englez. Colecţionarul a ı̂ncercat apoi să se folosească de acest
index pentru a determina ordinea caracterelor şi a reuşit cu greu să rezolve
această problemă. Problema noastră este de a scrie un program care, pe baza
unui index sortat dat, să determine ordinea literelor din alfabetul necunoscut.
În fişierul alfabet.in se găsesc cel puţin unul şi cel mult 100 de cuvinte, urmate
de o linie care conţine caracterul #. Cuvintele dintr-un index conţin numai
litere mari din alfabetul englez şi apar ı̂n ordinea crescătoare corespunzătoare
alfabetului. Rezultatul se va afişa ı̂n fişierul ”alfabet.out”, ordinea literelor se
va scrie sub forma unui şir de litere mari, fără spaţii ı̂ntre ele.
#include <stdio.h>
#include <string.h>
#include <conio.h>
short litere[26],a[26][26],k=0,rez[26];
FILE *f;
void adlalitere(char s[21]) {
unsigned int i;
for(i=0;i<strlen(s);i++)
litere[s[i]-’A’]=1;
}
int esteinlitere(short i) {
return litere[i];
}
int coloanazero(int i) {
for(int j=0;j<26;j++)
if(a[j][i]) return 0;
return 1;
}
int primalitera() {
int i,j;
for(i=0;i<26;i++)
if(esteinlitere(i) && coloanazero(i)) {
rez[k++]=i;
litere[i]=0;
for(j=0;j<26;j++)
a[i][j]=0;
132 CAPITOLUL 3. APLICAŢII
return 1; }
return 0; }
void main() {
char svechi[21],snou[21];
short l1,l2,i,j;
f=fopen(”alfabet.in”,”r”);
for(i=0;i<26;i++)
for(j=0;j<26;j++)
a[i][j]=0;
if(f) {
fscanf(f,”%s\n”,svechi);
adlalitere(svechi); }
if(f) fscanf(f,”%s\n”,snou);
while(strcmp(snou,”#”)!=0) {
adlalitere(snou);
i=0;
l1=strlen(svechi);
l2=strlen(snou);
while(svechi[i]==snou[i] && i<l1 && i<l2) i++;
if(i<l1 && i<l2)
a[svechi[i]-’A’][snou[i]-’A’]=1;
strcpy(svechi,snou);
fscanf(f,”%s\n”,snou); }
fclose(f);
f=fopen(”alfabet.out”,”w”);
while(primalitera()) {};
f=fopen(”alfabet.out”,”w”);
for(i=0;i<k;i++)
fprintf(f,”%c”,’A’+rez[i]);
fclose(f);
}
Problema 3.2.8 Pentru un graf neorientat se cunoaşte numărul de vârfuri,
n, şi pentru cele m muchii extremităţile, se cere să se afişeze toate com-
ponentele conexe precum şi numărul acestora. Se va folosi parcurgerea ı̂n
adâncime.
#include <iostream.h>
#include <conio.h>
3.2. PARCURGEREA UNUI GRAF 133
int a[20][20],n,m,vf,p,prim,s[20],viz[20],v[20];
int neviz() {
int j,primn;
primn=-1;
j=1;
while((j<=n)&&(primn==-1)) {
if(viz[j]==0) primn=j;
j++; }
return primn;
}
void main() {
int i,j,k,x,y,nc;
clrscr();
cout<<”Număr de noduri ”; cin>>n;
cout<<”Număr de muchii ”; cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(k=1;k<=m;k++) {
cout<<”Extremităţi ”;
cin>>x>>y;
a[x][y]=1;
a[y][x]=1;}
prim=1;
for(i=1;i<=n;i++) {
viz[i]=0;
v[i]=0; }
nc=0;
do{
nc++;
cout<<”Nodurile componentei conexe ”<<nc<<endl;
s[1]=prim;
p=1;
viz[prim]=1;
cout<<prim<<” ”;
while(p>=1) {
j=s[p];
vf=v[j]+1;
134 CAPITOLUL 3. APLICAŢII
c[k]=0;
for(k=1;k<=n;k++)
lung[k]=0; pi=1;
ps=1;
c[pi]=ns;
lung[ns]=-1;
gasit=0;
lg=0;
while((ps<=pi) && (gasit==0)) {
z=c[ps];
lg++;
for(k=1;k<=n;k++)
if ((a[z][k]==1)&& (lung[k]==0)) {
pi++;
c[pi]=k;
lung[k]=lg;
if(k==x) {
gasit=1;
cout<<”Lanţul are lungimea minimă ”<<lg; }
}
ps++; }
}
void main() {
clrscr();
citire();
cout<<”Nodul de plecare=”;
cin>>x;
cout<<”Nodul de sosire=”;
cin>>y;
parcurgere(y);
if(lung[x]==0)
cout<<”Între nodul ”<<x<<” şi nodul ”<<y<<” nu există lanţ”;
getch();
}
136 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc {
int x,y;
} v[20],w[20],af[20];
int n,m,i,j,n1,m1,g1[20],g2[20],f[20],k,e,k1;
clrscr();
cout<<”Număr de vârfuri ı̂n G1 ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g1[i]; }
cout<<”Număr de arce ı̂n G1 ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
cout<<”Număr de vârfuri ı̂n G2 ”; cin>>n1;
for(i=1;i<=n1;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g2[i]; }
cout<<”Număr de arce ı̂n G2 ”; cin>>m1;
for(i=1;i<=m1;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>w[i].x>>w[i].y; }
for(i=1;i<=n;i++)
f[i]=g1[i];
k=n;
for(j=1;j<=n1;j++) {
e=0;
for(i=1;i<=n;i++)
if(g1[i]==g2[j]) e=1;
if(e==0) {
3.3. OPERAŢII CU GRAFURI 137
k++;
f[k]=g2[j]; }
}
for(i=1;i<=m;i++) {
af[i].x=v[i].x;
af[i].y=v[i].y; }
k1=m;
for(j=1;j<=m1;j++) {
e=0;
for(i=1;i<=m;i++)
if((v[i].x==w[j].x)&&(v[i].y==w[j].y)) e=1;
if(e==0) {
k1++;
af[k1].x=w[j].x;
af[k1].y=w[j].y; }
}
cout<<”Mulţimea vârfurilor este ”;
for(i=1;i<=k;i++)
cout<<f[i]<<” ”;
cout<<endl;
cout<<”Arcele noului graf sunt ”;
for(i=1;i<=k1;i++)
cout<<”(”<<af[i].x<<”,”<<af[i].y<<”) ”;
getch();
}
Problema 3.3.2 Fiind date două grafuri orientate pentru care cunoaştem
numărul de vârfuri şi mulţimea arcelor, se cere să se scrie un program care
determină intersecţia grafurilor date.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20],w[20],af[20];
int n,m,i,j,n1,m1,g1[20],g2[20],f[20],k,e,k1;
138 CAPITOLUL 3. APLICAŢII
for(i=1;i<=k;i++)
cout<<f[i]<<” ”;
cout<<endl;
cout<<”Arcele noului graf sunt ”;
for(i=1;i<=k1;i++)
cout<<”(”<<af[i].x<<”,”<<af[i].y<<”) ”;
}
else cout<<”Nu există graful”;
getch();
}
Problema 3.3.3 Fiind date două grafuri orientate pentru care cunoaştem
numărul de vârfuri şi mulţimea arcelor, se cere să se scrie un program care
determină suma grafurilor date.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20],w[20],af[20];
int n,m,i,j,n1,m1,g1[20],g2[20],f[20],k,e,k1;
clrscr(); cout<<”Număr de vârfuri din cele două grafuri ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g1[i]; }
cout<<”Număr de arce ı̂n G1 ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
cout<<”Număr de arce ı̂n G2 ”; cin>>m1;
for(i=1;i<=m1;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>w[i].x>>w[i].y; }
for(i=1;i<=m;i++) {
af[i].x=v[i].x;
af[i].y=v[i].y; }
k1=m;
for(j=1;j<=m1;j++) {
140 CAPITOLUL 3. APLICAŢII
e=0;
for(i=1;i<=m;i++)
if((v[i].x==w[j].x)&&(v[i].y==w[j].y)) e=1;
if(e==0) {
k1++;
af[k1].x=w[j].x;
af[k1].y=w[j].y; }
}
cout<<”Mulţimea vârfurilor este ”;
for(i=1;i<=n;i++)
cout<<g1[i]<<” ”;
cout<<endl;
if(k!=0) cout<<”Graful nu are arce”;
else {
cout<<”Arcele noului graf sunt ”;
for(i=1;i<=k1;i++)
cout<<”(”<<af[i].x<<”,”<<af[i].y<<”) ”;
}
getch();
}
Problema 3.3.4 Fiind date două grafuri orientate pentru care cunoaştem
numărul de vârfuri şi mulţimea arcelor, se cere să se scrie un program care
determină produsul grafurilor date.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20],w[20],af[20];
int n,m,i,j,n1,m1,g1[20],g2[20],f[20],k,e,k1;
clrscr();
cout<<”Număr de vârfuri din cele două grafuri ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g1[i]; }
cout<<”Număr de arce ı̂n G1 ”; cin>>m;
for(i=1;i<=m;i++) {
3.3. OPERAŢII CU GRAFURI 141
Problema 3.3.5 Fiind dat un graf orientat pentru care cunoaştem numărul
de vârfuri şi mulţimea arcelor, se cere să se scrie un program care determină
transpusul grafului dat.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20],w[20];
int n,m,i,g1[20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
142 CAPITOLUL 3. APLICAŢII
cin>>g1[i]; }
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
for(i=1;i<=m;i++) {
w[i].x=v[i].y;
w[i].y=v[i].x; }
cout<<”Mulţimea vârfurilor este ”;
for(i=1;i<=n;i++)
cout<<g1[i]<<” ”;
cout<<endl;
cout<<”Arcele noului graf sunt ”;
for(i=1;i<=m;i++)
cout<<”(”<<w[i].x<<”,”<<w[i].y<<”) ”;
getch();
}
Problema 3.3.6 Fiind dat un graf orientat pentru care cunoaştem numărul
de vârfuri şi mulţimea arcelor, se cere să se scrie un program care determină
complementarul grafului dat.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20],w[20],c[20];
int n,m,i,j,g1[20],k,l,e;
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g1[i]; }
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
3.3. OPERAŢII CU GRAFURI 143
cin>>v[i].x>>v[i].y; }
k=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
k++;
c[k].x=g1[i];
c[k].y=g1[j]; }
l=0;
for(i=1;i<=k;i++) {
e=0;
for(j=1;j<=m;j++)
if((c[i].x==v[j].x)&&(c[i].y==v[j].y)) e=1;
if(e==0) {
l++;
w[l].x=c[i].x;
w[l].y=c[i].y; }
} cout<<”Mulţimea vârfurilor este ”;
for(i=1;i<=n;i++)
cout<<g1[i]<<” ”;
cout<<endl;
cout<<”Arcele noului graf sunt ”;
for(i=1;i<=l;i++)
cout<<”(”<<w[i].x<<”,”<<w[i].y<<”) ”;
getch();
}
#include <iostream.h>
#include <conio.h>
void main() {
struct muchie {
int x,y; };
int n1,a[10][10],n,nm,i,j,m[10],mgraf,b,aux,sg,k,ga;
144 CAPITOLUL 3. APLICAŢII
muchie v[10];
clrscr();
cout<<”Număr de noduri ”; cin>>n;
for(i=1;i<=n;i++) a[i][i]=0;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
cout<<”Daţi nodurile subgrafului,-1 pentru sfârşit”<<endl;
n1=0;
cout<<”Nod ”; cin>>b;
while(b!=-1) {
n1++;
m[n1]=b;
cout<<”Nod ”; cin>>b; }
cout<<”Număr de muchii din subgraf ”; cin>>nm;
for(i=1;i<=nm;i++) {
cout<<”Extremitaţi ”; cin>>v[i].x>>v[i].y; }
for(i=1;i<n1;i++)
for(j=i+1;j<=n1;j++) {
aux=m[i];m[i]=m[j];m[j]=aux;}
if(m[n1]<=n) sg=1;
else sg=0;
for(i=1;i<=nm;i++)
if(a[v[i].x][v[i].y]!=1) sg=0;
if(sg==1)
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
if((i<=m[n1])&&(j<=m[n1])) {
if(a[i][j]==0) ga=1;
else ga=0;
for(k=1;k<=nm;k++)
if(((v[k].x==i)&&(v[k].y==j))||((v[k].x==j)&&(v[k].y==i))) ga=1;
if(ga==0) sg=0; }
if(sg==1) cout<<”Subgraf”;
else cout<<”Nu este subgraf”;
getch();
3.3. OPERAŢII CU GRAFURI 145
#include <iostream.h>
#include <conio.h>
void main() {
int a[10][10],gp[10][10],n,m,n1,m1,i,j,x,y,ok;
clrscr();
cout<<”Număr de noduri ”;cin>>n;
cout<<”Număr de muchii ”;cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++) {
cout<<”x si y ”; cin>>x>>y;
a[x][y]=1; a[y][x]=1; }
cout<<”Număr de noduri din graful G1 ”; cin>>n1;
cout<<”Număr de muchii din graful G1 ”; cin>>m1;
for(i=1;i<=n1;i++)
for(j=1;j<=n1;j++)
gp[i][j]=0;
for(i=1;i<=m1;i++) {
cout<<”x si y ”; cin>>x>>y;
gp[x][y]=1;
gp[y][x]=1; }
ok=1;
if(n1!=n) ok=0;
if (ok==1) {
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
146 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
void main() {
struct arc{
int x,y;
}v[20],w[20];
int n,m,i,j,g[20],gg[20],es,es1,es2,e1,e,nn,mm;
clrscr();
cout<<”Număr de vârfuri pentru graful 1 ”; cin>>n;
for(i=1;i<=n;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>g[i]; }
cout<<”Număr de arce pentru graful 1 ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
cout<<”Număr de vârfuri pentru graful 2 ”; cin>>nn;
for(i=1;i<=nn;i++) {
cout<<”Vârful ”<<i<<” ”;
cin>>gg[i]; }
cout<<”Număr de arce pentru graful 2 ”; cin>>mm;
for(i=1;i<=mm;i++) {
cout<<”Extremităţile arcului ”<<i<<” ”;
cin>>w[i].x>>w[i].y; }
if(nn<n) {
e=1;
3.3. OPERAŢII CU GRAFURI 147
for(i=1;i<=nn;i++) {
e1=0;
for(j=1;j<=n;j++)
if(gg[j]==g[i]) e1=1;
e=e&&e1;
}
es=1;
for(i=1;i<=mm;i++) {
es1=0;
for(j=1;j<=nn;j++)
if(w[i].x==gg[j]) es1=1;
es2=0;
for(j=1;j<=nn;j++)
if(w[i].y==gg[j]) es2=1;
es=es&&es1&&es2; }
if ((e==1)&&(es==1)) cout<<”Este graf generat”;
else cout<<”Nu este graf generat”;
}
else cout<<”Nu sunt destule vârfuri”;
getch();
}
#include <fstream.h>
#include <conio.h>
int a[20][20],v[20],n,m,x,i,k,j;
int grad(int i) {
int j,g=0;
for(j=1;j<=n;j++)
g=g+a[i][j];
return g;
}
void main() {
clrscr();
148 CAPITOLUL 3. APLICAŢII
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”Există muchie ı̂ntre ”<<i<<” şi ”<<j<<” 0-nu,1-da ”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
cout<<”x=”; cin>>x;
k=0;
for(i=1;i<=n;i++)
f(grad(i)%2==0) {
k++;
v[k]=i; }
for(i=1;i<=k;i++)
if(a[v[i]][x]==1) {
a[v[i]][x]=0;
a[x][v[i]]=0;
m–; }
cout<<”Muchiile grafului parţial sunt”<<endl;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if(a[i][j]==1) cout<<i<<” ”<<j<<endl;
getch();
}
#include <iostream.h>
#include <conio.h>
typedef int stiva[20];
int n,m,p,k,ev,as,a[20][20],b[20][20],nr;
stiva st;
void citeste() {
int i,j;
cout<<”Număr de vârfuri ”;
cin>>n;
for(i=1;i<=n;i++)
3.3. OPERAŢII CU GRAFURI 149
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
if(a[i][j]==1) m++;}
m=m/2;
}
void trans() {
int i,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if(a[i][j]==1) {
b[i][k]=1;
b[j][k]=1;
k++; }
}
void init() {
st[k]=0;
}
int succesor() {
if(st[k]<m) {
st[k]=st[k]+1;
return 1; }
else return 0;
}
int valid() {
int i;
if ((k>1) && (st[k]<st[k-1])) return 0;
for (i=1;i<k;i++)
if (st[k]==st[i]) return 0;
return 1;
}
int solutie() {
return k==p;
}
void tipar() {
int i,j;
cout<<”Graful partial are muchiile ”;
for(i=1;i<=p;i++) {
150 CAPITOLUL 3. APLICAŢII
for(j=1;j<=n;j++)
if(b[i][st[i]]==1) cout<<j<<” ”;
}
cout<<endl;
}
void back() {
k=1;
init();
while (k>0) {
as=1;
ev=0;
while (as && !ev){
as=succesor();
if (as) ev=valid(); }
if (as)
if(solutie()) tipar();
else {
k++;
init(); }
else k–; }
}
void main() {
clrscr();
citeste();
trans();
for(p=m;p>=0;p–)
back();
getch();
}
#include <iostream.h>
#include <conio.h>
typedef int stiva[100];
int n,p,k,i,j,ev,as,a[10][10],nr;
stiva st;
3.3. OPERAŢII CU GRAFURI 151
void init() {
st[k]=0;
}
int succesor() {
if (st[k]<n) {
st[k]=st[k]+1;
return 1; }
else return 0;
}
int valid() {
if ((k>1) && (st[k]<st[k-1])) return 0;
return 1;
}
int solutie() {
return k==p;
}
void tipar() {
int i,j;
cout<<”Nodurile subgrafului: ”;
for(i=1;i<=p;i++)
cout<<st[i]<<” ”;
cout<<endl;
cout<<”Muchiile ”;
for(i=1;i<=p;i++)
for(j=i+1;j<=p;j++)
if(a[st[i]][st[j]]==1)
cout<<”(”<<st[i]<<”,”<<st[j]<<”) ”;
cout<<endl;
}
void back() {
k=1;
init();
while (k>0) {
as=1;
ev=0;
while (as && !ev) {
as=succesor();
if (as) ev=valid(); }
152 CAPITOLUL 3. APLICAŢII
if (as)
if(solutie()) tipar();
else {
k++;
init(); }
else k- -; }
}
void main() {
clrscr();
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”Există muchie ı̂ntre ”<<i<<” si ”<<j<<” 0-nu,1-da ”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
for(p=n;p>=1;p- -) {
back();
getch(); }
}
#include <iostream.h>
#include <conio.h>
void main() {
int n,i,j,a[20][20];
clrscr();
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j) {
cout<<”Există arc ı̂ntre ”<<i<<” şi ”<<j<<” 0-nu,1-da ”;
cin>>a[i][j]; }
3.4. LANŢURI ŞI CICLURI 153
else a[i][j]=0;
m=0;
for(i=2;i<=n;i++)
for(j=1;j<i;j++)
if((a[i][j]==0)&&(a[j][i]==0)) m++;
cout<<”Numărul de arce care trebuie adăugate este ”<<m;
getch();
}
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int a[20][20],n,m,i,j,x,y,vb,vb1;
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<” ”;
cin>>x>>y;
a[x][y]=1; }
cout<<”Număr de perechi din secvenţă ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Perechea ”<<i<<” ”;
154 CAPITOLUL 3. APLICAŢII
cin>>v[i].x>>v[i].y; }
vb=0;
for(i=1;i<m;i++)
if(v[i].y!=v[i+1].x) vb=1;
if(vb==0) {
vb1=0;
for(i=1;i<=m;i++)
if(a[v[i].x][v[i].y]==0) vb1=1;
if(vb1==0) cout<<”Secvenţa dată este drum”;
else cout<<”Nu toate perechile sunt arce”;
}
else cout<<”Secvenţa dată nu este drum”;
getch();
}
Problema 3.4.2 Fiind dat un graf orientat pentru care se cunoaşte numărul
de vârfuri, numărul de arce şi arcele, se cere să se scrie un program care
determină dacă o secvenţă de perechi de numere naturale reprezintă un drum
simplu sau nu ı̂n acel graf.
#include <iostream.h>
#include <conio.h>
void main( ) {
struct arc{
int x,y;
}v[20];
int a[20][20],n,m,i,j,x,y,vb,vb1,vb2;
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<” ”;
cin>>x>>y;
a[x][y]=1; }
cout<<”Număr de perechi din secvenţă ”; cin>>m;
for(i=1;i<=m;i++) {
3.4. LANŢURI ŞI CICLURI 155
cout<<”Perechea ”<<i<<” ”;
cin>>v[i].x>>v[i].y; }
vb=0;
for(i=1;i<m;i++)
if(v[i].y!=v[i+1].x) vb=1;
if(vb==0) {
vb1=0;
for(i=1;i<=m;i++)
if(a[v[i].x][v[i].y]==0) vb1=1;
if(vb1==0) {
vb2=0;
for(i=1;i<m;i++)
for(j=i+1;j<=m;j++)
if((v[i].x==v[j].x)&&(v[i].y==v[j].y)) vb2=1;
if(vb2==0) cout<<”Secvenţa dată este drum simplu”;
else cout<<”Secvenţa dată este drum”; }
else cout<<”Nu toate perechile sunt arce”; }
else cout<<”Secvenţa dată nu este drum”;
getch();
}
#include <iostream.h>
#include <conio.h>
void main()
{
int a[20][20],s[20],i,j,k,n,m,ok;
clrscr();
cout<<”Număr de vârfuri din graf=”;
cin>>n;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++) {
156 CAPITOLUL 3. APLICAŢII
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[i][j]=1-a[i][j]; }
cout<<”Număr de vârfuri din secvenţă=”;
cin>>m;
for(i=1;i<=m;i++) {
cout<<”s[”<<i<<”]=”;
cin>>s[i]; }
ok=1;
for(i=1;i<=m-1;i++)
if(a[s[i],s[i+1]]==0) ok=0;
if(ok==0) cout<<”Există noduri ı̂ntre care nu avem arc”;
else {
for(i=1;i<=m-1;i++)
for(j=i+1;j<=m;j++)
if(s[i]==s[j]) ok=0;
if (ok==0) cout<<”Secvenţa nu este drum elementar”;
else cout<<”Secvenţa este drum elementar”; }
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],st[20],n,i,j,v1,v2;
void tipar(int k) {
for(i=1;i<=k;i++)
cout<<st[i]<<” ”;
cout<<endl;
}
int valid(int k) {
int v;
1
Anexa B
3.4. LANŢURI ŞI CICLURI 157
v=1;
for(i=1;i<=k-1;i++)
if(st[i]==st[k]) v=0;
if (k>1) if(a[st[k-1]][st[k]]==0) v=0;
if(k>1) if (st[k]<st[k-1]) v=0;
return v; }
void back(int k) {
int j;
for(j=1;j<=n;j++) {
st[k]=j;
if (valid(k)) if (j==v2) tipar(k);
else back(k+1);
}
}
void main() {
clrscr();
cout<<”Număr de vârfuri=”; cin>>n;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,””<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
cout<<”v1=”; cin>>v1;
cout<<”v2=”; cin>>v2;
st[1]=v1;
back(2);
getch();
}
Problema 3.4.5 Să se scrie un program care să verifice dacă o secvenţă de
vârfuri ale unui graf neorientat, memorată ı̂ntr-un vector, formează un lanţ,
lanţ simplu sau lanţ elementar, ciclu sau ciclu elementar.
• dacă oricare două vârfuri consecutive ı̂n vector sunt adiacente, atunci
secvenţa de vârfuri formează un lanţ. Altfel, ea nu formează un lanţ,
158 CAPITOLUL 3. APLICAŢII
deci nici celelalte tipuri de lanţuri sau cicluri, ı̂n acest caz având loc
terminarea programului;
• dacă secvenţa este un lanţ elementar şi, ı̂n plus, primul vârf coincide
cu ultimul, atunci secvenţa formează un ciclu;
• dacă se formează deja un ciclu se verifică de câte ori a fost luat fiecare
vârf. Dacă numărul de apariţii ale tuturor vârfurilor cu excepţia primu-
lui vârf şi al ultimului este 1, iar pentru acestea numărul de apariţii
este 2, atunci ciclul este elementar.
#include <stdio.h>
#include <conio.h>
#include <mem.h>
void main() {
unsigned m,n,i,j,nr[20],a[10][10],l[20],u[10][2],k,ind;
clrscr();
printf(”Introduceţi numărul de vârfuri ”);scanf(”%d”,&n);
printf(”Introduceţi numărul de muchii ”);scanf(”%d”,&m);
for(i=1;i<=m;i++) {
printf(”Muchia %d: ”,i);
scanf(”%d%d”,&u[i][0],&u[i][1]); }
memset(a,0,sizeof(a));
for(i=1;i<=m;i++)
a[u[i][0]][u[i][1]]=a[u[i][1]][u[i][0]]=1;
printf(”Introduceţi lungimea secvenţei: ”);
scanf(”%d”,&k);
printf(”Introduceţi secvenţa: ”);
for(j=1;j<=k;j++)
scanf(”%d”,l+j);
for(i=1;i<=k-1;i++)
if(a[l[i]][l[i+1]]==0) {
puts(”Nu se formează un lanţ”); return; }
puts(”Vârfurile formează un lanţ”);
3.4. LANŢURI ŞI CICLURI 159
memset(nr,0,sizeof(nr));
for(i=1;i<=k-1;i++)
for(j=1;j<=m;j++)
if((u[j][0]==l[i]) && (u[j][1]==l[i+1]) || (u[j][1]==l[i]) &&
(u[j][0]==l[i+1]))
if(++nr[j]>1) {
puts(”Nu este un lanţ simplu”); return; }
puts(”Se formează un lanţ simplu”);
if(l[1]==l[k]) puts(”Se formează un ciclu”);
memset(nr,0,sizeof(nr));
ind=1;
for(i=1;i<=k;i++)
if(++nr[l[i]]>1) {
puts(”Nu se formează lanţ elementar”); ind=0; break; }
if(ind) puts(”Se formează un lanţ elementar”);
for(i=2;i<=k-1;i++)
if(nr[l[i]]>1) {puts(”Nu se formează ciclu elementar”);return;}
if((nr[l[1]]>2) || (l[1]!=l[k])) printf(”Nu ”);
puts(”Se formează ciclu elementar”);
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],st[20],n,i,j,v1,v2;
void tipar(int k) {
for(i=1;i<=k;i++)
cout<<st[i]<<” ”;
cout<<endl;
}
int valid(int k) {
int v;
v=1;
for(i=1;i<=k-1;i++)
160 CAPITOLUL 3. APLICAŢII
if(st[i]==st[k]) v=0;
if (k>1) if(a[st[k-1]][st[k]]==0) v=0;
if(k>1) if (st[k]<st[k-1]) v=0;
return v;
}
void back(int k) {
int j;
for(j=1;j<=n;j++) {
st[k]=j;
if (valid(k)) if (j==v2) tipar(k);
else back(k+1);
}
}
void main() {
clrscr();
cout<<”Număr de vârfuri=”; cin>>n;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,””<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
for(v1=1;v1<=n;v1++)
for(v2=1;v2<=n;v2++) if(v1!=v2) {
st[1]=v1;
back(2);
}
getch();
}
Problema 3.4.7 Scrieţi un program care citeşte dintr-un fişier text, ”graf.in”,
lista muchiilor unui graf neorientat şi caută toate lanţurile elementare ı̂ntre
două noduri x şi y, care trec printr-un nod z care are gradul minim ı̂n graf,
presupunem că există maxim un singur vârf cu această proprietate. Etichetele
nodurilor ı̂ntre care se caută lanţul se citesc de la tastatură.
#include <fstream.h>
#include <conio.h>
3.4. LANŢURI ŞI CICLURI 161
struct{
int x,y;
}v[20];
ifstream f;
int x,y,z,st[20],k,m,n,i,j,a[20][20],min,g;
int exista(int z,int k) {
int ok=0;
for(i=1;i<=k;i++)
if (st[i]==z) ok=1;
return ok;
}
void tipar(int k) {
for(i=1;i<=k;i++)
cout<<st[i]<<” ”;
cout<<endl;
}
int valid(int k) {
int v;
v=1;
for(i=1;i<=k-1;i++)
if(st[i]==st[k]) v=0;
if (k>1) if(a[st[k-1]][st[k]]==0) v=0;
return v;
}
void back(int k) {
int j;
for(j=1;j<=n;j++) {
st[k]=j;
if (valid(k)) if ((j==y) && exista(z,k)) tipar(k);
else back(k+1);
}
}
void main() {
clrscr();
f.open(”graf.in”);
m=0;
n=-1;
while (!f.eof()) {
162 CAPITOLUL 3. APLICAŢII
m++;
f>>v[m].x>>v[m].y;
if(n<v[m].x) n=v[m].x;
if(n<v[m].y) n=v[m].y;
};
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<=m;i++) {
a[v[i].x][v[i].y]=1;
a[v[i].y][v[i].x]=1; }
cout<<”x=”; cin>>x;
cout<<”y=”; cin>>y;
min=32000;
z=0;
for(i=1;i<=n;i++) {
g=0;
for(j=1;j<=n;j++)
g=g+a[i][j];
if(min>g) {
min=g;
z=i;
}
}
if (z==0) cout<<”Nu există nod cu grad minim”;
else {
st[1]=x;
back(2);
}
getch();
}
3.5 Arbori
Problema 3.5.1 Fiind dat un graf neorientat prin matricea sa de adiacenţă,
să se scrie un program care verifică dacă acel graf poate reprezenta un arbore.
#include <iostream.h>
#include <conio.h>
3.5. ARBORI 163
int a[20][20],viz[20],c[20],n,i,j,p,v,con,pr,nod,drum[20][20];
void dfmr(int nod) {
viz[nod]=1;
for(int k=1;k<=n;k++)
if(a[nod][k]==1&&viz[k]==0)
dfmr(k);
}
void main() {
clrscr();
cout<<”Număr de noduri=”;cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
for(i=1;i<=n;i++)
viz[i]=0;
c[1]=1;
p=1;
u=1;
while(p<=u) {
v=c[p];
for(i=1;i<=n;i++)
if(((a[v][i]==1) || (a[i][v]==1))&&(viz[i]==0)) {
u++;
c[u]=i;
viz[i]=1; }
p++; }
con=1;
pr=1;
for(i=1;i<=u;i++)
pr=pr*viz[i];
if(pr==0) con=0;
if (con==1) {
for(nod=1;nod<=n;nod++) {
for(j=1;j<=n;j++)
viz[j]=0;
dfmr(nod);
164 CAPITOLUL 3. APLICAŢII
viz[nod]=0;
for(j=1;j<=n;j++)
drum[nod][j]=viz[j];
}
ok1=0;
for(i=1;i<=n;i++)
if(a[i][i]==1) ok1=1;
if (ok1==0) cout<<”Graful este arbore”;
else cout<<”Graful are cicluri”;
}
else cout<<”Graful nu este conex”;
getch();
}
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <conio.h>
char n,i,s[128];
struct nod{
char inf;
struct nod *fs,*frd;
} *rad;
struct elem{
char inf,fs,frd;
} t[128];
struct nod*creare(void) {
3.5. ARBORI 165
printf(”%2d”,i);
printf(”\n Informaţia ”);
for(i=1;i<=n;i++)
printf(”%2c”,t[i].inf);
printf(”\n Fiu stâng ”);
for(i=1;i<=n;i++)
printf(”%2d”,t[i].fs);
printf(”\n Frate drept ”);
for(i=1;i<=n;i++)
printf(”%2d”,t[i].frd);
getch();
}
Problema 3.5.3 Fiind dat un arbore oarecare, se cere să se scrie un program
care permite parcurgerea arborelui ı̂n preordine, postordine şi pe orizontală.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
#include <alloc.h>
struct nod{
int inf,n;
struct nod*leg[10]; };
#define size sizeof(struct nod)
struct nod*s[100], *coada[100];
int ind2,ind3;
struct nod*creare(void);
void pre(struct nod*p);
void post(struct nod*p);
void oriz(struct nod*p);
struct nod*creare(void) {
int info,nr,i;
struct nod*p;
clrscr();
cout<<”Daţi informaţia ”; cin>>info;
p=(struct nod*)malloc(size);
p->inf=info;
cout<<”Daţi numărul de descendenţi pentru ”<<info<<” ”;
3.5. ARBORI 167
cin>>p->n;
for(i=0;i<p->n;i++)
p->leg[i]=creare();
return p;
}
void pre(struct nod*p) {
int i;
if(p!=NULL) {
cout<<p->inf<<” ”;
for(i=0;i<p->n;i++)
if(p->leg[i]!=NULL)
pre(p->leg[i]); }
}
void post(struct nod*p) {
int i;
if(p!=NULL) {
for(i=0;i¡p->n;i++)
if(p->leg[i]!=NULL) post(p->leg[i]);
cout<<p->inf<<” ”; }
}
void adaug(struct nod*p) {
if(ind2==ind3+1) cout<<”Coada plină”;
else {
coada[ind3]=p;
ind3++; }
}
struct nod*elim(void) {
if(ind3==ind2) return 0;
else return coada[ind2++];
}
void oriz(struct nod*rad) {
struct nod*p;
int i;
ind2=ind3=0;
adaug(rad);
do{
p=elim();
if(p!=NULL) {
168 CAPITOLUL 3. APLICAŢII
cout<<p->inf<<” ”;
for(i=0;i<p->n;i++)
adaug(p->leg[i]); }
} while(p!=NULL);
}
void main() {
struct nod*cap;
clrscr();
cout<<”Daţi arborele ”;
cap=creare();
cout<<endl<<”Arborele ı̂n preordine”<<endl;
pre(cap);
cout<<endl<<”Arborele ı̂n postordine”<<endl;
post(cap);
cout<<endl<<”Arborele pe nivele”<<endl;
oriz(cap);
getch();
}
#include <stdio.h>
FILE *f,*g;
void detdrum(int a[ ][20],int n) {
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if((i!=k)&& (j!=k) && (a[i][j]==0)&& (a[i][k]==1)&&
(a[k][j]==1))
3.6. MATRICEA DRUMURILOR 169
a[i][j]=1;
}
void main() {
int i,j,n,a[20][20];
f=fopen(”graf.in”,”r”);
g=fopen(”drumuri.out”,”w”);
fscanf(f,”%d”,&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
fscanf(f,”%d”,&a[i][j]);
detdrum(a,n);
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
fprintf(g,”%d ”,a[i][j]);
fprintf(g,”\n”); };
fclose(f);
fclose(g);
}
Problema 3.6.2 Fiind dat un graf cu n vârfuri şi m muchii, să se determine
componentele sale conexe.
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
void main() {
unsigned m,n,i,j,k,a[10][10],l[10][10],u[10][2],p[10];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de muchii ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Muchia ”<<i<<” ”;
cin>>u[i][0]>>u[i][1]; }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
170 CAPITOLUL 3. APLICAŢII
a[i][j]=0;
for(i=1;i<=m;i++)
a[u[i][0]][u[i][1]]=a[u[i][1]][u[i][0]]=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
l[i][j]=a[i][j];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(l[i][j]==1)
for(k=1;k<=n;k++)
if(l[j][k]) l[i][k]=l[k][i]=1;
k=0;
for(i=1;i<=n;i++)
p[i]=0;
for(i=1;i<=n;i++)
if(p[i]==0) {
p[i]=++k;
for(j=i+1;j<=n;j++)
if(l[i][j]==1) p[j]=k; }
cout<<”Număr de componente conexe ”<<k<<” ”;
for(i=1;i<=k;i++) {
cout<<endl<<”Componenta ”<<i<<endl;
for(j=1;j<=n;j++) if(p[j]==i)
cout<<” ”<<j; }
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],n,u[20][20],dd;
void main() {
int i,j,n,m,k,x,y,l,d[20][20];
clrscr();
3.6. MATRICEA DRUMURILOR 171
if(d[i][j]>dd) d[i][j]=d[i][j];
else d[i][j]=dd; }
}
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<d[i][j]<<” ”;
cout<<endl; }
getch();
}
Problema 3.6.4 Folosind algoritmul lui Chen, să se scrie un program care
determină matricea drumurilor pentru un graf orientat dat; se cunoaşte
numărul de vârfuri, numărul de arce şi pentru fiecare arc cele două
extremităţi.
#include <iostream.h>
#include <conio.h>
void main() {
int i,j,n,m,ok,k,x,y,v[20],w[20],b[20],a[20][20];
clrscr();
cout<<”Număr de vârfuri=”; cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
cout<<”Număr de arce=”; cin>>m;
for(k=1;k<=m;k++) {
cout<<”Extremităţi arc”<<k<<” ”;
cin>>x>>y;
a[x][y]=1; }
k=1;
int ok1=1;
while((k<=n)&&(ok1==1)) {
for(i=1;i<=n;i++)
w[i]=a[k][i];
for(j=1;j<=n;j++)
if(j!=k)
if(a[k][j]==1) {
for(i=1;i<=n;i++)
3.6. MATRICEA DRUMURILOR 173
v[i]=a[j][i];
for(i=1;i<=n;i++)
if(v[i]>w[i]) b[i]=v[i];
else b[i]=w[i];
for(i=1;i<=n;i++)
w[i]=b[i]; };
ok1=0;
for(i=1;i<=n;i++)
if(w[i]!=a[k][i]) ok1=1;
if(ok1==1) {
for(i=1;i<=n;i++) a[k][i]=w[i];
k=k; }
else {
for(i=1;i<=n;i++)
a[k][i]=w[i];
k++;
ok1=1; }
}
for(i=1;i<=n;i++) {
for(j=1;j<=n;j++)
cout<<a[i][j]<<” ”;
cout<<endl; }
getch();
}
#include <iostream.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
typedef char string[20];
int m,n,i,j,k,t;
char x,y;
string a[10][10],b[10][10],c[10][10],p,l;
174 CAPITOLUL 3. APLICAŢII
void main() {
clrscr();
cout<<”Număr de vârfuri ”;
cin>>n;
cout<<”Număr de arce ”;
cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
strcpy(a[i][j],”0”);
strcpy(b[i][j],”0”); }
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<” ”;
cin>>x>>y;
x=toupper(x);
y=toupper(y);
if(x!=y) {
char *z;
switch (x) {
case ’A’:z=”A”;break;
case ’B’:z=”B”;break;
case ’C’:z=”C”;break;
case ’D’:z=”D”;break;
case ’E’:z=”E”;break;
case ’F’:z=”F”;break;
case ’G’:z=”G”;break;
case ’H’:z=”H”;break;
case ’I’:z=”I”;break;
case ’J’:z=”J”;break;
}
strcpy(b[(int)x-64][(int)y-64],z);
switch (y) {
case ’A’:z=”A”;break;
case ’B’:z=”B”;break;
case ’C’:z=”C”;break;
case ’D’:z=”D”;break;
case ’E’:z=”E”;break;
case ’F’:z=”F”;break;
case ’G’:z=”G”;break;
3.6. MATRICEA DRUMURILOR 175
case ’H’:z=”H”;break;
case ’I’:z=”I”;break;
case ’J’:z=”J”;break;
}
strcpy(a[(int)x-64][(int)y-64],z);
strcat(b[(int)x-64][(int)y-64],z);
}
}
for(t=2;t<=n-1;t++) {
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
strcpy(c[i][j],”0”);
for(k=1;k<=n;k++) {
int i1,j1,e=0;
for (i1=0;i1<strlen(b[i][k]);i1++)
for(j1=0;j1<strlen(a[k][j]);j1++)
if(b[i][k][i1]==a[k][j][j1]) e=1;
if((strcmp(b[i][k],”0”)==0) || (strcmp(a[k][j],”0”)==0)||(e==1))
strcpy(l,”0”);
else
{
strcpy(l,””);
strcpy(l,b[i][k]);
strcat(l,a[k][j]);
}
if(strcmp(l,”0”)!=0){
if (strcmp(c[i][j],”0”)==0) strcpy(c[i][j],””);
if (strcmp(c[i][j],””)!=0) strcat(c[i][j],”,”);
strcat(c[i][j],l);
}
} }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
strcpy(b[i][j],c[i][j]);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
if(strcmp(c[i][j],”0”)!=0)
176 CAPITOLUL 3. APLICAŢII
cout<<c[i][j]<<endl; }
getch();
}
#include<fstream.h>
#include<mem.h>
#include <conio.h>
void main() {
int i,j,k,n,m,p,a[20][20];
clrscr();
ifstream f(”infl.in”);
f>>n>>m;
memset(a,0,n*sizeof(a[0]));
for(i=1;i<=m;i++) {
f>>j>>k;
a[j][k]=1;}
for(i=1;i<=n;i++)
for(k=1;k<=n;k++)
if(a[i][k])
for(j=1;j<=n;j++)
if(a[k][j])
a[i][j]=1;
p=m=0;
for(i=1;i<=n;i++) {
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 177
for(k=0,j=1;j<=n;j++)
k+=a[i][j];
if(k>m) {m=k; p=i;}
}
cout<<”Persoana cea mai influentă este ”<<p;
getch();
}
#include <iostream.h>
#include <conio.h>
typedef int stiva[100];
int a[20][20],n,k,as,ev,x,y,v[20],este=0;
stiva st;
void citeste() {
int i,j;
cout<<”Număr de noduri=”;
cin>>n;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
}
void init() {
st[k]=0;
}
int succesor() {
if(st[k]<n) {
st[k]=st[k]+1;
return 1; }
else return 0;
178 CAPITOLUL 3. APLICAŢII
}
int valid() {
int i;
if(k>1)
if(a[st[k-1]][st[k]]==0) return 0;
for(i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1;
}
int solutie() {
return st[k]==y;
}
void tipar() {
este=1;
}
void back() {
k=2;
init();
while (k>0) {
as=1;
ev=0;
while (as && !ev) {
as=succesor();
if (as) ev=valid(); }
if (as)
if(solutie()) tipar();
else {
k++;
init(); }
else k–; }
}
void compo() {
for(x=1;x<=n;x++)
if(v[x]==0) {
st[1]=x;
v[x]=1;
cout<<x<<” ”;
for(y=1;y<=n;y++)
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 179
if(x!=y) {
este=0;
back();
if (este) {
v[y]=1;
cout<<y<<” ”; }
}
cout<<endl; }
}
void main() {
clrscr();
citeste();
compo();
getch();
}
Problema 3.7.2 Fiind dat un graf orientat prin matricea sa de adiacenţă,
se cere să se scrie un program care determină toate componentele tare conexe
din graf (se va folosi metoda de programare backtracking).
#include <iostream.h>
#include <conio.h>
typedef int stiva[100];
int a[20][20],n,k,as,ev,x,y,v[20],este=0,este1,este2;
stiva st;
void citeste() {
int i,j;
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
}
void init() {
st[k]=0;
}
int succesor() {
if(st[k]<n) {
180 CAPITOLUL 3. APLICAŢII
st[k]=st[k]+1;
return 1; }
else return 0;
}
int valid() {
int i;
if(k>1)
if(a[st[k-1]][st[k]]==0) return 0;
for(i=1;i<k;i++)
if(st[k]==st[i]) return 0;
return 1;
}
int solutie() {
return st[k]==y;
}
void tipar() {
este=1;
}
void back() {
k=2;
init();
while (k>0) {
as=1;
ev=0;
while (as && !ev) {
as=succesor();
if (as) ev=valid(); }
if (as)
if(solutie()) tipar();
else {
k++;
init(); }
else k–; }
}
void compo() {
int i,j;
for(i=1;i<=n;i++)
if(v[i]==0) {
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 181
v[i]=1;
cout<<i<<” ”;
for(j=1;j<=n;y++)
if(j!=i) {
x=i; y=j; st[1]=x; este=0; back(); este1=este;
x=j; y=i; st[1]=x; este=0; back(); este2=este;
if (este1 && este2) {
v[j]=1;
cout<<j<<” ”; }
}
cout<<endl; }
}
void main() {
clrscr();
citeste();
compo();
getch();
}
#include <iostream.h>
#include <conio.h>
typedef int stiva[100];
int a[20][20],n,v[20],b[20][20],ap[20][20];
stiva st;
void citeste() {
int i,j;
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
}
void predecesor() {
182 CAPITOLUL 3. APLICAŢII
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
ap[i][j]=a[j][i];
}
void transs() {
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]==0 && i!=k && j!=k)
a[i][j]=a[i][k]*a[k][j];
}
void transp() {
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(ap[i][j]==0 && i!=k && j!=k)
ap[i][j]=ap[i][k]*ap[k][j];
}
void intersectie() {
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
b[i][j]=a[i][j]*ap[i][j];
}
void compo() {
int i,j;
for(i=1;i<=n;i++)
if(v[i]==0) {
v[i]=1;
cout<<endl<<”Componenta conţine ”<<i<<” ”;
for(j=1;j<=n;j++)
if(b[i][j]==1 && i!=j) {
cout<<j<<” ”;
v[j]=1; }
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 183
}
}
void main() {
clrscr();
citeste();
predecesor();
transs();
transp();
intersectie();
compo();
getch();
}
Problema 3.7.4 Fiind dat un graf neorientat prin numărul de noduri,
numărul de muchii şi extremităţile fiecărei muchii, se cere să se scrie un
program care determină componentele conexe ale grafului care conţin un nod
dat x (se va folosi algoritmul de scanare).
#include <iostream.h>
#include <conio.h>
int a[20][20],n,m,i,j,x,y,r[20],c[20],v[20];
int z,p,u,nar,k;
struct{
int x,y;
}ar[20];
void main() {
clrscr();
cout<<”Număr de noduri ”;
cin>>n;
cout<<”Număr de muchii ”;
cin¿¿m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi muchia ”<<i<<”:”;
cin>>x>>y;
a[x][y]=1;
a[y][x]=1; }
cout<<”Primul nod ”;
cin>>x;
for(k=1;k<=n;k++) {
184 CAPITOLUL 3. APLICAŢII
c[k]=0;
r[k]=0;
v[k]=0; }
p=u=1;
c[p]=x;
r[p]=x;
v[x]=1;
nar=0;
while(p<=u) {
z=c[p];
for(k=1;k<=n;k++)
if((a[z][k]==1)&&(v[k]==0)) {
u++;
nar++;
ar[nar].x=z;
ar[nar].y=k;
c[u]=k;
r[u]=k;
v[k]=1; }
p++; }
cout<<”Mulţimea R ”;
for(i=1;i<=u;i++)
cout<<r[i]<<” ”;
cout<<endl;
cout<<”Mulţimea A ”;
for(i=1;i<=nar;i++)
cout<<”(”<<ar[i].x<<”,”<<ar[i].y<<”) ”;
getch();
}
Problema 3.7.5 Fiind dat un graf orientat prin numărul de vârfuri, numărul
de arce şi extremităţile arcelor, se cere să se scrie un program care
determină toate componentele tare conexe ale grafului, folosind algoritmul lui
Malgrange.
#include <iostream.h>
#include <conio.h>
int a[20][20],n,m,i,j,x,y,l,k,ok,v1[20],v1c[20],v2[20],v2c[20],vi[20],vic[20];
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 185
int vb,l1,k1,m1,v11[20],v22[20],v111[20],v222[20],kk,e,p;
int viz[20],vb1;
void main() {
struct arc{
int x,y;
}v[20];
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
for(i=1;i<=n;i++)
viz[i]=0;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<” ”;
cin>>x>>y;
a[x][y]=1; }
vb1=0;
do {
int ee=1;
i=1;
vb1=0;
x=0;
while((i<=n)&&(ee==1))
if(viz[i]==0) {
ee=0;
x=i;
vb1=1; }
else i++;
if(x!=0) {
k=0;
for(i=1;i<=n;i++)
if((a[i][x]==1)&&(viz[i]==0)) {
k++;
v1[k]=i;
v11[k]=i;
v1c[k]=i; }
k1=k;
l=0;
for(i=1;i<=n;i++)
186 CAPITOLUL 3. APLICAŢII
if((a[x][i]==1)&&(viz[i]==0)) {
l++;
v2[l]=i;
v2c[l]=i;
v22[l]=i; }
l1=l;
m=0;
for(i=1;i<=k;i++) {
ok=0;
for(j=1;j<=m;j++)
if(v1[i]==v2[j]) ok=1;
if(ok) {
m++;
vi[m]=v1[i]; }
}
m1=m;
for(i=1;i<=m1;i++)
vic[i]=vi[i];
vb=1;
while (vb==1) {
vb=0;
k=0;
for(i=1;i<=k1;i++)
for(j=1;j<=n;j++)
if((a[j][v11[i]]==1)&&(viz[j]==0)) {
k++;
v1[k]=j;
v111[k]=j; }
kk=k;
for(i=1;i<=k1;i++) {
e=0;
for (p=1;p<=kk;p++)
if(v1[p]==v1c[i]) e=1;
if(e==0) {
k++;
v1[k]=v1c[i]; }
}
l=0;
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 187
for(i=1;i<=l1;i++)
for(j=1;j<=n;j++)
if((a[v22[i]][j]==1)&&(viz[j]==0)) {
l++;
v2[l]=j;
v222[l]=j; }
kk=l;
for(i=1;i<=l1;i++) {
e=0;
for(p=1;p<=kk;p++)
if(v2[p]==v2c[i]) e=1;
if(e==0) {
l++;
v2[l]=v2c[i]; }
}
m=0;
for(i=1;i<=k;i++) {
ok=0;
for(j=1;j<=l;j++)
if(v1[i]==v2[j]) ok=1;
if(ok) {
m++;
vi[m]=v1[i]; }
}
int aux;
if(m1!=0)
for(i=1;i<m1;i++)
for(j=i+1;j<=m1;j++)
if(vic[i]>vic[j]) {
aux=vic[i];
vic[i]=vic[j];
vic[j]=aux; }
if(m!=0)
for(i=1;i<m;i++)
for(j=i+1;j<=m;j++)
if(vi[i]>vi[j]) {
aux=vi[i];
vi[i]=vi[j];
188 CAPITOLUL 3. APLICAŢII
vi[j]=aux; }
if (m1!=m) vb=0;
else {
int vb1=0;
for(i=1;i<=m;i++)
if(vic[i]!=vi[i]) vb1=1;
if (vb1==1) vb=0;
else vb=2; }
if(vb==0) {
k1=k;
for(i=1;i<=k;i++) {
v1c[i]=v1[i];
v11[i]=v111[i]; }
l1=l;
for(i=1;i<=l;i++) {
v2c[i]=v2[i];
v22[i]=v222[i]; }
m1=m;
for(i=1;i<=m;i++)
vic[i]=vi[i];
vb=1; }
}
cout<<” ”;
for(i=1;i<=m;i++) {
cout<<vi[i]<<” ”;
viz[vi[i]]=1; } }
}while (vb1);
getch();
}
Problema 3.7.6 Folosind algortimul lui Foulkes, să se determine pentru
un graf orientat componetele sale tare conexe. Graful se găseşte ı̂n fişierul
”foulkes.in”; pe primul rând se găsesc două numere naturale, primul, n,
reprezintă numărul de vârfuri ale grafului, iar al doilea număr, m, stabileşte
numărul de arce din graf. Pe următorul rând se găsesc m perechi de numere
naturale ce reprezintă extremităţile arcelor.
Pentru următorul fişier de intrare:
7 10
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 189
12
23
42
35
54
43
71
61
62
16
Se vor afişa cele 3 componente tari conexe de mai jos:
7
16
2345
#include <stdio.h>
#include <stdlib.h>
FILE *f;
int a[20][20],b[20][20],c[20][20],ind[20],i,j,k,n,m,detect,egal;
define false 0
define true !false
void init(void) {
f=fopen(”foulkes.in”,”r”);puts(””);
fscanf(f,”%d%d”,&n,&m);
for(i=1;i<=m;i++) {
fscanf(f,”%d%d”,&j,&k);
a[j][k]=1;}
for(i=1;i<=n;i++)
a[i][i]=1;
}
void putere(void) {
int i,j,k;
do{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
c[i][j]=0;
for(k=1;k<=n;k++)
c[i][j]|=b[i][k]& b[k][j];
190 CAPITOLUL 3. APLICAŢII
}
egal=true;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(c[i][j]!=b[i][j]) {
egal=false;
b[i][j]=c[i][j];}
}while(!egal);
}
void elim(void) {
detect=false;
for(i=1;i<=n;i++)
if(ind[i]!=2) {
egal=true;
for(j=1;j<=n;j++)
if(ind[j]!=2)
if(c[i][j]==0) {
egal=false;
break;}
if(egal) {
ind[i]=1;
detect=true;} }
if(!detect) {
puts(”Graful nu este conex”);
exit(1); }
for(j=1;j<=n;j++)
if(ind[j]==1) {
egal=true;
for(i=1;i<=n;i++)
if(ind[i]==0)
if(c[i][j]==1) egal=false;
if(egal) {
printf(”%d”,j);
ind[j]=2;} }
puts(””);
}
void main() {
int i,j;
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 191
clrscr();
init();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
b[i][j]=a[i][j];
do {
detect=false;
for(i=1;i<=n;i++)
if(ind[i]!=2) {
detect=true;
putere();
elim();}
}while(!detect);
getch();
}
#include <iostream.h>
#include <fstream.h>
#define max 50
int a[max][max],gp[max],gm[max],v[max];
int n,i,j,k,ok;
int nevizitat() {
int i;
for (i=1;i<=n;i++)
if (v[i]==0) return i;
return -1;
}
void main() {
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
ifstream f;
f.open(”in.txt”);
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
192 CAPITOLUL 3. APLICAŢII
f>>a[i][j];
f.close();
for (i=1; i<=n; i++) v[i]=0;
do{
k=nevizitat();
if (k!=-1){
for (i=1;i<=n;i++) gp[i]=a[k][i];
do {
ok=0;
for (j=1;j<=n;j++)
if(gp[j]==1)
for (i=1;i<=n;i++)
if ((a[j][i]==10&& gp[i]==0)) {
ok=1;
gp[i]=1; }
} while (ok==1);
for (i=1;i<=n;i++) gm[i]=a[i][k];
do {
ok=0;
for(j=1;j<=n;j++)
if (gm[j]==1)
for(i=1;i<=n;i++)
if((a[i][j]==1)&&(gm[i]==0)) {
ok=1;
gm[i]=1; }
}while (ok==1);
for (i=1;i<=n;i++)
if ((gp[i]==1)&&(gm[i]==1)) {
cout<<i<<”,”;
v[i]=1; }
if (k==nevizitat()) {
v[k]=1;
cout<<k; }
cout<<endl;
} }while (k!=-1);
getch();
}
3.7. COMPONENTE CONEXE ŞI TARE CONEXE 193
Problema 3.7.8 Să se determine componentele tare conexe ale unui graf,
folosind un algoritm bazat pe algoritmul Roy-Warshall.
#include <stdio.h>
#include <conio.h>
int a[20][20],i,j,k,n,m,sel[20];
void init(void) {
FILE *f=fopen(”tareconx.in”,”r”);
fscanf(f,”%d%d”,&n,&m);
for(i=1;i<=m;i++) {
fscanf(f,”%d%d”,&j,&k);
a[j][k]=1;}
fclose(f); }
void main() {
clrscr();
init();
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]==0)
a[i][j]=a[i][k] & a[k][j];
k=1;
for(i=1;i<=n;i++)
if(!sel[i]) {
printf(”Componenta tare conexă %d: %d ”,k,i);
for(j=1;j<=n;j++)
if((j!=i) && (a[i][j]!=0 && (a[j][i]!=0)) {
printf(”%d”,j);
sel[j]=1; }
k++;
printf(”\n”); }
getch();
}
194 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
int a[10][10],l[20],l1[20],n,i,j,m;
int gasit, muchie,x,y,k,x1,k1,ii,p,jj;
void main() {
clrscr();
cout<<”Număr de vârfuri ”;
cin>>n;
cout<<”Număr de muchii ”;
cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi muchia ”<<i<<” ”;
cin>>x>>y;
a[x][y]=1;
a[y][x]=1; }
k=1;
cout<<”Vârf de ı̂nceput ”;
cin>>x;
l[k]=x;
x1=x;
do {
gasit=0;
i=1;
while((i<=n) && (gasit==0))
if(a[x][i]==1) {
gasit=1;
k++;
l[k]=i;
a[x][i]=0;
a[i][x]=0;
x=i; }
3.8. DETERMINAREA CIRCUITELOR EULERIENE 195
else i++;
}while(x!=x1);
do {
muchie=0;
for(i=1;i<=k;i++) {
for(j=1;j<=n;j++)
if(a[l[i]][j]==1) {
muchie=1;
x=l[i];
p=i;
x1=x;
k1=0;
do {
gasit=0;
i=1;
while((i<=n) && (gasit==0))
if(a[x][i]==1) {
gasit=1;
k1++;
l1[k1]=i;
a[x][i]=0;
a[i][x]=0;
x=i; }
else i++;
}while(x!=x1);
for(jj=1;jj<=k1;jj++) {
for(ii=k;ii>p;ii–)
l[ii+1]=l[ii];
k++; }
for(ii=1;ii<=k1;ii++)
l[p+ii]=l1[ii]; }
}
}while(muchie==0);
for(i=1;i<=k;i++)
cout<<l[i]<<” ”;
getch();
}
196 CAPITOLUL 3. APLICAŢII
#include <iostream.h>
#include <conio.h>
typedef stiva[20];
int n,a[20][20],viz[20],vf,k,m,g[20],p=1,c[20],c1[20];
stiva st;
void init(int i) {
vf=1;
st[vf]=1;
viz[i]=1;
}
int estevida() {
return vf==0;
}
void adaug(int i) {
vf++;
st[vf]=i;
viz[i]=1;
}
void elimin() {
vf- -;
}
void prelucrare() {
int i=1;
k=st[vf];
while(i<=n && (a[i][k]==0 || (a[i][k]==1 && viz[i]==1)))
i++;
if(i==n+1) elimin();
else {
p++;
adaug(i); }
}
int conex() {
k=1;
init(k);
3.8. DETERMINAREA CIRCUITELOR EULERIENE 197
while (!estevida())
prelucrare();
return (p==n);
}
void grad() {
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if (a[i][j]==1) {
g[i]++;
m++; }
m=m/2;
}
int izolat() {
for(int i=1;i<=n;i++)
if(g[i]==0) return 1;
return 0;
}
int gradpar() {
for(int i=1;i<=n;i++)
if(g[i]% 2==1) return 0;
return 1;
}
void ciclu() {
int i,j,k=1,p,q,gasit;
c[1]=1;
do for(j=1,gasit=0;j<=n && !gasit;j++)
if (a[c[k]][j]==1) {
k=k+1;
c[k]=j;
a[c[k-1]][j]=0;
a[j][c[k-1]]=0;
g[j]- -;
g[c[k-1]]- -;
gasit=1; }
while(c[k]!=1);
while(k-1<m) {
for(i=1,q=0;i<=k-1 && q==0;i++)
if(g[c[i]]>0) {
198 CAPITOLUL 3. APLICAŢII
c1[1]=c[i];
q=i; }
p=1;
do for(j=1,gasit=0;j<=n && !gasit;j++)
if(a[c1[p]][j]==1) {
p=p+1;
c1[p]=j;
a[c1[p-1]][j]=0;
a[j][c1[p-1]]=0;
g[j]- -;
g[c1[p-1]]- -;
gasit=1; }while(c1[p]!=c1[1]);
for(j=k;j>=q;j- -)
c[j+p-1]=c[j];
for(j=1;j<=p-1;j++)
c[j+q]=c1[j+1];
k=k+p-1; }
}
void main() {
int eulerian,m,x,y,i;
clrscr();
cout<<”Număr de noduri ”;
cin>>n;
cout<<”Număr de muchii ”;
cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi muchie ”<<i<<” ”;
cin>>x>>y;
a[x][y]=1;
a[y][x]=1;
}
grad();
eulerian=!(izolat()) && gradpar() && conex();
if(!eulerian) cout<<”Graful nu este eulerian ”;
else {
cout<<”Graful este eulerian”<<endl;
ciclu();
cout<<”Ciclul eulerian este ”;
3.9. DRUMURI ŞI CIRCUITE HAMILTONIENE 199
for(int i=1;i<=m+1;i++)
cout<<c[i]<<” ”;
}
getch();
}
#include <iostream.h>
#include <ctype.h>
#include <string.h>
#include <conio.h>
typedef char string[20];
int m,n,i,j,k,t;
char x,y;
string a[10][10],b[10][10],c[10][10],p,l;
void main() {
clrscr();
cout<<”Număr de vârfuri ”; cin>>n;
cout<<”Număr de arce ”; cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
strcpy(a[i][j],”0”);
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<” ”;
cin>>x>>y;
x=toupper(x);
y=toupper(y);
char *z;
switch (y) {
case ’A’:z=”A”;break;
200 CAPITOLUL 3. APLICAŢII
case ’B’:z=”B”;break;
case ’C’:z=”C”;break;
case ’D’:z=”D”;break;
case ’E’:z=”E”;break;
case ’F’:z=”F”;break;
case ’G’:z=”G”;break;
case ’H’:z=”H”;break;
case ’I’:z=”I”;break;
case ’J’:z=”J”;break;
}
strcpy(a[(int)x-64][(int)y-64],z); }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
strcpy(b[i][j],a[i][j]);
for(t=2;t<=n-1;t++) {
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
strcpy(c[i][j],”0”);
for(k=1;k<=n;k++) {
int i1,j1,e=0;
for (i1=0;i1<strlen(a[i][k]);i1++)
for(j1=0;j1<strlen(b[k][j]);j1++)
if(a[i][k][i1]==b[k][j][j1]) e=1;
if((strcmp(a[i][k],”0”)==0) ||
(strcmp(b[k][j],”0”)==0)||(e==1))
strcpy(l,”0”);
else {
strcpy(l,””);
strcpy(l,a[i][k]);
strcat(l,b[k][j]); }
if (strrchr(l,(char)(i+64))) strcpy(l,”0”);
if(strcmp(l,”0”)!=0) {
if (strcmp(c[i][j],”0”)==0) strcpy(c[i][j],””);
if (strcmp(c[i][j],””)!=0) strcat(c[i][j],”,”);
strcat(c[i][j],l); }
} }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
3.9. DRUMURI ŞI CIRCUITE HAMILTONIENE 201
strcpy(b[i][j],c[i][j]); }
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
strcpy(c[i][j],”0”);
for(k=1;k<=n;k++) {
int i1,j1,e=0;
for (i1=0;i1<strlen(a[i][k]);i1++)
for(j1=0;j1<strlen(b[k][j]);j1++)
if(a[i][k][i1]==b[k][j][j1]) e=1;
if((strcmp(a[i][k],”0”)==0) ||
(strcmp(b[k][j],”0”)==0)||(e==1))
strcpy(l,”0”);
else {
strcpy(l,””);
strcpy(l,a[i][k]);
strcat(l,b[k][j]); }
if(strcmp(l,”0”)!=0) {
if (strcmp(c[i][j],”0”)==0) strcpy(c[i][j],””);
if (strcmp(c[i][j],””)!=0) strcat(c[i][j],”,”);
strcat(c[i][j],l); }
}}
for(i=1;i<=n;i++) {
if(strcmp(c[i][i],”0”)!=0) {
switch(i) {
case 1:cout<<”A”;break;
case 2:cout<<”B”;break;
case 3:cout<<”C”;break;
case 4:cout<<”D”;break;
case 5:cout<<”E”;break;
case 6:cout<<”F”;break;
case 7:cout<<”G”;break;
case 8:cout<<”H”;break;
case 9:cout<<”I”;break;
case 10:cout<<”J”;break; }
cout<<c[i][i]<<endl; } }
getch();
}
202 CAPITOLUL 3. APLICAŢII
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
FILE *f;
int a[10][10], b[10][10], c[10][10],ind[10],i,j,k,n,m,detect,egal; int ad[10],tc;
struct {
int v,t; }dh[20],aux;
#define false 0
#define true !false
typedef int stiva[100];
int ev,as;
stiva st;
void init( ) {
st[k]=0;
}
int succesor( ) {
if (st[k]<n) {
st[k]=st[k]+1;
return 1;
}
else return 0;
}
int valid( ) {
if ((k>1) && (dh[st[k]].t<dh[st[k-1]].t))
return 0;
if ((k>1) && (a[dh[st[k-1]].v][dh[st[k]].v]==0))
return 0;
for(i=1;i<=k-1;i++)
if(dh[st[i]].v==dh[st[k]].v)
return 0;
3.9. DRUMURI ŞI CIRCUITE HAMILTONIENE 203
return 1;
}
int solutie( ) {
return k==n;
}
void tipar( ) {
int i;
for(i=1;i<=n;i++)
cout<<dh[st[i]].v<<” ”;
cout<<endl;
}
void back( ) {
k=1;
init();
while (k>0) {
as=1;
ev=0;
while (as && !ev) {
as=succesor();
if (as) ev=valid();
}
if (as)
if(solutie()) tipar( );
else {
k++;
init();
}
else k- -;
}}
void init1(void) {
f=fopen(”fulkes.in”,”r”);
puts(””);
fscanf(f,”%d%d”,&n,&m);
for(i=1;i<=m;i++)´ {
fscanf(f,”%d%d”,&j,&k);
a[j][k]=1; }
for(i=1;i<=n;i++)
204 CAPITOLUL 3. APLICAŢII
a[i][i]=1;
}
void putere(void) {
int i,k,j;
do {
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
c[i][j]=0;
for(k=1;k<=n;k++)
c[i][j]|=b[i][k]&b[k][j]; }
egal=true;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(c[i][j]!=b[i][j])
{ egal=false;
b[i][j]=c[i][j];
}
}while(!egal);
}
void elim(int tc) {
detect=false;
for(i=1;i<=n;i++)
if(ind[i]!=2) {
egal=true;
for(j=1;j<=n;j++)
if(ind[j]!=2)
if(c[i][j]==0) {
egal=false;
break; }
if(egal) {
ind[i]=1;
detect=true; }
}
if(!detect) {
printf(”Graful nu este conex”); exit(1); }
for(j=1;j<=n;j++)
if(ind[j]==1) {
egal=true;
3.9. DRUMURI ŞI CIRCUITE HAMILTONIENE 205
for(i=1;i<=n;i++)
if(ind[i]==0)
if(c[i][j]==1)
egal=false;
if(egal) {
ind[j]=2;
ad[j]=tc; }
}
puts(””);
}
void main() {
int i,j;
clrscr();
init1();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
b[i][j]=a[i][j];
tc=0;
do {
detect=false;
for(i=1;i<=n;i++)
if(ind[i]!=2) {
detect=true;
putere();
tc++;
elim(tc); }
}while(!detect);
for(i=1;i<=n;i++) {
dh[i].v=i;
dh[i].t=ad[i]; }
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
if(dh[i].t>dh[j].t) {
aux=dh[i];
dh[i]=dh[j];
dh[j]=aux; }
back();
206 CAPITOLUL 3. APLICAŢII
getch();
}
#include <iostream.h>
#include <conio.h>
void main() {
int i,j,n,m,ok,k,x,y,s,e,v[20],w[20],b[20],a[20][20];
struct putere{
int p,v;
}c[20],aux;
clrscr();
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
cout<<”Număr de arce=”;
cin>>m;
for(k=1;k<=m;k++) {
cout<<”Extremităţi arc ”<<k<<” ”;
cin>>x>>y;
a[x][y]=1; }
k=1;
int ok1=1;
while((k<=n)&&(ok1==1)) {
for(i=1;i<=n;i++)
w[i]=a[k][i];
for(j=1;j<=n;j++)
if(j!=k)
if(a[k][j]==1) {
for(i=1;i<=n;i++)
v[i]=a[j][i];
for(i=1;i<=n;i++)
3.9. DRUMURI ŞI CIRCUITE HAMILTONIENE 207
if(v[i]>w[i]) b[i]=v[i];
else b[i]=w[i];
for(i=1;i<=n;i++)
w[i]=b[i]; };
ok1=0;
for(i=1;i<=n;i++)
if(w[i]!=a[k][i]) ok1=1;
if(ok1==1) {
for(i=1;i<=n;i++)
a[k][i]=w[i];
k=k; }
else {
for(i=1;i<=n;i++)
a[k][i]=w[i];
k++;
ok1=1; }
}
e=0;
for(i=1;i<=n;i++)
if(a[i][i]==1) e=1;
if(e==1) cout<<”Graful nu are circuite”<<endl;
else cout<<”Graful are circuite”<<endl;
for(i=1;i<=n;i++) {
c[i].p=0;
c[i].v=i;
for(j=1;j<=n;j++)
if(a[i][j]==1) c[i].p++; }
s=0;
for(i=1;i<=n;i++)
s=s+c[i].p;
if(s==(n*(n-1))/2) {
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++)
if(c[i].p<c[j].p) {
aux=c[i];
c[i]=c[j];
c[j]=aux; }
cout<<”Drumul hamiltonian este:”;
208 CAPITOLUL 3. APLICAŢII
for(i=1;i<=n;i++)
cout<<c[i].v<<” ”; }
else cout<<”Graful nu are drum hamiltonian”;
getch();
}
#include <iostream.h>
#include <conio.h>
void main() {
int a[20][20],s[20],n,m,i,j,k,ok;
clrscr();
cout<<”Număr de vârfuri=”;
cin>>n;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j];
a[j][i]=a[i][j];}
cout<<”Număr de elemente din secvenţă ”; cin>>k;
for(i=1;i<=k;i++) {
cout<<”s[”<<i<<”]=”;
cin>>s[i];}
ok=1;
if(n+1!=k) ok=0;
if(ok) {
if(s[1]!=s[k]) ok=0;
if(ok) {
for(i=1;i<=k-2;i++)
for(j=i+1;j<=k-1;j++)
if(s[i]==s[j]) ok=0;
if(ok) {
for(i=1;i<=k-1;i++)
if(a[s[i]][s[i+1]]==0) ok=0;
if(!ok)
cout<<”Există noduri ı̂ntre care nu avem muchie”;
3.10. DRUMURI DE VALOARE OPTIMĂ 209
#include<stdio.h>
#include<conio.h>
int u[20][3],x0,dist[20],pred[20],atins[20],drum[20],m,n,i,j,k;
void main() {
FILE *f;
int w,x,y;
clrscr();
f=fopen(”ford.in”,”r”);
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=m;i++)
fscanf(f,”%d %d %d”,&u[i][1],&u[i][2],&u[i][0]);
fscanf(f,”%d”,&x0);
fcolse(f);
for(i=1;i<=n;i++) atins[i]=0;
dist[x0]=0;
atins[x0]=1;
for(j=0,i=1;i<=m;i++)
if(u[i][1]==x0)
drum[++j]=u[i][2];
dist[drum[j]]=u[i][0];
pred[drum[j]]=x0;
atins[drum[j]]=1; }
i=1;
x=u[i][1];
y=u[i][2];
w=u[i][0];
while(i<=m) {
while(i<=m) {
if(atins[x]==1)
3.10. DRUMURI DE VALOARE OPTIMĂ 211
if(atins[y]==1)
if(dist[y]<=dist[x]+w)i++;
else {
dist[y]=dist[x]+w;
pred[y]=x;
i=1;}
else {
dist[y]=dist[x]+w;
pred[y]=x;
atins[y]=1;
i=1;}
else i++;
x=u[i][1];
y=u[i][2];
w=u[i][0];
}}
for(i=1;i<=n;i+)
if(atins[i]==1) {
printf(”\n Costul până la vârful %d este:
%d\n Traseul:\n %d”,i,dist[i],x0);
k=0;
j=i;
while(pred[j]!=x0) drum[++k]=j=pred[j];
for(;k;) printf(”%d ”,drum[k- -]);
printf(”%d”,i”); }
getch();
}
Problema 3.10.2 Fiind dat un graf valorizat să se determine drumurile
de valoare minimă dintre două vârfuri date. Datele problemei se găsesc ı̂n
fişierul ”graf.in”, pe primul rând se găsesc două numere naturale, n şi m, ce
reprezintă numărul de vârfuri şi de arce din graful respectiv, pe următoarele
m rânduri se găsesc triplete de numere, extremităţile unui arc şi costul aso-
ciat arcului. Pe ultimul rând din fişier se găsesc două numere naturale
ce reprezintă cele două extremităţi ale drumurilor căutate. Pentru imple-
mentarea problemei se va folosi algoritmul Bellman-Kalaba.
#include <stdlib.h>
#include <stdio.h>
212 CAPITOLUL 3. APLICAŢII
#include <conio.h>
int v[20][20],l[20][20],v1[20],v2[20],x[20],p,s,m,n,s1;
void introd(void) {
int i,j,r;
FILE *f;
f=fopen(”graf.in”,”r”);
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
v[i][j]=0;
l[i][j]=32000; }
for(i=1;i<=m;i++) {
fscanf(f,”%d %d %d”,&p,&s,&r);
v[p][s]=1;
l[p][s]=r;}
fscanf(f,”%d %d”,&p,&s);
fclose(f);
}
void prod( ) {
int i,j,min,b;
for(i=1;i<=n-1;i++)
v1[i]=l[i][n];
v1[n]=0;
do {
for(i=1;i<=n-1;i++) {
min=32000;
for(j=1;j<=n;j++)
if(v1[j]+l[i][j]<min)
min=v1[j]+l[i][j];
v2[i]=min; }
v2[n]=0;
for(i=1,b=0;i<=n && b==0;i++)
if(v2[i]!=v1[i]) {
b=1;
for(j=1;j<n;j++)
v1[j]=v2[j];}
}while (b);
}
3.10. DRUMURI DE VALOARE OPTIMĂ 213
void tiparire(int k) {
int i;
printf(”Drum minim de la %d la %d ”,p,s);
for(i=1;i<k;i++)
printf(”%d ”,x[i]);
printf(”\n”);
}
void drummin(int k) {
int i;
if(x[k-1]==s) {
for(i=2,s1=0;i<=k-1;i++)
s1+=l[x[i-1]][x[i]];
if(s1==v2[1])
tiparire(k); }
else for(i=1;i<=n;i++) {
x[k]=i;
if(v2[i]<v2[x[k-1]] && v[x[k-1]][i]==1)
drummin(k+1); }
}
void main() {
clrscr();
introd();
prod();
printf(”\n Costul este %d \n”,v2[1]);
x[p]=1;
drummin(2);
getch();
}
• pe ultimul rând din fişier un număr ı̂ntreg care reprezintă vârful iniţial
al drumului.
#include <stdio.h>
#include <conio.h>
#include <mem.h>
int a[20][20],d[20],i,j,k,n,x,y,min,imin;
char c[20],varf[20];
void main( ) {
FILE *f;
f=fopen(”dijkstra.in”,”r”);
if (f==NULL) {
printf(”Eroare la deschidere ”);
return; }
fscanf(f,”%d”,&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
fscanf(f,”%d”,&a[i][j]);
fscanf(f,”%d”,&x);
memset(d,0,sizeof(d));
memset(varf,0,sizeof(varf));
for(i=1;i<=n;i++) {
c[i]=1;
if(a[x][i]) varf[i]=x;
}
c[x]=0;
for(i=1;i<=n;i++)
if(c[i]) d[i]=a[x][i];
for(y=1;y<=n;y++)
if(x!=y) {
for(k=1;k<=n-2;k++) {
min=10000;
for(i=1;i<=n;i++)
if(c[i]&& d[i]>0 && d[i]<min) {
min=d[i];
imin=i; }
if (imin==y) break;
c[imin]=0;
3.10. DRUMURI DE VALOARE OPTIMĂ 215
for(i=1;i<=n;i++)
if(c[i] && d[imin]!=0 && a[imin][i]!=0)
if(d[i]==0 || d[i]>d[imin]+a[imin][i]) {
d[i]=d[imin]+a[imin][i];
varf[i]=imin;
}
}
printf(”\n Distanţa minimă ı̂ntre %d şi %d este:
%d \n”,x,y,d[y]);
c[i=0]=y;
while(varf[i]!=x && varf[c[i]])
c[++i]=varf[c[i-1]];
if(c[i]!=x) c[++i]=x;
for(;i>=0;)
printf(”%d ”,c[i- -]);
}
getch();
}
#include <iostream.h>
#include <conio.h>
int a[20][20],t[20][20],c[20][20],drum[20][20],m,n,i,j,k;
void floyd( ) {
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
t[i][j]=c[i][j];
drum[i][j]=0; }
for(i=1;i<=n;i++)
t[i][i]=0;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
216 CAPITOLUL 3. APLICAŢII
for(j=1;j<=n;j++)
if(t[i][k]+t[k][j]<t[i][j]) {
t[i][j]=t[i][k]+t[k][j];
drum[i][j]=k; }
}
void traseu(int i,int j) {
int k=drum[i][j];
if(k!=0) {
traseu(i,k);
cout<<k<<” ”;
traseu(k,j); }
}
void main() {
int cost;
clrscr();
cout<<”Introduceţi numărul de vârfuri ”;
cin>>n;
cout<<”Introduceţi numărul de arce ”;
cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
a[i][j]=0;
c[i][j]=9999; }
for(i=1;i<=m;i++) {
cout<<”Extremităţi arc ”<<i<<”: ”;
cin>>j>>k;
a[j][k]=1;
cout<<”Costul arcului ”;
cin>>cost;
c[j][k]=cost; }
floyd();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
if(t[i][j]==9999)
cout<<endl<<”Nu există drum ı̂ntre ”<<i<<” şi ”<<j;
else {
3.10. DRUMURI DE VALOARE OPTIMĂ 217
#include <mem.h>
#include <stdio.h>
#include <conio.h>
int n,m,a[20][20],u[50][2],i,j,k,sel[20],c[20],cmin[20],l=0,cost[50],min,cos;
void introducere(void);
void circuit(int i);
void main() {
clrscr();
min=10000;
introducere();
c[0]=1;
circuit(1);
if(min==10000) {
218 CAPITOLUL 3. APLICAŢII
#include<iostream.h>
#include<conio.h>
int k,n,i,j,cont,c[20][20],x[20],y[20];
char nume[20][20]; int costcurent, costminim;
int potcontinua() {
if(c[x[k]][x[k-1]]==10000) return 0;
if(k==n)
if(c[x[n]][x[1]]==10000) return 0;
for(int i=1;i<k;i++)
if(x[i]==x[k]) return 0;
return 1;
}
void main() {
clrscr();
cout<<”Circuit hamiltonian de cost minim”<<endl;
cout<<”Număr de oraşe ”;
cin>>n;
for(i=1;i<=n;i++) {
cout<<”Nume oraş ”<<i<<” ”;
cin>>nume[i]; }
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++) {
cout<<”Cost drum de la ”<<nume[i];
cout<<” la ”<<nume[j]<<” 0-infinit :”;
cin>>c[i][j];
if(c[i][j]==0)
c[i][j]=10000;
c[j][i]=c[i][j]; }
x[1]=1;
k=2;
220 CAPITOLUL 3. APLICAŢII
x[k]=1;
costminim=10000;
while(k>1) {
cont=0;
while((x[k]<n) && (!cont)) {
x[k]++;
cont=potcontinua(); }
if(cont)
if(k==n) {
costcurent=0;
for(i=1;i<n;i++)
costcurent+=c[x[i]][x[i+1]];
costcurent+=c[x[n]][x[1]];
if(costcurent<costminim) {
costminim=costcurent;
for(i=1;i<=n;i++)
y[i]=x[i]; }
}
else x[++k]=1;
else - -k;
}
cout<<”Circuit de cost minim ”<<endl;
for(i=1;i<n;i++)
cout<<nume[y[i]]<<” ”;
cout<<nume[y[1]]<<” ”;
cout<<”Costul este ”<<costminim;
getch();
}
#include <iostream.h>
#include <conio.h>
struct muchie {
int x,y,c; } v[20];
int a1,a2,m,n,i,j,cost,k,l,nr,t[20];
muchie aux;
void main() {
clrscr();
cout<<”Număr de vârfuri ”;
cin>>n;
cout<<”Număr de muchii ”;
cin>>m;
for(i=1;i<=m;i++) {
cout<<”Extremităţi muchie ”<<i<<”:”;
cin>>v[i].x>>v[i].y;
cout<<”Cost muchie ”;
cin>>v[i].c; }
cout<<”Arborele de cost minim este ”<<endl;
for(i=1;i<=m-1;i++)
for(j=i+1;j<=m;j++)
if(v[i].c>v[j].c) {
aux=v[i];
v[i]=v[j];
v[j]=aux; }
for(i=1;i<=n;i++)
t[i]=i;
cost=0;
i=1;
nr=0;
while(nr<n-1) {
if(t[v[i].x]!=t[v[i].y]) {
nr++;
cost=cost+v[i].c;
cout<<v[i].x<<” ”<<v[i].y<<endl;
k=t[v[i].x];
l=t[v[i].y];
for(j=1;j<=n;j++)
if(t[j]==k) t[j]=l; }
222 CAPITOLUL 3. APLICAŢII
i++;
}
cout<<”Cost ”<<cost;
getch();
}
#include <iostream.h>
#include <conio.h>
void main( ) {
int a[20][20],s[20],t[20],c[20],n,cost,i,j,k,n1,n2,start,costm;
clrscr();
cout<<”Număr de vârfuri”;
cin>>n;
cout<<” Daţi 3200 dacă nu există muchie”<<endl;
for(i=1;i<=n;i++)
a[i][i]=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++) {
cout<<”Cost ı̂ntre ”<<i<<” şi ”<<j<<” ”;
cin>>a[i][j];
a[j][i]=a[i][j]; }
cout<<”Arborele parţial de cost minim”<<endl;
for(i=1;i<=n;i++)
s[i]=t[i]=c[i]=0;
start=1;
s[start]=1;
for(k=1;k<=n-1;k++) {
costm=32000;
n1=-1;
n2=-1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if((s[i]==1) && (s[j]==0))
3.11. ARBORE PARŢIAL DE COST MINIM 223
if(a[i][j]<costm) {
costm=a[i][j];
n1=i;
n2=j; }
s[n2]=1;
t[n2]=n1;
c[n2]=a[n1][n2];
}
for(i=2;i<=n;i++)
cout<<t[i]<<” ”<<i<<endl;
cost=0;
for(i=1;i<=n;i++)
cost+=c[i];
cout<<”Cost minim ”<<cost;
getch();
}
Problema 3.11.3 Să se scrie un program care determină toţi arborii parţiali
de cost minim ai unui graf. Datele se găsesc ı̂n fişierul ”graf.txt”.
Pentru rezolvarea problemei vom verifica mai ı̂ntâi dacă graful iniţial este
conex, ı̂n caz negativ neexistând niciun arbore parţial. Apoi vom genera
toate submulţimile de muchii ale grafului iniţial care pot forma un arbore
şi vom calcula costul arborelui găsit. Dacă acesta este mai mic decât costul
minim curent se va actualiza numărul de arbori parţiali de cost minim la 0
iar costul minim va lua valoarea costului curent. Dacă costul curent este egal
cu costul minim se incrementează numărul de arbori şi se stochează arborele
găsit.
#include <stdio.h>
#include <conio.h>
int m,n,i,j,k,cost,costmin=32767;
int a[50][50],c[50][50],l[50][50],u[50][2];
int x[50],arbori[50][50],sel[50],n1,m1,nrarb=0;
void introd(void) {
FILE*f;
int cost;
f=fopen(”graf.txt”,”r”);
224 CAPITOLUL 3. APLICAŢII
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=c[i][j]=0;
for(i=1;i<=m;i++){
fscanf(f,”%d %d %d”,&j,&k,&cost);
u[i][0]=j;
u[i][1]=k;
a[j][k]=a[k][j]=1;
c[j][k]=c[k][j]=cost;
}
fclose(f);
}
void sub(int mult[50]) {
int i=1;
while (mult[i]==1) mult[i++]=0;
mult[i]=1;
}
void lanturi(int a[][50],int l[][50]){
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
l[i][j]=a[i][j];
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (l[i][j]==1)
for(k=1;k<=n;k++)
if (l[k][j]==1)
l[i][k]=l[k][i]=1;
int conex(int l[][50]){
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (l[i][j]==0) return 0;
return 1;
}
void main(void){
int i,k,j;
3.11. ARBORE PARŢIAL DE COST MINIM 225
introd( );
lanturi(a,l);
if (!conex(l)) {
printf(”Graful nu este conex”);
return; }
for(k=1;k<=(1<<m);k++){
sub(sel);
m1=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++)
if(sel[i]==1){
a[u[i][0]][u[i][1]]=a[u[i][1]][u[i][0]]=1;
x[u[i][0]]=x[u[i][1]]=1;
m1++;
}
n1=0;
for(i=1;i<=n;i++)
if (x[i]==1) n1++;
lanturi(a,l);
if((n1-1==m1)&&(conex(l)==1)){
cost=0;
for(i=1;i<=m;i++)
if(sel[i]==1) cost+=c[u[i][0]][u[i][1]];
if(cost<costmin){
nrarb=0;
costmin=cost; }
if(cost==costmin){
nrarb++;
for(i=1;i<=m;i++)
arbori[nrarb][i]=sel[i];}
} }
printf(”Costul minim este %d sunt %d arbori”,costmin,nrarb);
for(i=1;i<=nrarb;i++){
for(j=1;j<=m;j++)
if (arbori[i][j]==1)
226 CAPITOLUL 3. APLICAŢII
printf(”%d %d”,u[j][0],u[j][1]);
printf(”\n”); }
getch();
}
Problema 3.11.4 Să se determine dacă un graf neorientat este sau nu
ciclic.
Problema are o rezolvare bazată pe algoritmul lui Kruskal de obţinere a
arborelui parţial de cost minim dintr-un graf.
Se citesc muchiile grafului şi se repartizează ı̂n componente conexe, ı̂n funcţie
de capetele lor. Dacă la un moment dat s-a citit o muchie care are am-
bele capete ı̂n aceeaşi componentă conexă, ı̂nseamnă că s-a ı̂ntâlnit un ciclu
deoarece ı̂ntre capetele muchiei există deja un lanţ (altfel nu ar fi făcut parte
din aceeaşi componentă conexă).
Se observă că nu este nevoie de stocarea muchiilor şi nici a matricii de
adiacenţă, vectorul care conţine pe poziţia i componenta conexă din care
face parte vârful i fiind suficient. Acest vector se iniţializează cu 0, după
care fiecare muchie va fi tratată distinct, ı̂n funcţie de componentele conexe
ı̂n care se află capetele sale:
• dacă ambele capete ale muchiei au componenta 0 atunci se va incre-
menta numărul de componente nr, iar cele două vârfuri vor fi ı̂n noua
componentă (cu indicele nr);
• dacă exact unul din capete are componenta 0, el va fi adăugat la com-
ponenta conexă a celuilalt vârf;
• dacă ambele capete se află ı̂n aceeaşi componentă, am obţinut un ciclu;
• dacă ambele capete se află ı̂n componente conexe diferite atunci muchia
citită uneşte cele două componente, deci se va obţine o singură compo-
nentă conexă.
#include <stdio.h>
#include <conio.h>
void main(){
int i,j,k,l,m,n,nr=0,con[100];
FILE *f=fopen(”aciclic.in”,”r”);
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=n;i++)
3.11. ARBORE PARŢIAL DE COST MINIM 227
con[i]=0;
for(i=0;i<m;i++){
fscanf(f,”%d %d”,&j,&k);
if(con[j])
if(con[k]){
if(con[j]==con[k]){
printf(”Ciclic, muchia [%d,%d]”,j,k);
return;}
k=con[k];
j=con[j];
for(l=1;l<=n;l++)
if(con[l]==k) con[l]=j;
}
else con[k]=con[j];
else
if(con[k]) con[j]=con[k];
else con[j]=con[k]=++nr;
}
puts(”Graful nu are cicluri”);
getch();
}
Problema 3.11.5 Edilii unui judeţ vor să refacă o reţea de drumuri care să
asigure legătura ı̂ntre oraşul reşedinţă de judeţ şi cele n localităţi ale judeţului
precum şi ı̂ntre cele n localităţi. Se cunosc distanţele ı̂ntre oricare două
localităţi din judeţ. Să se afişeze perechile de localităţi ı̂ntre care se vor
reface drumurile astfel ı̂ncât să existe drum ı̂ntre oricare două localităţi, iar
lungimea totală a drumului refăcut să fie minimă. (Se va folosi algoritmul
lui Prim).
#include <iostream.h>
#include <conio.h>
void main() {
int a[20][20],s[20],t[20],c[20],n,cost,i,j,k,n1,n2,start,costm;
clrscr();
cout<<”Număr de oraşe ”;
cin>>n;
for(i=1;i<=n;i++)
228 CAPITOLUL 3. APLICAŢII
a[i][i]=0;
for(i=1;i<n;i++)
for(j=i+1;j<=n;j++){
cout<<”Cost ı̂ntre ”<<i<<” şi ”<<j;
cin>>a[i][j];
a[j][i]=a[i][j]; }
for(i=1;i<=n;i++)
s[i]=t[i]=c[i]=0;
start=1;
s[start]=1;
for(k=1;k<=n-1;k++) {
costm=32767;
n1=-1;
n2=-1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if((s[i]==1)&&(s[j]==0))
if(a[i][j]<costm) {
costm=a[i][j];
n1=i;
n2=j; }
s[n2]=1;
t[n2]=n1;
c[n2]=a[n1][n2]; }
for(i=2;i<=n;i++)
cout<<t[i]<<” ”<<i<<endl;
cost=0;
for(i=1;i<=n;i++)
cost+=c[i];
cout<<”Cost minim ”<<cost;
gecth();
}
• verif, verifică dacă graful este sau nu reţea, face determinarea gradelor
şi iniţializarea fluxului cu 0;
• ver, verifică dacă fluxul ales este valid pentru arcul dat;
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int m,n;
typedef int mat[20][20];
typedef int vect[20];
typedef enum bool{false,true}bool;
mat c,a,l,f,f1;
vect di,de,l1;
int u[100][2],ei,ef;
bool gasit,sel[20];
int a1,b1,min;
void intr(void);
void matrice(void);
void verif(void);
bool ver(int,int);
void flux(int i1);
void prel(int);
230 CAPITOLUL 3. APLICAŢII
void detcap(void);
void intr() {
FILE*f;int i,j;
f=fopen(”flux.in”,”r”);
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=m;i++){
fscanf(f,”%d %d”,u[i],u[i]+1,&c[u[i][0],u[i][1]]);
fscanf(f,”%d”,&j); c[u[i][0][u[i][1]]=j; }
fclose(f);
}
void matrice(void) {
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=0;
for(i=1;i<=m;i++)
a[u[i][0]][u[i][1]]=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
l[i][j]=a[i][j];
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
if(l[i][k])
for(j=1;j<=n;j++)
if(l[i][j]<l[k][j]) l[i][j]=1;
}
void verif() {
int i,j;
for(i=1;i<=n;i++)
di[i]=de[i]=0;
for(i=1;i<=m;i++) {
de[u[i][0]]++;
di[u[i][1]]++;}
a1=b1=0;
for(i=1;i<=n;i++)
if(de[i]==0) b1=i;
for(i=1;i<=n;i++)
if(di[i]==0) {
3.12. PROBLEMA FLUXULUI MAXIM 231
a1=i;
break;}
if(a1==0 || b1==0) {
printf(”Nu este reţea”);
exit(1); }
for(i=1;i<=n;i++)
printf(”Vârful %d are gradul intern %d şi gradul extern:
%d\n”,i,di[i],de[i]);
printf(”Graful este reţea \n”);
printf(”Vârf iniţial %d vârf final %d \n”,a1,b1);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f[i][j]=0;
}
void prel(int nr) {
int i,i1,j1;
min=255;
for(i=1;i<nr;i++) {
i1=l1[i];
j1=l1[i+1];
if(a[j1][i1] && f[j1][i1]<min)
min=f[j1][i1];
if(a[i1][j1] && c[i1][j1]-f[i1][j1]<min)
min=c[i1][j1]-f[i1][j1]; }
for(i=1;i<nr;i++) {
i1=l1[i];
j1=l1[i+1];
if(a[i1][j1]==1)
f[i1][j1]+=min;
else f[i1][j1]-=min; }
}
bool ver(int i,int j) {
if(a[l1[i]][j]+a[j][l1[i]]==0) return false;
if(a[l1[i]][j]==1)
return c[l1[i]][j]>f[l1[i]][j];
else return f[l1[i]][j]>0;
}
void flux(int i) {
232 CAPITOLUL 3. APLICAŢII
int j;
for(j=1;!gasit && j<=n;j++)
if(ver(i-1,j) && sel[j]==false) {
l1[i]=j;
sel[j]=true;
if(j==b1) {
prel(i);
gasit=true; }
else if(i<n) flux(i+1);
sel[j]=false; }
}
void detcap(void) {
int i,flux1;
flux1=0;
l1[1]=a1;
do {
gasit=false;
for(i=1;i<=n;i++)
sel[i]=false;
sel[a1]=true;
flux(2);
if(gasit) flux1+=min;
}while(gasit);
for(i=1;i<=m;i++)
printf(”Arcul (%d%d) capacitatea: %d fluxul: %d \n”,
u[i][0],u[i][1],c[u[i][0]][u[i][1]],f[u[i][0]][u[i][1]]);
printf(”Fluxul este: %d \n”,flux1);
}
void main() {
clrscr();
intr();
matrice();
verif();
detcap();
getch();
}
3.13. PROBLEME DE AFECTARE 233
#include <iostream.h>
#include <conio.h>
int a[20][20],d[20],v[20],s,li0,i0,c0,j,k,n,R,c,i,u0,j0;
void calcul( ) {
d[1]=1;
v[1]=1;
s=a[1][1];
for(k=2;k<=n;k++) {
li0=a[1][k]+a[k][d[1]]-a[1][d[1]];
i0=1;
c0=d[i0];
j=d[i0];
for(i=1;i<k;i++) {
j=d[i];
R=a[i][k]+a[k][j]-a[i][j];
if(R<li0) {
li0=R;
i0=i;
j=d[i];
c0=j;
j0=j; }
for(c=1;c<k;c++)
if(c-j) {
int u = v[c];
R=a[i][k]+a[k][c]-a[i][j]-a[u][c]+a[u][j];
if(R<li0) {
li0=R;
c0=c;
i0=i;
234 CAPITOLUL 3. APLICAŢII
u0=u;
j0=j; }
}
}
if(li0>= a[k][k]) {
s+=a[k][k];
d[k]=k;
v[k]=k; }
else {
s+=li0;
if(c0==j0) {
d[i0]=k;
d[k]=c0;
v[c0]=k;
v[k]=i0; }
else {
d[i0]=k;
v[k]=i0;
d[u0]=j0;
v[j0]=u0;
d[k]=c0;
v[c0]=k; }
}
}
cout<<” S= ”<<s<<endl;
for(i=1;i<=n;i++)
cout<<i<<”->”<<d[i]<<” cost ”<<a[i][d[i]]<<” ”<<endl;
}
void main( ) {
clrscr();
cout<<”Număr de maşini şi lucrări ”;
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {
cout<<”a[”<<i<<”,”<<j<<”]=”;
cin>>a[i][j]; }
calcul();
3.14. PROBLEME DE ORDONANŢARE 235
getch();
}
#include<conio.h>
#include<stdio.h>
int i,n,m,u[30[2],a[30][30],l[30][30],di[30],de[30];
int ei,ef,cost[30],ti[30],tf[30],nr,ev[20],t[20][20];
void matricea(void);
void matricel(void);
void grade(void);
void introgract(void);
verif(void);
void adaugare(void);
void determinare(void);
void introgract() {
FILE*f;
memset(t,0,sizeof(t));
f=fopen(”grafact.in”,”r”);
fscanf(f,”%d %d”,&n,&m);
for(i=1;i<=m;i++) {
fscanf(f,”%d %d %d”,&u[i][0],&u[i][1],&cost[i]);
t[u[i][0]][u[i][1]]=cost[i]; }
fclose(f);
}
void determinare() {
int j,k,x[30],l1;
236 CAPITOLUL 3. APLICAŢII
memset(ti,0,sizeof(ti));
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[j][i]==1 && ti[i]<ti[j]+t[j][i])
ti[i]=ti[j]+t[j][i];
puts(”Timpii iniţiali ”);
for(k=1;k<=n;k++)
printf(”%d ”,ti[k]);
for(k=1;k<=n;k++)
tf[i]=ti[ef];
for(k=1;k<=n;k++)
for(i=1;i<=n;i++) {
tf[i]=ti[ef];
for(j=1;j<=n;j++)
if(a[i][j]==1 && tf[i]>tf[j]-t[i][j])
tf[i]=tf[j]-t[i][j]; }
puts(”\n Timpii finali ”);
for(k=1;k<=n;k++)
printf(”%d ”,tf[k]);
putchar(’\n’);
for(i=1;i<=n;i++)
if(ti[i]==tf[i]) ev[i]=1;
else ev[i]=0;
puts(”Evenimente critice ”);
for(k=1;k<=n;k++)
if(ev[k]) printf(”%d ”,k);
putchar(’\n’);
memset(x,0,sizeof(x));
puts(”Drumuri critice ”);
x[1]=ei;
k=2;
while(k>1)
if(x[k]<n) {
x[k]++;
if(ev[x[k]] && a[x[k-1]][x[k]]
&& ti[x[k-1]]+t[x[k-1]][x[k]]==ti[x[k]]) {
if(x[k]==ef) {
3.14. PROBLEME DE ORDONANŢARE 237
for(l1=1;l1<=k;l1++)
printf(”%d ”,x[l1]);
putchar(’\n’); }
x[++k]=0; } }
else k- -;
}
verif() {
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(l[i][j]==1 && l[j][i]==1 && i!=j) return 0;
return 1;
}
void adaugare() {
for(i=1;i<=n;i++)
if(di[i]==0) {
ei=i;
break; }
for(i=ei+1;i<=n;i++)
if(di[i]==0) {
u[++m][0]=ei;
u[m][1]=i; }
for(i=1;i<=n;i++)
if(de[i]==0) {
ef=i;
break; }
for(i=ef+1;i<=n;i++)
if(de[i]==0) {
u[++m][0]=i;
u[m][1]=ef; }
}
void grade() {
int i;
for(i=1;i<=m;i++) {
di[u[i][1]]++;
de[u[i][0]]++; }
}
void matricea() {
238 CAPITOLUL 3. APLICAŢII
int i;
memset(a,0,sizeof(a));memset(l,0,sizeof(l));
for(i=1;i<=m;i++)
a[u[i][0]][u[i][1]]=l[u[i][0]][u[i][1]]=1;
}
void matricel() {
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(l[i][j]==1)
for(k=1;k<=n;k++)
if(l[j][k]==1) l[i][k]=1;
}
void main() {
clrscr();
introdgract();
grade();
matricea();
matricel();
if(!verif()) {
puts(”Graful nu este graf de activităţi”);
return; }
adaugare();
determinare();
getch();
}
#include<iostream.h>
#include<conio.h>
float l[20][20],t[20],tb[20];
int n,i,j;
void citire() {
float c; int i,m,x,y;
clrscr( );
3.14. PROBLEME DE ORDONANŢARE 239
l[i][j]=-1; }
citire();
calct(n);
calctb(1);
cout<<”Evenimente critice ”;
for(i=1;i<=n;i++)
if(t[i]==tb[i]) cout<<i<<” ”;
cout<<endl;
getch();
}
Exemplul 3.14.4 Fie un proiect care este alcătuit din următoarele activităţi.
Foaia de calcul care conţine acest model este prezentată mai jos.
A B C D E F G H
1 Ativitate Durata DI DT TI TT Abatere Critica
2 0 0 0 0 -5 -5 -5 NU
3 1 5 0 5 -5 0 -5 NU
4 2 2 4 6 4 6 0 DA
5 3 4 0 4 0 4 0 DA
6 4 3 6 9 9 12 3 NU
7 5 6 6 12 6 12 0 DA
8 6 0 12 12 12 12 0 DA
9
10 Lung. max. 12
Datele şi formulele introduse sunt cele rezultate prin dezvoltarea grafului
ataşat proiectului. Formulele utilizate ı̂n foaia de calcul sunt:
3.14. PROBLEME DE ORDONANŢARE 241
vectorul de arce al unui graf orientat cu n noduri şi m arce, să se construiască
şi să se afişeze matricea de adiacenţă, apoi să se determine costul mediu al
grafului (media aritmetică a costurilor arcelor).
Problema 3.15.6 Scrieţi un program care citeşte din fişierul text ”graf.txt”
informaţii despre un graf orientat (de pe prima linie numărul de noduri,
apoi matricea de adiacenţă) şi de la tastatură o mulţime A de numere care
reprezintă etichetele unor noduri din graf şi afişează mulţimea arcelor ce au
o extremitate ı̂ntr-un nod din mulţimea A şi o extremitate ı̂n mulţimea X \ A
(X este mulţimea nodurilor grafului).
Problema 3.15.7 În fişierul text ”graf.txt” este scrisă o matrice, astfel:
pe primul rând două numere naturale separate prin spaţiu, care reprezintă
numărul de linii şi numărul de coloane ale matricei şi pe următoarle rânduri
valori numerice despărţite prin spaţiu, care reprezintă elementele de pe câte
o linie a matricei. Scrieţi un program care să verifice dacă această matrice
poate fi matricea de adiacenţă asociată unui graf orientat. În caz afirmativ,
să se determine câte noduri care au gradul intern egal cu gradul extern există.
Problema 3.15.10 În secolul XXI, locul clasicelor plăcuţe indicatoare care
ne ajută să ne orientăm ı̂n intersecţii, este luat de panouri electronice lu-
minoase. Primarul unui oraş a achiziţionat trei tipuri de astfel de panouri,
de culoare roşie, albastră şi verde. El doreşte să plaseze câte unul ı̂n fiecare
intersecţie, dar ı̂n aşa fel ı̂ncât pe fiecare stradă, delimitată la capete de două
intersecţii, să nu se ı̂ntâlnească acelaşi tip de panou de două ori. Găsiţi o
soluţie posibilă de aranjare a panourilor ı̂n intersecţii conform dorinţei pri-
marului, sau un răspuns negativ dacă aşa ceva nu e posibil. Presupunem
că s-a achiziţionat un număr suficient de panouri de fiecare tip. Se dau:
244 CAPITOLUL 3. APLICAŢII
Problema 3.15.18 Să se scrie un program care verifică dacă un graf ne-
orientat dat prin matricea sa de adiacenţă este un graf complet.
Problema 3.15.22 Din fişierul text ”graf.txt” se citesc muchiile unui graf
neorientat, fiecare muchie se găseşte pe câte un rând din fişier. Să se scrie
un program care caută şi afişează cel mai lung lanţ elementar care este format
din noduri care au etichete numere consecutive, ordonate crescător.
Problema 3.15.24 Scrieţi un program care citeşte lista muchiilor unui graf
neorientat şi afişează toate ciclurile elementare care trec printr-un nod cu
gradul minim.
Problema 3.15.25 Scrieţi un program care citeşte din fişierul ”g.in” lista
arcelor unui graf orientat, se presupune că pe fiecare rând al fişierului se
găseşte câte o pereche de numere naturale care reprezintă extremităţile unui
arc, şi care caută toate ciclurile elementare care există ı̂n graf şi le afişează.
Dacă nu există niciun ciclu elementar, se afişează un mesaj.
246 CAPITOLUL 3. APLICAŢII
Problema 3.15.26 Fiind dat un graf orientat, să se scrie un program care
verifică dacă graful respectiv este un graf turneu. (Un graf orientat ı̂n care,
ı̂ntre oricare două noduri există un singur arc şi numai unul, se numeşte graf
turneu.)
Problema 3.15.27 Fiind dat un graf orientat prin lista arcelor sale, se cere
să se scrie un program care determină toate drumurile elementare din graf.
Drumurile obţinute se vor afişa ı̂n fişierul ”drum.out”, fiecare drum se va
afişa pe un rând separat. Dacă nu se va găsi niciun drum, ı̂n fişier se va
afişa un mesaj corespunzător.
Problema 3.15.28 Fiind dat un graf orientat prin lista arcelor sale, se
cere să se scrie un program care determină toate drumurile elementare cu
lungimea cea mai mică dintre două vârfuri, x şi y. Etichetele vârfurilor se
citesc de la tastatură.
Problema 3.15.33 Într-o zonă de munte, există n cabane, ı̂ntre unele ca-
bane existând trasee de legătură. Să se determine, dacă există, o ordine de
vizitare a cabanelor, astfel ı̂ncât să se parcurgă o singură dată toate traseele
de legătură din zonă revenind la aceeaşi cabană de la care s-a pornit.
Problema 3.15.45 Cele n pieţe din Veneţia sunt legate printr-un sistem
de canale. În piaţa San Marco cineva uită robinetul deschis şi se produce o
inundaţie care se extinde ı̂n pieţele situate la distanţa <= r de San Marco.
Stabiliţi numărul de pieţe inundate. Pieţele sunt identificate prin numerele
de la 1 la n, iar canalele prin perechi de pieţe (i, j). Graful este reprezentat
prin liste de adiacenţă.
Problema 3.15.46 Harta unei ţări este formată din mai multe regiuni. O
parte dintre regiuni au frontiera comună. Scrieţi un program care afişează
regiunea care se ı̂nvecinează cu cele mai multe dintre regiuni.
Problema 3.15.49 Într-un oraş există n intersecţii, legate ı̂ntre ele prin
străzi cu sens unic. Stabiliţi grupele de intersecţii care nu comunică ı̂ntre
ele. Câte asemenea grupuri există?
Limbajul C/C++
Setul de caractere al limbajului cuprinde: literele mari şi mici ale alfa-
betului englez; cifrele sistemului de numeraţie zecimal; caracterele speciale
(+, −, ?, /, \, )
Identificatorii sunt succesiuni de litere, cifre sau caracterul , primul carac-
ter fiind obligatoriu o literă sau caracterul . Limbajul C++ este case-sensitiv
(literele mici se consideră distincte de cele mari).
Cuvintele cheie sunt identificatori cu semnificaţie specială, care nu pot fi
folosiţi ı̂n alt context decât cel precizat ı̂n definirea limbajului. Cuvintele
rezervate din C + + sunt următoarele:
251
252 ANEXA A. LIMBAJUL C/C++
A.3 Constante
Constantele sunt date care nu se modifică pe parcursul execuţie unui pro-
gram. Dacă au asociat un identificator, atunci se numesc constante sim-
bolice. Dacă nu au asociat nici un identificator, atunci ele se reprezintă prin
valoarea lor. Există constante ı̂ntregi, constante caracter, constante reale,
constante şir de caractere.
Pentru a defini constante simbolice vom folosi construcţia:
const [tip constanta] nume constanta = valoare;
A.5 Expresii
Prin expresie ı̂nţelegem o succesiune de operatori şi operanzi care respectă
anumite reguli. Un operand poate fi: o constantă, o constantă simbolică, nu-
mele unei variabile, referirea la elementul unei structuri, apelul unei funcţii,
expresie inclusă ı̂ntre paranteze rotunde. Operatorii pot fi unari sau binari.
O expresie are o valoare şi un tip şi pot fi folosite parantezele pentru a im-
pune o anumită ordine a operaţiilor.
Regula conversiilor implicite. Această regulă se aplică la evaluarea expre-
siilor. Ea acţionează atunci când un operator binar se aplică la doi operanzi
de tipuri diferite: operatorul de tip ”inferior” se converteşte spre tipul ”su-
perior”.
Operatorii care pot fi utilizaţi ı̂n C/C + + sunt:
Operatorii aritmetici sunt: - operatorii unari +, −; operatorii binari mul-
tiplicativi ∗, /, %; operatorii binari aditivi +, −.
Operatorii relaţionali sunt:<, <=, >=, >.
Operatorii de egalitate sunt: == (pentru egalitate) şi ! = (pentru diferit).
Operatorii logici sunt: ! (negaţia), && (şi logic), || (sau logic).
Operatorii logici pe biţi sunt: ∼ (complement faţă de 1, operator unitar),
¿ (deplasare stânga), À (deplasare dreapta), & (şi logic pe biţi), ˆ (sau
exclusiv logic pe biţi), | (sau logic pe biţi).
Operatorul de atribuire este =. El se utilizează ı̂n expresii de forma:
v=expresie
unde v este o variabilă sau o adresă.
Operatorul de atribuire se mai poate utiliza şi precedat de un operator binar
aritmetic sau logic pe biţi.
Operatorii de incrementare/decrementare (cu o unitate) sunt ++,
respectiv − −. Aceşti operatori pot fi folosiţi prefixat sau postfixat.
Operatorul de forţare a tipului sau de conversie explicită Conversia
valorii unui operand spre un anumit tip se poate face folosind construcţia:
(tip)operand.
Operatorul dimensiune este folosit pentru determinarea dimensiunii ı̂n
octeţi a unei date sau al uni tip. El poate fi utilizat sub formele: sizeof data
sau sizeof(tip) unde data poate fi o adresă sau o variabilă, iar tip poate fi
254 ANEXA A. LIMBAJUL C/C++
A.6 Tablouri
Un tablou reprezintă un tip structurat care ocupă o zonă de memorie con-
tinuă şi conţine elemente de acelaşi tip. Un tablou se declară astfel:
A.7 Funcţii
Un program conţine una sau mai multe funcţii. Dintre acestea una este oblig-
atorie şi se numeşte funcţia principală.
Orice funcţie are un nume. Numele funcţiei principale este main. Celelalte
au nume definit de utilizator. Forma generală a unei funcţii este:
A.8. APELUL ŞI PROTOTIPUL FUNCŢIILOR 255
A.11 Citiri/scrieri
• Funcţiile getch şi getche permit citirea direct de la tastatură a unui
caracter. Prototipurile celor două funcţii sunt ı̂n fişierul < conio.h >.
A.12 Instrucţiuni
1. Instrucţiunea vidă. Se reduce la caracterul ”;” şi nu are efect.
2. Instrucţiunea expresie. Se obţine scriind caracterul ”;” după o
expresie.
3. Instrucţiunea compusă. Este o succesiune de declaraţii urmate de
instrucţiuni, incluse ı̂ntre acolade. Declaraţiile sau instrucţiunile pot lipsi.
Formatul instrucţiunii:
{
declaratii
instructiuni
}
4. Instruţiunea if . Această instrucţiune ne permite ramificarea ı̂n funcţie
de valoarea unei expresii.
Format 1:
A.12. INSTRUCŢIUNI 259
if (expresie) instructiune1;
Efect:
P1. Se evaluează expresia din paranteză.
P2. Dacă valoarea expresiei este diferită de zero, atunci se execută instructiune1;
altfel se trece la următoarea instrucţiune.
Format 2:
if (expresie) instructiune1;
else instructiune2;
Efect:
P1. Se evaluează expresia din paranteză.
P2. Dacă valoarea expresiei este diferită de zero, atunci se execută instructiune1;
altfel se execută instructiune2.
P3. Se trece la instrucţiunea următoare.
5. Instruţiunea while Are următorul format:
while(expresie) instructiune;
Efect:
P1.Se evaluează expresia din paranteză.
P2. Dacă valoarea expresiei este diferită de zero, se execută instrucţiunea şi
se trece la pasul 1.
P3. Dacă valoarea expresiei este 0, se trece la următoarea instrucţiune.
6. Instrucţiunea do − while Are formatul:
do instructiune while(expresie);
Efect:
P1. Se execută instructiune.
P2. Se evaluează expresie.
P3. Dacă valoarea expresiei este diferită de zero, atunci se reia pasul 1; altfel
se trece la instrucţiunea următoare.
7. Instrucţiunea f or Formatul instrucţiunii este:
f or(e1; e2; e3) instructiune;
unde e1, e2, e3 sunt expresii; e1 reprezintă partea de iniţializare, e3 parte
de reiniţializare, iar e2 condiţia de continuare a executării instrucţiunii.
Efectul instrucţiunii:
P1. Se execută iniţializarea definită de e1.
P2. Se evaluează e2 şi, dacă valoarea este diferită de 0, atunci se execută
instructiune, altfel se termină executarea instrucţiunii f or.
P3. Se execută secvenţa de reiniţializare dată de e3, după care se reia etapa
precedentă.
8. Instrucţiunea switch Permite realizarea structurii selective. Formatul
260 ANEXA A. LIMBAJUL C/C++
instrucţiunii este:
switch(expresie){
case c1 : sir1 instr; |break; |
case c2 : sir2 instr; |break; |
...
case cn : sirn instr; |break; |
|def ault : sir instr; |
}
Paşii de execuţie ai instrucţiunii sunt:
P1. Se evaluează expresia din paranteză.
P2. Se compară pe rând valoarea expresiei cu valorile c1 , c2 , . . . , cn .
P3. Dacă valoarea expresiei coincide cu valoarea ck , atunci se execută secvenţa
de instrucţiuni definită prin sirk instr; dacă nu coincide cu niciuna, atunci
se execută sir instr, dacă există.
9. Instrucţiunea break Formatul instrucţiunii este:
break;
Această instrucţiune se utilizează pentru a ieşi dintr-o instrucţiune switch
sau pentru a ieşi dintr-o instrucţiune ciclică.
10. Instrucţiunea continue Formatul instrucţiunii este:
continue;
Efect:
A.13 Pointeri
Prin pointeri ı̂nţelegem o variabilă care are valori adrese de memorie.
Un pointer se declară ca orice variabilă, cu deosebirea că numele ei este
precedat de caracterul asterisc, adică vom folosi construcţia:
tip ∗ nume pointer;
Valoarea aflată la adresa dintr-un pointer se poate utiliza prin construcţia:
∗nume pointer
Pentru a putea fi folosiţi, variabilelor de acest tip trebuie să li se aloce zone de
memorie, acest lucru se realizează ı̂n C standard cu ajutorul funcţiei malloc,
iar ı̂n C + + cu ajutorul operatorului new:
A.14. FIŞIERE TEXT 261
Metoda BACKTRACKING
Observaţii:
263
264 ANEXA B. METODA BACKTRACKING
[1] T.H. Cormen, C.E. Leiserson, R.R. Rivest, Introducere ı̂n algoritmi,
Editura Computer Libris Agora, Cluj Napoca, 2000.
[8] T.Sorin, Tehnici de programare şi structuri de date, Editura L&S Info-
Mat, Bucureşti, 1995.
265