caricato da Utente1782

sinossiRO1 (1)

annuncio pubblicitario
• AVVERTENZA: Di seguito trovate alcuni appunti, poco ordinati e poco formali, che uso
come traccia durante le lezioni. Non sono assolutamente da considerarsi sostitutivi del
materiale didattico.
1
Di cosa tratta la ricerca operativa
• La Ricerca Operativa è la disciplina che tratta l’applicazione di metodi analitici avanzati
per la soluzione di problemi di decisione (o per prendere decisioni “migliori”). Utilizzando tecniche di diverse area della matematica, come la matematica discreta e la teoria
dei grafi, la modellazione matematica, l’analisi statistica, l’algebra lineare e l’ottimizzazione,
la Ricerca Operativa consente di arrivare alla soluzione ottima o sub-ottima di complessi
problemi decisionali, in tempi ragionevoli. Data la sua natura fortemente applicativa, la
Ricerca Operativa ha intersezioni con molte altre discipline, in particolare con molte aree
dell’economia e dell’informatica. È alla base della teoria dei giochi.
• Nelle prime settimane del corso ci occupiamo di Teoria dei Grafi.
2
Il problema dei ponti Königsberg [1], [2]
• La geometria delle “posizioni”. Descrizione del problema dei ponti: scegliere un qualsiasi punto di partenza (sulla terra o su un’isola) e tornarvi, dopo aver attraversato cisacun
ponte una e una sola volta. Esiste una soluzione? Un aiuto intermedio: passaggio alla
rappresentazione su grafo. Osservare come il grafo coglie gli elementi cruciali del problema, ovvero quali e quanti collegamenti ci sono tra i vari luoghi, mentre elimina quelli
inessenziali (lunghezza e forma dei ponti, forma delle isole etc.)
• Se non esiste soluzione, perché non esiste? Ovvero, come è possibile certificare la non
esistenza di una soluzione? Banalmente: basta considerare le 5040 = 7! possibili permutazioni dei ponti. E se il numero di ponti aumenta? 8! =40320; 20! numero di 19 cifre;
100! numero di 158 cifre) Si può fare di meglio?
• Il problema di Königsberg non ha soluzione perché la seguente condizione necessaria
non è soddisfatta: condizione necessaria per l’esistenza di una soluzione è che su ciascun
vertice del corrispondente grafo incida un numero pari di spigoli (i.e. ponti). La soluzione
è anche sufficiente?
Risponderemo più avanti quando torneremo sul problema dei ponti di Königsberg, presenteremo un semplice algoritmo per individuare una soluzione (quando esiste) e affronteremo un problema di ottimizzazione che in qualche modo lo generalizza: il Problema
del Postino Cinese [9]:
1
3
Definizioni di base di teoria dei grafi [5]
• Definizione di grafo (non orientato, semplice): una coppia di insiemi G(V, E) dove V è
l’insieme di vertici e E l’insieme degli spigoli, ovvero un insieme di coppie non ordinate
di vertici distinti (per indicare questo, spesso useremo la notazione E ⊆ V2 ).
• Definizione di multigrafo: una coppia di insiemi G(V, E) dove V è l’insieme di vertici e
E il multiinsieme degli spigoli, ovvero un multiinsieme di coppie non ordinate di vertici
distinti.
• Definizione di grafo orientato (semplice): una coppia di insiemi D(N, A) dove N è l’insieme
dei nodi e A l’insieme degli archi, ovvero un insieme di coppie ordinate di nodi distinti.
Nel seguito quando parliamo semplicemente di grafo, ci riferiamo a un grafo non orientato; per riferirci ai grafi orientati useremo appunto, esplicitamente, l’aggettivo “orientato”
• Osservare come la definizione di un grafo non sia grafica. Osservare come un grafo
con vertici V = {a, b, c, d} e E = {ab, ac, ad, bc, bd, cd} può essere disegnato in modi
profondamente diversi! La rappresentazione grafica introduce aleatorietà che invece non
sono presenti nella definizione come coppia di insiemi.
• Gli estremi di uno spigolo e ∈ E sono i vertici u, v della coppia individuata dallo spigolo,
ovvero i vertici tali che e ≡ uv. Se tra due vertici di un grafo esiste uno spigolo essi sono
adiacenti. Uno spigolo e è incidente in un vertice v se v è un estremo di e. Due spigoli
sono incidenti se hanno un estremo in comune.
• Sia G(V, E) un grafo e v ∈ V . Grado deg(v): il numero di vertici cui v è adiacente. N(v):
l’insieme dei vertici cui v è adiacente. δ(v): l’insieme degli spigoli incidenti su v.
• Handshaking Lemma [8]: per un qualunque grafo G(V, E) vale: ∑v∈V deg(v) = 2|E|.
Osservare come questo risultato banalmente si estende a multigrafi. Corollario: per un
qualunque grafo G(V, E), il numero di vertici di grado dispari è pari.
• Sia G(V, E) un grafo. Un vertice isolato di G è un vertice di grado 0. Il numero di spigoli
|E| è la dimensione di G. Il numero di vertici |V | è l’ordine di G.
• Sia G(V, E)
un grafo. Il grafo complemento di G è il grafo H(W, F) tale che W = V
W
e F = 2 \ E, ovvero il grafo complemento prende gli stessi vertici di G, mentre una
coppia di vertici è adiacente nel grafo complemento se e solo se non è adiacente in G.
Normalmente, lo indichiamo semplicemente come G. Osservare come il complemento
del complemento di G è proprio G.
• Sia G(V,
E) un grafo. Un sottografo H ⊆ G è un grafo H(W, F) tale che W ⊆ V e F ⊆
W
E ∩ 2 , ovvero W è un sottoinsieme di V , mentre F è un sottoinsieme di spigoli di E i
cui estremi sono in W .
2
• Sia G(V, E) un grafo e W ⊆ V un sottoinsieme di vertici.
Il sottografo indotto da W su G
W
è il grafo H(W, F) con vertici W e spigoli F = E ∩ 2 , ovvero prende tutti gli spigoli di
E i cui estremi sono in W . Normalmente, lo indichiamo semplicemente come G[W ].
• Sia G(V, E) un grafo. Un sottografo ricoprente H ⊆ G è un sottografo H(W, F) tale che
W = V.
3.1
Digressione: relazioni di conoscenza
• Osservare come i grafi consentono di rappresentare anche relazioni di conoscenza. È
vero che in un inseme qualsiasi di 5 persone esistono sempre 3 persone che si conoscono
reciprocamente o viceversa esistono sempre 3 persone che non si conoscono reciprocamente? È possibile riformulare il problema in modo equivalente su grafo: è vero che
per un qualunque grafo G con 5 vertici vale la seguente affermazione: in G e/o nel complemento di G esiste un triangolo (ovvero tre vertici mutuamente adiacenti)? Falso: un
controesempio è dato da un ciclo di lunghezza 5.
• Considerare il problema precedente con 6 persone. Sia G(V, E) un grafo con 6 persone e
sia v ∈ V . Osserviamo che: dG (v) + dG (v) = 5, quindi o degG (v) ≥ 3 oppure dG (v) ≥ 3.
Supponiamo che degG (v) ≥ 3 e siano x, y, z tre vertici in N(v): se esiste uno spigolo tra
due vertici, e.g. x, y, allora v, x, y è un triangolo; se non esiste alcuno spigolo tra x, y, z,
allora x, y, z è un triangolo nel complemento. Il caso dG (v) ≥ 3 segue banalmente perché
G è comunque un grafo con 6 vertici e quindi basta applicare il ragionamento precedente.
(Dove fallisce questa dimostrazione quando n = 5?)
• Osservare che il risultato precedente si estende a un qualunque grafo G con più di 6
vertici: basta considerare il sottografo indotto su G da 6 vertici qualsiasi.
4 Cenni sulle strutture dati per la rappresentazione dei
grafi
Illustriamo in breve le principali strutture dati più usate per memorizzare i grafi. Questi
argomenti sono trattati con maggiore dettaglio nel corso di Ingegneria degli algoritmi
[10].
• Matrice adiacenza: matrice binaria n × n A, dove n = |V (G)|, tale che ai j = 1 se e solo se
i j ∈ E(G). La matrice è simmetrica. Inoltre:
– Per sapere se un esiste uno spigolo tra un vertice i e un vertice j dobbiamo leggere il valore dell’elemento ai j (oppure a ji ) della matrice. Questa è un operazione
elementare, quindi ha complessità O(1).
3
– Per contare il numero di vertici adiacenti a un certo vertice i dobbiamo scorrere tutta
la riga di i (o la colonna di i), quindi questa operazione ha complessità O(n).
– Per contare il numero di spigoli del grafo dobbiamo scandire tutta la matrice, quindi
la complessità del conteggio del numero di spigoli è O(n2 ).
– L’occupazione di memoria di questa struttura dati è O(n2 ).
– Se abbiamo bisogno di memorizzare ulteriori informazioni, e.g. la lunghezza, la
capacità di uno spigolo, il generico elemento ai j della matrice non è più semplicemente un numero binario, ma un record composto di diversi campi: il primo campo,
a valore 0-1 ci dice se quello spigolo fa parte del grafo, i successivi campi riportano
appunto lunghezza, capacità etc.
– Se vogliamo memorizzare con matrice di adiacenza un grafo orientato, l’unica cosa
che cambia è che la matrice non è più simmetrica, in quanto ovviamente può capitare
che (i, j) ∈ E ma ( j, i) ∈
/ E.
Si osservi come, per un grafo non orientato, potremmo utilizzare la simmetria della matrice, e il fatto che per un grafo semplice la diagonale superiore si compone di tutti
0, e memorizzare solo la parte triangolare superiore della matrice di adiacenza. Tuttavia il vantaggio di questa rappresentazione “compatta” sarebbe trascurabile, perché e.g.
l’occupazione di memoria è sempre O(n2 ) (la diagonale superiore di una matrice n × n ha
n(n−1)
elementi).
2
Il vantaggio principale della matrice di adiacenza è quello di poter verificare in tempo
costante se un certo spigolo appartiene al grafo. Il suo svantaggio principale è quello di
essere una struttura statica che non è influenzata in alcun modo dal numero di spigoli
presenti nel grafo: per esempio, il grafo completo con n vertici e il grafo vuoto con
n vertici occupano la stessa quantità di memoria! Questo svantaggio è superato dalla
prossima rappresentazione basata su liste, che vediamo a breve. Prima però introduciamo
un altro modello di rappresentazione su matrice che sarà molto utile per formulazione di
problemi di flusso e altri problemi che studieremo più avanti.
• Matrice incidenza: matrice binaria n × m A, dove n = |V (G)| e m = |E(G)|. Ogni colonna
è associata univocamente a uno spigolo, e aih = 1 se e solo se i è estremo dello spigolo eh
(quindi ogni colonna ha esattamente due valori diversi da zero). Osserviamo che:
– Sapere se un esiste uno spigolo tra un vertice i e un vertice j dobbiamo scorrere tutte
le colonne di A, quindi l’operazione ha complessità O(m).
– Per contare il numero di vertici adiacenti a un certo vertice i dobbiamo scorrere tutta
la riga di i, quindi questa operazione ha complessità O(n).
– Per contare il numero di spigoli del grafo dobbiamo solo contare tutte le colonne,
quindi la complessità del conteggio del numero di spigoli è O(m).
– L’occupazione di memoria di questa struttura dati è O(n × m).
4
– Se abbiamo bisogno di memorizzare ulteriori informazioni, e.g. la lunghezza, la
capacità di uno spigolo, possiamo semplicemente utilizzare un vettore addizionale
di dimensione m opportunamente collegato alla matrice A.
– Se vogliamo memorizzare con matrice di adiacenza un grafo orientato, l’unica cosa
che cambia è che su ogni colonna h gli unici valori non zero saranno un 1 e un -1: 1
per la coda i dell’arco e -1 per la testa j dell’arco (i, j) = eh .
• Liste adiacenza. (Per una breve introduzione alle liste si veda [7].) Utilizziamo per ogni
vertice i una lista ad(i) in cui riportiamo tutti gli elementi cui i è adiacente; ogni elemento
della lista ad(i) ha due campi: l’etichetta del vertice cui i è adiacente e il puntatore alla
posizione del prossimo elemento della lista (o, in alternativa, il valore convenzionale
“NULL” se la lista è finita). La struttura è completata da un vettore di puntatori, in cui
è riportato per ogni vertice i del grafo, il puntatore al primo elemento della sua lista di
adiacenza ad(i) (o, in alternativa, “NULL” se i è un vertice isolato).
– Per sapere se esiste uno spigolo tra un vertice i e un vertice j dobbiamo scandire la
lista degli adiacenti di i (oppure di j). Questa operazione ha complessità O(deg(i))
(risp. O(deg( j))).
– Per contare il numero di vertici adiacenti a un certo vertice i dobbiamo scorrere tutta
la lista di i, quindi la complessità è O(deg(i)).
– Per contare il numero di spigoli del grafo dobbiamo scandire tutte le liste di adiacenza, quindi la complessità del conteggio del numero di spigoli è ∑i∈V O(deg(i)) =
O(m).
– L’occupazione di memoria è O(m) + O(n). Il termine O(n) proviene dal vettore di
puntatori. Il termine O(m) proviene invece dalle liste di adiacenze vere e proprie
(seguendo gli stessi argomenti utilizzati per il conteggio degli spigoli).
– Se abbiamo bisogno di memorizzare ulteriori informazioni, e.g. la lunghezza, la
capacità di uno spigolo, il generico elemento della lista di adiacenza di i, oltre a
riportare l’etichetta del vertice cui i è adiacente e il puntatore al prossimo (eventuale) elemento nella lista, riporta anche la lunghezza, capacità etc. dello spigolo
corrispondente.
– Se vogliamo memorizzare con liste di adiacenza un grafo orientato, l’unica cosa che
cambia è che per ciascun vertice i avremo due insiemi di liste: una per i successori
di i e una per i predecessori (e, ovviamente, il vettore dei puntatori deve ospitare
due puntatori per ciascun vertice). Si noti che tutte le informazioni in una lista,
e.g. quella dei predecessori, possono essere dedotte guardando tutte le liste dei
successori, quindi c’e’ una ridondanza nel memorizzare due diversi insiemi di liste;
tuttavia, in genere, si preferisce questa più pratica soluzione.
5
5
Strumenti: le dimostrazioni per induzione [5]
• Primo principio di induzione. Per dimostrare che una certa proposizione P(n) vale per un
qualunque numero naturale n posso procedere come segue. 1) Passo base: dimostro che
P(1) è vera, ovvero che la proposizione è vera per n = 1. 2) Passo induttivo: dimostro
che se P(n) è vera, allora anche P(n + 1) è vera. Illustrare il primo principio di induzione
con il passaparola e il domino.
• Dimostriamo con il primo principio che la seguente proposizione P(n): la somma dei
2
primi n numeri dispari, ∑n−1
h=0 (2h + 1), è pari a n . Passo base: l’affermazione è vera per
n = 1. Passo induttivo: supponiamo che l’affermazione sia vera per n, i.e. ∑n−1
h=0 (2h+1) =
2
n , e facciamo vedere che essa è vera per n + 1; infatti:
n
n−1
∑ 2h + 1 = ( ∑ 2h + 1) + 2n + 1 = n2 + 2n + 1 = (n + 1)2
h=0
h=0
.
• Secondo principio di induzione (apparentemente più forte del primo, ma in realtà equivalente). 1) Passo base: dimostro che P(1) è vera, ovvero che la proposizione è vera per
n = 1. 2) Passo induttivo: dimostro che se P(i) è vera per qualunque i ≤ n, allora anche
P(n + 1) è vera.
• Dimostrare con il secondo principio che ogni numero naturale può essere espresso come
prodotto di numeri primi. Passo base: l’affermazione è vera per n = 1. Passo induttivo:
supponiamo che l’affermazione sia vera per ogni numero minore o uguale a n, i.e. per
ogni 1 ≤ h ≤ n, i.e. vale h = a1 (h) · a2 (h) · . . . · ak(h) (h), con a1 (h), a2 (h), . . . , ak(h) (h)
primi, e facciamo vedere che essa è vera per n + 1. Se n + 1 è primo, allora l’affermazione
è vera poiché n + 1 = (n + 1) · 1; se n + 1 non è primo, allora n + 1 può essere fattorizzato
come il prodotto di numeri tra 2 e n, cioè n + 1 = b1 · b2 . Ognuno di questi due fattori
è minore di n + 1, vale quindi l’ipotesi induttiva e allora possiamo sostituire a ciascun
fattore la sua scomposizione in numeri primi, quindi alla fine esprimiamo n + 1 come
prodotto di numeri primi.
• Attenzione nell’uso del principio di induzione! Dimostriamo che “un qualunque insieme
di n cavalli è formato da cavalli dello stesso colore” (vedi [6]). Prendiamo un insieme
di n cavalli. Se n = 1, l’affermazione è banale. Supponiamo ora che l’affermazione
valga per insiemi con n cavalli e consideriamo un qualunque insieme X di n + 1 cavalli,
che indichiamo come X = {1, 2, 3, . . . , n + 1}. Consideriamo i due sottoinsiemi con n
elementi X1 = {1, 2, 3, . . . , n} e X2 = {2, 3, . . . , n + 1}: per ipotesi induttiva, ciascuno di
questi due insiemi è formato da cavalli dello stesso colore. Osserviamo anche che questi
due insiemi si intersecano, e quindi esiste un cavallo che appartiene sia a X1 che a X2 .
Concludiamo quindi che X è formato da cavalli dello stesso colore. O no?
6
6
Grafi connessi, aciclici e alberi [3]
• Sia G(V, E) un grafo. Un walk su G è una successione x1 e1 x2 e2 . . . , x p−1 , e p−1 x p , p ≥ 1,
dove xi ∈ V e ei ≡ xi xi+1 ∈ E. I vertici x1 e x p sono detti estremi del walk e il walk è
chiuso se x1 = x p .
• Un trail su G è un walk in cui gli spigoli non si ripetono (non passiamo più volte per lo
stesso spigolo, ma possiamo passare più volte per lo stesso vertice). In particolare, un
trail i cui estremi coincidono è detto circuito.
• Un path su G è un trail in cui i vertici non si ripetono (non passiamo più volte per lo stesso
vertice) con la sola eccezione, possibilmente, dei vertici estremi. In particolare, un path i
cui estremi coincidono è detto ciclo. La lunghezza di un path (in caso, di un ciclo) è pari
al numero degli spigoli del path.
• È facile verificare che se tra due vertici di un grafo esiste un walk che li connette, allora
esiste un path che li connette. Similmente, un grafo ha un circuito se e solo se ha un ciclo.
• Sia G(V, E) un grafo. Due vertici u e v sono connessi se esiste un path di G con estremi u
e v.
• Un grafo G(V, E) è detto connesso se per ogni coppia di vertici distinti u, v ∈ V , u e v sono
connessi. Come è fatto un grafo che non è connesso?
• Una famiglia di sottoinsiemi Q1 , Q2 , . . . , Qk di un insieme Q è una partizione di Q se
ogni elemento di Q appartiene a un e un solo sottoinsieme Qi . Un modo per definire una
partizione di un insieme è quello di definire sull’insieme una una relazione di equivalenza
(vedi [7]), ovvero una relazione tra coppie di elementi dell’insieme che sia: riflessiva,
simmetrica e transitiva. Una relazione di equivalenza definita su un insieme lo partiziona
in classi di equivalenza: due elementi appartengono alla stessa classe se e solo se sono
equivalenti.
• Osservare come la connessione definisca una relazione di equivalenza sui vertici di un
grafo. Infatti, la connessione è: riflessiva, ogni vertice è connesso a se stesso); simmetrica,
se u è connesso a v, allora v è connesso a u; transitiva, se u è connesso a v e se v è connesso
a z, allora u è connesso a z. La connessione determina quindi una partizione di V in
classi di equivalenza V1 ,V2 , . . .Vk e, in modo analogo una “partizione” di G nei sottografi
indotti G[V1 ], G[V2 ], . . . , G[Vp ], che sono detti componenti connesse di G. In altre parole
le componenti connesse di G, sono i più grandi pezzi connessi di G.
• Sia G(V, E) un grafo e siano e ∈ E e v ∈ V rispettivamente uno spigolo e un vertice di G.
Il grafo G − e è il grafo con insieme dei vertici V e insieme degli spigoli E \ {e}, ovvero
il grafo ottenuto da G rimuovendo lo spigolo e. Il grafo G − v è il grafo con insieme dei
vertici V \ {v} e insieme degli spigoli E \ δ(v), ovvero il grafo ottenuto da G rimuovendo
il vertice v e tutto gli spigoli ad esso adiacenti.
7
• Un grafo è detto aciclico se esso è privo di cicli.
Lemma 1 Sia G(V, E) un grafo connesso e e ∈ E un suo spigolo. Valgono:
(i) Il grafo G − e ha al più due componenti connesse.
(ii) Se G è aciclico, il grafo G − e ha esattamente due componenti connesse.
Dimostrazione Siano u, v ∈ V tali che e ≡ uv (i) Ci sono due casi possibili. 1) Se u e
v sono ancora connessi in G − e da un path P∗ , allora G − e è ancora connesso: infatti
a un qualsiasi path P di G con estremi x, y corrisponde un walk P0 di G − e con estremi
x, y, ottenuto sostituendo, eventualmente, allo spigolo e il path P∗ . 2) Se u e v non sono
connessi in G − e, allora G − e ha due sole componenti connesse: quella che contiene u
e quella che contiene v. Infatti supponiamo per assurdo che esista un terza componente
connessa G3 , che contenga un vertice z e non contenga u e v. Poiché G è connesso, in G
esiste un path da z a u che non usa uv oppure un path da z a v che non usa uv: questo path
è anche un path di G − e e questo contraddice il fatto che in G − e z non è connesso a u e
v.
(ii) Dobbiamo semplicemente dimostrare che u e v appartengono a diverse componenti
connessi di G − e. In caso contrario, esisterebbe un path di G − e che li connette, e questo
path, insieme ad e, formerebbe un ciclo in G, una contraddizione.
Corollario 2 Sia G(V, E) un grafo connesso e v ∈ V un vertice. Il grafo G − v ha al più
deg(v) componenti connesse.
Dimostrazione Basta iterare il Lemma 1 su tutti gli spigoli incidenti su v.
Teorema 3 Condizione necessaria perché un grafo sia connesso è che il numero degli
spigoli sia almeno pari al numero dei vertici -1, i.e. |E(G)| ≥ |V (G)| − 1.
La dimostrazione è per induzione sul numero dei vertici. In particolare, utilizziamo il
secondo principio di induzione. L’affermazione è banalmente verificata se |V (G)| = 1.
Supponiamo ora che un qualunque grafo connesso con al più n ≥ 1 vertici abbia almeno
n − 1 spigoli, e dimostriamo che allora un (qualunque) grafo connesso G con n + 1 vertici ha almeno n spigoli. Consideriamo un vertice v ∈ V (G) e il grafo G − v. Siano
G1 , G2 , . . . , Gk le componenti connesse di G − v, con k ≤ deg(v). Ogni componente connessa Gi è tale che |V (Gi )| ≤ n e quindi, per ipotesi induttiva, per ciascuna componente
connessa, vale |E(Gi )| ≥ |V (Gi )| − 1. Osserviamo anche che possiamo partizionare E(G)
in k + 1 classi: δ(v), E(G1 ), E(G2 ) . . . , E(Gk ). Segue:
k
k
|E(G)| = |δ(v)|+ ∑ |E(Gi )| ≥ deg(v)+ ∑ (|V (Gi )|−1) = deg(v)+n−k ≥ n = |V (G)|−1.
i=1
i=1
L’ultima disequazione segue dal Corollario 2, mentre per l’ultima equazione ricordiamo
che V (G) = V (G − v) ∪ {v}.
8
• Poniamo attenzione al fatto che |E(G)| ≥ |V (G)| − 1 è una condizione solo necessaria
perché G sia connesso. Considerate un grafo con 10 vertici {a1 , a2 , . . . , a5 , b1 , b2 , . . . , b5 }
e tale che tutti i vertici ai siano a coppie adiacenti, tutti i vertici bi siano a coppie adiacenti
e tale che non vi siano altri adiacenze. Malgrado il grafo abbia 20 >> 9 spigoli, esso non
è connesso.
• Lemma 4 Sia G(V, E) un grafo aciclico e e ∈ E uno spigolo. Il grafo G − e è ancora
aciclico e il suo numero di componenti connesse è pari al numero di componenti connesse
di G +1.
Infatti, siano u e v gli estremi dello spigolo e e siano G1 , G2 , . . . , Gk le componenti connesse di G. Supponiamo senza perdita di genaralità, che u, v ∈ Gk . È immediato verificare
che G1 , G2 , . . . , Gk−1 sono ancora componenti connesse di G − e. Infine segue dal Lemma
1 che Gk − e consta di due componenti connesse.
• Teorema 5 Condizione necessaria perché un grafo sia aciclico è che il numero degli
spigoli sia al più pari al numero dei vertici -1, i.e. |E(G)| ≤ |V (G)| − 1.
La dimostrazione è per induzione sul numero degli spigoli. In particolare, utilizziamo il
secondo principio di induzione. L’affermazione è banalmente verificata se |E(G)| = 1.
Supponiamo ora che un qualunque grafo aciclico con al più m ≥ 1 spigoli abbia almeno
m + 1 vertici e dimostriamo che allora un (qualunque) grafo aciclico G con m + 1 spigoli
ha almeno m + 2 vertici. Consideriamo uno spigolo e ∈ E(G) e il grafo G − e. Siano
G1 , G2 , . . . , Gk le componenti connesse di G−e, con k ≥ 2. Ogni componente connessa Gi
è tale che |E(Gi )| ≤ m. Quindi, per ipotesi induttiva, per ciascuna componente connessa,
vale |E(Gi )| ≤ |V (Gi )| − 1. Osserviamo anche che possiamo partizionare E(G) in k + 1
classi: e, E(G1 ), E(G2 ) . . . , E(Gk ). Segue:
k
k
|E(G)| = 1 + ∑ |E(Gi )| ≤ 1 + ∑ (|V (Gi )| − 1) = 1 + |V (G)| − k ≤ |V (G)| − 1
i=1
i=1
.
• Poniamo attenzione al fatto che |E(G)| ≤ |V (G)| − 1 è una condizione solo necessaria
perché G sia aciclico. Considerate un grafo con 10 vertici {a1 , a2 , . . . , a10 } e con spigoli
{a1 a2 , a2 a3 , a3 a1 }. Malgrado il grafo abbia 3 << 9 spigoli, esso non è aciclico.
• Un grafo aciclico e connesso è detto albero. Segue dai Teorema 3 + Teorema 5 che un
albero con n vertici ha n − 1 spigoli. Si osservi che un albero è un grafo “minimalmente
connesso”, in quanto la rimozione di un qualsiasi spigolo pregiudica la connettività e
“massimalmente aciclico”, in quanto l’aggiunta di un qualsiasi spigolo pregiudica la aciclicità. Si osservi, in particolare, che per ogni coppia di vertici di un albero, esiste un e
un solo cammino con estremi i due vertici.
• Un grafo ad albero è quindi un grafo che viene utilizzato in tutti quei casi, per esempio il
progetto di una rete irrigua, in cui l’esigenza primaria è quella della connessione, mentre
la robustezza non è un’istanza cruciale.
9
• Lemma 6 Un qualunque albero T (V, E) con almeno due vertici ha almeno due vertici di
grado uno, che sono detti foglie.
Si osservi che T non ha vertici di grado zero poiché stiamo assumendo che T abbia
almeno due vertici (ed è connesso). Partizioniamo quindi V in due classi: la classe
V1 dei vertici che hanno grado 1, e la classe V2 dei vertici che hanno grado > 1. Per
l’handshaking lemma, 2|E| = ∑v∈V deg(v) = ∑v∈V1 deg(v)+ ∑v∈V2 deg(v) = |V1 |+ ∑v∈V2 deg(v) ≥
|V1 | + 2|V2 |. Poiché 2|E| = 2(|V | − 1) = 2|V1 | + 2|V2 | − 2 segue: 2|V1 | + 2|V2 | − 2 ≥
|V1 | + 2|V2 |, quindi |V1 | ≥ 2.
7
Circuiti Euleriani ([3, 11])
• Dato G(V, E) un circuito euleriano è un circuito (i.e. un trial chiuso) che passa per ciascuno spigolo di G una e una sola volta. Per esempio, se visitiamo una mostra in cui le
opere sono disposte nei corridoi, un circuito euleriano ci permetterebbe di visitare tutta
la mostra senza passare più volte per lo stesso corridoio. Quando un grafo ammette un
circuito euleriano?
Teorema 7 Sia G(V, E) un grafo connesso. Allora le 3 affermazioni seguenti sono equivalenti:
1. G ammette un circuito euleriano.
2. Ogni vertice di G ha grado pari.
3. L’insieme degli spigoli di G può essere partizionato in cicli disgiunti sugli archi, i.e.
/
E(G) = E(C1 ) ∪ E(C2 ) ∪ . . . ∪ E(Cq ), dove ogni Ci è un ciclo e E(Ci ) ∩ E(C j ) = 0,
se i 6= j.
(1) → (2) – Banale, lo abbiamo già osservato per il problema dei ponti di Königsberg.
(2) → (3) – L’affermazione è banale se G ha tutti vertici di grado 0. Supponiamo quindi
che G abbia almeno un vertice v con grado > 0 e consideriamo la componente connessa
G0 di G che contiene v. G0 è connessa, quindi se fosse anche aciclica sarebbe un albero. Ma in questo caso avrebbe due vertici di grado 1, cosa che possiamo escludere,
poiché per ipotesi ogni vertice di G ha grado pari. Quindi G0 , e quindi anche G, ha un
ciclo C0 : lo rimuoviamo e consideriamo il grafo G1 = G − C0 , ovvero il grafo che ha
gli stessi vertici di G, ma insieme degli spigoli pari a E \ E(C0 ). Osserviamo che tutti i
vertici di questo grafo hanno ancora grado pari o nullo. Se G1 ha tutti vertici di grado
0, allora l’affermazione è dimostrata con E = E(C0 ). Altrimenti G1 ha degli spigoli e
quindi almeno una componente connessa: ragionando come prima possiamo dedurre che
in questa componente connessa esiste un ciclo C1 . Rimuoviamo C1 e consideriamo il
grafo G2 = G1 − C1 . Se questo grafo ha tutti vertici di grado 0, allora l’affermazione è
dimostrata con E = E(C0 ) ∪ E(C1 ), altrimenti, poiché è ancora vero che ogni vertice di
10
G2 ha grado pari o nullo, possiamo ripetere il ragionamento precedente. Poiché il numero
di spigoli di G è finito, allora esisteranno un numero p e successivi cicli C2 ,C3 , . . . ,C p , per
costruzione disgiunti sugli archi, tali che E(G) = E(C0 ) ∪ E(C1 ) ∪ E(C2 ) ∪ . . . ∪ E(C p ).
(3) → (1) – Consideriamo il ciclo C1 . L’affermazione è banale se q = 1. Se q > 1, poiché
/ È posil grafo è connesso, esiste un altro ciclo C j , j 6= 1, tale che V (C1 ) ∩ V (C j ) 6= 0.
sibile concatenare C1 e C j in un circuito Q1 come segue: 1) percorriamo C1 a partire da
un vertice arbitrario; 2) appena incontriamo un vertice v che appartiene a V (C1 ) ∩V (C j )
abbandoniamo C1 per percorrere interamente C j ; 3) quando abbiamo terminato di percorrere C j (quindi siamo di nuovo su v), terminiamo di percorrere C1 . L’affermazione è
dimostrata se q = 2. Se q > 2, sempre per l’ipotesi di connessione, possiamo concatenare
/ Naturalmente possiQ1 con un altro ciclo Ch , h ∈
/ {1, j}, tale che V (Q1 ) ∩ V (Ch ) 6= 0.
amo iterare questo procedimento fino a concatenare tutti i cicli C1 , . . . ,Cq in unico ciclo,
euleriano per G.
• È immediato verificare che la dimostrazione precedente, e quindi il teorema, si estende a
grafi con spigoli paralleli.
• Quando un grafo connesso G ammette un trail euleriano aperto, ovvero tale che il vertice
iniziale del trail è diverso dal vertice finale del trail? Se e solo se i vertici di grado
dispari di G sono esattamente due. Dimostrarlo attraverso il seguente lemma: G connesso
ammette percorso euleriano aperto se e solo se esistono due vertici u, v tali che G + uv
ammette circuito euleriano (si noti che in generale G + uv potrebbe non essere un grafo
semplice).
• Nelle pieghe della precedente dimostrazione intravediamo un algoritmo. In effetti il procedimento che ci siamo dati per concatenare i circuiti è già algoritmico. Per avere un
algoritmo vero e proprio, dobbiamo fornire un procedimento per individuare un circuito1
/ in cui tutti i vertici hanno grado pari. (Osserviamo che
in un grafo G, con E(G) 6= 0,
l’affermazione (2) → (3) non richiede l’ipotesi di connessione). Questo è semplice. In/
fatti, per trovare un circuito in un grafo in cui tutti i vertici hanno grado pari e E(G) 6= 0,
è sufficiente scegliere un vertice v con grado > 0 e percorrere a partire da v un cammino
qualsiasi, che però eviti di percorrere più volte uno stesso spigolo: è facile convincersi,
che poiché ogni vertice ha grado pari e il numero di spigoli è finito, questo cammino deve
necessariamente tornare a v ed essere quindi un circuito.
• Possiamo quindi enunciare il seguente algoritmo per trovare un circuito Euleriano in un
grafo connesso (vedremo più avanti un algoritmo per riconoscere se un grafo è connesso).
L’algoritmo è detto di Hierholzer. Si noti che l’implementazione che segue differisce da
quanto discusso prima per i seguenti dettagli:
a ogni passo cerchiamo di costruire circuiti invece che cicli, in particolare circuiti più
lunghi possibile (osservare che se tutti i nodi hanno grado pari ogni cammino ran1 È
semplice vedere che il Teorema 7 continua a valere se in (3) sostituiamo la parola “circuiti” alla parola
“cicli”. Nel seguito ci riferiamo a questa riformulazione
11
dom che parte da un nodo v e evita di percorrere più volte lo stesso arco è destinato
a riportarci in v. Nostra convenzione: risolviamo le situazioni di parità a favore
del nodo primo in ordine alfabetico o numerico; la concatenazione la facciamo man
mano, i.e. concateniamo il nuovo circuito a quello corrente.
Algoritmo di Hierholzer (Input G connesso e con almeno due vertici)
1. Se G contiene un vertice di grado dispari, STOP: G non ha un circuito euleriano. Se G
non ha spigoli, STOP: caso banale.
2. Scegli un vertice v0 di G.
3. **Costruzione di un circuito a partire da v0 in G**. Scegli uno spigolo e1 = v0 v1 di G.
A partire da e1 , costruisci un circuito C0 = {e1 , . . . , ek } come segue: finché è possibile,
scegli uno spigolo ei+1 di G tale che ei e ei+1 sono entrambi incidenti in vi e ei+1 6∈
{e1 , . . . , ei }.
4. Poni i = 0, G0 = G e Z0 = C0 .
5. Rimuovi gli spigoli di Zi dal grafo Gi e sia Gi+1 = Gi \ Ci . Se ogni vertice di Gi+1 è
isolato, allora il circuito Ci è un trail euleriano per Gi : STOP.
6. Scegli un vertice wi del circuito Ci incidente con qualche spigolo del grafo Gi+1 (wi
non è un vertice isolato per Gi+1 ). Costruisci un circuito Zi+1 , con inizio (e termine) wi
nella componente connessa di wi in Gi+1 , seguendo il procedimento indicato al passo 3
(ma con v0 = wi e G = Gi+1 ).
7. Forma un circuito Ci+1 concatenando Ci e Zi+1 (entrambi i circuiti contengono il vertice
wi ).
8. Poni i = i + 1 e vai a 5.
• È facile verificare che utilizzando liste d’adiacenza l’algoritmo di Hierholzer può essere
implementato con complessità O(|E|).
8
Alberi [3]
• Il seguente Lemma 8 mostra che, in modo alternativo, possiamo definire un albero come
un grafo connesso con n vertici e n − 1 spigoli, oppure come un grafo aciclico con n
vertici e n − 1 spigoli.
Lemma 8 Sia G un grafo con n vertici. Allora due qualunque delle seguenti affermazioni
implicano la terza:
1. G è connesso.
2. G è aciclico.
12
3. G ha n − 1 spigoli.
(1) + (2) → (3) – segue dal Teorema 3 + Teorema 5.
(2) + (3) → (1) – supponiamo viceversa che G è aciclico, con n-1 spigoli, ma non è
connesso. Allora G è fatto di componenti connesse G1 , G2 , . . . , Gk con k ≥ 2. Siano u e v
rispettivamente un vertice di G1 e un vertice di G2 ; naturalmente uv ∈
/ E(G).
Si osservi che il grafo G + uv, ovvero il grafo ottenuto aggiungendo a G lo spigolo uv, è
ancora aciclico: infatti, poiché G è aciclico, un qualunque ciclo di G + uv è necessariamente composto dallo spigolo uv e da un path con estremi u e v che già doveva appartenere
a G, contraddicendo il fatto che in G u e v appartengano a diverse componenti connesse.
Quindi G + uv è un grafo aciclico con n vertici e n spigoli, una contraddizione al Teorema
5.
(3) + (1) → (2) – supponiamo viceversa che G è connesso, con n-1 spigoli, ma non è
aciclico. Sia quindi C un ciclo di G e e uno spigolo del ciclo C. Si osservi che il grafo
G − e è ancora connesso: infatti a un qualsiasi path P di G con estremi x, y corrisponde
un walk P0 di G − e con estremi x, y, ottenuto sostituendo, eventualmente, allo spigolo e il
path P∗ (composto dagli archi di C − e) . Quindi G − e è un grafo connesso con n vertici
e n − 2 spigoli, una contraddizione al Teorema 3.
• Sottolineiamo due punti salienti della dimostrazione del Lemma 8.
Se G è un grafo, G1 e G2 sono due componenti connesse di G (n.b. G potrebbe avere
anche anche altre componenti connesse) e u e v sono rispettivamente un vertice di G1 e
un vertice di G2 , allora i cicli del grafo G + uv sono gli stessi di G. In altre parole, se
aggiungiamo uno spigolo tra 2 componenti connesse, non creiamo nuovi cicli.
Se G è un grafo, C è un ciclo di G e e è uno spigolo di C, allora le componenti connesse
di G − e sono le stesse componenti connesse di G. In altre parole, se rimuoviamo uno
spigolo di un ciclo, non creiamo nuove componenti connesse.
• Un grafo aciclico e connesso è dunque un albero. Un grafo solo aciclico è formato da
più componenti connesse, ognuna delle quali è un albero. Un grafo aciclico è quindi
anche detto foresta. Si osservi quindi che un grafo aciclico con n vertici e k componenti
connesse ha esattamente n − k spigoli.
• Spesso per riferirci a un grafo che è un albero useremo la notazione T (V, E).
• Illustriamo un’ulteriore definizione di albero, questa volta di tipo algoritmico. Consideriamo la seguente procedura, detta Growing Tree Procedure (144-145 [4]):
1. Partiamo dal grafo G con un solo vertice.
2. Ripetiamo un qualunque numero di volte i seguenti due passi:
2.1) sia G0 il grafo ottenuto aggiungendo a G un nuovo vertice adiacente a un solo
vertice di G;
2.2) sia G := G0 .
13
Lemma 9 Ogni grafo costruito dalla Growing Tree Procedure è un albero e ogni albero
può essere costruito dalla procedura Growing Tree Procedure.
La dimostrazione del Lemma 9 può ottenersi per induzione sul numero dei vertici sfruttando le seguenti oservazioni:
– Sia T (V, E) un albero. Consideriamo il grafo T 0 (V ∪ {v}, E ∪ {uv}), ottenuto aggiungendo a T un nuovo vertice v adiacente a esattamente un vertice u ∈ V . È facile
vedere che T 0 è anch’esso un albero. Cominciamo infatti dal mostrare che T 0 è connesso: due vertici (x, y), con x e y 6= v, sono connessi in T 0 cosı̀ com’erano connessi
in T ; inoltre v è connesso a qualunque vertice z ∈ V , poiché v è connesso a u e u
è connesso a z. Mostriamo quindi che T 0 è aciclico: un qualunque ciclo dovrebbe
includere il vertice v, che però ha grado 1, e quindi non può appartenere ad alcun
ciclo. T 0 è aciclico e connesso e quindi T 0 è un albero.
– Sia T (V, E) un albero con almeno due vertici e v ∈ V una foglia (v esiste, per via del
Lemma 6). Consideriamo il grafo T 0 (V − {v}, E \ δ(v)), ottenuto rimuovendo da T
la foglia v. È facile vedere che T 0 è anch’esso un albero. T 0 è aciclico: infatti T 0
proviene da un grafo aciclico, cui rimuoviamo uno spigolo e un vertice. Inoltre T 0 è
connesso: infatti, due qualunque vertici x, y, con x e y ∈ V (T 0 ), sono connessi in T
con un path P che non include v e/o uv, quindi P è anche un path di T 0 .
8.1
Prüfer Code ([12])
• Consideriamo un insieme V = {0, 1, . . . , n − 2, n − 1} di n vertici. Siamo interessati a
contare quanti sono i diversi alberi con insieme dei vertici V . Naturalmente, due alberi
T (V, E1 ) e T (V, E2 ) sono diversi se e solo esiste uno spigolo i j, con 0 ≤ i < j ≤ n − 1,
tale che i j ∈ E1 e i j ∈
/ E2 .
• Conteremo i diversi alberi in modo “indiretto”. Mostreremo infatti come ad ogni albero
T (V, E) possiamo associare in modo univoco un vettore con n − 2 componenti, ognuna
delle quali a valore intero tra 0 e n − 1. Mostreremo anche come, viceversa, a ogni vettore
con n − 2 componenti, ognuna delle quali a valore intero tra 0 e n − 1, possiamo associare
in modo univoco un albero con insieme dei vertici {0, 1, . . . , n − 2, n − 1}. Segue quindi
che contare i diversi alberi con insieme dei vertici V è la stessa cosa che contare i diversi
vettori, con n − 2 componenti e a valori interi tra 0 e n − 1. Abbiamo quindi il seguente
risultato, noto come:
Teorema di Cayley I diversi alberi con insieme dei vertici V = {0, 1, . . . , n − 2, n − 1}
sono n(n−2) .
• Per arrivare a questo risultato, analizzeremo diverse possibili rappresentazioni per gli
alberi riferendoci, per esempio, all’albero T̃ = (V, Ẽ) con Ẽ = {01, 04, 13, 16, 17, 24, 45}.
14
• Un primo semplice modo di memorizzare un albero è attraverso la matrice di adiacenza.
La matrice di adiacenza di un albero T (V, E) è una matrice binaria A di dimensione |V | ×
|V | (quindi nel nostro caso n × n) tale che ai j = 1 se e solo se i j ∈ E(T ). Si osservi che A è
simmetrica e con la diagonale principale di tutti 0. Naturalmente, ad ogni albero possiamo
associare un’unica matrice di adiacenza, e poiché il numero di matrici n × n, simmetriche,
n(n−1)
binarie e con la diagonale principale di tutti 0 è pari a 2 2 (perché ?), questo ci permette
n(n−1)
dire che il numero di diversi alberi con insieme dei vertici V è minore o uguale a 2 2
. . . ma di fatto strettamente minore perché ci sono matrici n × n, simmetriche, binarie e
con la diagonale principale di tutti 0 che non corrispondono ad alcun albero: per esempio
la matrice n × n con tutti 1! Riportiamo infine la matrice di adiacenza dell’albero T̃ :

0
1

0

0

1

0

0
0
1
0
0
1
0
0
1
1
0
0
0
0
1
0
0
0
0
1
0
0
0
0
0
0
1
0
1
0
0
1
0
0
0
0
0
0
1
0
0
0
0
1
0
0
0
0
0
0

0
1

0

0

0

0

0
0
• Un secondo semplice modo di memorizzare un albero è attraverso la lista degli spigoli.
Per ottenere questa rappresentazione, per prima cosa ordiniamo la lista degli spigoli in
un qualunque modo: sia e1 , . . . , en−1 i nostro ordinamento. Dopo di che memorizziamo
il nostro albero attraverso 2 vettori a e b, entrambi di dimensione n − 1, in questo modo:
per 1 ≤ h ≤ n − 1, a[h] = i e b[h] = j se e solo se eh = i j. Si osservi che cambiando
l’ordinamento degli spigoli lo stesso albero può dare luogo a diverse liste degli spigoli,
quindi la rappresentazione non è univoca. Per renderla tale introduciamo un ordinamento
lessicografico degli spigoli dell’albero e degli estremi di ogni spigolo: assumiamo quindi
che, per 1 ≤ h ≤ n − 1, ah < bh e che per ogni coppia (h, k), con 1 ≤ h < k ≤ n − 1 valga
ah < ak oppure ah = ak e bh < bk . La lista degli spigoli dell’albero T̃ è quindi:
a = [0 0 1 1 1 2 4]
b = [1 4 3 6 7 4 5].
Utilizzando l’ordinamento lessicografico abbiamo la proprietà che ad ad ogni albero
T (V, E) corrisponde una sola lista degli spigoli, ma di nuovo la rappresentazione è ridondante e ci sono molte più liste che alberi: per esempio, i vettori a = [0, 1, 2, 3, 4, 5] e
b = [1, 2, 3, 0, 5, 6] non corrispondono ad alcun albero (a che grafo corrispondono?).
• Si noti tuttavia che, dal punto di vista dell’occupazione di memoria, la lista degli spigoli
offre una rappresentazione molto più efficiente della matrice di adiacenza: con la prima
possiamo memorizzare un albero con 2(n−1)dlog ne bit, con la seconda abbiamo bisogno
bit.
di n(n−1)
2
15
• Una evoluzione della lista degli spigoli ci permette di memorizzare un albero con soli
(n − 1)dlog ne bit. L’idea, molto semplice, richiede innanzitutto di scegliere un vertice
dell’albero: nel seguito assumiamo sia il vertice 0. A questo punto, per ogni spigolo
i j dell’albero esiste un vertice, per esempio i, che è più vicino a 0 e un vertice j che
è più lontano: diciamo che i è il padre di j. L’osservazione fondamentale è che ogni
vertice, tranne 0, ha esattamente un padre (e ogni spigolo connette un vertice al padre).
Memorizziamo quindi il nostro albero con la lista degli spigoli, ma usiamo la convenzione
di memorizzare in a[1] il vertice 1 e in b[1] il padre di 1, in a[2] il vertice 2 e in b[2] il
padre di 2 . . . in a[n − 1] il vertice (n − 1) e in b[n − 1] il padre di (n − 1). Banalmente,
segue che a = [1, 2, . . . , n − 1] e possiamo quindi memorizzare il solo vettore dei padri b,
che va sotto il nome di father code. Il father dell’albero T̃ è :
b = [0 4 1 0 4 1 1].
Il father code è quindi un vettore di dimensione n − 1, in cui ogni elemento è un intero
tra 0 e n − 1. Osserviamo che, per n = 7 l’albero corrispondente al code [0, 1, 2, 3, 4, 5] è
un path, l’albero corrisponde al code [0, 0, 0, 0, 0, 0] è una stella mentre nessun albero corrisponde a [6, 5, 4, 3, 2, 1, 0]! Quindi, al solito, ad ogni albero T (V, E) possiamo associare
in modo univoco un father code (facile da verificare), ma non è vero ad ogni vettore di
dimensione n − 1, in cui ogni elemento sia un intero tra 0 e n − 1, possiamo associare un
albero.
• Una evoluzione del father code è il Prüfer code. Si noti che per il father code gli spigoli
sono implicitamente ordinati come segue: per primo consideriamo lo spigolo tra il vertice 1 e il padre del vertice 1. . . per ultimo consideriamo lo spigolo tra il vertice n − 1 e il
padre del vertice n − 1. In pratica, il codice di Prüfer ordina gli spigoli in modo diverso.
Per comprendere questo ordinamento supponiamo di “smontare” il nostro albero secondo
la Growing Tree Procedure. La procedura definisce una sequenza di alberi T1 . . . Tn dove
T1 = T e Tn è fatto da un unico vertice: ad ogni passo Th+1 si ottiene da Th rimuovendone
una foglia (quindi uno spigolo): in particolare, supponiamo di risolvere le situazioni di
parità (quando nell’albero corrente Th ci sono più foglie) in favore della foglia con indice più basso che però non sia il vertice 0. Per esempio, procedendo in questo modo,
rimuoveremmo i vertici di T̃ in quest’ordine: 2, 3, 5, 4, 6, 7, 1 fino a rimanere appunto
con l’albero T8 costituito dal solo vertice 0.
La procedura di rimozione dei vertici determina naturalmente anche un ordinamento degli
spigoli di T , che nel caso precedente è : 24, 31, 54, 40, 61, 71,10. Consideriamo la lista
degli spigoli corrispondente a questo ordiamente, avendo l’accortezza di mettere sempre
nel vettore a e nel vettore b i padri. Nel caso precedente:
a = [2 3 5 4 6 7 1]
b = [4 1 4 0 1 1 0].
Si osservi come necessariamente b[n − 1] = 0, quindi è inutile memorizzare b[n − 1].
Come mostriamo nel seguito, è anche inutile memorizzare il vettore a che può essere in16
duttivamente ricostruito da b. Le osservazioni chiave sono due: la prima è che in ogni albero un vertice è foglia oppure padre. La seconda è che, per 1 ≤ h ≤ n−1, il (sotto)vettore
[b[h]b[h + 1] . . . b[n − 1]] contiene tutti e soli i vertici che sono padri per l’albero Th .
Quindi, per costruzione, a[1] deve essere uguale al più piccolo intero compreso tra 0 e
n − 1 che non è appartiene al vettore [b[1]b[2] . . . b[n]]. Induttivamente, poi, a[i] deve
essere uguale al più piccolo intero compreso tra 0 e n − 1 che non appartiene nè al
(sotto)vettore [a[1]a[2] . . . a[h − 1]] (foglie che abbiamo rimosso fino al passo h-esimo)
nè al (sotto)vettore [b[h]b[h + 1] . . . b[n − 1]] (vertici che sono padri per Th ).
• Memorizziamo quindi solo il vettore b0 = [b[1]b[2] . . . b[n − 2]] (come abbiamo osservato
prima, b[n − 1] è sempre 0): è questo codice va sotto il nome di Prüfer code. Il Prüfer
code dell’albero T̃ è :
b0 = [4 1 4 0 1 1].
Il Prüfer code è quindi un vettore di dimensione n − 2, in cui ogni elemento è un intero
tra 0 e n − 1 e, al solito, ad ogni albero T (V, E) possiamo associare in modo univoco
un Prüfer code (facile da verificare). Questa volta è possibile dimostrare il viceversa:
ad ogni vettore di dimensione n − 2, in cui ogni elemento sia un intero tra 0 e n − 1
possiamo associare in modo univoco un albero con insieme dei vertici {0, 1, . . . , n − 2, n −
1} (omettiamo i dettagli, peraltro semplici, di questa dimostrazione). Naturalmente questi
due fatti insieme implicano il Teorema di Cayley menzionato in precedenza.
• Per concludere osserviamo due fatti molto interessanti. Quanto illustrato in precedenza
mostra che possiamo memorizzare un albero con n vertici con (n − 2)dlog ne bit, e che
non è possibile fare di meglio. Inoltre, utilizzando il codice di Prüfer è possibile generare
in modo random un albero con n vertici in modo tale che tutti gli alberi con n vertici compaiano con la stessa probabilità : questo sarebbe molto difficile da fare se non utilizassimo
il codice di Prüfer!
References
[1] https://en.wikipedia.org/wiki/Seven Bridges of Königsberg
[2] N.L. Biggs, E.K. Lloyd, R.J. Wilson. Graph Theory 1736-1936. Clarendon Press Oxford.
[3] D. Jungnickel. Graphs, Networks and Algorithms: Capitolo 1. Springer.
[4] L. Lovász, J. Pelikán, K.Vesztergombi Discrete Mathematics. Springer.
[5] K.H.Rosen. Discrete Mathematics and its Applications. Mc Graw-Hill.
[6] http://en.wikipedia.org/wiki/Mathematical induction
[7] https://en.wikipedia.org/wiki/Equivalence relation
17
[8] https://en.wikipedia.org/wiki/Handshaking lemma
[9] https://en.wikipedia.org/wiki/Route inspection problem
[10] https://sites.google.com/site/italianodidattica/didattica/ingegneria-degli-algoritmi
[11] https://en.wikipedia.org/wiki/Eulerian path
[12] https://en.wikipedia.org/wiki/Prüfer sequence
18
Scarica