Algoritmi e Strutture Dati
Capitolo 10
Tecniche algoritmiche
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Sommario
• Una tecnica algoritmica può essere vista come
un meta-algoritmo che permette di risolvere
un’ampia classe di problemi, i quali, per loro
natura, si prestano ad essere risolti appunto in
modo analogo
• In particolare, abbiamo già visto
dettagliatamente la tecnica divide et impera
• Oggi vedremo la Programmazione Dinamica e
il Metodo Goloso, che troveranno ampia
applicazione nei problemi su grafi
2
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Richiamo: la tecnica divide et impera
Tecnica top-down:
1. Dividi l’istanza del problema in due o più
sottoistanze (sottoproblemi)
2. Risolvi ricorsivamente il problema sulle
sottoistanze
3. Ricombina la soluzione dei sottoproblemi allo
scopo di ottenere la soluzione globale (si noti
quindi che la soluzione del sottoproblema non può
essere usata direttamente per produrre la soluzione
del problema, ma deve essere combinata
opportunamente con altre sottosoluzioni)
Esempi: mergesort, quicksort
3
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Programmazione dinamica
Tecnica bottom-up:
1. Identifica dei sottoproblemi del problema originario,
procedendo logicamente dai problemi più piccoli
verso quelli più grandi
2. Utilizza una tabella per memorizzare le soluzioni dei
sottoproblemi incontrati: quando si incontra lo stesso
sottoproblema, sarà sufficiente esaminare la tabella
3. Si usa quando i sottoproblemi non sono indipendenti,
ovvero quando vale il principo di sottostruttura
ottima della soluzione: una sottosoluzione può essere
usata direttamente per costruire la soluzione del
problema!
4
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Un esempio banale: Fibonacci3
algoritmo fibonacci3(intero n)  intero
sia Fib un array di n interi
Fib[1]  Fib[2]  1
for i = 3 to n do
Fib[i]  Fib[i-1] + Fib[i-2]
return Fib[n]
5
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Distanza tra stringhe
Siano X e Y due stringhe di lunghezza m ed n:
Vogliamo calcolare la distanza tra X e Y, ovvero il minimo
numero delle seguenti operazioni elementari da
eseguire su X che permetta di trasformare X in Y
6
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio
• Parto dalla stringa X=“RISOTTO”, e voglio trasformarla in Y=“PRESTO”
• La soluzione banale consiste nel fare 7 cancellazioni e 6 inserimenti, cioè 13
operazioni
• Un’altra soluzione semplice: sostituisco uno dopo l’altro i caratteri di
RISOTTO, ove necessario, e cancello i caratteri in eccesso; nel nostro
esempio, saranno 5 sostituzione e 1 cancellazione (cioè, 6 operazioni).
• Posso fare meglio? Vediamo una sequenza di operazioni controintuitiva:
 Abbiamo fatto solo 4 operazioni! Posso fare meglio??
7
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Approccio
•
Denotiamo con d(X,Y) la distanza tra X e Y
•
Definiamo Xi il prefisso di X fino all’i-esimo
carattere, per 0≤ i ≤m (X0 denota la stringa vuota):
•
Risolveremo il problema di calcolare d(X,Y)
calcolando d(Xi,Yj) per ogni i, j tali che 0 ≤i ≤m e
0 ≤j ≤n
Manterremo le informazioni in una tabella D di
dimensione (m+1)  (n+1)
•
8
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Inizializzazione della tabella
•
Alcuni sottoproblemi sono molto semplici:
d(X0,Yj)=j per trasformare la stringa vuota
X0 nella stringa Yj, basta inserire uno ad uno
gli j caratteri di Yj
• d(Xi,Y0)=i per trasformare la stringa Xi nella
stringa vuota Y0, basta rimuovere uno ad uno
gli i caratteri di Xi
• Queste soluzioni sono memorizzate
rispettivamente nella prima riga e nella prima
colonna della tabella D
•
9
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio
La tabella D
inizializzata
dall’algoritmo
10
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Avanzamento nella tabella (1/3)
•
Se xi=yj, il minimo costo per trasformare Xi in Yj è
uguale al minimo costo per trasformare Xi-1 in Yj-1
(infatti, non dovrò fare alcuna operazione su xi, visto
che esso coincide con yj)
D [ i,j] = D [ i-1, j-1 ]
•
Se xiyj, allora per trasformare Xi in Yj devo fare una
qualche operazione sull’i-esima posizione di Xi;
distinguiamo quindi in base all’ultima operazione che
dovremmo usare per trasformare Xi in Yj in una
sequenza ottima di operazioni
11
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Avanzamento nella tabella (2/3)
(in realtà questa operazione viene fatta
sulla posizione (i+1)-esima di Xi) il
minimo costo per trasformare Xi in Yj è
uguale al minimo costo per trasformare
Xi in Yj-1 più 1 per inserire il carattere yj
D [i,j] = 1 + D [i, j-1]
il minimo costo per trasformare Xi in Yj è
uguale al minimo costo per trasformare
Xi-1 in Yj più 1 per la cancellazione del
carattere xi
D [i,j] = 1 + D [i-1, j]
12
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Avanzamento nella tabella (3/3)
il minimo costo per trasformare
Xi in Yj è uguale al minimo costo
per trasformare Xi-1 in Yj-1 più 1
per sostituire il carattere xi con yj
D [i,j] = 1 + D [i-1, j-1]
In conclusione:
13
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Pseudocodice
Tempo di esecuzione ed occupazione di memoria: Θ(m n)
NOTA: Se tengo traccia della casella della tabella che utilizzo
per decidere il valore di D[i,j], ho un metodo costruttivo per
ricostruire la sequenza di operazioni di editing ottima.
14
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio
La tabella D costruita
dall’algoritmo.
In grassetto è indicata la
sequenza di operazioni
che permette di ottenere
la distanza tra le stringhe
(verificate che coincide
con quella data prima!)
mantenimento
15
sostituzione
inserimento
cancellazione
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
La tecnica golosa (o greedy)
• La tecnica golosa (greedy) si applica principalmente
a problemi di ottimizzazione in cui, dato un certo
numero di elementi come input, bisogna scegliere un
sottoinsieme di essi che ottimizzi una funzione
obiettivo rispettando un certo numero di vincoli.
• Richiede che l’algoritmo esegua il processo di
costruzione della soluzione in fasi successive, in cui
ad ogni fase viene aggiunto un elemento alla
soluzione.
• Anche in questo caso la tecnica può funzionare solo
se il problema gode della proprietà di sottostruttura
ottima (sebbene questa sia una condizione
necessaria, ma non sufficiente).
16
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Tecnica golosa (2)
• Un algoritmo greedy ordina dapprima gli oggetti in
base ad un criterio di appetibilità (da cui il termine
goloso), e poi ripete le seguenti operazioni:
1. Ad ogni fase i, la soluzione viene accresciuta selezionando
l’ i-esima componente, la quale, tra tutte quelle
ammissibili, risulta la migliore in questo momento rispetto
al criterio di appetibilità
2. Una volta fatta la scelta per la i-esima componente, si
aggiornano (eventualmente) le appetibilità degli elementi
rimanenti, e si passa a considerare le scelte successive,
senza più tornare sulla decisione presa.
• Questa strategia euristica non garantisce sempre la
determinazione di una soluzione ottima, come detto
prima e come vedremo con un esempio.
17
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Paradigma di tecnica golosa
18
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Un problema di sequenziamento
• Un server (e.g., una CPU, o un impiegato dell’ufficio
postale) deve servire n clienti, stabilendo un ordine sapendo
che il servizio richiesto dal cliente i richiede ti secondi
• Chiamiamo T(i) il tempo di attesa del cliente i (pari al suo
tempo di processamento sommato ai tempi di processamento
dei clienti che lo hanno preceduto) e sia
il tempo di attesa totale di tutti i clienti
• Vogliamo stabilire un ordine che minimizzi il tempo di
attesa medio:
 Devo minimizzare il
tempo di attesa totale!
19
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Esempio
Dei sei possibili ordinamenti, il migliore è evidenziato in
arancione
20
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Un algoritmo goloso ottimo
•
Il seguente algoritmo genera l’ordine di servizio in
maniera incrementale secondo una strategia greedy:
– Il primo cliente ad essere servito è quello con tempo di
processamento minimo.
– Al generico passo l’algoritmo serve la richiesta più corta tra
quelle rimanenti.
•
La sequenza generata è ottima: infatti, è facile osservare
che il tempo di attesa totale può essere riscritto come
segue:
T=n·t1+(n-1)·t2+(n-2)·t3+…+1·tn
e quindi è minimo quando t1≤t2 ≤ … ≤ tn
Tempo di esecuzione: Θ(n log n) (ordinamento ottimo)
•
21
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Un algoritmo goloso non ottimo
• Gli algoritmi greedy non sempre funzionano!
• Esempio:
Input: lista di interi che rappresentano il valore di monete disponibili e un
intero che rappresenta un resto.
Output: una collezione di cardinalità minima di monete la cui somma sia
uguale al resto.
Appetibilità: Taglio della moneta
Ma supponendo di dover formare un resto di 9, avendo a
disposizione monete da 1, 4 e 6.
 l’algoritmo darebbe 6 + 1 + 1 + 1 mentre la soluzione ottima è 4
+ 4 + 1!
Domanda: Nella pezzatura dell’Euro, le monete sono da
1,2,5,10,20,50 centesimi, e da 1,2 Euro. La tecnica greedy
funziona in questo caso? Se sì, perché?
22
Copyright © 2004 - The McGraw - Hill Companies, srl
Algoritmi e strutture dati
Camil Demetrescu, Irene Finocchi, Giuseppe F. Italiano
Applicazioni future su grafi
– Programmazione dinamica: cammini minimi tra
tutte le coppie di nodi (algoritmo di Floyd e
Warshall)
– Tecnica greedy: minimo albero ricoprente
(algoritmi di Prim, Kruskal, Boruvka) e cammini
minimi a sorgente singola (algoritmo di Dijkstra)
23
Copyright © 2004 - The McGraw - Hill Companies, srl