Sei sulla pagina 1di 42

Le applicazioni degli algoritmi

di visita dei grafi


Gianpiero Cabodi e Paolo Camurati
Dip. Automatica e Informatica
Politecnico di Torino
Rilevazione di cicli

Un grafo è aciclico se e solo se in una visita in


profondità non si incontrano archi etichettati
B.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 2


Componenti connesse

In un grafo non orientato rappresentato come lista


delle adiacenze:
 ogni albero della foresta della DFS è una
componente connessa
 cc[v] è un array locale a GRAPHcc che
memorizza un intero che identifica ciascuna
componente connessa. I vertici fungono da indici
dell’array
wrapper

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 3


ST Lista delle
0 A adiacenze
Esempio 1 B
0 5 6 2 1
2 C 1 0
Lista archi
3 D 2 0
AB 4 E
0 7 8 3 5 4
AC
A 6 5 F 4 5 6 3
DE H I
DF G 5 4 0 3
6 G
AG B 1 C 2 6 4 0
HI 9 10 7 H
3 7 8
JK J K 8 I 8 7
JL D 4
5 9 J 9 12 11 10
LM E L M
GE F 10 K 10 9
AF 11 12 11 12 9
11 L
FE 12 9 11
JM 12 M
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 4
0 7 9
0 7 8 T T T T
0/13
6 15/16
T T
B 14/17 1 2 5 10 11 B
T 8
T 3/4 T
T T
12
11/12
1 9/10
2 9 10
B 4 B

T 3 T T
T T
18/25 23/24
5/6 T 4 6 3
5 T T B
B 2/7
1/8 20/21 19/22
T
11 12

cc 0 0 0 0 0 0 0 1 1 2 2 2 2
0 1 2 3 4 5 6 7 8 9 10 11 12
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 5
void dfsRcc(Graph G, int v, int id, int *cc) {
link t;
cc[v] = id;
for (t = G->ladj[v]; t != G->z; t = t->next)
if (cc[t->v] == -1)
dfsRcc(G, t->v, id, cc);
}
int GRAPHcc(Graph G) {
int v, id = 0, *cc;
cc = malloc(G->V * sizeof(int));
for (v = 0; v < G->V; v++) cc[v] = -1;
for (v = 0; v < G->V; v++)
if (cc[v] == -1) dfsRcc(G, v, id++, cc);
printf("Connected component(s) \n");
for (v = 0; v < G->V; v++)
printf("node %s in cc %d\n",STsearchByIndex(G->tab,v),
cc[v]);
return id;
}
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 6
Connettività
Dato un grafo non orientato e connesso,
determinare se perde la proprietà di
connessione a seguito della rimozione di:
 un arco

 un nodo.

Ponte (bridge): arco la cui rimozione


disconnette il grafo.
Punto di articolazione: vertice la cui
rimozione disconnette il grafo. Rimuovendo il
vertice si rimuovono anche gli archi su di
esso insistenti.
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 7
Esempio
punto di articolazione bridge

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 8


Punto di articolazione

Dato un grafo non orientato G, dato l’albero


Gp della visita in profondità,
 la radice di Gp è un punto di articolazione di
G se e solo se ha almeno due figli
 ogni altro vertice v è un punto di
articolazione di G se e solo se v ha un figlio
s tale che non vi è alcun arco B da s o da un
suo discendente a un antenato proprio di v.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 9


ST Lista delle
0 A
Esempio adiacenze
1 B 0 77 66 11
2 C 1 33 22 00
AB
BC
Lista archi 3 D 2 55 44 33 11
0 10 4 21
BD 7 9 E 3 12
CD A K
H J 5 F 4 55 22
CE 8
CF 6 G I L G 5 4
12 124 22
6
EF 3 D E 4 11 7 H
6 88 00
AG 7 89 98 00
AH B 8 I 8
GI C F M 77 66
1 9 J 9
HI 2 5 12 11 10
10 77
HJ
10 K 10 11 9
JK
JL 11 L 11 10 9
KL 5
12 M 12
FM
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 10
0 T B
T
1 7 T
T T
B 3 9 8
T T T
2 B 11 6
T T
B
5 10
T T
4 12

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 11


Bridge

Un arco (v,w) Back non può essere un ponte


(i vertici v e w sono anche connessi da un
cammino nell’albero della visita DFS).
Un arco (v,w) Tree è un ponte se e solo se
non esistono archi Back che connettono un
discendente di w a un antenato di v
nell’albero della visita DFS.
Algoritmo banale: rimuovere gli archi uno alla
volta e verificare se il grafo rimane connesso.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 12


Esempio
0 T B
0 9 T
7 10
1 7 T
6 8 11 T T
B 3 9 8
3 4 T T
T
1 2 B 11 6
2 5 12 T T
B
5 10
T T
4 12
Bridge: (A, B), (F, M), (H, J)

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 13


Directed Acyclic Graph (DAG)

DAG: modelli impliciti per ordini parziali


utilizzati nei problemi di scheduling.
Scheduling:
 dati compiti (tasks) e vincoli di precedenza
(constraints)
 come programmare i compiti in modo che
siano tutti svolti rispettando le precedenze.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 14


Nei DAG esistono 2 particolari classi di nodi:
 i nodi sorgente («source») che hanno in-
degree=0
 i nodi pozzo o scolo («sink») che hanno
out-degree=0.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 15


Esempio
}

slip calzini

scarpe
pantaloni
camicia
orologio
cintura
cravatta

giacca

In rosso i nodi sorgente

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 16


}

slip calzini

scarpe
pantaloni
camicia
orologio
cintura
cravatta

giacca

In verde i nodi pozzo

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 17


Ordinamento topologico (inverso): riordino
dei vertici secondo una linea orizzontale, per
cui se esiste l’arco (u, v) il vertice u compare
a SX (DX) di v e gli archi vanno tutti da SX
(DX) a DX (SX).

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 18


Se in un ordinamento topologico tutte le
coppie di vertici consecutivi sono connessi da
archi, questi archi formano un cammino
hamiltoniano orientato e l’ordinamento
topologico è unico.

L’ordinamento topologico inverso è sempre


unico.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 19


Esempio: ord. topologico inverso
Lista delle
Lista archi ST
}

camicia
8 adiacenze
0 5
camicia cravatta 1 cravatta 0 3 1
cravatta giacca 6
camicia cintura 2 giacca
7
1 2
cintura giacca 3 cintura 2
orologio orologio 4 0
orologio
slip scarpe
5 3 3 2
slip pantaloni slip
calzini scarpe 1 4 4 4
6 scarpe
pantaloni scarpe
7 pantaloni
5 7 6
pantaloni cintura
8 2 6
calzini
7 3 6
8 6
arco fittizio necessario per poter creare il nodo
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 20
8 8 8
5 5 5

6 6 6
7 7 7
0 0 0
3 3 3
1 4 4 4
1 1

2 2 2

2 2 3 2 3 1

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 21


8 8
5 5

6 6
7 7
0 0
3 3
1 4 1 4

2 2

2 3 1 0 2 3 1 0 4

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 22


8
5

6
7
0
3
1 4

2 3 1 0 4 6

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 23


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 24


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7 5

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 25


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7 5 8

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 26


Strutture dati
 DAG come ADT di I classe
 rappresentazione come lista delle adiacenze

 vettori dove per ciascun vertice:


 si registra il tempo di scoperta (numerazione in preordine
dei vertici) pre[i]
 vettore ts[i] dove per ciascun tempo si registra quale
vertice è stato completato a quel tempo
 contatore time per tempi di completamento (avanza
solo quando un vertice è completato, non scoperto)
 time, *pre, e *ts sono locali alla funzione
DAGrts e passati by reference alla funzione ricorsiva
TSdfsR. wrapper
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 27
void TSdfsR(Dag D, int v, int *ts, int *pre, int *time) {
link t; pre[v] = 0;
for (t = D->ladj[v]; t != D->z; t = t->next)
if (pre[t->v] == -1)
TSdfsR(D, t->v, ts, pre, time);
ts[(*time)++] = v;
}
void DAGrts(Dag D) {
int v, time = 0, *pre, *ts;
pre = malloc(D->V*sizeof(int));
ts = malloc(D->V*sizeof(int));
for (v=0; v < D->V; v++) { pre[v] = -1; ts[v] = -1; }
for (v=0; v < D->V; v++)
if (pre[v]== -1) TSdfsR(D, v, ts, pre, &time);
printf("DAG nodes in reverse topological order \n");
for (v=0; v < D->V; v++)
printf("%s ", STsearchByIndex(D->tab, ts[v]));
printf("\n");
}
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 28
ordine topologico: con il DAG rappresentato da una
matrice delle adiacenze, basta invertire i riferimenti
riga-colonna (considerando gli archi incidenti):
void TSdfsR(Dag D, int v, int *ts, int *pre, int *time) {
int w;
pre[v] = 0;
for (w = 0; w < D->V; w++)
if (D->madj[w][v] != 0)
if (pre[w] == -1)
TSdfsR(D, w, ts, pre, time);
ts[(*time)++] = v;
}

0 1 5 7 3 2 4 8 6

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 29


Componenti fortemente
connesse
Algoritmo di Kosaraju (anni ’80):
 trasporre il grafo

 eseguire DFS sul grafo trasposto,


calcolando i tempi di scoperta e di fine
elaborazione
 eseguire DFS sul grafo originale per tempi
di fine elaborazione decrescenti
 gli alberi dell’ultima DFS sono le
componenti fortemente connesse.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 30


 Le SCC sono classi di equivalenza rispetto
alla proprietà di mutua raggiungibilità
 Si può “estrarre” un grafo ridotto G’
considerando un vertice come
rappresentativo di ogni classe
 Il grafo ridotto G’ è un DAG ed è detto
“kernel DAG” del grafo G.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 31


Grafo trasposto
Dato un grafo orientato G=(V, E), il suo grafo
trasposto GT =(V, ET) è tale per cui
(u, v)  E  (v,u)  ET.
Graph reverse(Graph G) {
int v;
link t;
Graph R = GRAPHinit(G->V);
for (v=0; v < G->V; v++)
for (t= G->ladj[v]; t != G->z; t = t->next)
GRAPHinsertE(R, t->v, v);
return R;
}

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 32


Esempio

Lista archi G ST
0 1 2 3 Lista delle
AB 0 A
BC A B C D adiacenze di G
1 B
CD 0 1
DC 2 C 1 5 4 2
EA E F G H
3 D 2 6 3
EF 4 5 6 7
BE 4 E 3 7 2
GT
BF 5 5 0
F 4
FG
A B C D 5 6
GF 6 G
CG 6 7 5
GH 7 H
7 7
DH E F G H
HH
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 33
Visita DFS del grafo trasposto GT (sono indicati
gli usuali tempi di scoperta e di fine elaborazione
della DFS). Il codice calcola solo i tempi di fine
elaborazione.
0 1 2 3
0/5 2/3 6/9 7/8

1/4 10/13 11/12 14/15

4 5 6 7

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 34


Visita DFS del grafo secondo tempi decrescenti di
fine elaborazione del grafo trasposto GT
0 1 2 3 4 5 6 7
scc 3 3 2 2 3 1 1 0

scc2
scc3

0 1 2 3
G
4 5 6 7

scc1 scc0
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 35
 Kernel DAG.

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 36


Algoritmo e strutture dati
 sccG[w] e sccR[w] sono array locali a
GRAPHscc che memorizzano un intero che
identifica ciascuna componente fortemente
connessa. I vertici fungono da indici dell’array
 time0, time1, *postG e *postR sono
locali alla funzione GRAPHscc e passati by
reference alla funzione ricorsiva SCCdfsR.
wrapper

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 37


 nella DFS del grafo trasposto il contatore del
tempo time0 avanza solo quando di un nodo è
terminata l’elaborazione (non serve il tempo di
scoperta). time1 è il contatore delle SCC.

 l’istruzione post[(*time0)++]=w registra che


al tempo (*time0) è stato terminato w, quindi
c’è un implicito ordinamento per tempi di
completamento crescenti. I nodi vengono presi
per tempo di completamento decrescenti con il
ciclo discendente da G->V-1 a 0.
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 38
void SCCdfsR(Graph G, int w, int *scc, int *time0,
int time1, int *post) {
link t;
scc[w] = atime1;
for (t = G->ladj[w]; t != G->z; t = t->next)
if (scc[t->v] == -1)
SCCdfsR(G, t->v, scc, time0, time1, post);
post[(*time0)++]= w;
}
int GRAPHscc(Graph G) {
int v, time0 = 0, time1 = 0, *sccG, *sccR, *postG, *postR;
Graph R = GRAPHreverse(G);

sccG = malloc(G->V * sizeof(int));


sccR = malloc(G->V * sizeof(int));
postG = malloc(G->V * sizeof(int));
postR = malloc(G->V * sizeof(int));
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 39
for (v=0; v < G->V; v++) {
sccG[v]=-1; sccR[v]=-1; postG[v]=-1; postR[v]=-1;
}
for (v=0; v < G->V; v++)
if (sccR[v] == -1)
SCCdfsR(R, v, sccR, &time0, time1, postR);
time0 = 0; time1 = 0;
for (v = G->V-1; v >= 0; v--)
if (sccG[postR[v]]==-1){
SCCdfsR(G,postR[v], sccG, &time0, time1, postG);
time1++;
}
printf("strongly connected components \n");
for (v = 0; v < G->V; v++)
printf("node %s in scc %d\n",STsearchByIndex(G->tab,v),
sccG[v]);
return time1;
}
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 40
Riferimenti
 Componenti connesse:
 Sedgewick Part 5 18.5
 Bridge e punti di articolazione:
 Sedgewick Part 5 18.6
 DAG e ordinamento topologico dei DAG:
 Sedgewick Part 5 19.5 e 19.6
 Cormen 23.4
 Componenti fortemente connesse:
 Sedgewick Part 5 19.8
 Cormen 23.5
A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 41
Esercizi di teoria
 10. Visite dei grafi e applicazioni
• 10.4 Componenti connesse
• 10.5 Componenti fortemente connesse
• 10.6 Punti di articolazione
• 10.7 Ordinamento topologico dei DAG

A.A. 2019/20 17 Le applicazioni degli algoritmi di visita dei grafi 42