Sei sulla pagina 1di 42

Le applicazioni degli algoritmi di visita dei grafi

Gianpiero Cabodi e Paolo Camurati


Rilevazione di cicli
Un grafo è aciclico se e solo se in una visita in profondità non si
incontrano archi etichettati B.

Non basta però per identificare I cicli!

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 3


ST
Lista delle
Esempio 0 A adiacenze
1 B
Lista archi 0 5 6 2 1
2 C
1 0
AB 3 D
AC 2 0
DE 4 E 3 5 4
0 7 8
DF A 6 H I 5 F 4 5 6 3
AG G 5 4 0 3
HI 6 G
B 1 C 2 6 4 0
JK 9 10 7 H
7 8
JL 3 J K 8 I
LM D 8 7
4 9
GE 5 J 9 12 11 10
E L M
AF F 10 K 10 9
FE 11 12 11 12 9
11 L
JM 12 9 11
12 M
A.A. 2021/22 13 APPLICAZIONI DELLE VISITE 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 12 B
T 8
T 3/4
T T T
11/12
1 9/10
2 9 10
B 4 B 11

T 3 T T
T T
18/25 23/24
5/6 T 4 6 3
5 B T B
2/7
1/8 20/21 19/22
T
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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 7


Esempio

punto di articolazione bridge

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 8


Punto di articolazione
Dato un grafo non orientato e connesso 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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 9


ST Lista delle
0 A adiacenze
Esempio 1 B 0 77 66 11
AB
Lista archi 2 C 1 33 22 00
BC
BD 3 D 2 55 44 33 11
CD 0 10 4 E 3 12 21
CE 7 9
CF
A
H J
K 5 F 4 55 22
EF 8
G
5 4
12 124 22
AG 6G I L 6
3D
6 88 00
AH E 4 11 7 H
GI 7 89 98 00
HI B 8 I 8 77 66
HJ 1 C F M 9 J 9 11 10
10 77
JK 2 5 12
JL 10 K 10 11 9
KL 11 L 11 10 9
FM 12 5
12 M
A.A. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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.

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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 14


Esempio
}

slip calzini

scarpe
pantaloni
camicia
orologio
cintura
cravatta

giacca

In rosso i nodi sorgente


A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 15
}

slip calzini

scarpe
pantaloni
camicia
orologio
cintura
cravatta

giacca

In verde i nodi pozzo


A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 16
Ordinamento topologico: riordino dei vertici secondo una linea
orizzontale, per cui se esiste l’arco (u, v) il vertice u compare a SX
di v e gli archi vanno tutti da SX a DX.

Ordinamento topologico inverso: riordino dei vertici secondo


una linea orizzontale, per cui se esiste l’arco (u, v) il vertice u
compare a DX di v e gli archi vanno tutti da DX a SX.

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 17


Unicità dell’ordinamento topologico
Se esiste un cammino hamiltoniano orientato, l’ordinamento topologico
è unico. Tutte le coppie di vertici consecutivi sono connesse da archi.

v
s z s w v z
w

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 18


Se  cammino hamiltoniamo orientato  l’ordinamento topologico non
è unico

v s v w z
s z
w
s w v z

Ogni DAG ha quindi sempre almeno un ordinamento topologico.


Data la rappresentazione del grafo, il codice calcolerà un solo
ordinamento topologico.

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 19


Esempio: ordinamento topologico inverso
Lista archi Lista delle
ST
}
adiacenze
8
camicia cravatta
cravatta giacca
0 camicia 5 0 3 1
camicia cintura 1 cravatta
6
1 2
cintura giacca 2 giacca
orologio orologio 7 2
slip scarpe
slip pantaloni
3 cintura 0 3 2
calzini scarpe
4 orologio 3 4 4
pantaloni scarpe 4
pantaloni cintura
5 slip 1 5 7 6
6 scarpe 6
7 pantaloni 2 7 3 6
8 calzini 8 6
arco fittizio necessario per poter creare il nodo

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 22


8
5

6
7
0
3
1 4

2 3 1 0 4 6

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 23


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 24


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7 5

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 25


8
5

6
7
0
3
1 4

2 3 1 0 4 6 7 5 8

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 26


Struttura 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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;
/* allocazione di pre e ts */
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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 28


ordinamento 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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.

Graphreverse(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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 32


Algoritmo e strutture dati
 GRAPHscc è il wrapper con i vettori e le variabili locali passati by
reference alla funzione ricorsiva SCCdfsR.
 in sccG[w] per ogni vertice si memorizza un intero che
 identifica la componente fortemente connessa cui esso
appartiene
 marca anche se il vertice è stato visitato dalla DFS
 sccR[w] serve per marcare i vertici visitati dalla DFS del grafo
trasposto
 time0 è il contatore del tempo che avanza solo quando di un
vertice è terminata l’elaborazione (non serve il tempo di scoperta)

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 33


 time1 è il contatore delle SCC
 *postR contiene per ogni valore del contatore di tempo
time0 quale vertice è stato terminato a quel tempo
 l’istruzione post[(*time0)++]=w registra che al tempo
(*time0) è stato terminato w, quindi c’è un implicito
ordinamento per tempi di completamento crescenti
 percorrendo in discesa il vettore postR si considerano i
vertici in ordine di tempo di fine elaborazione decrescente
senza bisogno di un algoritmo di ordinamento
 *postG viene introdotto soltanto per avere un’unica
versione della funzione ricorsiva SCCdfsR utilizzabile sia sul
grafo G, sia sul grafo trasposto GT.

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 34


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
FG
F 4
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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 35


Visita DFS del grafo trasposto GT

0 1 2 3
2 0 4 3
postR 1 4 0 3 2 6 5 7
0 1 2 3 4 5 6 7

1 6 5 7

4 5 6 7

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 36


Visita DFS del grafo secondo tempi decrescenti di fine
elaborazione del grafo trasposto GT (percorrimento in
discesa di postR) 0 1 2 3 4 5 6 7
sccG 3 3 2 2 3 1 1 0

scc2
scc3
0 1 2 3
G
4 5 6 7

scc1 scc0

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 37


Kernel DAG

A.A. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 38


void SCCdfsR(Graph G,int w,int *scc,int *time0,int time1,int *post) {
link t;
scc[w] = time1;
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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE 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. 2021/22 13 APPLICAZIONI DELLE VISITE DEI GRAFI 42

Potrebbero piacerti anche