Visite in Grafi BFS e DFS

Transcript

Visite in Grafi BFS e DFS
Visite in Grafi
BFS e DFS
Visita di un Grafo
Obiettivo:
Visitare una sola volta tutti i nodi del grafo.
Es.: visitare un porzione del grafo del Web
Difficoltà:
Presenza di cicli:
• Marcare i nodi visitati
Presenza di nodi isolati:
• La visita termina quando sono state considerate
tutte le componenti isolate del grafo
LASD 2004- 05
2
Breadth-first-search
Visita in ampiezza
3
Breadth-first-search (BFS) – 1
G=(V,E) direzionato/non-direzionato s∈V, s = sorgente
La BFS esplora gli archi di G alla ricerca dei
vertici che sono raggiungibili da s
Computa la distanza (= min numero di archi)
da s a tutti gli altri vertici raggiunti
1
1
2
23
5
2
3 3
5
4 6
1
1
1
2
s=1
4
1
LASD 2004- 05
4
2
4
Breadth-first-search (BFS) –2
G=(V,E) direzionato/non-direzionato s ∈ V, s=sorgente
Produce l’albero breadth-first avente come
radice s e come nodi tutti i vertici raggiunti
Il cammino da s ad un vertice v in tale albero
è il cammino minimo (shortest path) da s a v
in G
Il nome breadth-first-search è dovuto al fatto
che l’algoritmo scopre tutti i vertici a distanza
k da s prima di scoprire quelli a distanza k+1
LASD 2004- 05
5
Esempio – 1
2
1
1
1
1
Un esempio di applicazione della BFS su di un grafo non orientato
Si parte dal nodo a
Tra i nodi adiacenti allo stesso nodo si segue l’ordine alfabetico
Tra le parentesi è indicato il tempo di scoperta del nodo
Una volta visitati tutti i nodi in una componente si inizia nuovamente
partendo dal nodo con etichetta lessicograficamente minore (dalla c)
Gli archi pieni rappresentano l’albero breadth-first
LASD 2004- 05
6
Esempio – 2
1
1
2
Un esempio di applicazione della BFS su di un grafo non orientato
Si parte dal nodo a
Tra i nodi adiacenti allo stesso nodo si segue l’ordine alfabetico
Tra le parentesi è indicato il tempo di scoperta del nodo
Una volta visitati tutti i nodi raggiungibili da a si inizia nuovamente
partendo dal nodo con etichetta lessicograficamente minore (dalla b)
Gli archi pieni rappresentano l’albero breadth-first
LASD 2004- 05
7
Breadth-first-search (bfs): algoritmo
Per poter individuare i vertici scoperti o meno la
procedura colora i vertici utilizzando 3 colori:
bianco( ), grigio (G), nero (B)
Tutti i vertici hanno inizialmente colore bianco
Quando un vertice è incontrato per la prima volta
diventa grigio e rimane grigio fino a che tutti i suoi
adiacenti sono stati incontrati almeno una volta
Quando tutti gli adiacenti di un nodo grigio sono
stati visitati allora il nodo diventa nero
• Un nodo nero ha solo adiacenti grigi
LASD 2004- 05
8
BFS: Notazione per l’algoritmo
Input: – BFS(G,s)
Grafo G=(V,E) rappresentato con lista di
adiacenza;
s =sorgente
Per ogni u ∈ V
color[u] ∈ {B,G,W}
π[u] = predecessore di u (o padre di u)
• Nota che poiché nella procedura un vertice è
scoperto al più una volta esso ha al più 1 padre
• π[s] = NIL
perché non ha predecessori
d[u] = distanza di u da s
LASD 2004- 05
9
BFS: Notazione per l’algoritmo
Q
coda FIFO in cui sono inseriti i nodi grigi
restano in Q finché sono grigi
La procedura termina quando Q è vuota
• tutti gli adiacenti di nodi raggiungibili sono stati
esaminati
Output
π: albero delle precedenze
d: distanze da s dei nodi scoperti
LASD 2004- 05
10
BFS(G, s)
for each u ∈ V – {s} do color[u]ÅW, d[u] Å∞, π[u] ÅNIL endfor
color[s]ÅG , d[s] Å0, π[s] ÅNIL, ENQUEUE(Q,s)
while Q ≠∅ do
Nella coda Q ci saranno
u Å head[Q]
solo nodi di colore grigio
for v ∈ Adj[u] do
if color[v]=W then color[v] Å G
d[v] Å d[u]+1
π[v] Å u
ENQUEUE(Q,v)
endif
endfor
La BFS è alla base di molti
DEQUEUE(Q)
algoritmi. Le strutture d e π
sono utilizzati in tali algoritmi
color[u] ÅB
endwhile
LASD 2004- 05
11
BFS(G,s) : analisi
L’inizializzazione costa O(V)
Un vertice è bianco solo nella fase di inizializzazione
Non gli viene mai ridato quel colore e quindi un nodo viene messo
nella coda Q al più 1 sola volta
• il while viene iterato O(V) volte
Per ogni nodo u estratto dalla coda si esamina, con il for, la
sua lista di adiacenza alla ricerca di nodi adiacenti bianchi
La lista di adiacenza di un nodo è esaminata al più 1 volta
• il nodo infatti una volta uscito da Q non vi rientra
La somma delle lunghezze delle liste delle adiacenze è O(E)
Quindi il tempo per scandire le liste è O(E)
Complessità O(V+E)
Se il grafo è denso O(E)
Costo del while
∑v Adj(v) = |E|
LASD 2004- 05
12
BFS(G,s) : correttezza
s ∈ V s = sorgente
G=(V,E)
δ(s,v) = min numero di archi in un cammino da s a v, se c’è
∞
Lemma1
Lemma2
se non ci sono cammini
Per ogni (u ,v)∈ E δ(s,v) ≤ δ(s,u) +1
Dopo che BFS è terminata,
per ogni v∈V d[v] ≥ δ(s,v)
Teorema
• durante BFS ogni vertice v raggiungibile da s è scoperto
• alla fine di BFS, per ogni vertice scoperto, d[v]= δ(s,v)
• un percorso minimo da s a v è dato dal percorso minimo
da s a π[v] più (π[v],v)
LASD 2004- 05
13
Dimostrazione Lemma1
Per ogni (u ,v)∈ E δ(s,v) ≤ δ(s,u) +1
Se u è raggiungibile da s allora anche il
vertice v è raggiungibile
Il percorso minimo da s a v non può
essere più lungo dal percorso da s ad u
seguito dall’arco (u,v)
Se u non è raggiungibile da s allora
δ(s,u)= ∞ e la disuguaglianza è soddisfatta
LASD 2004- 05
14
Dimostrazione Lemma2 – 1
Al termine di BFS, d[v] ≥ δ(s,v) ∀ v∈V
Ipotesi induttiva
• d[v] ≥ δ(s,v) ∀ v∈V
Base (appena inseriamo s nella coda)
• d[s]=0= δ(s,s)
• d[v]= ∞ ≥ δ(s,v) ∀ v∈V\{s}
• Quindi l’ipotesi induttiva è soddisfatta
Per il passo induttivo sfruttiamo il Lemma1 e
l’assegnamento d[v]=d[u]+1
LASD 2004- 05
15
Dimostrazione Lemma2 – 2
Passo induttivo
• Consideriamo il vertice v scoperto durante l’analisi
dei vertici adiacenti al vertice u abbiamo che
d[v] = d[u]+1
per il passo dell’algoritmo
≥ δ(s,u) + 1 per l’ipotesi induttiva
≥ δ(s,v)
per il Lemma1
• Il vertice v è inserito in Q e non verrà mai più
inserito in Q (diventa grigio), quindi il valore di
d[v] non cambia più
• L’ipotesi induttiva è conservata
LASD 2004- 05
16
Breadth-first tree
Sia G=(V,E) ed s ∈ V, dopo l’esecuzione di BFS(G,s)
definiamo Gπ =(Vπ,Eπ) il sottografo predecessore di G con
Vπ={v ∈ V: π[v] ≠ NIL} ∪ {s}
Eπ ={(π[v],v) ∈ E : v ∈ Vπ-{s}}
Un sottografo predecessore è un breadth-first tree se
Vπ è costituito da tutti i vertici raggiungibili da s
Se c’è un cammino semplice da s a v in Gπ esso
coincide con lo shortest path da s a v in G
|Eπ|=|Vπ|-1
LASD 2004- 05
17
Breadth-first tree
Sia G=(V,E) ed s ∈ V, dopo l’esecuzione di BFS(G,s)
Lemma Gπ è un breadth-first tree
Stampa il percorso minimo da s a v
Print-Path (G,s,v)
if v=s then print s
else if π[v] =NIL then
“Non ci sono percorsi tra s e v”
else Print-Path(G,s, π[v])
print v
LASD 2004- 05
18
Depth-first-search
Visita in profondità
19
Depth-first-search (DFS)
G=(V,E)
direzionato/non direzionato
La DFS esplora in profondità in grafo G fino a
quando è possibile
Ad ogni passo l’arco esplorato è quello che esce
dal vertice v che è il vertice scoperto più di recente
e che ha inesplorati tutti i suoi archi uscenti
v
v
LASD 2004- 05
20
Depth-first-search (DFS)
G=(V,E)
direzionato/non direzionato (non orientato)
Quando tutti gli archi di v sono stati esplorati la
ricerca torna indietro (backtrack) per esplorare gli
altri archi che escono dal vertice u che ha scoperto v
predecessore di v
u
v
Questo processo continua fino a quando sono stati
raggiunti tutti i vertici da una sorgente iniziale.
Se però rimangono dei vertici inesplorati, allora uno di essi
viene scelto come nuova sorgente e la ricerca riparte da
essa.
LASD 2004- 05
21
Depth-first-search (DFS)
π[v]=u
v
Definiamo Gπ =(V,Eπ) il sottografo predecessore di
G con Eπ ={(π[v],v) ∈ E : v ∈ V e π[v]≠NIL}
LASD 2004- 05
22
Esempio – grafo non orientato
Un esempio di applicazione della DFS su di un grafo non orientato
Si parte dal nodo a
Tra i nodi adiacenti allo stesso nodo si segue l’ordine alfabetico
Tra le parentesi è indicato il tempo di scoperta del nodo
Una volta visitati tutti i nodi adiacenti ad un nodo (i) si torna al nodo
predecessore (f) si inizia nuovamente la visita scegliendo nodi non
visitati [dopo i si visiterà il nodo g]
Gli archi pieni rappresentano il sottografo predecessore
LASD 2004- 05
23
Esempio – grafo orientato
Un esempio di applicazione della DFS su di un grafo orientato
Si parte dal nodo a
Tra i nodi adiacenti allo stesso nodo si segue l’ordine alfabetico
Tra le parentesi è indicato il tempo di scoperta del nodo
Una volta visitati tutti i nodi adiacenti ad un nodo (i) si torna al nodo
predecessore (e) si inizia nuovamente la visita scegliendo nodi non
visitati [dopo i si visiterà il nodo f]
Gli archi pieni rappresentano il sottografo predecessore
LASD 2004- 05
24
DFS
versus
BFS
Come la BFS, ogni qual volta un vertice v è scoperto
scandendo la lista di adiacenza di un vertice u allora
viene identificato in u il predecessore di v, cioè π[v]=u
Al contrario della BFS, il cui grafo dei predecessori è un
albero, il grafo dei predecessori della DFS è una foresta
Come accadeva nella BFS i vertici sono colorati durante
la ricerca con un colore corrispondente al proprio stato
Tutti i vertici sono inizialmente
Non appena un vertice è scoperto diventa grigio G
Quando tutti i suoi adiacenti sono stati esaminati diventa nero B
LASD 2004- 05
25
DFS
versus
BFS
Una particolarità della DFS è l’assegnazione di
due timestamp (marche temporali)
Rappresentano il tempo in cui un vertice è
scoperto ed il tempo in cui è terminata la
scansione di tutti i suoi archi uscenti
time è una variabile che si incrementa ogni volta
viene incontrato un nuovo vertice o finisce la
scansione dei suoi adiacenti; inizialmente time=0
d[v] = tempo nel quale v è scoperto la prima
volta, cioè quando diventa G
f[v] = tempo nel quale finisce la scansione degli
adiacenti di v, cioè quando v diventa B
• 1 ≤ d[v] < f[v] ≤2|V|
LASD 2004- 05
26
DFS(G)
for each u ∈ V do color[u]ÅW, π[u] ÅNIL endfor
time=0
for each u ∈ V do
if color[u]=W then DFS_visit(u) endif
endfor
DFS_visit(u)
color[u] Å G, d(u) Å time, time Å time +1
for each v ∈ Adj[u] do
if color[v]=W then π[v] Å u
DFS_visit(v)
endif
endfor
color[u] Å B
f[u] Å time, time Å time +1
LASD 2004- 05
27
DFS
Ogni qual volta la DFS_visit è chiamata
dalla DFS il vertice u diventa la radice di
un nuovo albero nella depth-first forest
Quando la DFS finisce, ogni vertice u in
V ha avuto assegnati i valori d[u] e f[u]
LASD 2004- 05
28
DFS : analisi
L’inizializzazione richiede tempo O(V)
DFS_visit è chiamata esattamente 1 volta per
ogni vertice v in V
Durante la sua esecuzione viene esaminata la
lista di adiacenza di v
• quindi ogni chiamata alla DFS_visit richiede tempo
|Adj[v]|
ÎIl tempo totale del for in DFS_visit è
∑v∈ V |Adj[v]| = O(E)
ÎIl running time di DFS è O(V+E)
LASD 2004- 05
29
DFS : proprietà
1. Il grafo dei predecessori forma una foresta di
alberi
Questo perché gli alberi depth first rispecchiamo la
struttura delle chiamate ricorsive della DFS_visit
2. È possibile caratterizzare un vertice v
discendente di un altro vertice u nell’albero
Teorema v è discendente di u ⇔ al tempo d[u], v
può essere raggiunto da u con un cammino di tutti
nodi bianchi
LASD 2004- 05
30
DFS : proprietà
3. I tempi di scoperta e finali assegnati ai
vertici hanno una struttura a parentesi
Se si assegna (u quando si scopre u e si
assegna u) quando si è finito di scandire i suoi
adiacenti, l’intera sequenza di “scoperte” e
“fine scansione” fornisce una sequenza di
parentesi innestate ed a 2 a 2 accoppiate
Possiamo avere (u … (v …. v) … u) ma non
(u … (v …. u) … v)
LASD 2004- 05
31
DFS : proprietà
Teorema delle parentesi Dato G=(V,E) e
u,v ∈V solo 1 dei seguenti 3 casi si può
verificare:
• [d[u],f[u]] e [d[v],f[v]] sono disgiunti
• [d[u],f[u]] è contenuto interamente
[d[v],f[v]] e u è discendente di v nell’albero
•
in
[d[v],f[v]] è contenuto interamente in
[d[u],f[u]] e v è discendente di u nell’albero
Corollario v è un discendente di u ⇔
d[u]
f[u]
d[v]
LASD 2004- 05
f[v]
32
Esercizio
Scrivere lo pseudocodice di un algoritmo per
il calcolo di tutte le componenti connesse di
un grafo non orientato
Modificare opportunamente una delle
analizzate precedentemente (BFS, DFS)
visite
Discutere della complessità dell’algoritmo
proposto e delle strutture dati utilizzate
L’algoritmo deve avere una complessità di tempo
O(|V| + |E|)
LASD 2004- 05
33