Grafi: rappresentazione e visita Laboratorio di Algoritmi 02/03 Prof. Ugo de’ Liguoro AloLab - Grafi Grafi: definizione Un grafo diretto (orientato) è una coppia G = V, A dove • V è un insieme (non vuoto) di vertici • A V V è un insieme, eventulamente vuoto, di archi. 1 2 V = {1,2,3,4} A = 1,2, 1,3, 3,2, 2,4 3 4 G si dice pesato se esiste una funzione peso:A. G non è diretto se A è un insieme di coppie non ordinate. AloLab - Grafi Grafi: rappresentazione (1) Matrici di adiacenza: M rappresenta G = V,A se M è una matrice n n, dove n = |V|, e (ponendo ogni elemento di V in corrispondenza con un intero tra 1 e n): 1 se i,j A 0 altrimenti Mi,j = Nel caso di grafi pesati si pone Mi,j = peso(i,j) se i,j A, altrimenti. 1 2 3 4 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 AloLab - Grafi Grafi: rappresentazione (2) Liste di adiacenza: G = V,A è rappresentato da un vettore v[1..n] di liste su V, tale che n = |V|, ad ogni vertice in V sia associato un indice in 1..n, e j occorra nella lista v[i] se e solo se i,j A. Nel caso di grafi pesati le liste hanno elementi in V, e j,r occorre nella lista v[i] se e solo se i,j A e peso(i,j) = r. 1 3 2 4 1 2 2 4 3 2 3 4 AloLab - Grafi Cammini Dato un qualunque insieme di coppie (relazione binaria) R, la chiusura transitiva di R, R*, è il piu piccolo insieme di coppie tale che: i) R R*, ii) se x,y, y,z R*, allora x,z R*. Si osservi che la definizione è ricorsiva: un modo alternativo è • R0 = , • Rn+1 = R {x,z | x,y Rn, y,z R}, • R* = Rn n Un cammino in un grafo G = V, A è un elemento della chiusura transitiva A* di A: quindi un cammino è una sequenza finita di archi, = a,b, b,c, … , y,z che si dice un cammino da a a z, la cui lunghezza è pari al numero degli archi che lo compongono (lunghezza() = min{n | An}). AloLab - Grafi Visita di un grafo Una visita di un grafo G = V, A è un insieme di cammini in G con origine in uno stesso stesso vertice. Una visita è dunque un albero, i cui vertici sono contenuti in V ed i cui archi sono contenuti in A (è un sottografo di G), la cui radice è l’origine dei cammini. 1 2 3 3 1 1 2 4 3 2 4 4 AloLab - Grafi Partizioni per una visita (1) Un vertice j è adiacente ad i se i,j A. Per implementare un algoritmo di visita si considerano due partizioni dei vertici del grafo: una partizione in visitati e non visitati; ed una partizione nei tre sottoinsiemi: • frontiera (GRIGIO): insieme dei vertici visitati che possono avere altri vertici adiacenti non ancora visitati; • interno (NERO): insieme dei vertici visitati i vertici adiacenti sono stati visitati; • esterno (BIANCO): insieme dei vertici non ancora visitati. AloLab - Grafi Partizioni per una visita (2) v G Interno Frontiera Esterno AloLab - Grafi Pseudocodifica degli algoritmi di visita: schema generale Function visita_grafo (grafo G = V, A, vertice v): insieme; var albero, interno, esterno, frontiera, D, visitato: insieme; begin esterno := V / {v}; frontiera := {v}; interno := ; albero := ; visitato := {v}; while frontiera do begin {Inv. interno, frontiera, esterno soddisfano le rispettive definizioni e, se interno ha almeno due vertici allora albero è una copertura di interno } sia w frontiera; D : {u | w,u A and u esterno}; visitato := visitato D; if D = then begin frontiera := frontiera / {w}; interno:= interno {w}; end else foareach u D do begin esterno:= esterno / {u}; frontiera:= frontiera {u}; albero := albero {w,u} endforeach endif endwhile return albero AloLab - Grafi endfunction; Visita in ampiezza (BFS) La visita procede aggiungendo alla frontiera tutti i vertici esterni adiecenti ad un vertice nella frontiera; fatto questo il vertice considerato viene rimosso dalla frontiera ed aggiunto ai vertici interni. La scelta di D è: D := {u w,u A and u esterno} per qualche w in frontiera. La frontiera è costituita da una sequenza di vertici la cui distanza da v è non decrescente: il primo elemento è il più vicino a v. Quale struttura dati può implementare la frontiera? AloLab - Grafi Algoritmo BFS BFS (grafo G = V, A, vertice v) var interno, esterno, albero : insieme; frontiera: coda; interno := ; albero := ; esterno:= V/{v} Accoda(v,frontiera); while frontiera do u := EstraiDallaCoda(frontiera); foreach w s.t. u,w A and w esterno do esterno = esterno / {w}; albero := albero {u,w} Accoda(w,frontiera); interno := interno {u} return albero AloLab - Grafi Visita in ampiezza esempio. Frontiera = 1 2 3 4 5 6 1 Albero = 1 AloLab - Grafi Visita in ampiezza esempio. Frontiera = 1 2 3 4 5 6 2 4 1 Albero = 2 4 AloLab - Grafi Visita in ampiezza esempio. Frontiera = 1 2 3 4 5 6 5 1 Albero = 2 4 5 AloLab - Grafi Visita in ampiezza esempio. Frontiera = 1 2 3 4 5 6 3 6 1 Albero = 2 4 5 3 6 AloLab - Grafi Visita in ampiezza esempio. 1 2 3 4 5 6 Frontiera = 1 Albero = 2 4 5 3 6 AloLab - Grafi Visita in profondità (DFS) La scelta di D è: D := {u}, per qualche u tale che esiste w frontiera , w è l’ultimo vertice inserito e w,u A. La frontiera è un cammino che comincia da v; l’ultimo vertice aggiunto alla frontiera è il primo ad essere considerato: sia per aggiungere altri vertici, sia per rimuoverlo dalla frontiera. Con quale struttura conviene implementare la frontiera? AloLab - Grafi Algoritmo DFS-Visit DFS-Visit (grafo G = V, A, vertice v) var interno, esterno, albero : insieme; frontiera: pila; interno := ; albero := ; esterno:= V/{v} Push(v,frontiera); while frontiera do u := Top(frontiera); D := {w | u,w A and w esterno} if D then with w D do esterno = esterno / {w}; albero := albero {u,w} Push(w,frontiera); else interno := interno {u}; Pop(frontiera); return albero AloLab - Grafi Visita in profondità esempio. Frontiera = 1 1 2 3 4 5 6 Albero = 1 AloLab - Grafi Visita in profondità esempio. Frontiera = 2 1 1 2 3 4 5 6 Albero = 1 2 AloLab - Grafi Visita in profondità esempio. Frontiera = 1 2 3 4 5 6 5 2 1 Albero = 1 2 5 AloLab - Grafi Visita in profondità esempio. Frontiera = 3 1 2 3 4 5 6 5 2 1 Albero = 1 2 5 3 AloLab - Grafi Visita in profondità esempio. Frontiera = 1 2 3 4 5 6 5 2 1 Albero = 1 2 5 3 AloLab - Grafi Visita in profondità esempio. Frontiera = 1 2 3 4 5 6 6 5 2 1 Albero = 1 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 1 2 3 4 5 6 5 2 1 Albero = 1 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 2 1 1 2 3 4 5 6 Albero = 1 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 1 1 2 3 4 5 6 Albero = 1 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 4 1 1 2 3 4 5 6 1 Albero = 4 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 1 1 2 3 4 5 6 1 Albero = 4 2 5 3 AloLab - Grafi 6 Visita in profondità esempio. Frontiera = 1 2 3 4 5 6 1 Albero = 4 2 5 3 AloLab - Grafi 6 Fine AloLab - Grafi