1.6 Ricerca su grafi¶
Parte 1 · Grafi · Capitolo 1 · Capitolo 1: Grafi · Dispensa, volume 1 (PDF) · Esercizi: Grafi · App: Ricerca su grafo: BFS e DFS
Definizione 1.24: ricerca grafo
Dato un grafo diretto \(G=(N,A)\) e un nodo \(s \in N\), source, una graph search trova l'insieme \(R(s)\) dei nodi raggiungibili da \(s\). Durante la ricerca:
-
un nodo è etichettato quando la ricerca lo raggiunge e rimane etichettato;
-
ogni nodo etichettato \(j \neq s\) registra il suo predecessore \(\mathit{pred}(j)\), il nodo da cui è stato raggiunto;
-
i nodi etichettati ancora da elaborare vengono mantenuti in una lista, \(\mathit{LIST}\);
-
un arco \((i,j)\) è ammissibile se \(i\) è etichettato e \(j\) non lo è.
Algoritmo: Ricerca generica nel grafo
STOP. Altrimenti seleziona un nodo \(i \in \mathit{LIST}\):-
Nel BFS la lista \(\mathit{LIST}\) è una queue (first in, first out): i nodi vengono elaborati nell'ordine in cui sono etichettati.
-
Nel DFS la lista \(\mathit{LIST}\) è un stack (last in, first out): la ricerca parte sempre dal più nodo recentemente etichettato ancora in \(\mathit{LIST}\) e torna indietro solo quando quel nodo non ha archi ammissibili.
-
L'ordine degli elenchi di adiacenza decide quale arco ammissibile viene preso per primo; con elenchi ordinati in ordine crescente indice, come in questo modulo, il risultato è unico.
1.6.1 L'albero predecessore¶
Proposizione 1.25: albero predecessore
Ad ogni iterazione, gli archi \((\mathit{pred}(j),j)\), per i nodi etichettati \(j \neq s\), formano un albero sui nodi etichettati, albero predecessore. Per ogni nodo etichettato \(j\) contiene un percorso diretto da \(s\) a \(j\).
Dimostrazione
Sia \(r\) il numero di nodi etichettati.
-
Ogni nodo etichettato \(j \neq s\) ha un predecessore, etichettato prima di \(j\). A partire da \(j\) e passando a predecessore, i nodi sono etichettati sempre prima, quindi la sequenza termina con \(s\).
-
Letto al contrario, è un percorso diretto da \(s\) a \(j\) lungo gli archi \((\mathit{pred}(h),h)\).
-
Quindi gli archi \(r-1\) collegano i nodi etichettati \(r\) e formano un albero per Teorema 1.17(b). □
Teorema 1.26: correttezza della ricerca
Al termine della ricerca generica, BFS e DFS inclusi, i nodi etichettati sono esattamente i nodi di \(R(s)\).
Dimostrazione
Ogni nodo etichettato è raggiungibile da \(s\), da Proposizione 1.25. Viceversa, lasciamo \(j \in R(s)\) e lascia che \(s=i_0,i_1,\dots,i_k=j\) sia un percorso diretto; presupponiamo per assurdo che \(j\) non sia etichettato.
-
Sia \(i_t\) il primo nodo senza etichetta del percorso; \(t \ge 1\), poiché \(s\) è etichettato.
-
Il nodo \(i_{t-1}\) è etichettato, quindi è entrato in \(\mathit{LIST}\), e alla fine lo ha lasciato.
-
Un nodo esce da \(\mathit{LIST}\) solo quando non ha arco ammissibile. Ma \((i_{t-1},i_t)\) è ammissibile fino alla fine, perché le etichette non si tolgono mai: un controsenso. □
Teorema 1.27: tempo di esecuzione della ricerca
Con gli elenchi di adiacenza, la ricerca generica viene eseguita nel tempo \(O(|N|+|A|)\).
Dimostrazione
Ogni nodo mantiene un puntatore alla posizione corrente nella sua lista \(L(i)\); il puntatore si sposta in avanti oltre l'etica successori e non torna mai indietro, poiché le etichette non vengono mai rimosse.
-
Ogni iterazione etichetta un nodo o rimuove un nodo da \(\mathit{LIST}\). Ogni nodo viene etichettato al massimo una volta e rimosso a più una volta, quindi ci sono al massimo \(2n\) iterazioni, ciascuna con \(O(1)\) che funziona oltre al puntatore.
-
Il puntatore del nodo \(i\) si sposta al massimo \(\deg^+(i)\) volte in totale e \(\sum_{i \in N} \deg^+(i)=m\).
Il tempo totale è \(O(n+m)=O(|N|+|A|)\). □
- Con la matrice di adiacenza i successori di un nodo si trovano scansionando una riga di lunghezza \(n\), e la ricerca richiede tempo \(O(n^2)\).
1.6.2 La visita in ampiezza sul grafo di riferimento¶
Esempio 1.9: BFS dal nodo \(1\)
Eseguiamo il BFS sul grafo di riferimento da \(s=1\), con gli elenchi di adiacenza di Esempio 1.5. Ogni riga rappresenta un'iterazione e dopo di essa viene visualizzato \(\mathit{LIST}\):
| iterazione e \(i\) selezionato e azione | \(\mathit{LIST}\) | ||
|---|---|---|---|
| \(1\) | \(1\) | etichetta \(2\), \(\mathit{pred}(2)=1\) | \(1,2\) |
| \(2\) | \(1\) | etichetta \(3\), \(\mathit{pred}(3)=1\) | \(1,2,3\) |
| \(3\) | \(1\) | rimuovi \(1\) | \(2,3\) |
| \(4\) | \(2\) | etichetta \(4\), \(\mathit{pred}(4)=2\) | \(2,3,4\) |
| \(5\) | \(2\) | rimuovi \(2\) | \(3,4\) |
| \(6\) | \(3\) | etichetta \(5\), \(\mathit{pred}(5)=3\) (\(2\) è etichettato) | \(3,4,5\) |
| \(7\) | \(3\) | rimuovi \(3\) | \(4,5\) |
| \(8\) | \(4\) | etichetta \(6\), \(\mathit{pred}(6)=4\) (\(3\) è etichettato) | \(4,5,6\) |
| \(9\) | \(4\) | rimuovi \(4\) | \(5,6\) |
| \(10\) | \(5\) | rimuovi \(5\) (\(4\) e \(6\) sono etichettati) | \(6\) |
| \(11\) | \(6\) | rimuovi \(6\) | (vuoto) |
L'ordine di etichettatura è \(1,2,3,4,5,6\): ogni nodo è raggiungibile da \(1\). L'albero precedente ha gli archi \((1,2)\), \((1,3)\), \((2,4)\), \((3,5)\), \((4,6)\); è lo albero ricoprente di Esempio 1.7. Accanto a ciascuno nodo, in figura è riportato il numero \(d(j)\) di archi del percorso dell'albero da \(1\) a \(j\).
Proposizione 1.28: BFS trova i percorsi più brevi in numero di archi
Nell'albero precedente del BFS, lasciare \(d(s)=0\) e \(d(j)=d(\mathit{pred}(j))+1\) per ogni \(j \neq s\) etichettato. Quindi, per ogni \(j \in R(s)\), \(d(j)\) è il numero minimo di archi di un percorso diretto da \(s\) a \(j\).
Dimostrazione
Dimostriamo tre fatti.
-
Se \(\mathit{LIST}=u_1,u_2,\dots,u_r\), allora \(d(u_1) \le d(u_2) \le \dots \le d(u_r) \le d(u_1)+1\). Vale a Passaggio 0. Un nuovo nodo \(j\) viene etichettato da \(u_1\) e aggiunto con \(d(j)=d(u_1)+1\); rimuovendo \(u_1\) si mantiene la proprietà, perché \(d(u_r) \le d(u_1)+1 \le d(u_2)+1\).
-
I nodi sono etichettati in ordine non decrescente di \(d\). Ogni nuovo nodo ha \(d(j)=d(u_1)+1 \ge d(u_r)\), e \(u_r\) è l'ultimo nodo etichettato prima di \(j\).
-
Per ogni arco \((i,j)\) con \(i\) etichettato, \(d(j) \le d(i)+1\). Se \(j\) è etichettato dopo \(i\), allora \(j\) è etichettato prima che \(i\) lasci \(\mathit{LIST}\), da un nodo \(u\) nella parte anteriore di \(\mathit{LIST}\), etichettato non più tardi di \(i\): \(d(j)=d(u)+1 \le d(i)+1\). If \(j\) is labelled before \(i\), then \(d(j) \le d(i)\) di fatto 2.
Sia \(s=i_0,i_1,\dots,i_k=j\) un percorso diretto con il numero minimo \(k\) di archi. I suoi nodi sono etichettati (Teorema 1.26), e di fatto 3, \(d(j) \le d(i_{k-1})+1 \le \dots \le d(s)+k=k\). L'albero il percorso da \(s\) a \(j\) è un percorso diretto con archi \(d(j)\), quindi \(d(j) \ge k\). □
- In Esempio 1.9, i valori \(d=(0,1,1,2,2,3)\) sono il numero minimo di archi dal nodo \(1\): ad esempio, i percorsi diretti più brevi al nodo \(6\) hanno archi \(3\), come \(1,2,4,6\).
1.6.3 La ricerca approfondita sul grafo di riferimento¶
Esempio 1.10: DFS dal nodo \(1\)
Eseguiamo il DFS sul grafo di riferimento da \(s=1\): il nodo selezionato è sempre l'ultimo di \(\mathit{LIST}\).
| iterazione e \(i\) selezionato e azione | \(\mathit{LIST}\) | ||
|---|---|---|---|
| \(1\) | \(1\) | etichetta \(2\), \(\mathit{pred}(2)=1\) | \(1,2\) |
| \(2\) | \(2\) | etichetta \(4\), \(\mathit{pred}(4)=2\) | \(1,2,4\) |
| \(3\) | \(4\) | etichetta \(3\), \(\mathit{pred}(3)=4\) | \(1,2,4,3\) |
| \(4\) | \(3\) | etichetta \(5\), \(\mathit{pred}(5)=3\) (\(2\) è etichettato) | \(1,2,4,3,5\) |
| \(5\) | \(5\) | etichetta \(6\), \(\mathit{pred}(6)=5\) (\(4\) è etichettato) | \(1,2,4,3,5,6\) |
| \(6\) | \(6\) | rimuovi \(6\) | \(1,2,4,3,5\) |
| \(7\) | \(5\) | rimuovi \(5\) | \(1,2,4,3\) |
| \(8\) | \(3\) | rimuovi \(3\) | \(1,2,4\) |
| \(9\) | \(4\) | rimuovi \(4\) (\(3\) e \(6\) sono etichettati) | \(1,2\) |
| \(10\) | \(2\) | rimuovi \(2\) | \(1\) |
| \(11\) | \(1\) | rimuovi \(1\) (\(2\) e \(3\) sono etichettati) | (vuoto) |
L'ordine di etichettatura è \(1,2,4,3,5,6\) e l'albero precedente ha gli archi \((1,2)\), \((2,4)\), \((4,3)\), \((3,5)\), \((5,6)\): un unico percorso diretto. Accanto a ciascun nodo, la figura mostra la sua posizione \(o(j)\) nell'ordine di etichettatura.
- Entrambe le ricerche etichettano tutti i nodi, come garantisce Teorema 1.26, ma i loro alberi differire. L'albero DFS raggiunge il nodo \(6\) con archi \(5\), mentre l'albero BFS utilizza \(3\).
1.6.4 Utilizzo della ricerca¶
-
Componenti connessi. In un grafo non orientato, una ricerca da un vertice senza etichetta ne etichetta l'intero componente; ripetendolo da ogni vertice ancora non etichettato si trovano tutti i componenti in tempo \(O(n+m)\).
-
Componenti fortemente connessi. Una ricerca in \(G\) e una nel grafo invertito \(G'\) restituiscono \(R(i)\) e \(R'(i)\), quindi \(S(i)=R(i) \cap R'(i)\); ripeterlo per un nodo di ogni componente ancora sconosciuto richiede \(O(n(n+m))\) ora.
-
Spanning tree. Su un grafo connesso non orientato, l'albero predecessore di una ricerca da qualsiasi vertice è un albero di copertura.
Una ricerca sul grafo etichetta esattamente i nodi raggiungibili dalla sorgente, in tempo \(O(|N|+|A|)\), e i suoi predecessori formano un albero. Il BFS (una coda) fornisce percorsi con il numero minimo di archi; il DFS (uno stack) va prima in profondità.
1.7 Errori tipici¶
Attenzione
-
Scambio dei segni della matrice di incidenza. La voce è \(+1\) in coda e \(-1\) in testa: il la colonna di \((4,3)\) ha \(+1\) nella riga \(4\).
-
Chiamare una passeggiata un percorso. Un percorso ha vertici distinti; una passeggiata può ripeterli e contiene sempre a percorso con gli stessi punti finali.
-
Confusione tra connettività debole e forte. Il grafo di riferimento è debolmente connesso, ma ha tre componenti fortemente connessi.
-
Conteggio solo degli lati. Un grafo con lati \(n-1\) non deve essere un albero: deve anche essere connesso, oppure aciclico.
-
Credere che la matrice di incidenza abbia rango di riga completo. Il suo rango è \(|N|-k\): in un grafo connesso uno la riga è sempre ridondante.
-
Percorsi più brevi previsti dal DFS. Solo l'albero BFS fornisce il numero minimo di archi e solo quando ogni arco conta uno.
-
Dimenticare l'ordine degli elenchi. L'ordine di etichettatura e l'albero precedente dipendono dall'ordine in cui vengono scansionati i successori.
1.8 In sintesi¶
In sintesi
-
Un grafo non orientato \(G=(V,E)\) ha archi \(\{u,v\}\), un grafo diretto \(G=(N,A)\) ha archi \((i,j)\); i gradi sommare a \(2m\), i gradi in uscita e in entrata a \(m\).
-
Le liste di adiacenza necessitano di spazio \(n+m\); la matrice di incidenza nodo-arco ha \(+1\) in coda e \(-1\) in testa, e la riga \(i\) di \(\mat{B}\vet{x}\) è il deflusso meno l'afflusso del nodo \(i\).
-
Le componenti connesse e fortemente connesse sono classi di equivalenza; \(S(i)=R(i) \cap R'(i)\).
-
Un albero è connesso e aciclico, con lati \(n-1\) e un percorso unico tra ogni due vertici; un lato esterno uno albero ricoprente chiude un ciclo fondamentale.
-
\(\rank(\mat{B})=|N|-k\), e in un grafo connesso le basi di \(\mat{B}\) sono gli albero ricoprente.
-
La ricerca generica trova \(R(s)\) nel tempo \(O(|N|+|A|)\); il BFS fornisce il numero minimo di archi.
Il grafo di riferimento in sintesi.
| nodi e archi | \(n=6\), \(m=9\) |
| componenti collegati | \(1\) |
| componenti fortemente collegati | \(\{1\}\), \(\{2,3,4,5\}\), \(\{6\}\) |
| \(\rank(\mat{B})\) | \(5\) |
| BFS da \(1\) e ordina \(1,2,3,4,5,6\); \(d=(0,1,1,2,2,3)\) | |
| DFS da \(1\) e ordina \(1,2,4,3,5,6\) |
Esercizi su questo capitolo: Grafi