• Non ci sono risultati.

Algoritmi di Visita di Grafi Algoritmi di Visita di Grafi

N/A
N/A
Protected

Academic year: 2021

Condividi "Algoritmi di Visita di Grafi Algoritmi di Visita di Grafi"

Copied!
55
0
0

Testo completo

(1)

Algoritmi di Visita di Grafi Algoritmi di Visita di Grafi

Damiano Macedonio mace@unive.it

(2)

Original work Copyright © Alberto Montresor, Università di Trento, Italy

Modifications Copyright © 2010—2012, Moreno Marzolla, Università di Bologna, Italy Modifications Copyright © 2013, Damiano Macedonio, Università di Venezia, Italy This work is licensed under the Creative Commons Attribution-NonCommercial- ShareAlike License. To view a copy of this license, visit

http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.

(3)

Algoritmi e Strutture Dati 3

Attraversamento grafi

Definizione del problema

Dato un grafo G=(V, E) ed un nodo s di V (detto sorgente), visitare ogni nodo nel grafo raggiungibile da s

Ogni nodo deve essere visitato una sola volta

Visita in ampiezza (breadth-first search)

Visita i nodi “espandendo” la frontiera fra nodi scoperti / da scoprire

Es: Cammini più brevi da singola sorgente

Visita in profondità (depth-first search)

Visita i nodi andando il “più lontano possibile” nel grafo

Es: Componenti fortemente connesse, ordinamento

topologico

(4)

Visita: attenzione alle soluzioni

“facili”

Prendere ispirazione dalla visita degli alberi

utilizziamo una visita BFS basata su coda

trattiamo i “vertici adiacenti” come se fossero i “figli”

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor

endwhile

Sb ag lia to

(5)

Algoritmi e Strutture Dati 5

Perché non funziona?

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor endwhile

A B

D C

coda = { A }

(6)

Perché non funziona?

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor endwhile

A B

D C

coda = { A }

coda = { B, D }

(7)

Algoritmi e Strutture Dati 7

Perché non funziona?

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor endwhile

A B

D C

coda = { A }

coda = { B, D }

coda = { D, A, C }

(8)

Perché non funziona?

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor endwhile

A B

D C

coda = { A }

coda = { B, D }

coda = { D, A, C }

coda = { A, C, A, C }

(9)

Algoritmi e Strutture Dati 9

Perché non funziona?

algoritmo non-visita(grafo G, nodo s) coda := {s}

while (coda ≠ ) ∅ do u = coda.dequeue() “visita u”

for each “nodo v adiacente a u” do coda.enqueue(v)

endfor endwhile

Problema: questo algoritmo non termina se applicato a

grafi con cicli

(10)

Schema di algoritmo per la visita

algoritmo visita(G, s)→albero

rendi “non marcati” tutti i nodi T := s

F := { s }

“marca” il nodo s while (F ≠ ∅) do u := F.extract() “visita il nodo u”

for each v adiacente a u do if (v non è marcato) then marca il nodo v

F.insert(v) v.parent := u endif

endfor endwhile

F è l'insieme

frontiera (o frangia)

Il funzionamento di extract() e insert() non è specificato

T è l'albero che

viene costruito dalla visita

v.parent è il padre di

v nell'albero T

(11)

Algoritmi e Strutture Dati 11

Algoritmo generico per la visita

Alcune cose da notare:

I nodi vengono visitati al più una volta (marcatura)

Tutti i nodi raggiungibili da s vengono visitati

Ne segue che T è un albero che contiene esattamente tutti i nodi raggiungibili da s

Ciascun arco viene “percorso” al piú due volte nel caso dei grafi non orientati ( {u,v}, {v,u} ).

La visita avviene in base all'ordine di estrazione

Costo computazionale

O(n+m) usando liste di adiacenza

O(n

2

) usando matrice di adiacenza

n è il numero di nodi, m è il numero di archi

(12)

Visita in ampiezza

(breadth first search, BFS)

Visita i nodi a distanze crescenti dalla sorgente

visita i nodi a distanza k prima di quelli a distanza k+1

Genera un albero BF (breadth-first)

albero contenente tutti i vertici raggiungibili da s, e tale che il cammino da s ad un nodo nell'albero corrisponda al

cammino più breve nel grafo

Calcola la distanza minima da s a tutti i nodi da esso raggiungibili

distanza = numero di archi attraversati per andare da s ad

un nodo da esso raggiungibile

(13)

Algoritmi e Strutture Dati 13

Visita in ampiezza

(breadth first search, BFS)

algoritmo BFS(Grafo G, vertice s)→albero for each v in V do v.mark := false

T := s

F := new Queue() F.enqueue(s)

s.mark := true s.dist := 0

while (F ≠ ∅) do u := F.dequeue()

“visita il vertice u”

for each v adiacente a u do if (not v.mark) then

v.mark := true

v.dist := u.dist+1 F.enqueue(v)

v.parent := u endif

endfor endwhile return T

Insieme F gestito tramite una coda

v.mark è la

marcatura del nodo v

v.dist è la distanza del nodo v dal

vertice s

(14)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{F}

0

(15)

Algoritmi e Strutture Dati 15

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{B,D,I}

0 1

1

1

(16)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{D,I,C,A}

0 1

1

1 2

2

(17)

Algoritmi e Strutture Dati 17

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{I,C,A,E}

0 1

1

1 2

2

2

(18)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{C,A,E,H}

0 1

1

1 2

2

2

2

(19)

Algoritmi e Strutture Dati 19

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{A,E,H}

0 1

1

1 2

2

2

2

(20)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{E,H}

0 1

1

1 2

2

2

2

(21)

Algoritmi e Strutture Dati 21

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{H,G}

0 1

1

1 2

2

2

2 3

(22)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{G}

0 1

1

1 2

2

2

2 3

(23)

Algoritmi e Strutture Dati 23

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{}

0 1

1

1 2

2

2

2 3

(24)

Esempio

A

B

C

E

G F

H I

D L

M

Coda:{}

0 1

1

1 2

2

2

2 3

(25)

Algoritmi e Strutture Dati 25

Esempio

A

B

C

E

G F

H I

D

0 1

1

1 2

2

2

2 3

F

B D I

A C E

G

H

Albero prodotto

dalla visita BFS

(26)

Applicazioni

algoritmo print-path(G, s, v) if (v = s) then

print s

else if (v.parent = nil) then print “no path from s to v”

else

La visita BFS può essere utilizzata per ottenere il cammino più breve (minor numero di archi

attraversati) fra due vertici s e v

Esempio: se il grafo G è stato precedentemente

visitato con l'algoritmo BFS a partire da s e l'albero

della visita T è stato creato, si può applicare l'algoritmo

seguente:

(27)

Algoritmi e Strutture Dati 27

Esempio

cammino piú breve da F a G

A

B C

E G

F

H I

D

(28)

Esempio

cammino piú breve da F a G

A

B C

E G

F

H I

D

I.parent

(29)

Algoritmi e Strutture Dati 29

Esempio

print-path(G, s, v)

A

B C

E

G

F

H I

D

algoritmo print-path(G, s, v) if v = s then

print s

else if v.parent = nil then print “no path from s to v”

else

print-path(G,s,v.parent) print v

endif

s

v

(30)

Esempio

Percorso piú breve per uscire dal labirinto?

e

u

(31)

Algoritmi e Strutture Dati 31

Visita in profondità

(depth first search, DFS)

Segue ciascun percorso “il più a lungo possibile”

algoritmo DFS(Grafo G, nodo s) for each v in V do

v.mark := false;

v.parent := NULL;

endfor

DFS-visit(G, s)

algoritmo DFS-visit(Grafo G, nodo u) u.mark := true;

“visita il vertice u”

for each v adiacente a u do if (v.mark == false) then v.parent := u;

DFS-visit(v);

endif endfor

(32)

Esempio

A

B C

E G

F

H I

D

(33)

Algoritmi e Strutture Dati 33

Esempio

A

B C

E G

F

H I

D

(34)

Esempio

A

B C

E G

F

H I

D

(35)

Algoritmi e Strutture Dati 35

Esempio

A

B C

E G

F

H I

D

(36)

Esempio

A

B C

E G

F

H I

D

(37)

Algoritmi e Strutture Dati 37

Esempio

A

B C

E

G F

H I

D

(38)

Esempio

A

B C

E

G F

H

I

D

(39)

Algoritmi e Strutture Dati 39

Esempio

A

B C

E

G F

H I

D

(40)

Esempio

A

B C

E

G

F

H I

D

(41)

Algoritmi e Strutture Dati 41

Esempio

A

B C

E

G

F

H I

D

B I

F

H

G A

D

C

E

(42)

Esercizio

A

B

C

D

E

F

G

(43)

Algoritmi e Strutture Dati 43

Applicazioni degli algoritmi di visita

Individuare

le componenti connesse di un grafo non orientato

le componenti fortemente connesse di un grafo orientato

(44)

Componenti Connesse

algoritmo CC( Grafo G=(V,E) ) for each v in V do

v.cc := -1;

v.parent := NULL;

endfor k := 0;

for each v in V do if (v.cc < 0) then CC-visit(G, v,k);

k := k+1;

endif endfor

algoritmo CC-visit(Grafo G, nodo v, int k) v.cc := k;

for each u adiacente a v do if (u.cc < 0) then

u.parent := v;

CC-visit(u, k);

Etichetta con il valore k tutti i nodi della stessa componente

connessa cui

appartiene v

(45)

Algoritmi e Strutture Dati 45

Applicazione: floodfill

(46)

Applicazione: floodfill

(47)

Algoritmi e Strutture Dati 47

Componenti fortemente connesse

(Strongly Connected Components)

Un grafo orientato G è fortemente connesso se ogni coppia di vertici è connessa da un cammino

A

B C

E D

F A

B C

E D

F Questo grafo orientato è

fortemente connesso.

Questo grafo orientato non è

fortemente connesso; ad es.,

non esiste cammino da D a A.

(48)

Nel mondo reale

(49)

Algoritmi e Strutture Dati 49

Nel mondo reale

(50)

Componenti fortemente connesse (grafo orientato)

u e v appartengono alla stessa componente

fortemente connessa se e solo se esiste un cammino (orientato) che connette u con v e viceversa

La relazione di connettività forte è di equivalenza

Riflessiva

u è raggiungibile da se stesso per definizione

Simmetrica

Se u è fortemente connesso a v, allora esiste un cammino (orientato) che connette u e v e viceversa. Quindi anche v è fortemente

connesso a u.

Transitiva

Se u è fortemente connesso a v, e v è fortemente connesso a w,

u v

(51)

Algoritmi e Strutture Dati 51

Idea

Due nodi u e v appartengono alla stessa componente fortemente connessa se e solo se valgono entrambe le seguenti proprietà

Esiste un cammino u→→v

cioè v è discendente di u in una visita DFS che usa u come sorgente

Esiste un cammino v→→u

cioè u è discendente di v in una visita DFS che usa v come sorgente

(52)

Idea

A(x) = insieme degli antenati del nodo x

cioè insieme di tutti i nodi da cui si può raggiungere x

D(x) = insieme dei discendenti del nodo x

cioè insieme di tutti i nodi che si possono raggiungere da x

Per individuare la componente fortemente connessa

cui appartiene x, è sufficiente calcolare l'intersezione

A(x) ∩ D(x)

(53)

Algoritmi e Strutture Dati 53

Idea

Come calcolare D(x)?

D(x) include i nodi

raggiungibili da una visita (DFS o BFS) usando x come sorgente

Come calcolare A(x)?

È sufficiente invertire la direzione di tutti gli archi, ed effettuare una nuova visita (DFS o BFS)

usando ancora x come sorgente

Nota: il calcolo di A(x) o D(x) richiede tempo O(n+m)

x

x

(54)

Schema di soluzione

algoritmo SCC(Grafo G, nodo x)→lista di nodi L := lista vuota di nodi

(1) Esegui DFS(G, x) marcando i nodi visitati (2) Calcola il grafo trasposto GT

(inverti la direzione degli archi di G) (3) Esegui DFS(GT, x), mettendo in L i nodi

visitati che sono stati marcati durante (1) return L

(1) costa O(n+m)

(2) costa O(n+m)

(3) costa O(n+m)

(55)

Algoritmi e Strutture Dati 55

Calcolo di tutte le componenti fortemente connesse

Per calcolare tutte le SCC di un grafo G è necessario eseguire l'algoritmo SCC(G, x) per ogni nodo x V

Ogni esecuzione di SCC(G, x) costa O(n+m)

Costo complessivo: O(nm+n

2

)

Esiste un algoritmo più sofisticato che elenca tutte le SCC di

un grafo G in tempo complessivo O(n+m)

Riferimenti

Documenti correlati

To view a copy of this license, visit http://creativecommons.org/licenses/by-nc- sa/2.5/it/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San

 Ma in questo caso, i casi di prova devono essere scelti in base al profilo operazionale del sistema, piuttosto che scelti in modo da individuare il maggior numero di errori.

2)E' necessario un mese di tempo per addestrare i nuovi programmatori. Durante questo tempo nessun ulteriore progresso viene compiuto sul sistema. Assumere non ci siano

relazioni commerciali attraverso tecnologie di trasferimento elettronico di fondi e dati. Moreno Marzolla Tecnologie

Rete privata, basata sulle tecnologie WEB, che ospita le applicazioni Internet su una rete locale E' sostanzialmente una versione “chiusa” di Internet, messa in piedi per agevolare

Le prestazioni di alcuni server degradano pauro- samente all'aumentare del numero di accessi Vi sono tipi di pagine (pagine dinamiche) che vengono gestite meno efficientemente da

Tutti i valori degli attributi vanno racchiusi tra virgolette (“) I tag di apertura e chiusura devono essere bilanciati Elementi di markup (&lt;, ]]&gt; ecc) non possono apparire

Utile per verificare la presenza di una pagina, o per la gestione della cache lato client. PUT, DELETE,