Grafi, visita DFS, ordinamento topologico

Ricapitoliamo - la volta scorsa abbiamo visto...
Componente connessa - un algoritmo generale
Nozioni di base di teoria dei grafi
Componente connessa. Trova tutti i nodi raggiungibili da s.
・G = (V, E) vertici e archi
- grafi non orientati (oggi parleremo anche di grafi orientati)
- |V| = n, |E| = m
- il grado di un vertice è il numero di vicini (vertici collegati da un arco)
- somma dei gradi = 2 m
s
・rappresentazione di grafi
R
u
- liste di adiacenza (preferita) spazio O(m+n)
- matrice di adiacenza, spazio O(n2)
v
possiamo aggiungere v
・
connettività:
- quali vertici connessi da un cammino ad un dato vertice
Teorema. Alla terminazione, R è la componente connessa di s.
・BFS = esplora in ordine di distanza da s.
- componente connessa
- distanza minima in numero di vertici da attraversare
・visita BFS - ricerca di tutti i vertici raggiungibili da un vertice
Usando BFS, possiamo trovare tutte le componenti connesse in tempo O(n+m)
・inizializza un array con tutti i nodi non visitati
・per ogni nodo s non visitato esegui BFS(s) Esercizio: Scrivere l’intero
- complessità O(m+n)
- struttura dati: coda
algoritmo con la complessità O(n+m)
46
47
Visita in profondità (Depth first search)
Visita in profondità (Depth-first search)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
Struttura dati: Stack o Pila
・visita il primo nodo s
・per ogni vicino x di s non visitato
Una pila P è una lista ordinata di oggetti, dinamica, in cui ogni nuovo
oggetto viene aggiunto all’inizio (al top) della lista ed ogni oggetto che
- visita ricorsivamente a partire da x
lascia la pila viene preso dall’inizio (top) della lista.
prima di visitare un altro vicino di s può allontanarsi molto da s, lungo un
qualche cammino che parte da s
1
2
DFS(v)
// versione ricorsiva
Set visited[v] = true
4
7
3
5
The tree produced by
DFS(1)
8
add edge (v,u) to the BFS tree T
DFS(u)
costano O(1)
1
for each u in Adj[v]
6
if (visited[u] = false)
・politica LIFO (last in, first out)
・implementabile da una lista a puntatori,
・le operazioni di inserimento (Stack-in(P,u)) e di estrazione (Stack-out(P))
2
The graph G
3
Adj[1] : 2, 3
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
5
4
7
6
8
48
49
Strutture dati: Stack (Pila)
Visita in profondità (Depth first search) usando una pila (o stack)
La pila P contiene gli elementi: x, z, w (entrati in quest’ordine)
w
Top
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
L’elemento w è al top
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
z
x
Aggiungere un elemento: Stack-in(P, u) - La pila diventa
u
Top
w
z
x
DFS(v)
Estrarre/Rimuovere un elemento: a = Stack-out(P)
dalla pila eliminiamo u, e ad a viene assegnato il valore u
// versione ricorsiva
Set visited[v] = true
w
Top
}
for each u in Adj[v]
a=u
if (visited[u] = false)
z
add edge (v,u) to the BFS tree T
DFS(u)
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
x
link to its parent in DFS tree
50
execute DFS on the extracted
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
1
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
1
2
4
1
1
7
3
5
8
6
2
The graph G
3
:
:
:
:
1,
1,
2,
2,
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
add edge (v,u) to the BFS tree T
DFS(u)
2
1
3
Pila P
// versione ricorsiva
Set visited[v] = true
1
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
Pila P
DFS(v)
DFS(1)
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
51
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
for each u in Adj[v]
if (visited[u] = false)
}
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
52
53
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
Adj[1] : 2, 3
6
The graph G
1
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
2
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
2
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
1
2
1
2
3
4
7
3
5
8
6
5
The graph G
3
Adj[1] : 2, 3
2
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
2
2
2
1
Pila P
DFS(v)
DFS(v)
}
for each u in Adj[v]
if (visited[u] = false)
add edge (v,u) to the BFS tree T
DFS(u)
2
1
3
4
5
3
Pila P
// versione ricorsiva
Set visited[v] = true
1
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
4
DFS(1)
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
}
for each u in Adj[v]
if (visited[u] = false)
remember their parent is v
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
54
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
1
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
1
2
2
2
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
4
3
7
3
5
8
4
6
5
The graph G
3
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
add edge (v,u) to the BFS tree T
DFS(u)
3
3
3
2
1
1
DFS(1)
2
1
5
2
7
8
2
3
4
5
3
Pila P
// versione ricorsiva
Set visited[v] = true
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
Pila P
DFS(v)
3
55
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
for each u in Adj[v]
if (visited[u] = false)
}
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
56
57
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
Adj[1] : 2, 3
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
6
3
3
3
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
The graph G
3
2
1
1
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
5
2
7
8
1
2
2
4
3
7
3
5
8
6
5
The graph G
3
Adj[1] : 2, 3
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
1
DFS(v)
}
for each u in Adj[v]
if (visited[u] = false)
add edge (v,u) to the BFS tree T
DFS(u)
2
7
8
2
3
4
5
5
3
Pila P
// versione ricorsiva
Set visited[v] = true
3
2
Pila P
DFS(v)
1
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
4
DFS(1)
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
}
for each u in Adj[v]
if (visited[u] = false)
remember their parent is v
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
58
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
5
5
5
5
3
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
2
1
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
2
DFS(1)
3
4
1
6
2
7
8
1
2
2
4
3
7
3
5
8
4
5
5
6
The graph G
3
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
add edge (v,u) to the BFS tree T
DFS(u)
5
3
3
2
1
2
DFS(1)
3
4
1
6
2
7
8
2
3
4
5
5
3
Pila P
// versione ricorsiva
Set visited[v] = true
5
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
Pila P
DFS(v)
5
5
59
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
for each u in Adj[v]
if (visited[u] = false)
}
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
60
61
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
Adj[1] : 2, 3
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
6
The graph G
5
3
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
1
6
1
2
7
2
2
8
4
3
7
3
5
8
5
3
6
The graph G
4
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
DFS(v)
}
for each u in Adj[v]
if (visited[u] = false)
add edge (v,u) to the BFS tree T
DFS(u)
3
3
1
2
DFS(1)
5
1
6
2
7
2
8
3
4
5
5
3
4
Pila P
// versione ricorsiva
Set visited[v] = true
5
2
Pila P
DFS(v)
4
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
4
5
Adj[1] : 2, 3
4
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
}
for each u in Adj[v]
if (visited[u] = false)
remember their parent is v
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
62
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
4
4
5
3
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
2
1
2
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
5
1
6
1
2
7
2
2
8
4
3
7
3
5
8
4
5
5
3
6
The graph G
4
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
add edge (v,u) to the BFS tree T
DFS(u)
3
2
1
2
7
2
8
3
4
5
5
3
4
6
Pila P
// versione ricorsiva
Set visited[v] = true
1
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
Pila P
DFS(v)
DFS(1)
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
63
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
for each u in Adj[v]
if (visited[u] = false)
}
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
64
65
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
Adj[1] : 2, 3
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
6
The graph G
6
3
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
1
5
1
2
7
2
2
8
4
3
7
3
5
8
5
5
3
6
4
The graph G
6
Adj[1] : 2, 3
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
2
1
DFS(v)
}
for each u in Adj[v]
if (visited[u] = false)
add edge (v,u) to the BFS tree T
DFS(u)
2
8
3
4
5
5
3
7
4
6
Pila P
// versione ricorsiva
Set visited[v] = true
2
3
2
Pila P
DFS(v)
1
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
4
DFS(1)
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
}
for each u in Adj[v]
if (visited[u] = false)
remember their parent is v
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
66
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
7
7
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
2
1
1
3
1
2
8
2
2
8
4
3
7
3
5
8
4
5
5
3
4
7
6
The graph G
6
:
:
:
:
1,
1,
2,
2,
3, 4, 5
2, 5, 7, 8
5
3, 4, 6
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
add edge (v,u) to the BFS tree T
DFS(u)
2
3
2
1
2
8
3
4
5
5
3
4
7
6
8
Pila P
// versione ricorsiva
Set visited[v] = true
1
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
Pila P
DFS(v)
DFS(1)
Adj[1] : 2, 3
Adj[2]
Adj[3]
Adj[4]
Adj[5]
67
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
for each u in Adj[v]
if (visited[u] = false)
}
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
Insert all neighbors of v in a stack
remember their parent is v
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
68
69
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
1
2
4
7
3
5
8
6
The graph G
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
DFS(1)
Adj[1] : 2, 3
8
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
2
1
1
3
1
2
7
2
2
8
4
3
7
3
5
8
4
5
5
3
4
7
6
6
The graph G
8
DFS(1)
Adj[1] : 2, 3
8
Adj[2] : 1, 3, 4, 5
Adj[3] : 1, 2, 5, 7, 8
8
Adj[4] : 2, 5
Adj[5] : 2, 3, 4, 6
3
2
Adj[6] : 5
Adj[7] : 3, 8
Adj[8] : 3, 7
2
1
Pila P
DFS(v)
for each u in Adj[v]
if (visited[u] = false)
DFS(v)
}
DFS(u)
2
8
3
4
5
5
3
4
7
6
8
// versione ricorsiva
Set visited[v] = true
Insert all neighbors of v in a stack
remember their parent is v
add edge (v,u) to the BFS tree T
2
7
Pila P
// versione ricorsiva
Set visited[v] = true
1
3
for each u in Adj[v]
if (visited[u] = false)
}
Insert all neighbors of v in a stack
remember their parent is v
add edge (v,u) to the BFS tree T
extract them one at a time
DFS(u)
if not visited yet
extract them one at a time
if not visited yet
link to its parent in DFS tree
link to its parent in DFS tree
execute DFS on the extracted
execute DFS on the extracted
70
Visita in profondità (Depth first search) usando una pila (o stack)
Visita in profondità (Depth first search) usando una pila (o stack)
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
DFS(s) visita gli stessi nodi di BFS(s) ma in ordine (anche molto) diverso
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
71
・per ogni vicino x di s non visitato
・visita ricorsivamente a partire da x
・si noti che l’implementazione mediante la pila è “identica” alla DFS
tranne che per il fatto che usiamo una pila al posto di una coda
- il ciclo for è eseguito al più una volta per nodo
DFS(v)
//
utilizzando uno stack
Set visited[u] = false
DFS(v)
// versione ricorsiva
Set visited[v] = true
for each u in Adj[v]
if (visited[u] = false)
add edge (v,u) to the BFS tree T
DFS(u)
DFS(v)
for each vertex u
Stack-in(P, v); parent[v] = nil
DFS(v)
while (P is not empty) {
// versione ricorsiva
Set visited[v] = true
v ⟵ Stack-out(P)
for each u in Adj[v]
if (visited[v] = false)
if (visited[u] = false)
visited[v] = true
add edge (v,parent[v]) to the DFS tree T
for each u in Adj[v] //in reverse order
Stack-in(P,u); parent[u] = v
//
utilizzando uno stack
Set visited[u] = false
72
add edge (v,u) to the BFS tree T
DFS(u)
for each vertex u
Stack-in(P, v); parent[v] = nil
while (P is not empty) {
v ⟵ Stack-out(P)
if (visited[v] = false)
visited[v] = true
add edge (v,parent[v]) to the DFS tree T
for each u in Adj[v] //in reverse order
Stack-in(P,u); parent[u] = v
73
Visita in profondità (Depth-first search): analysis
Un confronto tra BFS e DFS (il grafo in questo caso è un albero)
Teorema. La DFS può essere implementata in tempo O(m + n) se il grafo è
rappresentato dalle liste delle adiacenze.
1
3
2
Dim.
・ogni nodo può entrare nella pila P più volte
5
4
- diventa visited la prima volta che ne esce
8
1
6
9
- il nodo viene aggiunto nell’albero al più una volta
- il ciclo for viene eseguito al più una volta per ogni nodo
・per un nodo v il for viene eseguito d(v) volte (il grado del nodo v)
・spendiamo in tutto tempo
DFS(v) // utilizzando uno stack
Σv∈V d(v) = 2m =O(m)
nelle iterazioni del while
・all’inizio spendiamo O(n) per
settare
visited[]=false
- quindi O(n+m)
per tutti
Set visited[u] = false
2
7
3
10 11
4
BFS(s)
DFS(v)
Set visited[v] = false
6
8
5
9
10
11
Ordine di visita DFS
Ordine di visita BFS
for each vertex u
7
for each vertex v
//
utilizzando uno stack
Set visited[u] = false
for each vertex u
Stack-in(P, v); parent[v] = nil
Enqueue(S, s), visited[s] = true
Stack-in(P, v); parent[v] = nil
while (P is not empty) {
while (S is not empty) {
while (P is not empty) {
v ⟵ Stack-out(P)
u ⟵ Dequeue(S)
v ⟵ Stack-out(P)
if (visited[v] = false)
for each v in Adj[u]
if (visited[v] = false)
visited[v] = true
if (visited[v] = false)
visited[v] = true
add edge (v,parent[v]) to the DFS tree T
add edge (u,v) to the BFS tree T
add edge (v,parent[v]) to the DFS tree T
for each u in Adj[v] //in reverse order
visited[v] = true
for each u in Adj[v] //in reverse order
Stack-in(P,u); parent[u] = v
74
Enqueue(S,v)
Stack-in(P,u); parent[u] = v
75
Grafi Bipartiti
Def. Un grafo (non orientato) G = (V, E) è bipartito se i nodi possono essere
colorati di blu o bianco in modo tale che ogni arco unisca un nodo bianco
con un nodo blu.
A PPLICAZIONI DELLE VISITE
BFS E DFS
Applicazioni.
・Stable matching/marriage: men = blu, women = bianco.
・Scheduling: machines = blu, jobs = bianco.
‣ testare se un grafo è bipartito
‣ connettività in grafi orientati
‣ DAG e ordinamento topologico
un grafo bipartito
76
77
Testare se un grafo è bipartito
Un ostacolo all’essere bipartito
Molti problemi su grafi diventano:
Lemma. Se un grafo G è bipartito, non può contenere un ciclo di lunghezza
・più facili se il grafo è bipartito (matching).
dispari.
- trattabili (polinomiali) se il grafo in input è bipartito, mentre solo
algoritmi esponenziali sono noti in generale (es. independent set).
Dim. Non è possibile avere una bicolorazione di un ciclo dispari, quindi a
maggior ragione non esiste una bi-colorazione di G.
E’ utile avere una procedura che può dirci in maniera efficiente se un grafo è
bipartito
v2
v2
v3
v1
v4
v5
v6
v3
v4
v5
v6
v7
v1
v7
un grafo bipartito G
bipartito
non bipartito
(2-colorabile)
(non 2-colorabile)
lo stesso grafo G
78
79
Grafi bipartiti
Grafi bipartiti
Lemma. Sia G un grafo connesso, e siano L0, …, Lk i livelli prodotti da una
Lemma. Sia G un grafo connesso, e siano L0, …, Lk i livelli prodotti da una
BFS con nodo di partenza s. Solo una delle seguenti affermazioni è vera:
BFS con nodo di partenza s. Solo una delle seguenti affermazioni è vera:
(i) Nessun arco di G unisce due nodi dello stesso livello, e G è bipartito.
(i) Nessun arco di G unisce due nodi dello stesso livello, e G è bipartito.
(ii) Un arco di G unisce due nodi dello stesso livello, e G contiene un
(ii) Un arco di G unisce due nodi dello stesso livello, e G contiene un
ciclo di lunghezza dispari (e quindi NON è bipartito).
ciclo di lunghezza dispari (e quindi NON è bipartito).
Dim. (i)
・Supponiamo che nessun arco unisca nodi dello stesso livello.
Avevamo provato che la BFS riorganizza il grafo in modo da avere tutti
gli archi tra nodi di livelli adiacenti o tra nodi sullo stesso livello
・quindi, tutti gli archi sono tra nodi di livelli adiacenti.
・Bipartizione: bianchi = nodi di livello dispari, blu = nodi su livelli pari.
L1
L2
Case (i)
L3
L1
L2
L3
L1
Case (ii)
80
L2
Case (i)
L3
81
Grafi bipartiti
L’unico ostacolo all’essere bipartito
Lemma. Sia G un grafo connesso, e siano L0, …, Lk i livelli prodotti da una
Corollario. Un grafo G è bipartito se e solo se NON contiene un ciclo di
BFS con nodo di partenza s. Solo una delle seguenti affermazioni è vera:
lunghezza dispari.
・l’abbiamo provato (al contrario) facendo vedere che:
(i) Nessun arco di G unisce due nodi dello stesso livello, e G è bipartito.
- un grafo non è bipartito se e solo se contiene un ciclo dispari
(ii) Un arco di G unisce due nodi dello stesso livello, e G contiene un
ciclo di lunghezza dispari (e quindi NON è bipartito).
Dim. (ii)
・Supponiamo (x, y) sia un arco con x, y nel livello Lj.
・Sia z = lca(x, y) = il più vicino antenato comune di x,y.
・Sia Li il livello di z.
・Consideriamo il ciclo C costituito da: (i) l’arco tra x e y,
z = lca(x, y)
5-ciclo C
(ii) il cammino da y a z, (iii) il cammino da z a x.
・la lunghezza di C è
quindi dispari. ▪
1
(x, y)
+ (j – i) + (j – i) = 2(j – i) + 1 ,
cammino da
yaz
cammino da
zax
82
bipartito
non bipartito
(2-colorabile)
(non 2-colorabile)
Esercizio: Scrivere l’intero pseudocodice per testare se un grafo è bipartito
Modificare BFS, ottenendo un algoritmo con la complessità O(n+m)
83
Grafi orientati
Notazione. G = (V, E).
・Arco (u, v) esce dal nodo u ed entra nel nodo v.
A PPLICAZIONI DELLE VISITE
BFS E DFS
‣ testare se un grafo è bipartito
‣ connettività in grafi orientati
‣ DAG e ordinamento topologico
Es. Web: gli hyperlink creano collegamenti da una pagina web ad un’altra.
・L’orientamento degli archi è cruciale.
・I motori di ricerca sfruttano la struttura degli hyperlink per classificare
le pagine (determinare quelle più importanti)
84
85
World wide web
La rete stradale
To see all the details that are visible on the screen,use the
"Print" link next to the map.
Address Holland Tunnel
New York, NY 10013
Il Grafo del Web
・Nodi: pagine web.
・Archi: hyperlink da
Vertici = incroci; archi = strade a senso unico.
una pagina ad un’altra.
- la struttura degli hyperlink è sfruttata dai motori di ricerca per
determinare l’importanza delle pagine web.
cnn.com
netscape.com
novell.com
cnnsi.com
timewarner.com
hbo.com
sorpranos.com
©2008 Google - Map data ©2008 Sanborn, NAVTEQ™ - Terms of Use
86
87
Cammini e connettività in grafi orientati
Ricerca in un grafo (orientato)
Def. Un cammino in un grafo orientato G = (V, E) è una sequenza di nodi v1,
Raggiungibilità. Dato un nodo s, trova tutti i nodi raggiungibili da s.
v2, …, vk con la proprietà che ogni coppia di nodi consecutivi vi–1, vi risulta
connessa da un arco (orientato) in E.
Il problema del cammino minimo (orientato). Dati due nodi s e t, qual è la
lunghezza del cammino minimo da s a t ?
Osservazione. La visita BFS si può estendere al caso di grafi orientati.
Web crawler. Cominciano da una pagina s. Trovano tutte le pagine web
collegate (attraverso una sequenza di hyperlink) ad s (sia direttamente che
Un cammino (orientato)
indirettamente).
Questo NON è un cammino
(nel grafo orientato)
Domande:
1. Possiamo risolvere il problema della raggiungibilità usando la visita DFS ?
2. Possiamo risolvere il problema del cammino minimo orientato, usando la DFS?
88
89
Connettività forte (in grafi orientati)
Connettività forte: algoritmo
Def. Nodi u e v sono mutuamente raggiungibili se esiste sia un cammino
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
(orientato) da u a v che un cammino (orientato) da v ad u.
Dim.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
Def. Un grafo è fortemente connesso se ogni coppia di nodi è mutuamente
raggiungibile.
Lemma. Sia s un nodo. G è fortemente connesso sse ogni nodo è
raggiungibile da s, ed s è raggiungibile da ogni nodo.
▪
Dim. ⇒ segue dalla definizione.
Dim. ⇐ Cammino da u a v: concatena il cammino u s col cammino s v .
Cammino da v a u: concatena v s con s u path. ▪
ok se i cammini si sovrappongono
s
fortemente connesso
u
non fortemente connesso
v
90
91
Connettività forte: algoritmo
Connettività forte: algoritmo
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Dim.
Dim.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
▪
s
▪
s
G
G
s
s
Greverse
Greverse
92
93
Connettività forte: algoritmo
Connettività forte: algoritmo
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Dim.
Dim.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
▪
s
▪
s
G
G
s
s
Greverse
Greverse
94
95
Connettività forte: algoritmo
Connettività forte: algoritmo
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Dim.
Dim.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
▪
▪
s
s
G
G
fortemente connesso
s
s
G
Greverse
96
97
Connettività forte: algoritmo
Connettività forte: algoritmo
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Dim.
Dim.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
▪
s
▪
s
G
G
da s non raggiungiamo nodi in Greverse
da nessun nodo raggiungiamo s in G
-> G non è fortemente connesso
s
s
Greverse
Greverse
98
99
Connettività forte: algoritmo
Componenti fortemente connesse
Teorema. è possibile determinare se G è fortemente connesso in O(m + n).
Def. Una componente fortemente connessa è un sottinsieme di nodi
Dim.
massimale rispetto alla mutua raggiungibilità.
・Scegliamo arbitrariamente un nodo s.
・Eseguiamo BFS da s in G. Ottenuto invertendo la direzione di ogni arco di G
・Eseguiamo BFS da s in Greverse.
・Ritorna “true” sse tutti i nodi risultano visitati da entrambe le BFS.
・La correttezza è una diretta conseguenza del lemma precedente.
▪
A digraph and its strong components
Teorema. [Tarjan 1972] Tutte le componenti fortemente connesse possono
essere trovate in tempo O(m + n).
fortemente connesso
non fortemente connesso
100
101
Grafi orientati aciclici (Directed acyclic graphs, DAG)
Def. Un DAG è un grafo orientato che non contiene un ciclo orientato.
Def. Un ordinamento topologico di un grafo orientato G = (V, E) è un
A PPLICAZIONI DELLE VISITE
BFS E DFS
ordinamento dei suoi nodi v1, v2, …, vn tale che per ogni arco (vi, vj) vale i < j.
‣ testare se un grafo è bipartito
v2
v3
‣ connettività in grafi orientati
‣ DAG e ordinamento topologico
v6
v5
v7
v4
v1
un DAG G
102
103
Grafi orientati aciclici (Directed acyclic graphs, DAG)
DAG e Vincoli di precedenza
Def. Un DAG è un grafo orientato che non contiene un ciclo orientato.
Vincoli di precedenza. L’arco (vi, vj) indica che vi deve apparire prima di vj.
Def. Un ordinamento topologico di un grafo orientato G = (V, E) è un
Applicazioni.
・Grafo dei prerequisiti tra corsi: il corso vi deve essere superato prima di vj.
・Compilazione: modulo vi deve essere compilato prima di vj.
・Gene networks: nodi = proteine o geni; archi = interazioni (attivazioni,
ordinamento dei suoi nodi v1, v2, …, vn tale che per ogni arco (vi, vj) vale i < j.
inibizioni, specificità di binding); orientamento (relazione di precursione)
v2
- ordinamento topologico = risoluzione di vincoli di precedenza
v3
v2
v6
v5
v4
v1
v2
v3
v4
v5
v6
v6
v7
v3
v7
v5
v4
v1
v2
v3
v4
v5
v6
v7
v1
un DAG G
un ordinamento tolopogico di G
v7
104
v1
un DAG G
un ordinamento tolopogico di G
105
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Dim. [per assurdo]
Dim. [per assurdo]
・Supponiamo che G abbia un ordinamento topologico v1, v2, …, vn e che in
G ci sia anche un ciclo orientato C. Vediamo cosa succede.
il ciclo orientato C
v1
vi
vj
vn
l’ordinamento topologico che assumiamo esistere: v1, …, vn
106
107
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Dim. [per assurdo]
Dim. [per assurdo]
・
・Supponiamo che G abbia un ordinamento topologico v1, v2, …, vn e che in
Supponiamo che G abbia un ordinamento topologico v1, v2, …, vn e che in
G ci sia anche un ciclo orientato C. Vediamo cosa succede.
G ci sia anche un ciclo orientato C. Vediamo cosa succede.
・
・Sia vi il nodo in C di indice minimo nell’ordinamento, e sia vj il nodo che
Sia vi il nodo in C di indice minimo nell’ordinamento, e sia vj il nodo che
lo precede nel ciclo; quindi (per il ciclo) (vj, vi) è un arco (orientato).
lo precede nel ciclo; quindi (per il ciclo) (vj, vi) è un arco (orientato).
・Per la scelta di i (il minimo indice di un nodo nel ciclo) deve valere i < j.
il ciclo orientato C
v1
vi
il ciclo orientato C
vj
vn
v1
l’ordinamento topologico che assumiamo esistere: v1, …, vn
vi
vj
vn
l’ordinamento topologico che assumiamo esistere: v1, …, vn
108
109
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Lemma. Se G ha un ordinamento topologico, allora G è un DAG.
Dim. [per assurdo]
Q. e’ anche vero che ogni DAG ha un ordinamento topologico?
・
Supponiamo che G abbia un ordinamento topologico v1, v2, …, vn e che in
G ci sia anche un ciclo orientato C. Vediamo cosa succede.
Q. Se sì, come possiamo trovarlo?
・Sia vi il nodo in C di indice minimo nell’ordinamento, e sia vj il nodo che
lo precede nel ciclo; quindi (per il ciclo) (vj, vi) è un arco (orientato).
・Per la scelta di i (il minimo indice di un nodo nel ciclo) deve valere i < j.
・Tuttavia, poiché (vj, vi) è un arco e v1, v2, …, vn è un ordinamento
topologico, deve valere j < i, quindi abbiamo una contraddizione. ▪
il ciclo orientato C
v1
vi
vj
vn
l’ordinamento topologico che assumiamo esistere: v1, …, vn
110
111
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Dim. [per assurdo]
Dim. [per assurdo]
・Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
・Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
Cosa succede?
Cosa succede?
・Prendiamo un nodo v, e seguiamo gli archi all’indietro cominciando da
v. Poiché v ha almeno un arco entrante (u, v) possiamo andare ad u.
u
112
v
113
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Dim. [per assurdo]
Dim. [per assurdo]
・
・Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
Cosa succede?
Cosa succede?
・Prendiamo un nodo v, e seguiamo gli archi all’indietro cominciando da
・Prendiamo un nodo v, e seguiamo gli archi all’indietro cominciando da
・Quindi, poiché u ha almeno un arco entrante (x, u), possiamo passare al
・Quindi, poiché u ha almeno un arco entrante (x, u), possiamo passare al
v. Poiché v ha almeno un arco entrante (u, v) possiamo andare ad u.
v. Poiché v ha almeno un arco entrante (u, v) possiamo andare ad u.
nodo x.
nodo x.
・Possiamo continuare così fino a quando visitiamo un nodo, diciamo
w,
per la seconda volta (deve capitare dopo al più n passi)
x
u
v
w
x
u
v
114
115
Grafi orientati aciclici
Grafi orientati aciclici
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti.
Dim. [per assurdo]
Dim. [per assurdo]
・Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
・Supponiamo che G sia un DAG e ogni nodo abbia un arco entrante.
Cosa succede?
Cosa succede?
・
・Prendiamo un nodo v, e seguiamo gli archi all’indietro cominciando da
・Quindi, poiché u ha almeno un arco entrante (x, u), possiamo passare al
・Quindi, poiché u ha almeno un arco entrante (x, u), possiamo passare al
・
・Possiamo continuare così fino a quando visitiamo un nodo, diciamo
・Sia C la sequenza di nodi visitati tra le due visite di w. C è un ciclo.
・Sia C la sequenza di nodi visitati tra le due visite di w. C è un ciclo.
・Poiché c’è un ciclo (orientato) C, allora G non può essere un DAG▪
Prendiamo un nodo v, e seguiamo gli archi all’indietro cominciando da
v. Poiché v ha almeno un arco entrante (u, v) possiamo andare ad u.
v. Poiché v ha almeno un arco entrante (u, v) possiamo andare ad u.
nodo x.
nodo x.
Possiamo continuare così fino a quando visitiamo un nodo, diciamo w,
per la seconda volta (deve capitare dopo al più n passi)
w
x
u
w,
per la seconda volta (deve capitare dopo al più n passi)
v
w
116
x
u
v
117
Grafi orientati aciclici
Algoritmo di ordinamento topologico: running time
Lemma. Se G è un DAG, allora G ha un nodo senza archi entranti. (Provato!)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Lemma. Se G è un DAG, allora G ha un ordinamento topologico.
Dim.
・Manteniamo le seguenti informazioni:
Dim. [per induzione su n]
・
・Dato un DAG su n > 1 nodi, troviamo un nodo v senza archi entranti.
・G – { v } è un DAG, in quanto eliminando v non creiamo cicli.
・Per ipotesi induttiva, G – { v } ha un ordinamento topologico.
・Se ora creiamo la sequenza che comincia con v e continua con l’ordinamento
- c(w) = numero di archi entranti rimanenti
Base di induzione: vero se n = 1.
- S = insieme di nodi rimanenti senza archi entranti
・Inizializzazione:
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
topologico di G – { v }
・otteniamo un ordinamento topologico per G. Nota che v non ha archi entranti .
▪
・Aggiornamento:
dichiara v il primo nodo nell’ordinamento topologico di G
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
DAG
- questo richiede tempo O(1) per ogni arco
Sia H = G - v il grafo ottenuto da G eliminando v
Trova, ricorsivamente, un ordinamento topologico S di H
La sequenza ottenuta mettendo prima v e poi S
per eliminare un nodo v
- rimuoviamo v da S
Ordinamento-topologico(G)
Trova un nodo v senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
▪
v
è un ordinamente topologico di G
118
119
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v3) = 1
a
b
a
c(f) = 1
b
c(f) = 1
f
g
e
c
f
d
un DAG G
g
e
120
c
d
un DAG G
121
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v3) = 1
a
c(b) = 1
b
a
c(f) = 1
b
c(f) = 1
f
g
c(v5) = 1
e
c
c(c) = 1
f
d
g
c(g) = 1
e
122
un DAG G
c
d
123
un DAG G
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(b) = 1
a
c(a) = 0
b
c(f) = 1
g
c(g) = 2
e
c
c(c) = 2
f
d
un DAG G
b
c(f) = 2
c(c) = 1
f
c(b) = 1
a
c(e) = 3
124
g
c(g) = 4
e
d
un DAG G
c
c(d) = 0
125
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 1
v2
S = {v1, v2}
v3
c(v6) = 2
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
v5
c(v5) = 4
v4
S = {v2}
v3
c(v6) = 2
c(v4) = 2
v6
c(v3) = 1
v2
c(v4) = 2
v6
v5
c(v5) = 4
v4
v1
c(v7) = 3
v7
v1
c(v1) = 0
c(v7) = 3
v7
126
un DAG G
v1
c(v1) = 0
127
un DAG G
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 1
v2
S = {v2}
v3
c(v6) = 2
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
v5
c(v5) = 3
v4
S = {}
v3
c(v6) = 2
c(v4) = 1
v6
c(v3) = 1
v2
c(v4) = 1
v6
v5
c(v5) = 3
v4
v1
c(v7) = 2
v7
v1
un DAG G
v1
c(v1) = 0
c(v7) = 2
128
v7
v1
un DAG G
v2
c(v1) = 0
129
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 0
v2
S = {v3}
v3
c(v6) = 1
c(v2) = 0
v5
c(v5) = 2
v4
v1
S = {}
v3
c(v4) = 1
v6
v1
v7
c(v3) = 0
v2
c(v6) = 1
c(v4) = 1
v6
c(v7) = 2
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
v5
c(v5) = 2
v4
v2
v1
c(v1) = 0
c(v7) = 2
v7
130
un DAG G
v1
v2
v3
c(v1) = 0
131
un DAG G
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 0
v2
S = {v4}
v3
c(v6) = 1
c(v2) = 0
v5
c(v5) = 1
v4
v1
un DAG G
v2
S = {}
v3
c(v4) = 0
v6
v1
v7
c(v3) = 0
v2
c(v6) = 1
c(v4) = 0
v6
c(v7) = 2
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
v5
c(v5) = 1
v4
v3
v1
c(v1) = 0
c(v7) = 2
132
v7
v1
un DAG G
v2
v3
v4
c(v1) = 0
133
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 0
v2
S = {v5}
v3
c(v6) = 1
c(v2) = 0
v5
c(v5) = 0
v4
v1
v2
v3
S = {}
v3
c(v4) = 0
v6
v1
v7
c(v3) = 0
v2
c(v6) = 1
c(v4) = 0
v6
c(v7) = 2
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
v5
c(v5) = 0
v4
v4
v1
c(v1) = 0
c(v7) = 2
v7
134
un DAG G
v1
v2
v3
v4
v5
c(v1) = 0
135
un DAG G
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 0
v2
S = {v6}
v3
c(v6) = 0
c(v2) = 0
v5
c(v5) = 0
v4
v1
un DAG G
v2
v3
v4
S = {}
v3
c(v4) = 0
v6
v1
v7
c(v3) = 0
v2
c(v6) = 0
c(v4) = 0
v6
c(v7) = 1
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
v5
c(v5) = 0
v4
v5
v1
c(v1) = 0
c(v7) = 1
136
v7
v1
un DAG G
v2
v3
v4
v5
v6
c(v1) = 0
137
Ordinamento Topologico in O(n+m)
Ordinamento Topologico in O(n+m)
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
Dim.
・
・ Inizializzazione:
・
・
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
Inizializzazione: O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
c(v2) = 0
c(v3) = 0
v2
S = {v7}
v3
c(v6) = 0
c(v2) = 0
v5
c(v5) = 0
v4
v1
v2
v3
v4
v5
c(v1) = 0
c(v7) = 0
138
Teorema. L’algoritmo trova un ordinamento topologico in tempo O(m + n) .
Dim.
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
・ Inizializzazione:
・
v3
v5
v7
v4
v1
v2
v3
v4
v5
v6
v7
v1
un DAG G
c(v5) = 0
v4
v1
Ordinamento Topologico in O(n+m)
v6
v5
v6
un DAG G
v2
S = {}
v3
c(v4) = 0
v6
v1
v7
c(v3) = 0
v2
c(v6) = 0
c(v4) = 0
v6
c(v7) = 0
- c(w) = # archi entranti rimanenti; S = nodi senza archi entranti
O(m + n) - mentre leggiamo l’input.
- per ogni arco (v,w) che troviamo, incrementiamo c(w) ;
- poi controlliamo per ogni w se c(w)=0, se sì mettiamo w in S
Aggiornamento: per eliminare un nodo v
- rimuoviamo v da S
- decrementiamo c(w) per ogni arco da v a w;
e aggiungiamo w ad S se c(w) diventa 0
- questo richiede tempo O(1) per ogni arco ▪
un ordinamento tolopogico di G
140
v7
v1
un DAG G
v2
v3
v4
v5
v6
v7
c(v1) = 0
139