Salta al contenuto
Note per Studenti Esercizio 23 · escursioni e componenti connesse

Esercizio 23escursioni e componenti connesse

In questa pagina 4

Testo (scritto del 07/08/2026, seconda parte, esercizio 1, 5 punti). Un parco naturale è costituito da numerosi punti di interesse collegati da sentieri. Il parco è rappresentato mediante un grafo non orientato G=(V,E)G = (V, E), in cui ogni vertice rappresenta un punto di interesse e ogni arco rappresenta un sentiero percorribile. Un'escursione può visitare tutti e soli i punti di interesse appartenenti alla stessa componente connessa del grafo. Progettare un algoritmo planExcursions(G) che restituisca: il numero minimo di escursioni necessarie per visitare tutti i punti di interesse; il numero di punti di interesse visitabili durante l'escursione più lunga. Si assuma di avere già a disposizione gli algoritmi di visita DFS e BFS.

(a) Descrivere a parole la strategia adottata, indicando quale algoritmo di visita si intende utilizzare e quali eventuali modifiche di tale algoritmo è necessario apportare. (b) Scrivere lo pseudocodice dell'algoritmo. Non è necessario riportare lo pseudocodice completo di DFS o BFS; è sufficiente richiamare l'algoritmo scelto e descrivere in dettaglio le eventuali modifiche necessarie. (c) Analizzare la complessità al caso pessimo, giustificando il risultato anche in relazione ai dettagli implementativi del grafo.


(a) Strategia

Ogni escursione copre una componente connessa (vedi Grafi - definizioni e proprietàGrafo G=(V,E) diretto e non diretto, grafo semplice e pesato; incidenza, adiacenza, grado; cammini, cicli, sottografi, grafi connessi e componenti connesse; alberi liberi, foreste, spanning tree e spanning forest; proprietà con dimostrazioni (somma dei gradi = 2m, m <= n(n-1)/2, alberi m = n-1, connessi m >= n-1, foreste m <= n-1).Grafi - definizioni e proprietà →). Quindi:

  • il numero minimo di escursioni è il numero di componenti connesse (non se ne possono fare meno: due vertici di componenti diverse non stanno nella stessa escursione; e con una escursione per componente si coprono tutti);
  • il numero di punti nell'escursione più lunga è la dimensione della componente più grande.

Si usa la BFS (la DFS va ugualmente bene, vedi Visite di grafi - BFS e DFSVisite in ampiezza (BFS) e in profondità (DFS) come design pattern; etichette discovery, cross e back edge; BFS tree e distanze; complessità Theta(n+m) con liste di adiacenza; applicazioni (connettività, componenti, spanning tree, cammini minimi non pesati, cicli, vertici a distanza al più d); esempio svolto su un grafo di 7 vertici.Visite di grafi - BFS e DFS →). Si scorrono i vertici: appena se ne trova uno non visitato (vv.ID =0= 0) si è trovata una nuova componente e si lancia la visita da lì. Modifica: la visita conta i vertici che scopre, con un contatore count azzerato a ogni visita; ogni vertice scoperto riceve come ID il valore corrente del contatore (positivo: serve solo a distinguere "visitato" da "non visitato", e a ricordare l'ordine di scoperta). Il valore finale di count è la dimensione della componente appena esplorata. La BFS modificata, BFS-COUNT(G, v), restituisce questo valore.

Esempio: 77 punti, sentieri 1 ⁣− ⁣21\!-\!2, 2 ⁣− ⁣32\!-\!3, 3 ⁣− ⁣43\!-\!4, 5 ⁣− ⁣65\!-\!6 (il punto 77 è isolato). Si lancia la BFS da 11: scopre 1,2,3,41, 2, 3, 4 e restituisce 44; si passa a 55 (non visitato): scopre 5,65, 6 e restituisce 22; 77 è non visitato: restituisce 11. Risultato: 33 escursioni, la più lunga con 44 punti.

(b) Pseudocodice

Algoritmo planExcursions(G)
Input: grafo non orientato G=(V,E) con liste di adiacenza; per ogni v, v.ID = 0 (non visitato)
Output: (numExcursions, maxSize): numero di componenti connesse e dimensione della maggiore
numExcursions <- 0; maxSize <- 0
forall v in V do
    if v.ID = 0 then
        numExcursions <- numExcursions + 1
        size <- BFS-COUNT(G, v)
        if size > maxSize then maxSize <- size
return (numExcursions, maxSize)

Algoritmo BFS-COUNT(G, s)           (BFS di G, s con una modifica)
count <- 1; s.ID <- count; L0 <- lista con s
mentre la lista di livello corrente non è vuota: per ogni vertice v del livello
    per ogni arco e incidente su v: sia w il vertice opposto
        se w.ID = 0 allora count <- count + 1; w.ID <- count; w va nel livello successivo
return count

(Se GG non è vuoto, maxSize ≥1\ge 1.) Il contatore è azzerato a ogni chiamata, quindi gli identificatori sono progressivi all'interno della singola visita: non serve che siano distinti tra componenti diverse.

(c) Complessità

Ogni vertice viene scoperto, e inserito nelle liste della BFS, una sola volta in tutte le chiamate (dopo la scoperta ha ID ≠0\ne 0, quindi non genera altre visite). Con le liste di adiacenza di una visita si scorre per ogni vertice la sua lista, e ogni arco compare in due liste (una per estremo, grafo non orientato): ogni arco è esaminato due volte. Il ciclo esterno sui vertici costa Θ(n)\Theta(n). In totale:

Θ(n+m).\Theta(n + m).

Se il grafo fosse rappresentato con matrice di adiacenza scorrere i vicini di un vertice costerebbe Θ(n)\Theta(n) e il totale salirebbe a Θ(n2)\Theta(n^2); con la sola lista degli archi LEL_E ogni visita costerebbe Θ(m)\Theta(m) per vertice, quindi Θ(nm)\Theta(nm) (vedi Rappresentazione dei grafiStrutture di base (lista dei vertici LV, lista degli archi LE), liste di adiacenza, matrice di adiacenza; operazioni incidentEdges, opposite, areAdjacent; spazio e tempi a confronto; esempio con un grafo di 5 vertici.Rappresentazione dei grafi →). Lo stesso conteggio vale se si usa la DFS al posto della BFS. (Controllato con una implementazione confrontata con un calcolo diretto delle componenti su 300 grafi casuali.)

Errori comuni

  • Lanciare la BFS da ogni vertice senza controllare ID: ogni componente verrebbe visitata più volte, con costo Θ(n(n+m))\Theta(n(n+m)) al caso pessimo.
  • Non azzerare il contatore tra una visita e l'altra: la dimensione della componente risulterebbe cumulativa.
  • Contare le escursioni come il numero di vertici o di archi, o restituire solo una delle due informazioni.
  • Dimenticare di specificare (come chiede il testo) il collegamento tra la complessità e la rappresentazione del grafo.

Versione ripasso

Testo. Grafo non orientato di punti di interesse e sentieri; un'escursione = una componente connessa. planExcursions(G) restituisce il numero minimo di escursioni e la dimensione della più grande; strategia, pseudocodice, complessità.

Teoria collegata