Algoritmi e Strutture Dati

64 downloads 169 Views 4MB Size Report
Alberto Montresor. 1. Algoritmi e Strutture Dati. Capitolo 9 - Grafi. Alberto Montresor. Università di Trento. This work is licensed under the Creative Commons ...
Esempi di grafi

Algoritmi e Strutture Dati Capitolo 9 - Grafi Alberto Montresor Università di Trento

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.

© Alberto Montresor

1

Problemi sui grafi ✦

Grafi orientati e non orientati: definizione

Visite ✦

Visite in ampiezza (numero di Erdös)



Visite in profondità (ordinamento topologico, componenti (fortemente) connesse)



Un grafo orientato G è una coppia 
 (V, E) dove: ✦

✦ ✦

Cammini minimi ✦

Da singola sorgente



Fra tutte le coppie di vertici



Alberi di connessione minimi



Problemi di flusso



....

© Alberto Montresor

2

© Alberto Montresor



Insieme finito dei vertici V



Insieme degli archi E: relazione binaria tra vertici 2

Un grafo non orientato G è una coppia (V, E) dove:



Insieme finito dei vertici V Insieme degli archi E: 
 coppie non ordinate 2

3

3

A 1

1 6 4

3

V = {1, 2, 3, 4, 5, 6 } E = { (1,2), (1,4), (2,3), (4,3), (5,3), (4,5), (4,1) } © Alberto Montresor

5

6 4

5

V = {1, 2, 3, 4, 5, 6 } E = { [1,2], [1,4], [2,3], [3,4], [3,5], [4,5] }

4

oi ad inventarne una fittizia. discuteremo dei principali approcci per realizzare la struttura di Definizioni: incidenza e adiacenza otesi semplificativa che l’insieme statico degli n nodi possa essere un eseguire grafo orientato 1 a ✦n.InPer un’operazione su tutti i nodi e su tutti gli archi, ✦ un segue: arco (u,v) si dice incidente da u in v each come ✦

Rappresentazione grafi ✦

In un grafo non orientato

la relazione di incidenza tra vertici è simmetrica ) do e sull’arco (u, v) ✦ Un vertice v si dice adiacente a u 
 ✦



(1,2) è incidente da 1 a 2 (1,4) è incidente da 1 a 4 (4,1) è incidente da 4 a 1

se e solo se (u, v) ∈ E

utti i nodi del grafo, mentre il secondo scorre tutti i nodi adiacenti 2 azione. Per semplificare il testo3inoltre, useremo il termine 2 è adiacente ad 1G.n 1 ).size(). 3 è adiacente a 2, 4, 5 6

on matrici

4

5



1 è adiacente a 4 e viceversa 2 non è adiacente a 3,4 6 non è adiacente ad alcun vertice

ici per rappresentare un grafo e` basata su matrici. Dato un grafo diacenza M = [muv ] (detta anche matrice di adiacenza nodi-nodi) Matrice di adiacenza: grafo orientato o non orientato n ⇥ n, tale che:

5

© Alberto Montresor

muv =

1, se (u, v) ⌅ E, 0, se (u, v) ⌅ / E.

2

3

n = |V|

numero di nodi



m = |E|

numero di archi

Matrice di adiacenza ✦

Spazio richiesto O(n2)



Verificare se il vertice u è adiacente a v richiede tempo O(1)



Elencare tutti gli archi costa O(n2)

Liste / vettori di adiacenza ✦

Spazio richiesto O(n+m)



Verificare se il vertice u è adiacente a v richiede tempo O(n)



Elencare tutti gli archi costa O(n+m) 6

© Alberto Montresor

G.adj(u) = { v | (u,v) ∈ E } 4

to, la matrice e` simmetrica, ovvero muv = mvu 1 per 0 ogni 1 u,0v. Un 1 nza e` mostrata nella Fig. 9.6. 2 0 0 1 0 e e` banale verificare in tempo O(1) se un dato arco e` presente nel 2 3 adj0(u) 0di un 0 qual0 il tempo per ricavare l’insieme di 3 adiacenza G. 1 , indipendentemente dalla cardinalit`a di G.adj4(u), 1perch´ 0 e occorre 1 0 matrice alla ricerca degli elementi muv = 1. Inoltre, lo spazio 5 0 0 0 1 6 n2 ) e il tempo per esaminare tutti gli archi e` (n2 ), anche se il 6 0e` pesato, 0 0 allora 0 4 di archi che e` O(n). ene un numero m Se il grafo 5 o i pesi degli archi al posto degli elementi binari. Se puv e` il peso trice M diventa: © Alberto Montresor



Liste di adiacenza: grafo orientato

Spazio: n2 1

Poniamo

Spazio: a⋅n + b⋅m a

5

6

0

0

1

2

0

0

2

3

nil

1

0

3

4

nil

0

0

4

1

0

0

5

3

0

0

2

3

1 6 4

7

© Alberto Montresor

6

b 4

nil

5

nil

nil

nil

5

8

⇧i ⌅ [j + 1, ultimo] : A[i] ⇤ A[j]

Vettore di adiacenza: grafo orientato

G.adj(u) = { v | (u,v) ∈ E }

muv =

a

2

3

1 6 4

2

2

3

3

4

4

1

5

3

6

nil

5

Liste/vettore di adiacenza: grafo non orientato

G.adj(u) = { v | [u,v] ∈ E or [v,u] ∈ E} a 1 2

3

A 1

3 4 6 4

b

1

© Alberto Montresor

2

foreach u ⌅ G.V() do Matrice di adiacenza: grafo non orientato foreach v ⌅ G.adj(u) do ⌅ (u, v) fai un’operazione sull’arco 1, se [u, v] ⌅ E, Spazio: a⋅n + b⋅m

5

5 6

4

0, se [u, v] ⌅ / E.

Il primo foreach scorre tutti i nodi del grafo, mentre il secondo scorre tutti i nodi 1 adiacenti 2 3 al nodo u preso in considerazione. Per semplificare il testo inoltre, useremo il termine G.n 0 1 0 1 come abbreviazione di G.V().size().

2

5

6

1

0

0

1

0

1

0

0

0

3

0

1

0

1

1

0

Uno dei modi pi`u semplici per rappresentare un grafo e` basata su matrici. 1 un0 grafo1 4 Dato 5 6 di adiacenza nodi-nodi) G = (V, E), la matrice di adiacenza M = [muv ] (detta anche matrice 5 0 0 1 e` una matrice di dimensione n ⇥ n, tale4 che: 5 6 0 0 0 1, se (u, v) ⌅ E, muv = 0, se (u, v) ⌅ / E.

0

1

0

1

0

0

0

0

0

1

Se il grafo non e` orientato, la matrice e` simmetrica, ovvero muv = mvu per ogni u, v. Un esempio di matrice e` mostrata nella Fig. 9.6. 9 di adiacenza © Alberto Montresor Con questa realizzazione e` banale verificare in tempo O(1) se un dato arco e` presente nel grafo oppure no. Purtroppo, il tempo Grafi pesati per ricavare l’insieme di adiacenza G.adj(u) di un qualsiasi nodo u e` sempre (n), indipendentemente dalla cardinalit`a di G.adj(u), perch´e occorre scandire un’intera riga della matricecasi allaogni ricerca degli elementi muv = 1. Inoltre,associato lo spazio ✦ In alcuni arco ha un peso (costo, guadagno) 2 2 Spazio: a⋅n + di 2⋅b⋅m memoria occupato e` (n✦ ) e il tempo per esaminare tutti gli archi e` (n ), anche se il a b Il peso può essere determinato tramite una funzione di costo
 grafo e` sparso, ovvero contiene un numero m di archi che e` O(n). Se il grafo e` pesato, allora p: V ×V → R, dove R è l’insieme dei numeri reali nella matrice M si utilizzano i pesi degli archi al posto degli elementi binari. Se puv e` il peso b ✦ Quando tra due vertici non esiste un arco, il peso è infinito dell’arco (u, v), allora la matrice M diventa: nil 2 4 1 2 3 puv , se (u, v) ⌅ E, 1 3 nil muv = +⇤ (oppure ⇤) se (u, v) ⌅ / E. * 3 * 1 2 4 5 nil

1

3

3

4

5

nil

nil

nil

1

© Alberto Montresor

3

4 4

11

4

2

3 1

© Alberto Montresor

4

2

3

9.3 Realizzazioni con matrici A 5

Spazio: n2 o n(n+1)/2

7 8 5

6

10

4

5

6

1

*

*

2

3

*

4

*

*

*

3

*

4

*

4

7

*

4

1

*

4

*

8

*

5

*

*

7

8

*

*

6

*

*

*

*

*

* 12

prevedono la possibilit`a di inserire o cancellare nodi o archi, di ottenere l’insieme di tutti i nodi

Specifica o dei nodi adiacenti ad un particolare nodo.

Definizioni: Grado

Infine, la situazione pu`o essere ulteriormente complicata dal fatto che in molte applicazioni ulteriori informazioni (dette etichette, o pesi) sono associate ai nodi e/o agli archi. In tal caso, ✦ In un grafo non orientato G RAPH si parla di grafi etichettati (o pesati), i quali richiedono ulteriori operatori, per reperire e/o ✦ il grado di un vertice è il numero di archi che partono da esso Graph( ) % Crea un grafo vuoto modificare le informazioni associate a nodi e/o archi. Non e` quindi un caso che nelle librerie insertNode(N ODE u) % Aggiunge il nodo u al grafo dei pi`u diffusi linguaggi di programmazione siano disponibili numerose realizzazioni per✦ leIn un grafo orientato insertEdge(N ODE u, N ODE v) % Aggiunge l’arco (u, v) al grafo strutture di dati insieme, dizionario, etc., ma che non vi sia una realizzazione standard per i ✦ il grado entrante (uscente) di un vertice è il numero di archi incidenti in (da) esso (N ODE u) % Rimuove il nodo u dal grafo grafi. deleteNode Non staremo quindi noi ad inventarne una fittizia. in : 1 deleteEdge (N ODEsezioni u, N ODEdiscuteremo v) % Rimuove l’arco (u, v) realizzare nel grafo in : 2 Nelle prossime dei principali approcci per la struttura di out: 1 in : 1 out: 1 2 S ET adj (N ODE u) % Restituisce l’insieme dei nodi adiacenti ad u 2 dati grafo. Partiremo dall’ipotesi semplificativa che l’insieme statico degli n nodi possa essere out: 2 3 3 2 S ET V() dai numeri da 1 a n. Per eseguire%un’operazione Restituisce l’insieme di tutti i nodie su tutti gli archi, rappresentato su tutti i nodi A 1 1 3 utilizzeremo il costrutto foreach come segue: 2

Di tutte u queste sole procedure adj() e V(); Complessità foreach ⌅ G.procedure, V() do discuteremo la realizzazione delle il motivo principale e` che, in questo testo, i grafi sono usati per rappresentare relazioni tra ✦ O(n+m) liste di adiacenza foreach v ⌅ G.adj(u) do oggetti che non mutano nel tempo. In altri termini, non si effettuano mai n´e cancellazioni n´e (u, v) 2 forniti in ingresso, al inserzioni, fai n´e diun’operazione nodi n´e di archi, sull’arco ma si esplorano sistematicamente grafi ✦ ✦

4

O(n ) matrice di adiacenza

5 2

3

4 in : 2 out: 2

fine di determinarne sottoinsiemi di nodi e/o di archi che soddisfino certe propriet`a. ✦ 6 “operazioni” Qualora il grafo sia dinamico, la struttura di dati pi`u adatta O(m) per rappresentarlo dipende 0 dalla particolare utilizzazione grafo stesso. efficienti di insiemi e dizionari Il primo foreach scorre del tutti i nodi delRealizzazioni grafo, mentre il secondo scorre tutti i nodi 13adiacenti © Alberto Montresor © Alberto Montresor sono state trattatein ampiamente nei capitoliPer precedenti, ed il lettore pu`o cercare combinar- il termine G.n al nodo u preso considerazione. semplificare il testo inoltre,di useremo le per esercizio in modo da fornire realizzazioni efficienti per le operazioni di inserzione e Definizioni: Cammini Definizioni: Cicli come abbreviazione di G.V().size(). cancellazione di nodi e/o archi. Inoltre, nella vita di un programmatore capita di lavorare con i grafi senza menzionarli ✦ esplicitamente. ✦ In un grafo orientato G=(V,E) In un grafo orientato Ad esempio,G=(V,E) un file system pu`o essere visto come un albero di directory e file, 9.3ma laRealizzazioni con matrici presenza di hard link e symbolic link fanno s`ı che l’albero sia in realt`a un grafo. Le ope✦ un cammino di lunghezza k è una sequenza di vertici u , u , ..., u tale che 
 ✦ un ciclo di lunghezza k è un cammino u , u , ..., u tale che 
 0 1 k 0 1 k razioni per la creazione di nodi e archi sono quindi condizionate dalla particolare “semantica” (u , u ) ∈ E per 0 ≤ i ≤ k–1 (u , u ) ∈ E per 0 ≤ i ≤ k–1, u = u , e k>2 i i+1 i i+1 0 k Uno dei modiepi` u semplici per rappresentare grafo e` dibasata associata al grafo, parleremo di creazione di file al posto un di creazione nodi. su matrici. Dato un grafo

5 6

in : 1 out: 1

in : 0 out: 0 14

G✦ = (V, E), la matrice di adiacenza M = [muv ] (detta anche matrice di adiacenza nodi-nodi) ✦ In un grafo non orientato G=(V,E) In un grafo non orientato G=(V,E) e` una matrice di dimensione n ⇥ n, tale che: ✦

una catena di lunghezza k è una sequenza di vertici u0, u1, ..., uk tale che 
 [ui, ui+1] ∈ E per 0 ≤ i ≤ k–1 1, se (u, v) ⌅ E,

muv =

2

3



0, Esempio: se (u, v)1,⌅ / 2,E.3, 5, 4 è una 


catena nel grafo con lunghezza 4

Se il grafo non e` orientato, la matrice e` simmetrica, ovvero muv = mvu per ogni u, v. Un esempio di matrice di adiacenza e` mostrata nella 9.6. (catena) si dice semplice Un Fig. cammino se tutti i suoi O(1) verticisesono distinti Con questa realizzazione e` banale verificare in tempo un dato arco e` presente nel (compaiono una sola volta nella grafo oppure no. Purtroppo, il tempo per ricavare l’insieme di adiacenza G.adj(u) di un qualsequenza) 4 5 siasi nodo u e` sempre (n), indipendentemente dalla cardinalit`a di G.adj(u), perch´e occorre scandire un’intera riga della matrice alla ricerca degli elementi muv = 1. Inoltre, lo spazio di memoria occupato e` (n2 ) e il tempo per esaminare tutti gli archi e` (n2 ), anche se il 15 1

© Alberto Montresor

un circuito di lunghezza k è una catena u0, u1, ..., uk tale che 
 [ui, ui+1] ∈ E per 0 ≤ i ≤ k–1, u0 = uk, e k>2 2

3

1

© Alberto Montresor

Esempio: 1, 2, 3, 5, 4, 1 è un 
 circuito con lunghezza 5 Un ciclo (circuito) si dice semplice se tutti i suoi vertici sono distinti (tranne ovviamente il primo / l’ultimo)

4

5 16

Definizioni: Grafi aciclici

Definizioni: Grafo completo

Un grafo senza cicli è detto aciclico



2 1

Questo grafo è aciclico

2

6

Questo grafo non è completo

2 5

2 6 4

Questo grafo non è aciclico

4

5

5

6

4

3

1

3

3

1

3

1

2 1

Questo grafo è completo

Un grafo orientato aciclico 
 è chiamato DAG (Directed Acyclic Graph)

3

4

Un grafo completo è un grafo che ha un arco tra ogni coppia di vertici.



4

m=

5

n X1 i=1

5 17

© Alberto Montresor

Definizioni: Alberi

i=

1)

n(n 2

18

© Alberto Montresor

Definizioni: Alberi di copertura



Un albero libero è un grafo non orientato connesso, aciclico



Se qualche vertice è detto radice, otteniamo un albero radicato



Un insieme di alberi è detta foresta

In un grafo non orientato G=(V, E)





rad

un albero di copertura T è un albero libero T = (V, E′) composto da tutti i nodi di V e da un sottoinsieme degli archi (E′ ⊆ E), tale per cui tutte le coppie di nodi del grafo sono connesse da una sola catena nell’albero.

ice

2

2

3

1

2

3

1

1

6 4

5

3

6 4

6 4

5

5

7 8 © Alberto Montresor

9 19

© Alberto Montresor

20

Un esempio di utilizzo dei grafi ✦

Un esempio di9.utilizzo CAPITOLO GRAFI dei grafi

Sherlock Holmes indaga sulla morte del duca McPollock, ucciso da un’esplosione nel suo maniero: ✦





F

Watson: “Ci sono novità, Holmes: pare che il testamento, andato distrutto nell’esplosione, fosse stato favorevole ad una delle sette ‘amiche’ del duca”

G

H

A

(2) Betty ha incontrato Ann, Charlotte, Edith, Felicia e Helen;



(3) Charlotte ha incontrato Ann, Betty e Edith;



(4) Edith ha incontrato Betty, Charlotte, Felicia;



(5) Felicia ha incontrato Ann, Betty, Edith, Helen;



(6) Georgia ha incontrato Ann e Helen;



(7) Helen ha incontrato Betty, Felicia e Georgia.

G

?

A

?

A

B H

E

F

G

C

c)

Holmes: “Elementare, Watson: ciò che mi avete detto individua inequivocabilmente l’assassino!” 21

© Alberto Montresor Figura

9.5: a) Il grafo degli incontri. b) Rappresentazione di circuiti di lunghezza 4 come intersezione di intervalli della retta. c) Possibili periodi di soggiorno al castello cancellando il nodo A.

Definizione del problema

Watson: “Ho interrogato personalmente le sette donne, ma ciascuna ha giurato di essere stata nel castello una sola volta nella sua vita. Dagli interrogatori risulta che:



Prendere ispirazione dalla visita degli alberi



(2) Betty ha incontrato Ann, Charlotte, Edith, Felicia e Helen; Ad esempio:

(1) Ann ha incontrato Betty, Charlotte, Felicia e Georgia;

Dato un grafo G=(V, E) ed un vertice r di V (detto sorgente o radice), 
 visitare ogni vertice raggiungibile nel grafo a partire dal vertice r

(3) Charlotte ha incontrato Ann, Betty e Edith;

visita Betty, BFS Charlotte, basata suFelicia; coda 6 utilizziamo (4) Edith hauna incontrato

Ogni nodo deve essere visitato una volta sola

Visita in ampiezza (breadth-first search) Visita i nodi “espandendo” la frontiera fra nodi scoperti / da scoprire



Esempi: Cammini più brevi da singola sorgente



Esempi: Componenti fortemente connesse, ordinamento topologico

© Alberto Montresor

i “figli”

Q UEUE S Queue Holmes: “Elementare, mio caro() Watson: ci`o che mi avete detto individua inequivocabilmente l’assassino!” S.enqueue(r) while not S.isEmpty () do Soluzione di Holmes: Il grafo degli incontri tra le donne, indicate con le loro iniziali, e` disegnatoN nella Fig.u9.5a).S. Sedequeue ogni donna() avesse detto la verit`a, questo grafo dovrebbe rappreODE sentare l’intersezione di 7 intervalli della retta reale (un grafo siffatto si dice grafo di intervalli). { esamina il nodo u } In tal caso, per`o, ogni circuito di lunghezza maggiore o uguale a 4 dovrebbe possedere un arco

Sb

Visita i nodi andando il “più lontano possibile” nel grafo

Algoritmi e Strut

visita (GHolmes, RAPH G, ODE r) Vedete, che N le testimonianze concordano. Ma chi sar`a l’assassino?”

Visita in profondità (depth-first search) ✦

(5) Felicia ha incontrato Ann, Betty, Edith, trattiamo i “vertici adiacenti” come seHelen; fossero (6) Georgia ha incontrato Ann e Helen; (7) Helen ha incontrato Betty, Felicia e Georgia.

ag lia to



22

Visita: attenzione alle soluzioni “facili”





G

B

b)





B

H

Problema: Visita grafi



H

G

(1) Ann ha incontrato Betty, Charlotte, Felicia e Georgia;

© Alberto Montresor



A

B

Vedete, Holmes, che le testimonianze concordano. Ma chi sarà l’assassino?” ✦

C

a)

Watson: “Ho interrogato personalmente le sette donne, ma ciascuna ha giurato di essere stata nel castello una sola volta nella sua vita. ✦

E

B

H

Holmes: “Ciò che è più strano, è che la bomba sia stata fabbricata appositamente per essere nascosta nell’armatura della camera da letto, il che fa supporre che l’assassino abbia necessariamente fatto più di una visita al castello”





149

foreach v ⇥ G.adj(u) do S.enqueue(v)

23

© Alberto Montresor

24

Esempio di visita - errata

Esempio di visita - errata r

r

6

u = 6

6

2

2 3

3

9

1

9

1 11 4

5

11 4

10

8

7

5

7

Coda:{6}

Coda:{2,4,9}

25

© Alberto Montresor

Esempio di visita - errata

26

© Alberto Montresor

Esempio di visita - errata r

r

u = 2

6

u = 4

6

2

2 3

3

9

1

9

1 11 4

5

8

11 4

10

7

5

7

Coda:{4,9,3,1,6}

© Alberto Montresor

10

8

Coda:{9,3,1,6,5,6,1,3}

27

© Alberto Montresor

u

8

10

Nodi già visitati: u “Marcare” un nodo visitato in modo che 
 non possa essere visitato di nuovo u Bit di marcatura: nel vertice, array 
 separato, etc. 28

Algoritmo generico per la visita Genericamente, la visita di un grafo pu`o essere descritta dalla procedura visita(). Visita in ampiezza (breadth first search, BFS)

visita(G RAPH G, N ODE r)

l

Cosa vogliamo fare?

S è l'insieme frontiera


✦ Visitare i nodi a distanze crescenti dalla sorgente S ET S Set() Il funzionamento di 
 S.insert(r) insert() e remove() ✦ visitare i nodi a distanza k prima di visitare i nodi a distanza k+1 non è specificato { marca il nodo r come “scoperto” } ✦ Generare un albero BF (breadth-first) while S.size() > 0 do CAPITOLO 9. GRAFI 155 ✦ albero contenente tutti i vertici raggiungibili da r e tale che il cammino da r 
 N ODE u S.remove() ad un nodo nell'albero corrisponde al cammino più breve nel grafo { esamina il nodo u } 9.5.1 foreach Visitav BFS ⇥ G.adj(u) do ✦ Calcolare la distanza minima da s a tutti i vertici raggiungibili { esamina l’arco (u, v) } ✦ numero Nella visita BFS, i nodi sono visitati in ordine di distanza crescente dal nodo di partenza r, di archi attraversati per andare da r ad un vertice if v non e` gi`a stato scoperto then dove la distanza{ da r adilunnodo generico nodo u e` il minimo numero di archi in un cammino da r marca v come “scoperto” } a u. Tale metodo visita e` un’estensione di una visita per livelli di un albero radicato, in cui i S.di insert(v) figli di un nodo sono visitati dopo aver visitato tutti gli altri nodi che stanno allo stesso livello del padre. Poich´e la BFS visita i nodi pi`u vicini ad r prima di quelli lontani, l’insieme S e` una coL’insieme S contiene i nodiFIFO). che sono stati scoperti, ma non e`ancora visitati. nodi vengono da Montresor (con politica di rimozione Il processo di marcatura realizzato con29I un vettore di © Alberto © Alberto Montresor estratti da S uno dopo l’altro per essere visitati, e nel contempo si esaminano tutti gli archi booleani; la posizione corrispondente al nodo u viene inizializzata a false, per diventare true uscenti nodoviene visitato per scoprire nuovi nodi. Grazie al controllo effettuato nel costrutto if, Visita indal (breadth first search, BFS) Applicazione BFS: Numero di Erdös quando ilampiezza nodo “scoperto” durante la visita. ogni nodo del grafo e` inserito nell’insieme S una sola volta; poich´e per ogni nodo v, l’insieme Insieme S gestito
 Erdös (1913-1996) G.bfs adj(G (v)RAPH vieneG,scandito una sola volta, questo algoritmo tramite e` ottimo ha complessit`a ✦(nPaul + m). N ODE r) unae coda
 ✦ Matematico Nel Q caso di S grafi da UEUE ⇥ orientati Queue( )e fortemente connessi, o non orientati e connessi, la visita parte visitato[v] corrisponde
 un generico nodo “passata”. Nei grafi non connessi odi 1500 articoli, con più di 500 co-autori ✦ Più S.enqueue (r) r e raggiunge tutti i nodi in una singolaalla marcatura del nodo v
 nonboolean[ fortemente connessi, e` necessario invece fare pi`u passate, ovvero far ripartire l’algoritmo ] visitato ⇥ new boolean[1 . . . G.n] ✦ Numero di Erdös da un nodo non precedenza. foreach u ⇤ scoperto G.V() in {r} do visitato[u] ⇥ false ✦ Erdös ha erdös = 0 L’ordine vengono visitati i nodi dipende dalla politica di estrazione della procedura visitato[r]in⇥cuitrue ✦ I co-autori di Erdös hanno erdös = 1 remove ().not Esistono due () approcci principali: while S.isEmpty do N ODE u ⇥ S.dequeue() ✦ Se X ha scritto una pubblicazione scientifica con 
 – Breadth-First-Search { esamina il nodo (uBFS } ), ovvero visita in ampiezza (detta anche a ventaglio); un co-autore con erdös = k, ma non con 
 – Depth-First-Search (DFS ovvero visita in profondit`a (detta anche a scandaglio). foreach v ⇤ G.adj (u)),do un co-autore con erdös < k, X ha erdös=k +1 { esamina l’arco (u, v) } ✦ Chi non è raggiunto da questa definizione ha erdös = +∞ if not visitato[v] then visitato[v] ⇥ true S.enqueue(v) l

30

l

l

© Alberto Montresor

31

© Alberto Montresor

32

Alberto Montresor, erdos = 4

Alan Bertossi, erdos = 3 8

7

3

11

2

6

4

5

9

Figura 9.9: Un grafo non orientato

Come tributo scherzoso alla sua estrema prolificit`a, e` nato il concetto di “numero di Erd˝os”, un coefficiente assegnato ad ogni matematico (in generale, ad ogni autore scientifico) per misurare la sua “distanza” da Erd˝os. Paul Erd˝os ha erd˝os = 0. I co-autori dei suoi articoli hanno erd˝os = 1. Chi ha scritto articoli in collaborazione con autori con erd˝os = 1 (ma non con Erd˝os) ha erd˝os = 2. Ricorsivamente, chi ha collaborato con autori con erd˝os = k (ma non con autori con erd˝os < k), ha erd˝os = k + 1. Chi non e` raggiunto da questa definizione, ha erd˝os = ⇤. Il massimo numero di Erd˝os finito e` 15; e` scherzosamente considerato un punto d’onore avere un numero di Erd˝os basso. Gli autori di questo libro hanno erd˝os 3 e 4, rispettivamente. © Alberto Montresor Dato il grafo delle collaborazioni scientifiche (dove ogni autore e` un nodo e due autori sono33 uniti da un arco se e solo se hanno scritto un articolo scientifico insieme), e` possibile calcolare delErd˝ numero di Erdös ilCalcolo numero di os di ogni autore utilizzando una visita in ampiezza a partire da Erd˝os.

34

© Alberto Montresor

Esempio 0

erdos(G RAPH G, N ODE r, integer[ ] erd˝os, N ODE[ ] p)

Q UEUE S ⇥ Queue() S.enqueue(r) foreach u ⌅ G.V() {r} do erd˝os[u] = ⇤ erd˝os[r] ⇥ 0 p[r] ⇥ nil while not S.isEmpty() do N ODE u ⇥ S.dequeue() foreach v ⌅ G.adj(u) do if erd˝os[v] = ⇤ then erd˝os[v] ⇥ erd˝os[u] + 1 p[v] ⇥ u S.enqueue(v)

6 2 3

10

1 11 4

% Esamina l’arco (u, v) % Il nodo u non e` gi`a stato scoperto

5

9

12

7

Coda:{6} In questa versione della BFS, invece di utilizzare un vettore di booleani per la marcatura, utilizziamo il vettore erd˝os di interi, in cui i nodi non ancora scoperti hanno numero di Erd˝os pari a ⇤. Il nodo radice (Erd˝os) viene inizializzato a zero; ogni volta che viene analizzato un35 © Alberto Montresor

© Alberto Montresor

36

Esempio

Esempio 0

0

1

1

6 1

2 3

1

2

3

9

1

1

5

8

11

4

10

5

8

10

7

Coda:{2,4,9}

Coda:{4,9,3,1}

37

© Alberto Montresor

Esempio

38

© Alberto Montresor

Esempio 0 1

0 1

6 1

2 3

2

3

8

2

9

2

11

1 5 2

1

9 1

4

6

2

2

11

1 5 2

4

10

2

7

8

10

7

Coda:{9,3,1,5}

© Alberto Montresor

9

1

7

1

2

2

11

1 4

6

Coda:{3,1,5,8}

39

© Alberto Montresor

40

Esempio

Esempio 0 1

0 1

6 1

2 3 1

2

1

2 3

9

2

1

5 2 2

8

11 5 2

4

10

2

8

10

7

Coda:{1,5,8}

Coda:{5,8}

41

© Alberto Montresor

Esempio

42

© Alberto Montresor

Esempio 0 1

0 1

6 1

2 3

2

3

2 2

3

8

2

9

2

11

1 5

1

9 1

4

6

2

2

11

1 5 2

4

10

2

3

7

8

10

7

Coda:{8,7}

© Alberto Montresor

9

1

7

1

2

2

11

1 4

6

Coda:{7}

43

© Alberto Montresor

44

che e` un albero di copertura del grafo G radicato in r. In questo albero, i figli di u p[r]di⇥ nil(u, v). Il cammino nell’albero che u sonodei tutti i nodi vBFS scoperti durante la visita archi Albero cammini while not S.isEmpty () ed doha lunghezza erd il nodo r ad un nodo s e` ovviamente un cammino anche nel grafo, N ODE u ⇥ S. dequeue () La procedura () utilizzata memorizza l’albero deiilcammini un vettore ✦ La visita BFS puòerdos essere per ottenere camminoBFS piùin breve fra duedi padri p ⌅ G. adj(u) p[v] contiene u se v e` stato scoperto duranteforeach la visitavdel nodo u e do in particolare de vertici (numero di archi) if erd˝ o s[v] = ⇤ then (u, v). Il vettore p e` passato in input alla procedura erdos(), con ogni elemento del ✦ Albero di copertura di G radicato in r erd˝os[v] ⇥ erd˝os[u] + 1 inizializzato a nil. ✦ Memorizzato tramite vettore dei padri p ⇥ u dal nodo radice r ad u Una volta ottenuto il vettore p, e` possibile ottenere ilp[v] cammino ✦ Figli di u - nodi v tali che (u,v) ∈ E 
 enqueue (v) rico nodo s tramite la procedura stampaCammino(). SiS.noti l’interessante uso della rico v non è ancora visitato che epermette di stampare gli
 autori nell’ordine atteso da r ad s. BFS ,

Esempio 0 1

6 1

2 3

2

9

2

1

11

1 5 2

4

2

3

8

10

stampaCammino(N ODE r, N ODE s, N ODE[ ] p)

In questa versione della BFS, invece di u

if r = s then print s utilizziamo il vettore erd˝os di interi, in cui i n else if p[s] = nil then print “nessun cammino da r apari s” a ⇤. Il nodo radice (Erd˝os) viene inizial

7

else

Coda:{}

arco (u, v) e il nodo v non e` ancora stato scop

stampaCammino(r, p[s], p)

print s 45

© Alberto Montresor

Algoritmo generico per la visita ✦

Alcune definizioni ✦









Visita in profondità (depth first search, DFS) 9.5.4 Visita DFS ✦

Alcune cose da notare:

L'albero T contiene i vertici visitati



S ⊆ T contiene i vertici aperti:
 vertici i cui archi uscenti non sono ancora stati percorsi



T-S ⊆ T contiene i vertici chiusi:
 vertici i cui archi uscenti sono stati tutti percorsi





I nodi vengono visitati al più una volta (marcatura) Tutti i nodi raggiungibili da r vengono visitati Ne segue che T contiene esattamente tutti i nodi raggiungibili da r



V-T contiene i vertici non visitati Se u si trova lungo il cammino che va da r al nodo v, diciamo che: ✦

u è un antenato di v



v è un discendente di u

© Alberto Montresor

46

© Alberto Montresor

✦ Struttura Visita in profondità dati in ordine anticipato di un Il metodo di visita DFS e` una diretta estensione delladivisita 158 ordinato. Quando viene visitato un nuovo nodo✦ u,Ricorsione ci si allontana da esso il pila pi`u possibil ✦ E' spesso una “subroutine” della al posto di una un cammino (o catena), visitando nodi (e archi) nel cammino fino a giungere in un “vico soluzione di altri problemi esplicita zato a tutti false). Come negli alberi, e` possibile d co”, ovvero in un nodo v i cui nodi adiacenti sono gi`a stati tutti visitati. Quando si e` rag ✦ Utilizzata per coprire l'intero grafo, postvisita (riga (2)). v si torna indietro lungo l’ultimo arco visitato e si riprende la visita allontanandosi lu non solo i nodi raggiungibili da altro cammino di nodi (e archi) non ancoradfs visitati. Questa tecnica di visita] visitato) e` un’applic (G RAPH G, N ODE u, boolean[ una singola sorgente 
 della(diversamente tecnica backtrack [cfr. § 16]. da BFS) visitato[u] true Nella visita DFS, l’insieme S potrebbe realizzato una pila} (politic (1) essere { esamina il nodo utramite (caso previsita) Output mozione LIFO). E` pi`u naturale invece descrivere l’algoritmo in do maniera ricorsiva, in foreach v ⇥ G.adj(u) { esamina l’arco (u, ✦u Invece pi` coinciso di ed un elegante. albero, unaL’algoritmo foresta DF viene richiamato su un grafov)G a partire da un n if not visitato[v] mentre visitato e`Gilπ=(V, vettore l’insiemethen di nodi gi`a scoperti (in (depth-first) Eπ)di booleani che rappresenta ✦

47

© Alberto Montresor

Contenente un insieme di alberi DF

dfs(G, v, visitato)

(2)

{ esamina il nodo u (caso postvisita) }

Esempio 9.14 (DFS). L’ordine di visita DFS dei n mendo di partire dal nodo r = 1 e che gli insiemi a 48

Componenti connesse e fortemente connesse u

u

Definizioni: Raggiungibilità

Terminologia



u

Componenti connesse (connected components, CC)

u

Componenti fortemente connesse (strongly connected components, SCC)

In grafo orientato (non orientato) ✦

1 è raggiungibile da 4 e viceversa

Motivazioni u

u

u

Se esiste un cammino (catena) c tra i vertici u e v, si dice che v è raggiungibile da u tramite c

Molti algoritmi che operano sui grafi iniziano decomponendo
 il grafo nelle sue componenti L'algoritmo viene poi eseguito su ognuna delle componenti

2

I risultati vengono poi ricomposti assieme

49

© Alberto Montresor

Definizioni: Grafi connessi e componenti connesse





1



G è connesso ⇔ esiste un cammino da ogni vertice ad ogni altro vertice Un grafo G′ = (V′, E′) è una componente connessa di G ⇔ 
 è un sottografo di G connesso e massimale



G′ è massimale ⇔ non esiste un 
 sottografo G′′ di G che sia 
 connesso e “più grande” di G′, 
 ovvero tale per cui G′ ⊆ G′′ ⊆ G





Verificare se un grafo non orientato è connesso



Identificare le componenti connesse di cui è composto

5

50

Soluzione



2

3

A 1



4

Un grafo è connesso se, al termine della DFS, tutti i nodi sono stati marcati Altrimenti, una singola passata non è sufficiente e la visita deve ripartire da 
 un nodo non marcato, scoprendo una nuova porzione del grafo

Strutture dati ✦

Vettore id degli identificatori di componente



id[u] è l’identificatore della componente connessa a cui appartiene u

5 6

© Alberto Montresor

4

Problema



G′ è un sottografo di G (G′ ⊆ G) se 
 e solo se V′ ⊆ V e E′ ⊆ E

5

© Alberto Montresor

Definizioni ✦

3

Applicazioni DFS: Componente connesse

In un grafo non orientato G ✦

2

3

1

4



4 è raggiungibile da 1 ma non
 viceversa

51 © Alberto Montresor

52

Componenti connesse

Componenti connesse 1

integer[ ] cc(G RAPH G, S TACK S) integer[ ] id new integer[1 . . . G.n] foreach u 2 G.V() do id[u] 0 integer counter 0 while not S.isEmpty() do u S.pop() if id[u] = 0 then counter counter + 1 ccdfs(G, counter , u, id)

2

1

1

53

Alberi di copertura DFS





se l’arco è esaminato passando da un nodo 
 di T ad un suo discendente (che non sia figlio) 
 in T è detto arco in avanti

2 9

3 11

2

CAPITOLO 9. GRAFI

1

2

3

4

Variabili globali ✦

time orologio



dt

discovery time



ft

finish time

1 2

4

altrimenti, è detto arco di attraversamento 3

© Alberto Montresor

7

© Alberto Montresor



Tutte le volte che viene incontrato un arco che connette un nodo marcato ad uno non marcato, esso viene inserito nell’albero T

se l’arco è esaminato passando da un nodo di T 
 ad un altro nodo che è suo antenato in 12T , è 
 detto arco all’indietro

3

54

Schema DFS

La visita DFS genera l’albero (foresta) dei cammini DFS



6

8

© Alberto Montresor

Gli archi non inclusi in T possono essere divisi 
 in tre categorie durante la visita:

5

2

4

id[u] counter foreach v 2 G.adj(u) do if id[v] = 0 then ccdfs(G, counter , v, id)



2

10

ccdfs(G RAPH G, integer counter , N ODE u, integer[ ] id)



2

1

return id



3

1

dfs-schema(G RAPH G, N ODE u)

esamina il nodo u prima (caso pre-visita) time time + 1; dt[u] time foreach v ⇥ G.adj(u) do esamina l’arco (u, v) di qualsiasi tipo if dt[v] = 0 then esamina l’arco (u, v) in T dfs-schema(g, v) else if dt[u] > dt[v] and ft[v] = 0 then esamina l’arco (u, v) all’indietro else if dt[u] < dt[v] and ft[v] ⇤= 0 then esamina l’arco (u, v) in avanti else esamina l’arco (u, v) di attraversamento esamina il nodo u dopo (caso post-visita) time time + 1; ft[u] time

55

© Alberto Montresor

56

CAPITOLO 9. GRAFI

Esempio [1, ] B

C

A

D

[1, ]

dfs-schema(G RAPH G, N ODE u)

F

E

G

161

Esempio

F

[2, ]

esamina il nodo u prima (caso pre-visita) time time + 1; dt[u] time foreach v ⇥ G.adj(u) do I esamina l’arco (u, v) di qualsiasi tipo if dt[v] = 0 then esamina l’arco M (u, v) in T dfs-schema(g, v) else if dt[u] > dt[v] and ft[v] = 0 then esamina l’arco (u, v) all’indietro else if dt[u] < dt[v]Land ft[v] ⇤= 0 then H esamina l’arco (u, v) in avanti else esamina l’arco (u, v) di attraversamento

B

I

A M D

E

L

H

G

esamina il nodo u dopo (caso post-visita) time time + 1; ft[u] time

e` un antenato di u, allora esiste un cammino da v a u e un arco da u a v, ovvero un ciclo. Se esiste un ciclo, sia v il primo nodo del ciclo che viene visitato e sia (u, v) un arco del ciclo. Il cammino che connette v ad u verr`a prima o poi visitato, verr`a scoperto l’arco all’indietro 57 e da u © Alberto Montresor (u, v). Adattando opportunamente lo schema di cui sopra, si ottiene l’algoritmo ciclico() che restituisce true se il grafo contiene un ciclo. Si noti che non appena viene trovato un arco Esempio all’indietro, la procedura termina restituendo true e chiudendo tutte le chiamate ricorsive.

© Alberto Montresor

Esempio [1, ]

58

[1, ] F

[2, ] [3, ]

C

B

C

A

D

E

G

boolean ciclico(G RAPH G, N ODE u) time time + 1; dt[u] time foreach v ⇥ G.adj(u) do I if dt[v] = 0 then if ciclico(G, v) then return true else if dt[u] > dt[v] and ft[v] = 0 then return trueM time time + 1; ft[u] return false;

H

F

[2, ] B

[3, ]

C

I

A M

time

[4, ]

L

9.5.8 Applicazione schema

DFS :

D

E

H

L

componenti fortemente connesse G

In alcuni casi, e` possibile dimostrare la correttezza di un algoritmo in base ai tempi di inizio e di fine, senza doverli effettivamente calcolare! Come esempio, si consideri il problema

© Alberto Montresor

59

© Alberto Montresor

60

Esempio

Esempio [1, ]

[1, ] F

[2, ] B

[3, ]

F

[2, ] C

B

[3, ]

I

A

C

I [6, ]

A M [4, ]

M [5, ]

[5, ]

D

E

[4, ]

L

H

D

G

61

Esempio

62

© Alberto Montresor

Esempio [1, ]

[1, ] F

[2, ] B

F

[2, ] C

B

[3, ]

I [6, 7]

A

C

I [6, 7]

A M

M

[5, ] [4, ]

D

E

[5, ] H

[4, ]

L

G

© Alberto Montresor

L

H

G

© Alberto Montresor

[3, ]

E

D

E

G

63

© Alberto Montresor

H

L

[8, ]

64

Esempio

Esempio [1, ]

[1, ] F

[2, ] B

[3, ]

F

[2, ] C [6, 7]

A

B

[3, ]

I

C

I [6, 7]

A

[10, ]

M

M

[5, ] [4, ]

D

E

[5, ] [4, ]

L

H

D

E

[9, ] G

[9, ] G

[8, ]

65

© Alberto Montresor

Esempio

[8, ]

66

© Alberto Montresor

Esempio

[2, 17] B

[3, 16]

L

H

[1, 18] F C

[3, 16]

I [6, 7]

A

[2, 17] B

[1, 18] F C

I [6, 7]

A

[10, 11]

[10, 11]

M

M

[5,14 ] [4,15]

D

E

[5,14 ] H

[4,15]

L

D

E

[9, 12] G

© Alberto Montresor

[19, ]

H

L

[9, 12] G

[8, 13]

67

© Alberto Montresor

[8, 13]

68

Esempio

Esempio

[2, 17] B

[3, 16]

[1, 18] F C

[3, 16]

CAPITOLO 9. GRAFI

I [6, 7]

A

[10, 11] M

D

E

L

[8, 13]

69

© Alberto Montresor

CAPITOLO 9. GRAFI

M

[19, 22] [20, 21]

L

H [9, 12]

70

161esamina il nodo u dopo (caso post-visita) time + 1; ft[u]

time

Classificazione degli archi

dfs-schema(G RAPH G, N ODE u)

u

[6, 7] D

u

[1, 8] A

E [9, 10]

Cosa serve la classificazione?

e` un antenato di u, allora esiste un cammino da v a u e un arco da u a v, ovvero un ciclo. Se E' possibile dimostrare proprietà, che 
 e sia (u, v) un arco del ciclo. Il esiste uun ciclo, sia v il primo nodo delalcune ciclo che viene visitato cammino che u verr` a prima o negli poi visitato, e da u verr`a scoperto l’arco all’indietro poi connette possonov ad essere sfruttate algoritmi (u, v). Adattando opportunamente lo schema di cui sopra, si ottiene l’algoritmo ciclico() che u restituisce true se il grafo contiene un ciclo. Si noti che non appena viene trovato un arco Esempio: all’indietro, la procedura termina restituendo true e chiudendo tutte le chiamate ricorsive.

[2, 5]

B

DAG non hanno archi all'indietro (dimostrare)

boolean ciclico(G RAPH G, N ODE u) time time + 1; dt[u] time foreach v ⇥ G.adj(u) do if dt[v] = 0 then if ciclico(G, v) then return true else if dt[u] > dt[v] and ft[v] = 0 then return true

C [3, 4]

time time + 1; ft[u] return false;

esamina il nodo u dopo (caso post-visita) time time + 1; ft[u] time © Alberto Montresor

[10, 11]

© Alberto Montresor

time

Classificazione degli archi

esamina il nodo u prima (caso pre-visita) time time + 1; dt[u] time foreach v ⇥ G.adj(u) do esamina l’arco (u, v) di qualsiasi tipo if dt[v] = 0 then esamina l’arco (u, v) in T dfs-schema(g, v) else if dt[u] > dt[v] and ft[v] = 0 then esamina l’arco (u, v) all’indietro else if dt[u] < dt[v] and ft[v] ⇤= 0 then esamina l’arco (u, v) in avanti else esamina l’arco (u, v) di attraversamento

[6, 7] [5,14 ] esamina il nodo u prima (caso pre-visita) time time +D1; dt[u] time E [4,15] foreach v ⇥ G.adj(u) do esamina l’arco (u, v) di qualsiasi tipo if dt[v] = 0 then esamina l’arco (u,Gv) in T [8, 13] dfs-schema(g, v) else if dt[u] > dt[v] and ft[v] = 0 then esamina l’arco (u, v) all’indietro else if dt[u] < dt[v] and ft[v] ⇤= 0 then esamina l’arco (u, v) in avanti else esamina l’arco (u, v) di attraversamento

[9, 12] G

161

I

dfs-schema(G RAPH G, N ODE u)

[20, ] H

C

A

[19, ]

[5,14 ] [4,15]

[2, 17] B

[1, 18] F

71

© Alberto Montresor

Variabile time: ✦

variabile globale, oppure



passata per riferimento)

time

72

Ordinamento topologico ✦

Ordinamento topologico

Dato un DAG G (direct acyclic graph), un ordinamento topologico su G è un ordinamento lineare dei suoi vertici tale per cui: ✦





Problema: ✦

se G contiene l’arco (u,v), allora u compare prima di v nell’ordinamento Per transitività, ne consegue che se v è raggiungibile da u, 
 allora u compare prima di v nell'ordinamento



Soluzioni ✦



Nota: possono esserci più ordinamenti topologici

2 1

1

3

3

5

2



1

2

3

4

73

Soluzione diretta 2 4

3

5

2 4

5



74

Algoritmo

4



5 ✦

Output:

Output: 1

Output: 1 3 ✦

2 4 ✦

Output: 1 3 5 2

[2,5]

Si effettua una DFS L’operazione di visita consiste 
 nell’aggiungere il vertice alla 
 testa di una lista“at finish time”

2 [1, 10] 1

[6,9] 3

Si restituisce la lista di vertici

Output ✦

4

© Alberto Montresor

Esercizio: scrivere lo pseudocodice per 
 questo algoritmo Qual è la complessità? l con matrici di adiacenza l con liste di adiacenza

© Alberto Montresor



Output: 1 3 5

Trovare un vertice che non abbia alcun arco incidente in ingresso Stampare questo vertice e rimuoverlo, 
 insieme ai suoi archi Ripetere la procedura finché tutti i vertici risultano rimossi

Ordinamento topologico basato su DFS

2 3

Basata su DFS

5

© Alberto Montresor

1

Diretta
 (INEFFICIENTE!)
 
 


4

4

5

Fornire un algoritmo che dato un grafo orientato aciclico, ritorni un ordinamento topologico

[3,4] 4

[7,8] 5

Sequenza ordinata di vertici,
 in ordine inverso di finish time

Perché funziona?

Output: 1 3 5 2 4 75

© Alberto Montresor

76

12

Algoritmi e Strutture di Dati inverso di tempo di fine.

Ordinamento topologico basato su DFS - Liste

Ordinamento topologico basato su DFS - Stack

topSort(G RAPH G, S TACK S)

topSort(G RAPH G, S EQUENCE L)

boolean[ ] visitato boolean[1 . . . G.n] foreach u 2 G.V() do visitato[u] false foreach u 2 G.V() do if not visitato[u] then ts-dfs(G, u, visitato, L)

boolean[ ] visitato boolean[1 . . . G.n] foreach u 2 G.V() do visitato[u] false foreach u 2 G.V() do if not visitato[u] then ts-dfs(G, u, visitato, S)

ts-dfs(G RAPH G, N ODE u, boolean[ ] visitato, S EQUENCE L)

ts-dfs(G RAPH G, N ODE u, boolean[ ] visitato, S TACK S)

visitato[u] true foreach v 2 G.adj(u) do if not visitato[v] then ts-dfs(G, v, visitato, L)

visitato[u] true foreach v 2 G.adj(u) do if not visitato[v] then ts-dfs(G, v, visitato, S)

L.insert(L.head(), u)

S.push(u) 77

© Alberto Montresor

Definizioni: Grafi fortemente connessi e componenti fortemente connesse T REE lookupNode(T REE T, I TEM x) ✦

Soluzione errata

InifunTgrafo G 6= x then 6= nilorientato and T.key return lookupNode iif(x < T.key, T.left, x)ad ogni altro ✦ G è fortemente connesso(⇔ esiste un cammino da T.right), ogni vertice





Proviamo ad utilizzare l’algoritmo per le componenti connesse? ✦

else vertice return T



78

© Alberto Montresor

Risultati variano a seconda del nodo da cui si parte

Un grafo G′ = (V′, E′) è una componente fortemente connessa di G ⇔ 
 è un sottografo di G fortemente connesso e massimale

Definizioni ✦



G′ è un sottografo di G (G′ ⊆ G) se 
 e solo se V′ ⊆ V e E′ ⊆ E 1 G′ è massimale ⇔ non esiste un 
 sottografo G′′ di G che sia 
 fortemente connesso e “più grande” 
 di G′, ovvero tale per cui G′ ⊆ G′′ ⊆ G.

© Alberto Montresor

2 2

3

1

3

6 6 4 4

5

5 79

© Alberto Montresor

80

Componenti fortemente connesse ✦

Componenti fortemente connesse - algoritmo

Algoritmo (Kosaraju, 1978)

integer[ ] scc(G RAPH G)

1. Effettua una DFS di G 2. Calcola il grafo trasposto

GT

CAPITOLO 9. GRAFI

S TACK S

topSort(G)

163

% Prima visita

G RAPH GT Graph() % Calcolo grafo trasposto T T foreach u 2 G. V () do G . insertNode (u) 3. Effettua una DFS di G esaminando i vertici in ordine inverso di tempo di fine Questo algoritmo si basa sull’osservazione foreach u 2 G.che V() un do grafo G e il suo trasposto GT hanno le 4. Fornisci i vertici di ogni albero della foresta depth-first prodotta al passo 3. 
 stesse componenti fortemente connesse; questo dalla foreach v 2 deriva G.adj(u) do simmetria della definizione, che come una diversa SCC GTalmeno .insertEdge (v, u) da u a v e almeno un cammino prevede per ogni coppia di nodi u, v, esista un cammino ✦





da v ad u. return cc(GT , S) Per capire il funzionamento, e` utile considerare il grafo delle componenti Gc = (V c , E c ) Dato un grafo G = (V, E), il grafo trasposto GT = (V, ET ) è formato dagli del grafo G, stessi definito come segue: nodi, mentre gli archi hanno direzioni invertite: i.e, – V c = {C1 , C2 , . . . , Ck }, dove Ci e` l’i-esima componente connessa di G; ✦ ET ={(u,v) | (v,u) ∈ E} – E c = {(Ci , Cj ) : ⇤(ui , uj ) ⇥ E : ui ⇥ Ci , uj ⇥ Cj }

Grafo trasposto

Costo computazione

% Seconda visita

In altre parole, le componenti sono “contratte” in un singolo vertice, e cos`ı gli archi che vanno da componente a componente. E` facile notare che il grafo delle componenti e` aciclico: se cos`ı non fosse, i nodi delle componenti appartenenti al ciclo potrebbero tutti raggiungersi 81 82 © Alberto Montresor © Alberto Montresor l’uno con l’altro; farebbero quindi parte di un’unica componente, una contraddizione. Estendiamo il concetto di tempo di inizio e di fine per le componenti. Sia C un sottoinComponenti fortemente connesse - dimostrazione correttezza sieme di V ; definiamo dt(C) come Componenti connesse - dimostrazione il primo fortemente tempo di scoperta e ft(C) come l’ultimocorrettezza tempo di completamento: ✦ Si può estendere il concetto di dt e ft al grafo delle componenti ✦ Domanda dt(C) = min{dt[u] : u ⇥ C} ✦ Che rapporto c’è fra le SCC del grafo G e del suo trasposto GT ? ft(C) = max{ft[u] : u ⇥ C} ✦ Grafo delle componenti Gc = (Vc, Ec) ✦ Teorema In base a queste definizioni, possiamo enunciare il seguente teorema. ✦ Vc = {C , C , . . . , C }, dove C è l’i-esima componente fortemente connessa di G; 1 2 k i ✦ Siano C e C′ due componenti distinte nel grafo orientato G = (V, E). 
 13 Teorema 9.1. Siano C e C due componenti distinte nel grafo orientato G = (V, E). Suppo✦ Ec ={(C ,C ): ∃(u ,u ) ∈ E :u ∈C ,u ∈C } Supponiamo che esista un arco (C, C′) ∈ Ec. Allora ft(C) > ft(C′) i j i j i i j j niamo che esista un arco (C, C ) ⇥ E c . Allora ft(C) > ft(C ). [9,10] [2,11] Il grafo delle [1, 8] Dimostrazione Sono dati due casi: viene scoperto prima un nodo di C oppure di C . 2 [11,12] 2 [3,10] componenti [1,12] 2 3 3 è aciclico? • dt(C) < dt(C ): sia x il primo nodo scoperto in C, all’istante dt(C). Poich´e tutti i nodi 3 1 1 in C ⌅ C sono raggiungibili 1 da x e non ancora scoperti, la loro visita inizier`a e terminer`a 6 [5,7] 6 prima della terminazione della visita di x. Quindi ft(C) = ft(x) > ft(y), per ogni y ⇥ 6 [7,8] C ⌅C {x}. Ne segue che ft(C) > ft(C ). [2, 7] [4,9] 4 4 5 5 • dt(C ) < dt(C): sia y il primo nodo scoperto in C ; tutti i nodi in C sono raggiungibili 4 5 da y e non ancora scoperti. Al termine della visita di tutti i nodi di C , tutti i nodi[3,4] di C [5,6] non sono ancora stati scoperti. La loro visita inizier` a e terminer` a dopo ft(C ); ne segue che 83 84 © Alberto Montresor © Alberto Montresor ✦

O(m+n)

ro quindi parte di un’unica componente, una contraddizione. to diComponenti tempo di inizio e di fine per le componenti. Sia C un sottoinfortemente connesse - dimostrazione correttezza (C) come il primo tempo di scoperta e ft(C) come l’ultimo tempo di ✦

Componenti fortemente connesse

Si può estendere il concetto di dt e ft al grafo delle componenti



dt(C) = min{dt[u] : u ⇥ C}



ft(C) = max{ft[u] : u ⇥ C}

✦ Corollario ni, possiamo enunciare il seguente teorema. ✦ Siano C e C′ due componenti distinte nel grafo orientato G = (V, E). SuppoC due componenti distinte nel grafo orientato G = (V, E). Supponiamo che esista un arco (u,v) ∈ ET con u ∈ C, v ∈ C′. Allora ft(C) < ft(C′) c (C, C ) ⇥ E . Allora ft(C) > ft(C ). ✦ (u,v) ∈ ET ⇒
 [9,10] [1, 8] (v,u)scoperto ∈ E ⇒
 prima un nodo di C oppure di C . ati due casi: viene 2 [11,12] c (C’, C) ∈ E ⇒
 3 x il primo nodo scoperto ft(C) < ft(C′)
in C, all’istante dt(C). Poich´e tutti i nodi 1 inizier`a e terminer`a ungibili da x e non ancora scoperti, la loro visita 6 ione della visita di x. Quindi ft(C) = ft(x) > ft(y), per ogni y ⇥ gue che ft(C) > ft(C ). [2, 7]

4 y il primo nodo scoperto in C ; tutti i nodi in C sono raggiungibili operti. Al termine della visita di tutti i nodi di C , tutti i nodi di C [3,4] © Alberto Montresor scoperti. La loro visita inizier`a e terminer`a dopo ft(C ); ne segue che

essere letto nel modo seguente: l’ultimo nodo della componente C err`a inserito nella pila prima dell’ultimo nodo della componente C . otata in ordine inverso, questo significa che almeno un nodo di C odi di C nella seconda visita. A questo punto entra in gioco il grafo c un arco che connette C con C , in GT esso e` sostituito da un arco ella seconda visita quindi i nodi di C non sono raggiungibili dai nodi viduata come una componente a s´e stante.

Algoritmo di Tarjan (1972)





Tarjan, R. E. "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1(2): 146–160 (1972) Algoritmo con costo O(m+n) come Kosaraju E’ preferito a Kosaraju in quanto necessita di una sola visita e non richiede il grafo trasposto

[5,7]

5 © Alberto Montresor

86