⋔ Grafi e ottimizzazione

Che cos'è un grafo: vertici, archi e tipi principali

Vertici, archi, grado, grafi orientati, pesati e bipartiti: il vocabolario di base della teoria dei grafi spiegato con esempi presi da reti e mappe reali.

Una rete stradale, gli amici su un social network, le dipendenze tra i pacchetti di un progetto software, i collegamenti tra pagine web: sono oggetti molto diversi, ma hanno la stessa struttura. Ci sono delle cose e delle relazioni tra coppie di cose. La matematica chiama questa struttura grafo, e una parte enorme dell'informatica pratica consiste nel riconoscere un grafo dentro un problema che a prima vista sembra tutt'altro.

La definizione essenziale

Un grafo G è una coppia (V, E):

  • V è l'insieme dei vertici (o nodi): le città, le persone, i file;
  • E è l'insieme degli archi (o spigoli): ogni arco collega due vertici.

Se le città sono Milano, Bologna e Firenze e ci sono strade Milano–Bologna e Bologna–Firenze, allora V = {Milano, Bologna, Firenze} ed E = {{Milano, Bologna}, {Bologna, Firenze}}. Niente di più: il grafo non conosce le coordinate, la lunghezza delle strade o il paesaggio. Conosce solo chi è collegato a chi. Tutto il resto, se serve, si aggiunge come informazione extra.

Di solito si indica con n il numero di vertici e con m il numero di archi. Queste due quantità compaiono in tutte le stime di costo degli algoritmi sui grafi.

Grado, vicini e cammini

Due vertici collegati da un arco si dicono adiacenti, o vicini. Il grado di un vertice è il numero di archi che lo toccano. Nell'esempio, Bologna ha grado 2, Milano e Firenze grado 1.

Un fatto semplice ma utilissimo: la somma dei gradi di tutti i vertici è uguale al doppio del numero di archi, perché ogni arco viene contato una volta per ciascuno dei suoi due estremi. Ne segue che il numero di vertici di grado dispari è sempre pari. È un controllo rapido per scoprire errori nei dati: se in una rete non orientata trovate un numero dispari di nodi con grado dispari, qualcosa nel caricamento è andato storto.

Un cammino è una sequenza di vertici in cui ogni coppia consecutiva è collegata da un arco. Un ciclo è un cammino che torna al punto di partenza senza ripetere archi. Un grafo è connesso se esiste un cammino tra ogni coppia di vertici.

I tipi di grafo che incontrerete più spesso

Orientati e non orientati

In un grafo non orientato l'arco {A, B} vale nei due sensi: se Anna è amica di Bruno, Bruno è amico di Anna. In un grafo orientato (o digrafo) gli archi hanno un verso: (A, B) va da A a B e non viceversa. «Segue» su un social, «importa» tra moduli software, «rimanda a» tra pagine web sono relazioni orientate. Nei digrafi si distinguono grado entrante e grado uscente.

Pesati

Spesso a ogni arco si associa un numero: la lunghezza di una strada, il tempo di percorrenza, il costo di un collegamento, la capacità di un tubo. Si parla allora di grafo pesato. Gran parte dei problemi di ottimizzazione sui grafi, come il cammino minimo o l'albero ricoprente di costo minimo, ha senso solo con i pesi.

Semplici e multigrafi

Un grafo semplice non ha archi multipli tra la stessa coppia di vertici né cappi (archi da un vertice a sé stesso). Un multigrafo li ammette: due linee ferroviarie distinte tra le stesse due stazioni sono un esempio naturale.

Alberi, DAG e bipartiti

  • Un albero è un grafo connesso senza cicli; con n vertici ha esattamente n − 1 archi. Le cartelle di un file system ne sono l'esempio classico.
  • Un DAG (grafo orientato aciclico) è un digrafo senza cicli orientati. Le dipendenze di compilazione e i fogli di calcolo con formule devono formare un DAG, altrimenti c'è un riferimento circolare.
  • Un grafo bipartito ha i vertici divisi in due gruppi, con archi solo tra gruppi diversi: lavoratori e turni, studenti e corsi, utenti e prodotti acquistati.

Grafi densi e sparsi

In un grafo semplice non orientato con n vertici ci possono essere al massimo n(n − 1)/2 archi. Quando m è vicino a questo massimo il grafo è denso; quando m è dello stesso ordine di n il grafo è sparso. Quasi tutti i grafi reali sono sparsi: una persona conosce qualche centinaio di altre persone, non miliardi; un incrocio stradale ha in genere tre o quattro strade, non migliaia. Questa osservazione guida la scelta di come rappresentare il grafo in memoria e di quale algoritmo usare.

Riconoscere un grafo in un problema

Nel mio lavoro il passo più utile è spesso il primo: tradurre il problema. Qualche esempio:

Problema Vertici Archi
Ordine di installazione dei pacchetti Pacchetti «A richiede B» (orientato)
Orario degli esami senza sovrapposizioni Esami «hanno studenti in comune»
Navigatore satellitare Incroci Tratti di strada (pesati)
Analisi di un'intrusione nei log Host e account Connessioni e accessi osservati

Una volta fatta la traduzione, si possono usare decenni di algoritmi già studiati, invece di inventare una soluzione ad hoc.

In sintesi

  • Un grafo è formato da vertici e archi; descrive solo chi è collegato a chi.
  • Grado, cammino, ciclo e connessione sono i concetti di base su cui si costruisce tutto il resto.
  • Orientato, pesato, bipartito, albero e DAG sono le varianti più frequenti nei problemi reali.
  • La maggior parte dei grafi reali è sparsa, e questo influenza rappresentazione e algoritmi.
  • Riconoscere il grafo nascosto in un problema è spesso metà della soluzione.
MM
Marco Marzaduri

Marco Marzaduri si occupa di cybersecurity, informatica forense e sviluppo web. Laureato in informatica, unisce il rigore dell'analisi tecnica all'attenzione per le persone che usano la tecnologia.

Leggi anche