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