• No results found

Streng samenhangende componenten

2.2 Bomen

2.2.7 Streng samenhangende componenten

In deze paragraaf gaan we uit van een gerichte graaf G = (V, A) en willen we de streng samen-hangende componenten (afgekort: s.s.c.) van G bepalen. We gebruiken daartoe een variant van DFS. DFS verdeelt de graaf in gerichte bomen, aangevuld met eventuele andere pijlen, maar deze deelgrafen hoeven niet per se streng samenhangend te zijn. Wel is het zo (Stelling 2.8) dat de knooppunten van een s.s.c. in dezelfde gerichte boom komen: de met DFS geconstrueerde bomen bevatten elk een aantal s.s.c., maar we weten nog niet hoe de onderverdeling er uitziet. Zo bevat in Voorbeeld 2.10 de eerste boom de knooppunten 1, 2, 3 en 4, terwijl {1} en {2, 3, 4} de s.s.c. zijn; de tweede boom bestaat uit de knooppunten 5 en 6, die ieder zelf een s.s.c. zijn.

Bij DFS worden de pijlen van de graaf verdeeld in F, I, D en C. Het basisidee om een s.s.c. op te sporen is het ontdekken van ronden, omdat knooppunten die tot een ronde behoren in dezelfde s.s.c. zitten (zie ook Vraag 2.16). Als we uitgaan van F , dan is volgens Lemma 2.4 de verz. I niet van belang (in F was al een pad, dus een pijl van I voegt niets toe voor de strenge samenhang). Zij V1 de knooppunten van een s.s.c. met bijbehorende boom T1 van F . Dan is de wortel z van T1 het knooppunt van V1 met de kleinste N -waarde. De vraag is nu hoe we zo’n wortel z kunnen bepalen zonder V1 zelf te kennen. Het idee is om dit te doen door de laagste N -waarde van knooppunten op een ronde te zoeken.

We voeren hiervoor de volgende begrippen in:

r(v) is de wortel van de deelboom van de s.s.c. waar v tot behoort. R[v] = l d.e.s.d. als knooppunt v als l-de knooppunt is afgehandeld. CU RREN T (v) = {w ∈ V | R[v] ≤ R[r(w)]}.

CU RREN T (v) is dus de verz. van knooppunten w zdd. v niet later is afgehandeld dan de wortel van de deelboom van de s.s.c. waar w toe behoort, d.w.z. de knooppunten van de deelbomen die niet eerder zijn afgehandeld dan v.

Definieer vervolgens het getal Z[v] door:

Z[v] = min{N [v], min{N [w] | (v, w) ∈ D ∪ C; w ∈ CU RREN T (v)}, min{Z[w] | (v, w) ∈ F }}. De waarde Z[v] is dus het minimum van een drietal getallen, waaronder ook Z-getallen. Dit is dus een recursieve definitie. We merken tevens op dat (v, w) ∈ D ∪ C d.e.s.d. als N [w] ≤ N [v], zodat Z[v] gelijk is aan

min{N [v], min{N [w] | (v, w) ∈ A; N [w] ≤ N [v]; w ∈ CU RREN T (v)}, min{Z[w]|(v, w) ∈ F }}. We zullen bewijzen dat z een wortel van een s.s.c. is d.e.s.d. als Z[z] = N [z] en dat verder tot deze s.s.c. de knooppunten behoren die eerder dan z zijn afgehandeld en nog niet zijn ingedeeld in een s.s.c. We zullen dit eerst in een voorbeeld laten zien.

Voorbeeld 2.12

Neem de graaf uit Voorbeeld 2.10. We hebben bij DFS gezien dat R[1] = 4, R[2] = 1, R[3] = 3, R[4] = 2, R[5] = 6 en R[6] = 5. We weten dat, als we gebruik maken van de wetenschap dat {1}, {2, 3, 4}, {5} en {6} de s.s.c. zijn, het volgende geldt: r(1) = 1, r(2) = 3, r(3) = 3, r(4) = 3, r(5) = 5 en r(6) = 6.

Hiermee liggen de verz. CURRENT(v) vast:

CURRENT(1) = {1, 5, 6}, CURRENT(2) = {1, 2, 3, 4, 5, 6}, CURRENT(3) = {1, 2, 3, 4, 5, 6}, CURRENT(4) = {1, 2, 3, 4, 5, 6}, CURRENT(5) = {5} en CURRENT(6) = {5, 6}.

De Z-getallen kunnen worden berekend in de volgorde waarin de knooppunten worden afgehan-deld, d.w.z. in de volgorde van de R-getallen:

Z[2] = min{N [2] = 4, min{N [3]} = 2, min{∅} = ∞} = 2 6= N [2]: 2 is geen wortel van een s.s.c. Z[4] = min{N [4] = 3, min{∅} = ∞, min{Z[2] = 2}} = 2 6= N [4]: 4 is geen wortel van een s.s.c. Z[3] = min{N [3] = 2, min{∅} = ∞, min{Z[4] = 2}} = 2 = N [3]: 3 is de wortel van een s.s.c. die bestaat uit {3, 4, 2}.

Z[1] = min{N [1] = 1, min{∅} = ∞, min{Z[3] = 2}} = 1 = N [1]: 1 is de wortel van een s.s.c. die alleen uit {1} bestaat.

Z[6] = min{N [6] = 6, min{∅} = ∞, min{∅} = ∞} = 6 = N [6]: 6 is de wortel van een s.s.c. die alleen uit {6} bestaat.

Z[5] = min{N [5] = 5, min{∅} = ∞, min{Z[6]} = 6} = 5 = N [5]: 5 is de wortel van een s.s.c. die alleen uit {5} bestaat.

We zullen nu de beweringen gaan bewijzen. Lemma 2.5

Voor ieder knooppunt v geldt: Z[v] ≥ N [r(v)]. Bewijs

We beschouwen de volgende drie mogelijkheden voor Z[v]:

a. Z[v] = N [v]: dan kunnen we schrijven: N [r(v)] ≤ N [v] = Z[v].

b. Z[v] = N [w] < N [v] voor zekere w en v is niet later afgehandeld dan r(w). Nu geldt: N [r(w)] ≤ N [w] < N [v]: omdat v is niet later is afgehandeld dan r(w), geldt r(v) = r(w). Maar dan kunnen we schrijven: Z[v] = N [w] ≥ N [r(w)] = N [r(v)].

c. Het laatste geval is: Z[v] = Z[w] < N [v] met (v, w) ∈ F .

Om dit geval te bewijzen passen we inductie naar de waarde R[v] toe.

Als R[v] = 1, dan is er geen enkele w met (v, w) ∈ F , zodat geval a of b van toepassing is, waarvoor reeds is bewezen dat Z[v] ≥ N [r(v)]. Vervolgens beschouwen we de inductie stap. Omdat (v, w) ∈ F geldt R[w] < R[v]. Dus voor w geldt het lemma volgens de inductiever-onderstelling, zodat Z[w] ≥ N [r(w)]. Nu zijn er twee mogelijkheden:

`ofwel r(w) = r(v), en dan geldt: Z[v] = Z[w] ≥ N [r(w)] = N [r(v)].

Gevolg 2.4

Als z de wortel is van een s.s.c., dan geldt: Z[z] = N [z]. Bewijs

Omdat z de wortel is van een s.s.c., is r(z) = z, zodat we kunnen schrijven: Z[z] ≥ N [r(z)] = N [z] ≥ Z[z]. Dus Z[z] = N [z].

Stelling 2.10

Knooppunt z is de wortel van een streng samenhangende component d.e.s.d. Z[z] = N [z]. Bewijs

Op grond van bovenstaand gevolg is het voldoende te bewijzen dat Z[z] = N [z] impliceert dat z de wortel is van een s.s.c. Veronderstel dat Z[z] = N [z], dat z ligt in de s.s.c. G1= (V1, A1) met bijbehorende boom T1 van F , en dat r 6= z de wortel is van T1.

In T1 is er dus een pad P1 van r naar z met pijlen van F . In verband met de strenge samenhang is er in G1 een pad P2 van z naar r. Omdat F geen kringen bevat behoren niet alle pijlen van P2 tot F . Beschouw nu onder alle mogelijke paden in G1 van z naar r een pad dat zo lang mogelijk pijlen van F kiest en noem dat weer P2:

P2 = {z = v0, v1, . . . , vi−1, vi, . . . , vk= r}

met (vi−1, vi) de eerste pijl van P2 die niet tot F behoort. Dan behoort (vi−1, vi) tot D ∪ C (als (vi−1, vi) ∈ I, dan is er ook een pad in F van z naar vi en nemen we dit pad omdat het langer de pijlen van F volgt). Er geldt nu:

Z[z] = Z[v0] ≤ Z[v1] ≤ · · · ≤ Z[vi−1] en N [vi] < N [z]

(want vi moet eerder bezocht zijn dan z = v0, v1, . . . , vi−1). Omdat vi ∈ G1 is r(vi) = r, dus R[r(vi)] = R[r] ≥ R[vi−1], zodat vi ∈ CURRENT(vi−1). Hieruit volgt:

Z[vi−1] ≤ N [vi] < N [z] = Z[z] ≤ Z[vi−1]: tegenspraak.

Onze veronderstelling dat r 6= z is dus onjuist, waarmee het bewijs geleverd is.

Om daadwerkelijk Z[v] te kunnen berekenen moeten we voor w met N [w] ≤ N [v] kunnen nagaan of w ∈ CU RREN T (v), d.w.z. dat N [w] ≤ N [v] en v is eerder afgehandeld dan r(w). Zet daartoe de knooppunten zodra ze bezocht worden op een stapel S. De knooppunten blijven in het algoritme op S staan totdat de wortel van hun ’deelboom’ wordt afgehandeld, d.w.z. totdat voor een z wordt ontdekt dat Z[z] = N [z]. Op dat moment worden de bovenste knooppunten van S tot en met knooppunt z in een s.s.c. gestopt. De test of een knooppunt tot S behoort kan in O(1) worden uitgevoerd door tevens een array S met componenten 0 of 1 bij te houden, waarbij S[v] = 1 d.e.s.d. als v ∈ S. Hiermee is het niet meer nodig de R-waarden expliciet bij te houden.

De berekening van Z[v] verloopt nu als volgt:

1. Als v voor het eerst wordt bezocht: Z[v] := N [v], zet v op S en S[v] := 1.

2. Als we (v, w) bekijken en N [w] ≤ N [v]: als S[w] = 1 en N [w] < Z[v]: Z[v] := N [w]. 3. Als w wordt afgehandeld en v = pred[w]: als Z[w] < Z[v]: Z[v] := Z[w].

Het bovenstaande leidt tot het volgende algoritme met daarin weer een procedure V ISIT . Aan het einde van het algoritme heeft voor een knooppunt v het getal COM P [v] de waarde k d.e.s.d. als v in de k-de streng samenhangende component zit.

Algoritme 2.12 Bepaling streng samenhangende componenten in een gerichte graaf

Invoer: Een gerichte graaf G = (V, A), gegeven door lijsten L[v] = {w | (v, w) ∈ A}, v ∈ V . Uitvoer: De verzamelingen van de streng samenhangende componenten van G: COM P [j] = k d.e.s.d. als j in de k-de streng samenhangende component zit.

1. Initialisatie

S := ∅; i := k := 1;

for j = 1 step 1 until n do N [j] := Z[j] := S[j] := COM P [j] := 0. 2. for j = 1 step 1 until n do

if N [j] = 0 then V ISIT (j). Procedure V ISIT (j) begin N [j] := Z[j] := i; i := i + 1; push(j, S); S[j] := 1. for all l ∈ L[j] do if N [l] = 0 then begin V ISIT (l); if Z[l] < Z[j] then Z[j] := Z[l] end

else begin if N [l] ≤ N [j] then

begin if S[l] = 1 then

begin if N [l] < Z[j] then Z[j] := N [l] end end

end end V ISIT Voorbeeld 2.13

Neem weer de graaf uit Voorbeeld 2.10.

S = ∅; i = k = 1; N [j] = Z[j] = S[j] = COM P [j] = 0, j = 1, 2, . . . , 6. j = 1.

V ISIT (1) : N [1] = Z[1] = 1; i = 2; S = {1}; S[1] = 1; l = 3. V ISIT (3) : N [3] = Z[3] = 2; i = 3; S = {3, 1}; S[3] = 1; l = 4.

V ISIT (4) : N [4] = Z[4] = 3; i = 4; S = {4, 3, 1}; S[4] = 1; l = 2.

V ISIT (2) : N [2] = Z[2] = 4; i = 5; S = {2, 4, 3, 1}; S[2] = 1; l = 3; Z[2] = 2. ga verder met V ISIT (4) : Z[4] = 2.

ga verder met V ISIT (3) : omdat Z[3] = N [3] krijgen we: S = {1, 3, 4}; S[2] = 0; COM P [2] = 1;

S = {1, 3}; S[4] = 0; COM P [4] = 1; S = {1}; S[3] = 0; COM P [3] = 1; k = 2.

ga verder met V ISIT (1) : l = 4; omdat Z[1] = N [1] krijgen we: S = ∅; S[1] = 0; COM P [1] = 2; k = 3.

j = 5.

V ISIT (5) : N [5] = Z[5] = 5; i = 6; S = {5}; S[5] = 1; l = 1; l = 2; l = 3. V ISIT (6) : N [6] = Z[6] = 6; i = 7; S = {5, 6}; S[6] = 1; l = 2;

omdat Z[6] = N [6] krijgen we: S = {5}; S[6] = 0; COM P [6] = 3; k = 4. ga verder met V ISIT (5) : omdat Z[5] = N [5] krijgen we:

S = ∅; S[5] = 0; COM P [5] = 4; k = 5.

De streng samenhangende componenten zijn: C1= {2, 4, 3}; C2 = {1}; C3 = {6} en C4= {5}.

Stelling 2.11

Algoritme 2.12 heeft complexiteit O(p), waarbij p = max(n, m). Bewijs

Uit Stelling 2.7 volgt dat, zonder de bewerkingen aan Z, S en S mee te tellen, de complexiteit O(p) is. De bewerkingen aan Z zijn: O(n) bij de eerste toekenning in stap 3; stap 4 geeft voor het totale algoritme O(m) en stap 5 O(n). Totaal geeft dit O(p) voor het werk aan Z.

Voor het werk aan S en S geldt het volgende. Ieder knooppunt wordt ´e´enmaal op S gezet en er ook ´e´enmaal afgehaald; ieder knooppunt krijgt bij initialisatie de S-waarde 0, dan zodra het bereikt wordt de waarde 1 en tenslotte, nadat het van S is afgehaald weer de waarde 0.

Verder wordt voor iedere pijl (v, w) in stap 4b getest of S[w] = 1. De totale hoeveelheid werk aan S en S is dus O(n).

Vraag 2.16

Beschouw een gerichte samenhangende graaf G.