Strutture dati, algoritmi e complessità. I problemi intrinsecamente

Algoritmi e complessità
1
Anno accademico 2010-2011
Sommario
• La complessità
 Complessità in tempo e spazio
 Complessità asintotica
• Algoritmi e complessità
 Strutture dati: array, liste, alberi, tabelle hash
 Ricerca e ordinamento
• La macchina di Turing e le classi di complessità
• Ai limiti del calcolo: i problemi intrinsecamente difficili
2
Anno accademico 2010-2011
La complessità
3
Anno accademico 2010-2011
La complessità
• L’analisi di complessità definisce le risorse teoricamente
consumate da un algoritmo
 Complessità temporale: tempo necessario all’esecuzione del-
l’algoritmo
 Complessità spaziale: memoria necessaria all’esecuzione dell’algoritmo
• Poiché ad ogni algoritmo corrispondono più implementazioni
(più programmi), lo studio della complessità non definisce
esattamente il tempo e la memoria usata: si concentra sulle
proprietà che sono indipendenti dall’implementazione, fornendo un’idea di quanto sia efficiente un algoritmo
4
Anno accademico 2010-2011
Che cosa si misura?  1
• Complessità temporale
 Si contano le istruzioni eseguite dall’algoritmo
 Poiché le istruzioni potrebbero essere di natura diversa, si
individuano quelle che incidono principalmente sul tempo di
esecuzione
Le operazioni in virgola mobile: le più lente da eseguire per una
CPU; sono predominanti se il loro numero è paragonabile al numero
delle altre istruzioni
Le istruzioni di controllo (gli if) e le istruzioni più frequenti (sono
predominanti se sono in numero molto superiore rispetto alle altre
istruzioni)
Le istruzioni di accesso alla memoria secondaria e alle periferiche:
sono decine di migliaia di volte più lente delle istruzioni svolte nella
memoria principale; se un’applicazione ne richiede molte, queste
potrebbero essere predominanti (ad es., nei database, l’analisi di
complessità è concentrata sugli accessi al disco)
Anno accademico 2010-2011
5
Che cosa si misura?  2
• Complessità spaziale
 Si misurano le “posizioni” di memoria occupate dai dati
necessari allo svolgimento dell’algoritmo
 La
complessità spaziale sarà misurata relativamente alla
memoria principale se i dati dell’algoritmo possono essere
allocati in memoria principale, in base all’occupazione di
memoria secondaria quando le strutture dati dell’algoritmo sono
troppo grandi per poter risiedere nella memoria centrale
6
Anno accademico 2010-2011
Complessità asintotica
• Lo studio della complessità si concentra su i casi in cui il
problema è grande:
 non importa se un programma di contabilità impiega 1 o 100
millisecondi a calcolare il bilancio
 cambia molto se il programma della segreteria impiega 1 o 10
secondi a trovare i dati di uno studente nell’archivio
• Complessità asintotica
 Definisce le risorse usate da un algoritmo al crescere della
dimensione del problema affrontato
 Ad esempio: come cambia il tempo di accesso ai dati quando
cresce il numero degli studenti nell’archivio della segreteria
7
Anno accademico 2010-2011
Complessità temporale asintotica  1
• Formalmente, si usa il concetto matematico di ordine di
grandezza
 sia n la dimensione del problema, cioè la dimensione dell’input
dell’algoritmo
 sia T(n) il tempo impiegato per l’esecuzione dell’algoritmo
quando l’ingresso ha dimensione n
 sia f(n) una qualsiasi funzione di n, ad esempio 3, n, n2, n5, 2n
 Si dice che la complessità asintotica dell’algoritmo è dell’ordine
di f(n) e si scrive O (f(n)) se esiste una costante  tale che
T(n) f(n)
• Osservazione importante: in base alla definizione data,
algoritmi che differiscono solo per una costante moltiplicativa
hanno lo stesso ordine di complessità
• Esempio: due algoritmi che richiedono 4n e 7n operazioni
sono entrambi O (n)
Anno accademico 2010-2011
8
Complessità temporale asintotica  2
• Informalmente…
 L’ordine O (f(n)) fornisce una misura della complessità temporale di ogni programma che implementa l’algoritmo
• Esempio: Calcolare la somma degli elementi di un array
 n: numero di elementi dell’array
 complessità: O (n)
9
Anno accademico 2010-2011
Complessità media e
relativa al caso peggiore
• Un algoritmo può richiedere un numero di operazioni diverse
per ingressi di dimensione uguale:
 Complessità media: complessità valutata su tutti i possibili
ingressi
 Complessità nel caso peggiore: complessità dell’algoritmo per
l’ingresso che richiede più operazioni
• Di solito, quando si parla di complessità, ci si riferisce alla
complessità nel caso peggiore
10
Anno accademico 2010-2011
Algoritmi e complessità
11
Anno accademico 2010-2011
Complessità asintotica:
array e liste
• Array

n: numero degli elementi dell’array
 Ricerca/inserimento/cancellazione di un elemento
Complessità O (n)
• Liste semplici

n: numero delle posizioni nella lista
 Ricerca/cancellazione di un elemento
Complessità O (n)
 Inserimento di un elemento all’inizio della lista (in testa)
Complessità O (1)
12
Anno accademico 2010-2011
Complessità asintotica:
alberi binari di ricerca  1
• Albero binario, cioè tale che da ogni nodo si dipartono al più
due archi, che soddisfa le seguenti proprietà:
 ogni nodo v contiene un elemento elem(v) cui è associata una
chiave chiave(v) presa da un dominio totalmente ordinato
 le chiavi nel sottoalbero sinistro di v sono tutte  chiave(v)
 le chiavi nel sottoalbero destro di v sono tutte  chiave(v)
Albero binario
di ricerca
Albero binario
non di ricerca
13
Anno accademico 2010-2011
Complessità asintotica:
alberi binari di ricerca  2
• Alberi binari di ricerca
 n: numero dei nodi dell’albero
 Inserire, eliminare o ricercare un elemento in un albero binario
bilanciato
Complessità media pari all’altezza dell’albero: O (h) O (log2n)
Complessità nel caso peggiore pari a O(n) (alberi molto sbilanciati e profondi)
6
3
1
Anno accademico 2010-2011
4
8
7
9
14
Alberi binari di ricerca:
Ricerca
• Si traccia un cammino nell’albero partendo dalla radice e, su
ogni nodo, si usa la proprietà di ricerca per decidere se
proseguire nel sottoalbero sinistro o destro
15
Anno accademico 2010-2011
Alberi binari di ricerca:
Inserimento
• A partire dalla radice, confronta la chiave k con chiave(v)
 In caso di coincidenza, l’elemento da inserire è già presente
nell’albero (che non deve contenere duplicati)
 Altrimenti, si prosegue ricorsivamente nel sottoalbero sinistro o
destro in base al risultato del confronto fino a trovare un nodo
foglia o un nodo dotato di un solo figlio relativamente al quale
l’elemento con chiave k possa opportunamente occupare il
posto del figlio mancante
16
Anno accademico 2010-2011
Alberi binari di ricerca:
Cancellazione  1
• Sia u il nodo contenente l’elemento da cancellare:
 Se u è una foglia, viene direttamente rimosso
 Se u è un nodo dotato di un solo figlio w, il sottoalbero con
radice w va ad occupare il posto di u
17
Anno accademico 2010-2011
Alberi binari di ricerca:
Cancellazione  2

Se u ha due figli, deve essere sostituito dal suo predecessore v
(che ha un solo figlio e) che deve essere fisicamente rimosso
18
Anno accademico 2010-2011
Alberi binari di ricerca:
Cancellazione  3
19
Anno accademico 2010-2011
Complessità asintotica:
tabelle hash
• Problema
Memorizzare in maniera opportuna un insieme di dati 
tipicamente sotto forma di record  in modo da poter
reperire un qualsiasi elemento dell’insieme con un numero
“piccolo” di tentativi
 Cosa significa “piccolo” ?
Indipendente (o quasi) dalla dimensione della tabella su cui si
effettua la ricerca, quindi con una complessità in tempo pari
ad O (1)
20
Anno accademico 2010-2011
Funzioni hash  1
•
•
h: K → {0, 1, 2, …, m1}
K: insieme dei valori distinti che possono essere assunti
dalle chiavi dei record
• m: dimensione del vettore in cui si intende memorizzare la
tabella
• Ipotesi: K sottoinsieme dei numeri naturali
 Possibile funzione di accesso:
h(k)  k MOD m, kK
 Valore della funzione sempre compreso fra 0 e m1
21
Anno accademico 2010-2011
Funzioni hash  2
• Se K non è un sottoinsieme dei numeri naturali
 Esempio: insieme di stringhe alfanumeriche
 Problema: la funzione hash si applica a numeri
• Per utilizzarla in corrispondenza di una chiave non numerica
occorre associare alla chiave un valore numerico
 Necessità di definire funzioni hash generali
 Associazione di un valore numerico ad una chiave di qualunque
tipo
 Applicazione della funzione hash a tale valore
 Esempio: si utilizza la somma dei codici ASCII dei caratteri che
costituiscono la stringa
• Comunque… metodo non adatto a reperire sottoinsiemi di
dati con chiave che soddisfi una data relazione
22
Anno accademico 2010-2011
Collisioni  1
• Associazione, da parte di una trasformazione, della stessa
posizione a chiavi distinte
• Sinonimi
k1 k2, ma h(k1) h(k2)
• Esempio: [10,12,20,23,27,30,31,39,42,44,45,49,53,57,60]
 h(chiave)  (chiave MOD 15)
Posizione 0 ← 30, 45, 60
Posizione 8 ← 23, 53
Posizione 12 ← 12, 27, 42, 57
• Ciascuna posizione dell’array può contenere al più un
elemento; occorre…
 Ridurre al massimo le collisioni
 Gestirle quando si verificano
23
Anno accademico 2010-2011
Collisioni  2
• Funzioni di hashing perfetto (che evitano i duplicati) sono
difficili da trovare, anche per tabelle grandi
• Esempio: paradosso del compleanno
Dato un gruppo di 23 persone, ci sono più del 50% di
probabilità che due di esse siano nate nello stesso giorno
dell’anno
 In altre parole, se scegliamo una funzione aleatoria (a valori
casuali) che trasforma 23 chiavi in un indirizzo di una tabella di
365 elementi, la probabilità che due chiavi NON collidano è
solo 0.4927 (meno della metà)
• Individuare una funzione di accesso che porti ad un numero
ridotto di collisioni è un problema complesso
24
Anno accademico 2010-2011
Collisioni  3
• Tuttavia… numero di collisioni ridotto drasticamente se
accettiamo uno spreco del 25% di memoria
0
57
• Esempio: array di 19 elementi (indicizzati da 0 a 18) 12 20, 39











Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
0 ← 57
8 ← 27
1 ← 20, 39
10 ← 10
3 ← 60
11 ← 30, 49
4 ← 23, 42
12 ← 12, 31
6 ← 44
15 ← 53
7 ← 45
60
4
23, 42
5
h(chiave)  (chiave MOD 19)
• Collisioni non eliminate del tutto
Anno accademico 2010-2011
3
6
44
7
45
8
27
9
10
10
11
30, 49
12
12, 31
13
14
15
53
16
17
18
25
Collisioni  4
• Diminuire il fattore di carico n/m, con n numero degli
oggetti da inserire ed m dimensione della tabella, garantisce
un minor numero di collisioni
 Lo spazio utilizzato è proporzionale ad m, non al numero n di
elementi: può esserci grande spreco di memoria!
• Inoltre… per ridurre la probabilità di collisioni, una buona
funzione hash dovrebbe essere in grado di distribuire in
modo uniforme le chiavi nello spazio degli indici della tabella
• Ipotesi: la funzione hash gode della proprietà di uniformità
semplice
26
Anno accademico 2010-2011
Collisioni  5
• Sia P(k) la probabilità che la chiave k sia presente
nell’insieme delle chiavi da allocare e sia:
la probabilità che la cella i sia occupata
• Una funzione hash h gode della proprietà di uniformità
semplice se:
27
Anno accademico 2010-2011
Collisioni  6
• Esempio: Se U è l’insieme dei numeri reali in [0,1] e ogni
chiave in U ha la stessa probabilità di essere scelta, allora si
può dimostrare che la funzione hash:
soddisfa la proprietà di uniformità semplice
28
Anno accademico 2010-2011
Gestione delle collisioni
• Uso di liste concatenate destinate alla memorizzazione degli
elementi che, in inserimento, hanno portato ad una
collisione; gli elementi sono contenuti in liste esterne alla
tabella: t[i] punta alla lista degli elementi tali che h(k)i
• Indirizzamento aperto: tutti gli elementi sono contenuti nella
tabella; se una cella è occupata, se ne cerca un’altra libera
29
Anno accademico 2010-2011
Liste concatenate  1
• Ricerca di un elemento di chiave k
 Si calcola h(k): se si verifica una collisione allora si accede alla
lista associata alla posizione h(k) e la si scandisce
30
Anno accademico 2010-2011
Liste concatenate  2
• Il costo dell’operazione di ricerca  realizzata in modo
lineare relativamente alle liste di elementi in collisione  si
mantiene pressoché indipendente da n (numero degli
elementi contenuti nella tabella)
• Inserimento/cancellazione costano O (1)
31
Anno accademico 2010-2011
Indirizzamento aperto  1
• Supponiamo di voler inserire un elemento con chiave k e
che la sua posizione “naturale” h(k) sia già occupata
• L’indirizzamento aperto consiste nell’occupare un’altra cella,
anche se potrebbe spettare di diritto ad una chiave diversa
• Si cerca la cella vuota (se c’è) scandendo le celle secondo
una sequenza di indici, per esempio utilizzando una tecnica
di scansione lineare
t(k,i)  (h(k)i) mod m, per 0im
Per i1 la ricerca parte dalla cella indicizzata e procede a
scandire le successive (ad una ad una) fino alla prima cella
libera
32
Anno accademico 2010-2011
Indirizzamento aperto  2
• La scansione lineare provoca effetti di agglomerazione, cioè
lunghi gruppi di celle consecutive occupate, che rallentano
la scansione
33
Anno accademico 2010-2011
Indirizzamento aperto  3
• L’hashing doppio riduce il problema delle agglomerazioni e
produce funzioni hash che sono “quasi” semplicemente
uniformi:
t(k,i)  h1(k)i h2(k) mod m
per 0im, con h1 e h2 funzioni hash distinte
• L’idea sottesa all’hashing doppio è quella di partire da un
valore hash ed esaminare le posizioni successive saltando di
una quantità pari a multipli di un valore determinato da una
altra funzione hash
• In questo modo la prima posizione esaminata è h1(k)
mentre le successive sono distanziate di h2(k)
34
Anno accademico 2010-2011
Hashing doppio  1
• Esempio:
 m=13
 h1(k)=k mod 13
 h2(k)=1 + (k mod 11)
Si consideri l’inserimento della chiave 14 nella seguente tabella:
h1(14) = 14 mod 13 = 1
h2(14) = 1+(14 mod 11) = 1+3 = 4
t(14,i) = (h1(k)+ih2(k)) mod m = (1+i4) mod m
35
Anno accademico 2010-2011
Hashing doppio  2
i=0  1° posizione esaminata t(14,0) = 1
i=1  2° posizione esaminata t(14,1) = 1+4 = 5
i=2  3° posizione esaminata t(14,2) = 1+42 = 9
36
Anno accademico 2010-2011
Hashing doppio  3
• Si deve porre attenzione a far sì che h2(k) sia primo rispetto
alla dimensione della tabella m
• ..infatti, se m e h2(k) hanno un massimo comune divisore d,
allora si esaminerebbero solo m/d elementi della tabella
(invece di m)
• Esempio: m10 e h2(k)2, partendo da 0 si ha la sequenza
0 2 4 6 8 0 2 4 6 8…
• Per garantire che h2(k) sia primo rispetto a m si può:
 prendere m=2p e scegliere h2(k) in modo che produca sempre
un numero dispari
 prendere m primo e scegliere h2(k) in modo che produca
sempre un intero positivo minore di m
37
Anno accademico 2010-2011
Complessità asintotica fattoriale
• Sia dato un programma che prende in ingresso i partecipanti
ad una competizione e genera (ad esempio per stamparle)
tutte le possibili classifiche finali

n: numero di partecipanti
 Complessità: O (n!)
• Si osservi che n! è un numero molto grande anche per n
relativamente piccoli
20!  2.432.902.008.176.640.0002.41018
38
Anno accademico 2010-2011
Complessità asintotica polinomiale
• Sia dato un programma che ha come ingresso due array a, b
e cerca tutte le coppie (i,j) tali che a[i]b[j]
 n: dimensione di a
 m: dimensione di b
 Complessità: O (nm)
void search(int a[], int b[], int alength, int blength)
{ …
for(i0;ialength;i){
for(j0;jblength;j){
if(a[i]b[j])
printf(“Trovata corrispondenza: a[%d]b[%d]%d”,i,j,a[i]);
}
}
}
39
Anno accademico 2010-2011
Algoritmi facili e difficili
• In base alla loro complessità temporale asintotica, gli algoritmi
sono tipicamente divisi in classi
 Algoritmi a complessità costante O (1) o lineare O (n)
Molto veloci, “scalabili”
 Algoritmi a complessità polinomiale O (na) per un qualche valore
Usabili se l’esponente
a
a è piccolo
 Algoritmi a complessità esponenziale O(an) per un qualche valore
a (1)
Usabili solo per n molto piccoli
40
Anno accademico 2010-2011
Algoritmi a complessità esponenziale
• Fondamentale: perché gli algoritmi a complessità esponenziale sono considerati quasi inusabili?
 Perché richiedono talmente tante operazioni che probabilmente
anche i calcolatori futuri non saranno in grado di eseguire in
tempi ragionevoli le loro possibili implementazioni (programmi)
per dati in ingresso ad alta dimensionalità
41
Anno accademico 2010-2011
Esempio
• Si consideri il programma che genera tutte le classifiche finali
di una competizione con n partecipanti, complessità O (n!) (è
esponenziale, perché n!nsqrt(n))
 Con 20 concorrenti le classifiche sono 20! 2.41018
Un computer che generi 1 miliardo di classifiche al secondo, circa
31016 l’anno, impiegherebbe circa 79 anni per generare tutte le
classifiche richieste
Tendenzialmente, i computer diverranno sempre più veloci e fra
dieci anni forse saranno abbastanza veloci da realizzare in un mese
quello per cui adesso occorrono 79 anni ma…
…comunque, fra dieci anni per risolvere il problema con 21
partecipanti occorreranno ancora 21 mesi e per 25 partecipanti circa
531300 anni!!
42
Anno accademico 2010-2011
La ricerca dicotomica  1
• Per “cercare” un elemento in un vettore ordinato esiste un
metodo detto ricerca binaria o dicotomica
 Si confronta il valore val da ricercare con l’elemento
centrale del vettore A[length/2]
 Se val è minore dell’elemento mediano, si ripete la
ricerca sulla metà sinistra del vettore, altrimenti si ricerca
nella metà destra
43
Anno accademico 2010-2011
La ricerca dicotomica  2
• Esempio: ricerca del numero 23
Si confronta 23 con 13
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà destra (da ind. 8 a ind. 14): si confronta 23 con 27
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà sinistra (da ind. 8 a ind. 10): si confronta 23 con 20
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà destra (da ind. 9 a ind. 9): trovato!!
0
2
4
5
8
9
13 16 20 23 27 30 34 35
44
Anno accademico 2010-2011
La ricerca dicotomica  3
int search(int val, int A[], int from, int to)
{
int center(fromto)/2;
if (from  to) return 1;
if (fromto) {
if (A[from]val) {return from;}
return 1;} // si esegue solo se A[from]!val
//si esegue solo se (fromto)
if (valA[center]){ return search(val,A,from,center1); }
if (valA[center]){ return search(val,A,center1,to); }
return center;
}
45
Anno accademico 2010-2011
Complessità della ricerca dicotomica
• La ricerca dicotomica divide il vettore in due ad ogni passo:
 dopo
p passi la dimensione del vettore è n/2p
 nel caso peggiore, la ricerca si ferma quando
n/2p è 1, cioè
quando plog2n
• Quindi la ricerca dicotomica è O (log2n)
46
Anno accademico 2010-2011
Mergesort  1
• Il Mergesort è un algoritmo basato sul paradigma del divide
et impera
• Una strategia divide et impera consiste nel suddividere un
problema in sottoproblemi, nel risolvere i sottoproblemi, e nel
ricomporre le soluzioni parziali per ottenere la soluzione del
problema originale
• Il Mergesort è composto da due fasi:
 una fase di divisione del vettore da ordinare in sottovettori
 una fase di ricomposizione dei risultati (merge)
47
Anno accademico 2010-2011
Mergesort  2
• Idea: Dato un vettore da ordinare, lo si divide in due
sottovettori di ugual dimensione, si ordinano i sottovettori e
poi si “fondono” insieme
6
6
1
2
1
2
8
3
4
Divisione
8
7
5
3
4
Anno accademico 2010-2011
2
5
Ordinamento
Ordinamento
1
7
6
8
1
2
Fusione
3
4
5
6
3
4
7
8
5
7
48
Mergesort: la divisione ricorsiva
• Come si ordinano i due sottovettori ?
 Applicando ricorsivamente la divisione fino a quando il vettore
contiene un solo elemento: in tal caso l’ordinamento è banale
6
6
6
6
1
1
2
1
Anno accademico 2010-2011
2
8
3
4
Divisione
8
2
1
2
8
3
8
3
7
5
3
4
7
4
5
7
4
7
5
5
49
Mergesort: la fusione ricorsiva  1
• I sottovettori ordinati verranno poi ricorsivamente fusi
1
2
3
4
5
6
7
8
Fusione
1
1
2
6
2
6
6
1
3
8
2
8
3
8
3
4
5
7
4
5
4
7
7
5
50
Anno accademico 2010-2011
Mergesort: la fusione ricorsiva  2
• La fusione viene realizzata utilizzando due indici che scorrono i due
sottovettori da fondere:
1. Ad ogni passo si confrontano i due elementi indicati dagli indici i e j, A[i], A[j]
2. Si copia l’elemento minore in un vettore d’appoggio e si incrementa l’indice
corrispondente
3. Si torna al passo 1. fino a quando i due vettori non sono stati completamente
visitati
1
2
6
8
1
i
3
4
5
2
3
4
5
6
7
8
7
k
j
Anno accademico 2010-2011
51
Complessità del Mergesort
• Il Mergesort ha complessità O (nlog2n) sia nel caso medio
che nel caso pessimo
• Mergesort è un algoritmo ottimo!
 La sua complessità asintotica è la migliore possibile
• Comunque…
 …esistono algoritmi che per alcuni ingressi fanno meglio di

nlog2n (ad es., Bubblesort su vettori ordinati)
…esistono altri algoritmi con complessità nlog2n anche nel caso
pessimo  Heapsort
52
Anno accademico 2010-2011
Quicksort  1
• Quicksort, come Mergesort, è un algoritmo divide et impera
• Idea
 Si divide il vettore A in due sottovettori, che contengono
rispettivamente tutti gli elementi minori e maggiori di (per
esempio) A[0], cioè il primo elemento del vettore  detto
perno
 Si ripete ricorsivamente la divisione…
53
Anno accademico 2010-2011
Quicksort  2
4
2
1
6
3
8
7
5
Si ripartisce il vettore rispetto ad A[1]  4
3
3
2
2
1
4
6
1
8
7
6
8
5
7
Si divide rispetto a 3
1
1
2
Anno accademico 2010-2011
2
3
Si divide rispetto a 6
5
5
5
6
7
8
7
8
54
Quicksort: l’operazione perno  1
• Come si divide il vettore?
 Si usano due indici i, j che
scorrono il vettore da sinistra e
da destra, rispettivamente
 L’indice i scorre fino a quando
A[i]A[1]
 L’indice j scorre fino a quando
A[j]A[1]
 Si effettua lo scambio fra A[i] e
A[j] e quindi si procede come
sopra
Anno accademico 2010-2011
Si scorrono i, j confrontando con 4
4
2
8
6
3
1
7
5
j
i
Si scambiano gli elementi
4
2
8
6
3
i
1
7
5
j
Si scorrono i, j confrontando con 4
4
2
1
i
6
3
8
j
7
5
55
Quicksort: l’operazione perno  2
 Alla fine si scambia il perno con l’elemento in posizione
j
Si scambiano gli elementi
4
2
1
6
i
3
8
7
5
j
Si scambia A[j] con il perno
4
2
1
3
6
8
7
5
6
8
7
5
j
3
2
1
4
56
Anno accademico 2010-2011
Implementazione
void perno(int A[], int from, int to)
{
int ifrom1, jto;
while(ij){
while(A[i]A[from]) i;
while(A[j]A[from]) j;
if(ij) scambia(A,i,j);
}
scambia(A,from,j);
}
57
Anno accademico 2010-2011
Complessità del Quicksort
• Il Quicksort ha complessità media O (nlog2 n)
• Il caso pessimo si verifica quando il perno finisce in fondo o
in testa al vettore
 In tal caso, Quicksort ha complessità pari ad O (n2)
58
Anno accademico 2010-2011
Mergesort vs Quicksort
• Mergesort ha il vantaggio di avere sempre complessità pari a
O (nlog n)
• Quicksort ha il vantaggio di non richiedere un vettore di
appoggio: ordina il vettore “in loco” (minore complessità
spaziale)
• In media, Quicksort si comporta “bene” e, per questo motivo,
in pratica spesso è preferito a Mergesort
59
Anno accademico 2010-2011
Heap  1
• Ospita gli elementi dell’insieme A di cardinalità n, su cui è
definita una relazione d’ordine totale “”
• Lo heap (mucchio) è un albero binario
 Proprietà 1
L’albero è quasi perfettamente bilanciato: è completo fino al
livello k1, cioè contiene il numero massimo di nodi, 2k1,
mentre al livello k contiene un numero di nodi (foglie) compreso
tra 1 e 2k; i nodi a livello massimo sono tutti addossati a sinistra
 Proprietà 2
Ogni nodo contiene un elemento  dell’elemento contenuto nel
padre
60
Anno accademico 2010-2011
Heap  2
• Noto il valore di n, la forma dell’albero è fissata dalla Proprietà 1
• L’allocazione degli elementi nei
nodi può variare, nel rispetto
della Proprietà 2
• L’elemento massimo dell’insieme
è allocato nella radice
• I sottoalberi di ciascun nodo sono
ancora heap
• Lo heap può essere allocato in un
array
63
38
23
12 28
10
5
18
17 22
1
2
3
4
5
6
7
8
9
10
63
38
23
12
28
17
22
10
5
18
61
Anno accademico 2010-2011
Heap  3
• Con l’allocazione lineare…
 A[1] è l’elemento contenuto nella radice dello heap
 Per ogni A[i], gli elementi corrispondenti ai figli sinistro e destro,
se esistono, sono memorizzati in A[2i] e A[2i1]
Se 2i  n e/o 2i1 n il figlio sinistro e/o destro di A[i] non esiste
nell’albero
A[2i]A[i] e A[2i1]A[i], quando tali elementi sono definiti
62
Anno accademico 2010-2011
Heapsort  1
• Lo heap trova la sua applicazione più elegante nel metodo di
ordinamento noto come Heapsort
 Si estrae l’elemento massimo dallo heap (quello nella radice, o in
prima posizione nella rappresentazione lineare)
 Si ricostruisce lo heap
 …fino a quando non ci sono più elementi nello heap (ovvero gli
elementi del vettore sono ordinati)
63
Anno accademico 2010-2011
Heapsort  2
• Come si ricostruisce lo heap, dopo l’estrazione della radice?
18
63
38
12 28
10
5
38
23
23
12 28
17 22
10
18
17 22
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
63
38
23
12
28
17
22
10
5
18
18
38
23
12
28
17
22
10
5
63
Anno accademico 2010-2011
Continua…
64
Heapsort  3
 Si considera il massimo fra i due figli della radice e, se
max{A[2],A[3]}A[1], si effettua lo scambio
38
18
Si scambia A[1] con A[2]
38
12 28
10
18
23
23
12 28
17 22
10
5
17 22
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
18
38
23
12
28
17
22
10
5
63
38
18
23
12
28
17
22
10
5
63
Anno accademico 2010-2011
Continua…
65
Heapsort  4
 Si
considera il massimo fra i due figli di A[2] e, se
max{A[4],A[5]}A[2], si effettua lo scambio
38
38
Si scambia A[2] con A[5]
18
12 28
10
28
23
23
12 18
17 22
5
10
5
17 22
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
38
18
23
12
28
17
22
10
5
63
38
28
23
12
18
17
22
10
5
63
Anno accademico 2010-2011
Continua…
66
Heapsort  5
 Si estrae A[1] che è l’elemento più grande… e si ricomincia
il procedimento di ricostruzione
5
38
28
12 18
10
28
23
23
12 18
17 22
17 22
10
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
38
28
23
12
18
17
22
10
5
63
5
28
23
12
18
17
22
10
38
63
67
Anno accademico 2010-2011
Heapsort  6
• Poiché ogni estrazione e ricostituzione dello heap richiede
tempo O (log2n'), se n′ è il numero di elementi attualmente
contenuti nello heap…
 Heapsort ha complessità O (nlog2n)
• L’algoritmo di ordinamento può essere realizzato facilmente
sulla “rappresentazione sequenziale” dello heap
68
Anno accademico 2010-2011
Heapsort  7
void heapsort(int a[], int left, int right)
{
int k, temp, sizerightleft1, *paleft1;
/*
/*
*
*/
si costruisce lo heap */
for (ksize2; k1; k)
heap(p, k, size);
si scambia l’elemento più grande con quello finale
e si ricostruisce lo heap
while (size1)
{
temp  p[1];
p[1]  p[size];
p[size]  temp;
heap(p, 1, size);
}
exit(0);
}
69
Anno accademico 2010-2011
Heapsort  8
/* Costruzione topdown di uno heap */
#define LESS(A,B)((A)(B))
void heap(int a[], int k, int size)
{
int j, temp;
while(2ksize)
{
j  2k;
if (jsize && LESS(a[j],a[j1]))
j;
if (!LESS(a[k],a[j]))
break;
temp  a[k];
a[k]  a[j];
a[j]  temp;
k  j;
}
}
70
Anno accademico 2010-2011
Ancora sulla complessità
71
Anno accademico 2010-2011
Problemi e algoritmi
• Anche per i problemi si parla di complessità
• Tipicamente non si riesce a definire univocamente la
complessità di un problema, perché...
 ...lo stesso problema può essere risolto con algoritmi diversi che
hanno diversa complessità
 …anche se si riesce a stabilire qual è il miglior algoritmo per la
risoluzione di un dato problema, tale stima ha comunque un
valore non assoluto, ma limitato nel tempo, in quanto non è
dato prevedere se in futuro potrà esistere un metodo risolutivo
migliore
• Per questi motivi, si parla solo di limite inferiore e superiore
alla complessità di un problema
72
Anno accademico 2010-2011
Complessità di un problema
• In alcuni casi è possibile dimostrare che nessun algoritmo
che risolve un dato problema può/potrà impiegare meno
risorse di un certo limite inferiore
• Esempi banali
 Nessun algoritmo che genera tutte le classifiche possibili per n
concorrenti può farlo in meno di n! operazioni (il limite inferiore
alla complessità è O (n!))
 Nessun
algoritmo può effettuare la somma fra vettori
ndimensionali in meno di n operazioni (il limite inferiore alla
complessità è O (n))
• Esempio non banale
 Nessun algoritmo può ordinare un vettore di
di nlog2n operazioni, nel caso peggiore
Anno accademico 2010-2011
n elementi in meno
73
Algoritmi ottimi
• Un algoritmo si dice ottimo, quando ha complessità pari al
limite inferiore
• Esempi
 Mergesort e Heapsort sono ottimi
 Si consideri il problema di sommare gli elementi di un vettore:
un algoritmo che scorre tutti gli elementi e li somma uno ad uno
richiede O (n) operazioni: tale algoritmo è ottimo perché la sua
complessità corrisponde con quella minima
 Si consideri il problema di inserire un elemento in un albero
binario di ricerca, bilanciato, che contiene n elementi:
Abbiamo visto una soluzione algoritmica che impone O (log2n)
operazioni  log2n è un limite superiore per tale problema
Si può dimostrare che tale complessità corrisponde con il limite
inferiore e che l’algoritmo proposto è ottimo
Anno accademico 2010-2011
74
Algoritmi e computer
• Dubbi:
 La complessità è indipendente dal computer su cui “gira” il
programma?
 Ad esempio, se si inventasse un calcolatore in grado di generare
contemporaneamente tutte le classifiche di n concorrenti, allora
quel problema non avrebbe più complessità n!
 Oppure… potrebbe esistere in futuro un computer in grado di
ordinare un vettore di qualsiasi lunghezza per mezzo di una sola
istruzione
• Nessuno conosce la risposta ma, fino ad ora, nessuno è
riuscito a progettare un computer con queste capacità: tutti i
calcolatori conosciuti sono equivalenti, in termini di capacità di
calcolo, ad un computer semplicissimo  la macchina di Turing
75
Anno accademico 2010-2011
La macchina di Turing  1
• Alan Turing (19121954) è considerato uno dei padri
dell’informatica
• Nel 1936 propose l’idea di una macchina immaginaria che
fosse capace di eseguire ogni tipo di calcolo su numeri e
simboli (nell’articolo On computable numbers with an
application to the Entscheidungsproblem)
 Il problema della decisione era stato proposto da David Hilbert
nel suo programma di fondazione formalista della matematica
• La macchina di Turing è una macchina formale, cioè un
sistema formale che può descriversi come un meccanismo
ideale, ma in linea di principio realizzabile concretamente
76
Anno accademico 2010-2011
La macchina di Turing  2
• È una macchina a stati, può cioè trovarsi in stati ben
determinati, opera su stringhe in base a regole precise e
costituisce un modello di calcolo
• È retta da regole molto semplici, ovvero la sua modalità
operativa può essere descritta mediante meccanismi
elementari
• Si “presume” abbia il massimo potere computazionale e si
dimostra che è equivalente, ovvero in grado di effettuare le
stesse elaborazioni, ai modelli di calcolo di più ampia portata
(formali e implementati)
77
Anno accademico 2010-2011
La macchina di Turing  3
• Per le sue caratteristiche, la macchina di Turing è un
efficace strumento teorico che viene largamente usato nella
teoria della calcolabilità e nello studio della complessità degli
algoritmi
• Inoltre, per definire in modo formalmente preciso la nozione
di algoritmo, oggi si sceglie preferenzialmente di ricondurlo
al concetto di elaborazione effettuabile da una macchina di
Turing
• Esistono varie versioni (computazionalmente equivalenti)
della macchina di Turing, quella più simile ai nostri
calcolatori è quella cosiddetta a registri (o counter machine,
MinskyLambek, 1961)
78
Anno accademico 2010-2011
La macchina di Turing a registri
• È costituita da un insieme di registri di lavoro R1, R2, R3,… e
di registri di ingresso I1, I2, I3,…
 Ogni registro contiene un intero non negativo
• I programmi sono costituiti da tre semplici tipi di istruzioni:
Ri 
Il registro i viene incrementato di 1
 decremento: Ri 
Il registro i viene decrementato di 1; se
il registro ha già valore 0, l’istruzione
non ha effetto
 salto condizionato: IF Ri GOTO L1
Se il registro i contiene un valore maggiore di 0, si salta all’istruzione L1
 incremento:
Anno accademico 2010-2011
IF I1 GOTO ciclo
ciclo:
I3
IF I3 GOTO fine
I2
I1
IF I1 GOTO ciclo
fine:
Programma che somma i
contenuti di I1 e I2 in I2
79
La tesi di ChurchTuring
• La tesi di ChurchTuring afferma che:
Ogni problema intuitivamente calcolabile (risolubile) da un
qualsiasi elaboratore è calcolabile da una macchina di
Turing, purché dotata di memoria (e tempo di elaborazione)
sufficiente
• Nessuno è mai riuscito a confutare la tesi di ChurchTuring
• La maggior parte dei ricercatori ritiene che sia vera
80
Anno accademico 2010-2011
Il problema della terminazione
• Supponiamo che esista un programma halt in grado di
risolvere il problema della terminazione
 halt(P,I) restituisce:
true se P con ingresso I termina
false se P con ingresso I non termina
• Consideriamo il programma Q
• Cosa succede se si applica Q a Q ?
 Q(Q) termina o no ?
void Q(Program P){
while (halt(P,P)) {}
}
• Se Q(Q) termina allora halt(Q,Q) dovrebbe essere vero… ma
allora Q(Q) non dovrebbe terminare
• Se Q(Q) non termina allora halt(Q,Q) dovrebbe essere falso
… ma allora Q(Q) dovrebbe terminare
• Quindi il programma halt non esiste!!
81
Anno accademico 2010-2011
Problemi impossibili
• Esistono problemi molto difficili… problemi non calcolabili
con una macchina di Turing e  se la tesi di ChurchTuring
è vera  con nessun calcolatore!!
• Esempi
 Problema della terminazione
Dato un programma e un suo ingresso, dire se il programma
terminerà (o entrerà in un ciclo indefinito)
 Problema di Post
Dato un programma e due stati (uno stato è definito da un
certo valore delle variabili), dire se a partire dal primo stato si
potrà raggiungere il secondo
82
Anno accademico 2010-2011
La macchina di Turing
non deterministica  1
• Nella macchina non deterministica, i programmi includono
anche altre istruzioni
 scelta casuale: FORK
prende in ingresso un insieme di istruzioni e ne esegue una a caso
 istruzione di accettazione: ACCEPT
quando viene eseguita, il programma termina correttamente
• Un problema è risolubile se esiste un programma e una scelta
casuale per cui il programma termina con ACCEPT e fornisce la
risposta desiderata
83
Anno accademico 2010-2011
La macchina di Turing
non deterministica  2
• Esempio: Programma che assegna a caso valori in {0, 1} a R1 e
R2 e termina solo se R1R21
R4
FORK{
cont:
ok:
no:
Anno accademico 2010-2011
R1,
R1 }
FORK{
R2,
R2 }
IF R1 GOTO cont
IF R4 GOTO no
IF R2 GOTO ok
IF R4 GOTO no
ACCEPT
84
La macchina di Turing
non deterministica  3
• La macchina non deterministica “non calcola più di quella
deterministica”
 Si può dimostrare che tutto ciò che è calcolabile sulla macchina di
Turing non deterministica è calcolabile anche sulla macchina
deterministica
• La macchina non deterministica è però più efficiente di quella
deterministica
• Il non determinismo può essere pensato infatti come una
forma di parallelismo:
 FORK è un’istruzione che genera più programmi paralleli
• Il parallelismo permette di risolvere i problemi velocemente: ad
esempio, si può cercare un elemento in un vettore guardando
contemporaneamente a tutti i suoi elementi
85
Anno accademico 2010-2011
Problemi P ed NP
• I problemi decisionali richiedono solo una risposta binaria
(sì/no), correlata in genere all’esistenza di una soluzione
(es., problema della terminazione)
• Nella teoria della complessità, i problemi decisionali si
dividono in due classi
 P  problemi risolubili in tempo polinomiale sulla macchina di
Turing deterministica
 NP  problemi risolubili in tempo polinomiale sulla macchina di
Turing non deterministica
Includono sia i problemi “facili”, sia anche la quasi totalità dei
problemi che si incontrano nelle situazioni pratiche
• Ovviamente vale PNP, ma non è noto se PNP
86
Anno accademico 2010-2011
Problemi NP-completi  1
• Problema decisionale della soddisfattibilità: Data una forma
normale congiuntiva F(x1,x2,…,xn) stabilire se esiste un
assegnamento di valori delle variabili booleane x1,x2,…,xn
che soddisfi F
 Qualunque problema della classe NP si riduce, in tempo
polinomiale, al problema della soddisfattibilità PS
 PS è il “più difficile” fra i problemi di NP
87
Anno accademico 2010-2011
Problemi NP-completi  2
• Un problema P è detto NPcompleto se PNP e PS si riduce a P
• I problemi NPcompleti sono tutti equivalenti fra loro:
 Sarebbe sufficiente trovare un algoritmo polinomiale per uno solo di
essi ed avremmo trovato un algoritmo polinomiale per risolvere
tutti i problemi
 Inoltre, tutti i problemi in NP sarebbero risolubili in tempo
polinomiale sulla macchina di Turing deterministica, cioè avremmo
dimostrato che NPP!
88
Anno accademico 2010-2011
Problemi NP-completi: esempi
• Problema decisionale del commesso viaggiatore
Dato un insieme di n città con le relative distanze, trovare,
se esiste, un cammino di lunghezza k che, partendo da una
città, le visiti tutte tornando in quella di partenza
• Un problema NParduo (non decisionale)
 Programmazione lineare intera
Data una matrice A e due vettori b, c, calcolare un vettore di
interi x che soddisfi Axb e minimizzi f(x)cx
 Problemi di programmazione lineare
definire l’orario dei treni e degli autobus
definire l’orario delle lezioni
…
89
Anno accademico 2010-2011
PNP e tesi di ChurchTuring
• Attualmente si pensa che NPP
 …ma nessuno è ancora riuscito a dimostrarlo
• Si pensa anche che la tesi di ChurchTuring sia vera:
 ovviamente questo non si può dimostrare ma è, eventualmente,
solo confutabile
• Talvolta, problemi con complessità proibitiva sono utili:
 Ad esempio, gli algoritmi crittografici sono basati sul fatto che
“decrittare” una chiave è molto complesso e richiederebbe un
tempo troppo lungo
 Se la tesi di ChurchTuring non fosse vera o se PNP, tali
metodi non sarebbero più efficaci
90
Anno accademico 2010-2011
Ai limiti del calcolo:
I problemi intrinsecamente difficili
91
Anno accademico 2010-2011
Il problema del commesso viaggiatore
• Il problema del commesso viaggiatore è uno
dei più celebri tra i problemi di
«soddisfacimento di vincoli» non calcolabili
• Una sua versione piuttosto diffusa è la
seguente:
È possibile stimare il percorso più breve per
un commesso viaggiatore che deve fare
visita ai suoi clienti in tutte le città indicate
sulla mappa?
• A prima vista, sembra facile, ma all’aumentare del numero delle città, il problema
diventa esponenzialmente più difficile,
mettendo nei guai anche i più potenti
computer
Anno accademico 2010-2011
92
I problemi difficili  1
• Ma dove sta scritto che tutti i problemi si devono risolvere
facilmente e che la loro soluzione deve essere calcolabile in modo
efficiente?
• Eppure lascia perplessi il fatto che alcuni calcoli siano tanto più
complessi di altri…
• L’esempio classico è quello della moltiplicazione e della
scomposizione in fattori

Se vengono dati due numeri primi grandi moltiplicarli è semplice…

…ma cercare, una volta dato il prodotto, di ritrovare i due fattori
sconosciuti è un problema molto difficile

…fino al punto che una delle tecniche crittografiche più diffuse (RSA)
si basa sulla difficoltà di risoluzione di questo «problema inverso»
93
Anno accademico 2010-2011
I problemi difficili  2
• E dunque, dove sono i problemi difficili?


In matematica, in informatica, in fisica
Il tema comune che lega strettamente queste tre discipline è
infatti la presenza di problemi con transizioni improvvise da un
tipo di comportamento ad un altro
94
Anno accademico 2010-2011
In matematica…  1
• Il filo matematico comincia negli anni
‘60 con lo studio dei grafi aleatori,
iniziato da Paul Erdós e Alfred Rényi
• Un grafo è una struttura matematica
astratta: un insieme di vertici e archi,
disegnato in genere come uno schema
di punti (i vertici) e linee che li uniscono
(gli archi)
• Per disegnare un grafo aleatorio si inizia
distribuendo n vertici sul foglio, scegliendo casualmente, per ogni coppia e
con probabilità p, se tracciare o no un
arco che connetta i due vertici
Costruzione di un grafo aleatorio
95
Anno accademico 2010-2011
In matematica…  2
• Quando p è vicino a 0, gli spigoli sono pochi e il grafo è composto
di molti piccoli pezzi, o componenti connesse, separate le une dalle
altre
• Al crescere di p, il grafo comincia a essere dominato da una singola
componente connessa «gigante», che comprende la maggior parte
dei vertici
• L’esistenza di questa componente gigante non è certo una
sorpresa, ma il modo in cui essa si sviluppa non è ovvio:
 La componente non evolve gradualmente al crescere di p, bensì
emerge all’improvviso quando viene superata una certa soglia
 La soglia è definita in termini di un parametro che chiameremo : il
rapporto fra numero dei lati e numero dei vertici
 La componente gigante nasce quando  è circa 1/2
96
Anno accademico 2010-2011
In informatica…  1
• In campo informatico un simile fenomeno di
soglia attirò molta attenzione nei primi anni
‘90
• In questo caso la soglia determina la
probabilità che certi problemi computazionali
abbiano soluzione
• Uno di questi problemi, che deriva dalla teoria
dei grafi, è il problema della kcolorazione,
che richiede di dipingere ogni vertice di un
grafo con uno di k colori, con la regola che
due vertici adiacenti non possano avere lo
stesso colore
• Trovare una colorazione corretta diventa
sempre più difficile al crescere di , perché
più sono i lati più sono anche i vincoli imposti
su ogni vertice
Anno accademico 2010-2011
Problema di 3-colorazione
97
In informatica…  2
• Di nuovo, la soglia è netta: al di sotto di un certo valore del rapporto 
quasi tutti i grafi sono kcolorabili, mentre al di sopra di questa soglia non
lo è quasi nessuno
• Inoltre, la soglia non solo influisce sull’esistenza di soluzioni, ma anche
sulla difficoltà di trovarne: lo sforzo computazionale necessario per
decidere se un grafo è kcolorabile ha un picco significativo vicino al
valore critico di 
• Il problema della colorazione dei grafi è strettamente correlato al
problema della colorazione delle carte geografiche politiche, nelle quali
regioni adiacenti devono avere colori distinti

Se i nodi del grafo rappresentano regioni, collegate da un arco se adiacenti… il
gioco è fatto ed il grafo è un RAG, per «Region Adjacency Graph»
98
Anno accademico 2010-2011
In fisica…
• Anche i fisici sanno qualcosa dei problemi di soglia: li chiamano transizioni di
fase
• Ma i cambiamenti di stato osservati nei grafi aleatori sono veramente
analoghi ad eventi fisici come il congelamento dell’acqua e la comparsa della
magnetizzazione nel ferro? O la somiglianza è una semplice coincidenza?
• Per qualche tempo l’argomento è stato controverso, ma ora è chiaro che i
fenomeni di soglia nei grafi e in altre strutture matematiche sono autentiche
transizioni di fase e, quindi, gli strumenti e le tecniche della fisica statistica
sono adattissimi a studiarli
 Il problema della kcolorazione è in corrispondenza esatta con un modello di
sistema magnetico nella fisica dello stato solido
99
Anno accademico 2010-2011
Il problema della 3-colorazione  1
• La 3colorazione è un problema complesso, ma non
impossibile
• La domanda «Questo grafo è 3-colorabile?» ha sempre
risposta, almeno in linea di principio: visto che a ogni vertice
può essere assegnato un colore qualunque e che ci sono n
vertici, ci devono essere esattamente 3n modi di colorare il
grafo
100
Anno accademico 2010-2011
Il problema della 3-colorazione  2
• Per decidere se uno specifico grafo è 3-colorabile, basta
prendere in esame, una per una, tutte le possibilità
 Se si trova un’assegnazione di colori che soddisfa il vincolo,
cioè in cui nessun arco congiunge vertici dello stesso colore,
allora la risposta alla domanda è sì
 Se si esauriscono tutte le possibilità senza trovare una
colorazione appropriata, si può essere certi che non esiste
• Questo algoritmo è semplice e sicuro, ma anche inutile,
perché enumerare 3n colorazioni è al di là di ciò che si può
fare in pratica per qualsiasi n maggiore di 15 o 20
101
Anno accademico 2010-2011
Il problema della 3-colorazione  3
• Procedure più sofisticate possono garantire una ricerca
esatta ed esaustiva pur riducendo il numero di operazioni a
meno di 1,5n  è un miglioramento significativo, ma si tratta
sempre di una funzione esponenziale che innalza il limite a
n50
 Per grafi grandi, con migliaia di vertici, tutti i metodi brute
force non offrono speranze
• D’altro canto, se si potesse in qualche modo “sbirciare” la
soluzione di un problema di 3-colorazione su molti vertici, se
ne potrebbe controllare la correttezza facendo assai meno
fatica: tutto quello che si dovrebbe fare sarebbe verificare
che i vertici alle estremità di ciascun lato abbiano colori
diversi
Anno accademico 2010-2011
102
Il problema della 3-colorazione  4
• Il numero di lati in un grafo non può essere maggiore di n2,
che è una funzione polinomiale anziché esponenziale, e
quindi cresce molto più lentamente
• I problemi con risposte che sono difficili da trovare ma facili
da verificare sono (nondeterministic polynomial) NP e, a
meno di un miracolo, non si avranno mai algoritmi in tempo
polinomiale per risolverli
• Avendo appurato le credenziali della 3-colorazione come
problema ufficialmente difficile, possiamo rivelare che la
maggior parte dei problemi di 3-colorazione su grafi aleatori
è in realtà piuttosto semplice
103
Anno accademico 2010-2011
Il problema della 3-colorazione  5
• Dato un grafo tipico, si hanno buone probabilità di trovare
rapidamente una 3-colorazione o di dimostrare che non
esiste
• Questa curiosa situazione non è veramente paradossale: la
classificazione della 3-colorazione come problema NP si basa
sull’analisi del «caso peggiore»
• Esistono infatti molti algoritmi che hanno, nella maggior
parte dei casi, un tempo di elaborazione rapido, a patto di
accettare un occasionale fallimento
104
Anno accademico 2010-2011
Il problema della 3-colorazione  6
• Una strategia diffusa per algoritmi che colorano grafi è il
backtracking (letteralmente: «tornare sui propri passi») ed
assomiglia al modo in cui la maggior parte delle persone
affronterebbe il problema se dovesse cercare di colorare il
grafo a mano:
 si inizia assegnando un colore arbitrario a un vertice arbitrario
 poi si passa ai vertici vicini, assegnando loro colori che non
causino un conflitto
 proseguendo così si può arrivare a un vertice per cui non c’è
un colore lecito; a questo punto si torna sui propri passi
annullando alcune scelte precedenti, e si riprova
105
Anno accademico 2010-2011
Il problema della 3-colorazione  7
• Per mostrare che un grafo non può essere 3-colorato occorre
un altro tipo di algoritmo
• L’approccio fondamentale consiste nel cercare un sottoinsieme di vertici che, anche se fosse isolato dal resto del
grafo, non potrebbe essere 3-colorato
 Per esempio, una cricca costituita da quattro vertici ognuno dei
quali sia collegato con tutti gli altri ha questa proprietà
 Se si trova anche solo una di queste strutture, la questione è
risolta per l’intero grafo
106
Anno accademico 2010-2011
Il problema della 3-colorazione  8
• Algoritmi come questi sono molto diversi dai metodi di
ricerca esaustiva
• La semplice enumerazione di tutte le 3n colorazioni può
essere inammissibilmente lenta, ma almeno è prevedibile
• Ciò non è vero per il backtracking e per altri algoritmi inesatti
o incompleti; le loro prestazioni variano notevolmente a
seconda della natura del grafo
107
Anno accademico 2010-2011
Il problema della 3-colorazione  9
• In particolare, questi algoritmi sono sensibili al valore di  
il rapporto tra il numero di lati e il numero di vertici  che è
di nuovo il parametro che controlla la transizione tra fasi
colorabili e non colorabili
• Molto al di sotto del valore critico di , dove gli spigoli sono radi, c’è
un numero tale di modi di colorare il grafo che qualsiasi strategia
ragionevole ha buone probabilità di trovarne uno
• All’estremo opposto, molto al di sopra della soglia, i grafi sono
densamente interconnessi, ed è facile trovare un sottografo che renda
impossibile la 3-colorazione
• La regione problematica è situata tra questi estremi, vicino alla soglia;
in questa zona intermedia possono esserci pochissime colorazioni o
nessuna: distinguere tra queste due situazioni può rendere necessario
controllare quasi ogni possibile assegnazione di colori
108
Anno accademico 2010-2011
Dove sono le soluzioni?  1
• Il valore critico di  è circa 2.35
• In altre parole, se un grafo aleatorio con n vertici ha meno di
2.35n archi, può essere quasi sicuramente 3-colorato; se ne
ha di più, una 3-colorazione è improbabile
• Inoltre si sa che la transizione tra questi due regimi è netta:
è una vera discontinuità, un salto improvviso anziché un
passaggio graduale
• Per esprimere più formalmente questa idea si dice che
l’ampiezza della regione di transizione tende a zero quando n
tende all’infinito
109
Anno accademico 2010-2011
Dove sono le soluzioni?  2
• La nettezza della transizione di fase può essere considerata
una notizia incoraggiante
 Se gli algoritmi per decidere la colorabilità si impantanano solo
nella regione di transizione, e se essa è tanto ristretta da essere
quasi trascurabile, allora la probabilità di incontrare un grafo
difficile da classificare è proporzionalmente piccola
• Tuttavia, la nettezza della transizione è garantita solo per grafi
infinitamente grandi; se n è finito, gli angoli della curva di
transizione sono arrotondati
• Inoltre, sebbene la fase non colorabile non inizi fino ad 2.35,
gli esperimenti hanno mostrato che gli algoritmi cominciano a
rallentare un po’ prima, a valori di  attorno a 2.2
110
Anno accademico 2010-2011
Dove sono le soluzioni?  3
• Per capire la causa, giova visualizzare tutte le possibili 3colorazioni di un grafo distese su una curva: l’altezza della
curva in ogni punto rappresenta il numero di conflitti nella
colorazione corrispondente
• Così le colorazioni perfette (quelle senza conflitti) si trovano
tutte al livello del mare, mentre le colorazioni peggiori
creano picchi o altipiani ad alta quota
• Naturalmente la topografia di questo paesaggio dipende dal
particolare grafo che stiamo esaminando
111
Anno accademico 2010-2011
Dove sono le soluzioni?  4
• Si consideri come evolve la superficie via via che  cresce
gradualmente
 Per piccoli valori di  ci sono ampi bacini e vallate, che
rappresentano i molti modi di colorare perfettamente il grafo
 Per grandi valori di  il paesaggio è alpino, e anche il punto
più basso è molto al di sopra del livello del mare, denotando
una completa assenza di colorazioni perfette
 Il valore di transizione  ≈ 2.35 segna il momento in cui
scompaiono le ultime aree estese che si trovano al livello del
mare
112
Anno accademico 2010-2011
Dove sono le soluzioni?  5
• Che cosa avviene nello «spazio delle soluzioni» per 2.2?
 Si è scoperto che questo è il momento in cui un’ampia distesa di terreno




a livello zero si frammenta in piccoli bacini isolati
Al di sotto di 2.2, quasi tutte le colorazioni perfette formano un’unica
gigantesca regione connessa (fatta di tante soluzioni vicine)
Al di sopra di 2.2, ogni bacino rappresenta un insieme isolato di
soluzioni
Le colorazioni che si trovano in bacini separati sono sostanzialmente
diverse e per trasformarne una in un’altra si dovrebbe scalare una
catena montuosa formata da colorazioni che presentano un alto numero
di conflitti
È improbabile che gli algoritmi che funzionano conducendo una ricerca
locale riescano a valicare queste catene montuose, e quindi rimangono
confinati a lungo nel primo bacino in cui capitano
113
Anno accademico 2010-2011
Dove sono le soluzioni?  6
• Al crescere di α sopra 2.2, il numero di colorazioni perfette
all’interno di ogni bacino decresce fino a zero e quindi gli
algoritmi possono non riuscire a trovare una soluzione anche
se esistono ancora molte colorazioni valide in altre parti della
superficie delle soluzioni
114
Anno accademico 2010-2011
Dove sono le soluzioni?  7
Grafi identici con 100 nodi e 218 archi (poco al di sotto della
soglia di trattabilità). La disposizione circolare dei vertici, a destra
nella figura, rende più facile verificare che nessuno spigolo
connette vertici dello stesso colore
Anno accademico 2010-2011
115
Quanti problemi difficili!
Che fare?
• Alcuni problemi richiedono un tempo di calcolo semplicemente
troppo lungo, nei casi peggiori addirittura esponenziale
• Ma forse risposte rapide e semplici a problemi
computazionalmente complessi non sono qualcosa che
abbiamo il diritto di aspettarci in questo mondo…
• …e forse non è un «baco», è una caratteristica voluta:
impedisce che l’universo si esaurisca troppo rapidamente
116
Anno accademico 2010-2011