Greedy Algorithms Problemi di ottimizzazione. Vogliamo trovare non una semplice soluzione ma la migliore soluzione. Chapter 4 Un algoritmo greedy viene utilizzato per risolvere problemi di ottimizzazione (in alcuni casi ci riesce, in altri no). Greedy Algorithms Un algoritmo greedy lavora in passi: Ad ogni passo fa la scelta più promettente subito (secondo un criterio locale) senza pensare alle conseguenze future senza mai più riconsiderare questa scelta La speranza è che la scelta di un ottimo locale ad ogni passo, conduce ad un ottimo globale. 1 2 Greedy Algorithms 4.1 Interval Scheduling Problemi che vedremo: Interval Scheduling Interval Partitioning Scheduling to Minimize Lateness Optimal Caching Shortest Paths in a Graph Minimum Spanning Tree Huffman Codes and Data Compression Esercizi: Coin Changing Selecting Breakpoints Fractional Knapsack problem Connecting wires Collecting coins 3 Schedulazione intervalli Schedulazione intervalli Schedulazione intervalli. Job j inizia a sj e finisce a fj. Schedulazione intervalli. Job j inizia a sj e finisce a fj. Due job sono compatibili se hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Due job sono compatibili se hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Qual’è la soluzione ottimale? a a b b c c d d e e f f g g h 0 1 2 3 4 5 6 7 8 9 10 11 h tempo 0 1 2 3 4 5 6 7 8 9 10 11 tempo 5 6 Schedulazione intervalli Schedulazione intervalli: Algoritmi Greedy Scelta Greedy. Considera job in qualche ordine. Prendere job se è compatibile con quelli già presi. Schedulazione intervalli. Job j inizia a sj e finisce a fj. Due job sono compatibili se hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Qual’è la soluzione ottimale? Sottoinsieme massimale = {b,e,h} a b c d e f g h 0 1 2 3 4 5 6 7 8 9 10 11 [tempo inizio minimo] Considera job in ordine crescente del tempo di inizio sj. [tempo fine minimo] Considera job in ordine crescente del tempo di fine fj. [intervallo più corto] Considera job in ordine crescente del tempo della lunghezza dell intervallo fj - sj. [minori conflitti] Per ogni job j, contare il numero cj di job che lo intersecano. Considera job in ordine crescente di conflitti cj. tempo 7 8 Schedulazione intervalli: Algoritmi Greedy Schedulazione intervalli Scelta Greedy. Considera job in qualche ordine. Prendere job se è compatibile con quelli già presi. Schedulazione intervalli. Job j inizia a sj e finisce a fj. tempo inizio minimo Due job sono compatibili se non hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Osservare: • Job più corto c non è in alcuna soluzione ottimale • Job che inizia per primo a non è in alcuna soluzione ottimale a intervallo più corto non portano all’ottimo! b c d minori conflitti e f g h 0 1 2 3 4 5 6 7 8 9 10 11 9 Schedulazione intervalli: Algoritmo Greedy tempo 10 Schedulazione intervalli: Algoritmo Greedy Algoritmo Greedy. Considera job in ordine crescente del tempo di fine fj. Prendere job se è compatibile con quelli già presi. 11 12 Schedulazione intervalli Schedulazione intervalli Schedulazione intervalli. Job j inizia a sj e finisce a fj. Schedulazione intervalli. Job j inizia a sj e finisce a fj. Due job sono compatibili se non hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Qual’è la soluzione greedy? Due job sono compatibili se non hanno intersezione vuota. Obiettivo: trovare sottoinsieme massimale di job mutuamente compatibili. Qual’è la soluzione greedy? a Sottoinsieme greedy = {b,e,h} a b b c c d d e e f f g g h 0 1 2 3 4 5 6 7 8 9 10 11 h tempo 0 1 2 3 4 5 6 7 8 9 10 11 tempo 13 14 Schedulazione intervalli: Algoritmo Greedy Schedulazione intervalli: Implementazione Algoritmo Greedy Algoritmo Greedy. Considera job in ordine crescente del tempo di fine fj. Prendere job se è compatibile con quelli già presi. Implementazione Algoritmo Greedy. O(n log n). Denota j* l ultimo job aggiunto ad A. Ordina job per tempo di fine f1 ≤ f2 ≤ ... ≤ fn. Job j è compatibile con A se sj ≥ fj*. Ordina job per tempo di fine f1 ≤ f2 ≤ ... ≤ fn. insieme job scelti A ← {1} j* = 1 for j = 2 to n { if sj ≥ fj* {A ← A ∪ {j} j* = j } } return A A ← {1} for j = 2 to n { if (job j è compatibile con A) A ← A ∪ {j} } return A 15 16 Schedulazione intervalli: Analisi Schedulazione intervalli: Analisi Teorema. L algoritmo greedy è ottimale. Teorema. L algoritmo greedy è ottimale. Prova. (per assurdo) Assumiamo che la scelta greedy non sia ottimale. Siano i1, i2, ... ik job scelti in modo greedy. Siano j1, j2, ... jm job in una soluzione ottimale con i1 = j1, i2 = j2, ..., ir = jr dove r è il più grande valore possibile. Prova. (per assurdo) Assumiamo che la scelta greedy non sia ottimale. Siano i1, i2, ... ik job scelti in modo greedy. Siano j1, j2, ... jm job in una soluzione ottimale con i1 = j1, i2 = j2, ..., ir = jr dove r è il più grande valore possibile. job ir+1 termina prima di jr+1 job ir+1 termina prima di jr+1 greedy: i1 i1 ir ottimo: j1 j2 jr ir+1 jr+1 ... greedy: i1 i1 ir ir+1 ottimo: j1 j2 jr ir+1 sostituiamo job jr+1 con job ir+1 ... soluzione ancora ottima, ma contraddice la massimalità di r 17 18 Interval Partitioning 4.1 Interval Partitioning Interval partitioning. Lezione j inizia ad sj e termina a fj. Obiettivo: trovare il minimo numero di aule per schedulare tutte le lezioni in modo che non ci siano due lezioni contemporaneamente nella stessa aula. Esempio: Schedulazione con 4 aule per 10 lezioni. e c j g d b h a 9 9:30 f 10 10:30 11 11:30 12 12:30 1 1:30 i 2 2:30 3 3:30 4 4:30 tempo 20 Interval Partitioning Interval Partitioning Interval partitioning. Lezione j inizia ad sj e termina a fj. Interval partitioning. Lezione j inizia ad sj e termina a fj. Obiettivo: trovare il minimo numero di aule per schedulare tutte le lezioni in modo che non ci siano due lezioni contemporaneamente nella stessa aula. Obiettivo: trovare il minimo numero di aule per schedulare tutte le lezioni in modo che non ci siano due lezioni contemporaneamente nella stessa aula. Esempio: Schedulazione con 3 aule per le stesse 10 lezioni. Si può far meglio? Si possono usare 2 aule? c d b a 9 9:30 f j g i h e 10 10:30 11 11:30 12 12:30 1 1:30 2 2:30 3 3:30 4 4:30 tempo 21 Interval Partitioning: Limiti inferiori per soluzione ottima 22 Interval Partitioning: Limiti inferiori per soluzione ottima Definizione. La profondità di un insieme di intervalli è il massimo numero di intervalli che contiene un dato tempo. Definizione. La profondità di un insieme di intervalli è il massimo numero di intervalli che contiene un dato tempo. Osservazione. Numero di aule che necessitano ≥ profondità. Esempio: Profondità insieme intervalli = 3 a, b, c contengono 9:30 Esempio: Aule nella schedulazione = 3 ⇒ schedulazione ottimale Domanda. Esiste sempre una schedulazione uguale alla profondità degli intervalli? c d b a 9 9:30 f j g i 10:30 11 11:30 12 12:30 1 1:30 2 2:30 3 d b a h e 10 c 3:30 4 4:30 9 tempo 23 9:30 f j g i h e 10 10:30 11 11:30 12 12:30 1 1:30 2 2:30 3 3:30 4 4:30 tempo 24 Interval Partitioning: Algoritmo Greedy Interval Partitioning: Algoritmo Greedy Algoritmo Greedy. Consideriamo lezioni in ordine crescente di tempo di inizio: assegniamo lezioni ad aule compatibili. Algoritmo Greedy. Consideriamo lezioni in ordine crescente di tempo di inizio: assegniamo lezioni ad aule compatibili. Ordina intervalli per tempo di inizio s1 ≤ s2 ≤ ... ≤ sn. d ← 0 Ordina intervalli per tempo di inizio s1 ≤ s2 ≤ ... ≤ sn. d ← 0 for j = 1 to n { if (lezione j è compatibile con qualche aula k) schedula lezione j nell aula k else alloca una nuova aula d + 1 schedula lezione j nell aula d + 1 d ← d + 1 } for j = 1 to n { if (lezione j è compatibile con qualche aula k) schedula lezione j nell aula k else alloca una nuova aula d + 1 schedula lezione j nell aula d + 1 d ← d + 1 } numbero aule allocate numbero aule allocate Implementazione. O(n log n). Per ogni aula k, manteniamo il tempo di fine dell’ultimo job aggiunto. Coda a priorità per i tempi di fine per ogni aula. 25 26 Coda a priorità Heap Un heap è un albero binario pieno livello per livello Ultimo livello da sx a dx Implementazioni: 5 min 14 89 32 30 24 15 6 . . . . . 24 28 15 9 17 81 Rappresentato con un array 10 19 13 31 11 5 ∅ 14 Head Operazione PQ Lista ordinata Lista non ordinata (a puntatori) (array) 24 Binary heap Insert O(n) O(1) O(log n) Min O(1) O(n) O(1) ExtractMin O(1) O(n) O(log n) ChangeKey O(n) O(1) O(log n) IsEmpty O(1) O(1) O(1) 10 28 81 A= 27 17 19 13 31 5 14 10 24 17 19 13 28 81 31 28 05/11/12 Heap Heap Un heap è un albero binario pieno livello per livello Ultimo livello da sx a dx Un heap è un albero binario pieno livello per livello Ultimo livello da sx a dx Parent(i) { return 'i/2(; } Rappresentato con un array Proprietà di heap Rappresentato con un array Left(i) { return 2*i; } A[Parent(i)] ≥ A[i] per tutti i nodi i > 1 right(i) { return 2*i + 1; } 5 5 14 10 24 28 17 81 A= 14 19 13 24 31 5 14 24 17 19 13 28 81 81 31 A= 13 31 5 14 10 24 17 19 13 28 81 31 30 05/11/12 05/11/12 Priority Queue con Binary Heap: inserimento Un heap è un albero binario pieno livello per livello Ultimo livello da sx a dx Inserimento 12 13 Rappresentato con un array Il valore massimo è alla radice A[1] 21 Altezza Θ(lg n) 5 25 14 37 35 43 10 24 17 81 A= 19 29 Heap 28 17 28 10 10 19 13 31 5 14 10 24 17 19 13 28 81 31 31 05/11/12 32 Priority Queue con Binary Heap: inserimento Inserimento 12 Priority Queue con Binary Heap: inserimento Inserimento 12 13 13 13 21 21 35 21 35 21 25 25 37 13 37 43 35 12 25 43 25 35 37 43 37 43 12 Violazione proprietà di heap 33 34 Priority Queue con Binary Heap: inserimento Inserimento 12 Priority Queue con Binary Heap: inserimento Inserimento 12 13 13 13 21 21 37 35 21 35 21 25 25 43 37 43 25 25 Violazione proprietà di heap 37 25 37 43 43 21 35 25 35 37 37 43 12 Violazione proprietà di heap 13 12 35 35 12 13 21 13 12 12 43 21 35 25 37 13 43 35 36 Priority Queue con Binary Heap: estrazione minimo Priority Queue con Binary Heap: estrazione minimo Minimo = 13 21 25 37 43 Minimo = 13 13 13 35 21 43 25 37 21 35 43 25 35 37 Violazione proprietà di heap 37 38 Priority Queue con Binary Heap: estrazione minimo 43 Minimo = 13 13 21 25 37 21 35 43 25 Priority Queue con Binary Heap: estrazione minimo 35 21 37 25 Violazione proprietà di heap 37 21 43 25 43 Minimo = 13 13 21 35 43 25 37 Violazione proprietà di heap 21 35 43 37 25 39 37 35 21 35 25 43 35 37 40 Priority Queue con Binary Heap: cambio chiave Cambio da 21 a 11 Interval Partitioning: Analisi Algoritmo Greedy Osservazione. L’algoritmo greedy non schedula mai due lezioni incompatibili nella stessa aula. 13 13 11 21 Teorema. L’algoritmo greedy è ottimale. Prova. Sia d = numero aule allocate dall’algoritmo greedy. Aula d è allocata perchè si deve schedulare un job, diciamo j, che è incompatibile con le altre d-1 aule. Dato l’ordinamento rispetto al tempo di inizio, tutte le incompatibiità sono dovute a lezioni che iniziano prima di sj. Quindi, ci sono d lezioni con intersezione al tempo sj + ε. Profondità almeno d. Tutte le schedulazioni necessitano di un numero di aule ≥ d. ▪ 35 25 25 35 37 43 37 43 Violazione proprietà di heap 11 13 25 37 35 43 41 42 Schedulazione per minimizzare ritardo 4.2 Scheduling to Minimize Lateness Problema minimizzazione ritardo. Una singola risorsa processa un job alla volta. Job j richiede tj unità di tempo e deve terminare al tempo dj. Se j inizia al tempo sj, finisce al tempo fj = sj + tj. Ritardo: j = max { 0, fj - dj }. Obiettivo: schedulare tutti job per minimizzare massimo ritardo L = max j. 44 Schedulazione per minimizzare ritardo Schedulazione per minimizzare ritardo: Algoritmi greedy Problema minimizzazione ritardo. Una singola risorsa processa un job alla volta. Job j richiede tj unità di tempo ed deve terminare al tempo dj. Se j inizia al tempo sj, finisce al tempo fj = sj + tj. Ritardo: j = max { 0, fj - dj }. Obiettivo: schedulare tutti job per minimizzare massimo ritardo L = max j. Metodo Greedy. Considera job in qualche ordine. [Minimo tempo di processamento] Considera job in ordine crescente di tempo di processamento tj. [Minima deadline] Considera job in ordine crescente di deadline dj. Esempio: 1 2 3 4 5 tj 3 2 1 4 3 6 2 dj 6 8 9 9 14 15 ritardo = 2 d3 = 9 0 d2 = 8 1 2 d6 = 15 3 4 d1 = 6 5 6 ritardo = 0 max ritardo = 6 d5 = 14 7 8 9 [Slack minimo] Considera job in ordine crescente di tempo di slack dj - tj. 10 d4 = 9 11 12 13 14 15 45 46 Minimizzare Ritardo: Greedy Algorithms Minimizzare Ritardo: Greedy Algorithms Metodo Greedy. Considera job in qualche ordine. Metodo Greedy. Considera job in qualche ordine. [Minimo tempo di processamento] Considera job in ordine crescente di tempo di processamento tj. 1 2 tj 1 10 dj 100 10 ritardo = 0 2 tj 1 10 dj 2 10 ritardo = 0 d2 = 10 scelta greedy d2 = 10 1 d2 = 10 ritardo = 0 d1 = 100 10 10 ritardo = 0 ottimo d1 = 2 11 0 47 controesempio ritardo = 9 d1 = 2 0 11 ritardo = 0 0 controesempio 1 ritardo = 1 d1 = 100 0 [Slack minimo] Considera job in ordine crescente di tempo di slack dj - tj. scelta greedy 11 ritardo = 1 ottimo d2 = 10 1 11 48 Minimizzare Ritardo: Greedy Algorithm Minimizzare Ritardo: Greedy Algorithm Greedy algorithm. Minima deadline. Greedy algorithm. Minima deadline. Ordina n job per deadline d1 ≤ d2 ≤ … ≤ dn Ordina n job per deadline d1 ≤ d2 ≤ … ≤ dn t ← 0 for j = 1 to n Assegna job j all intervallo [t, t + tj] sj ← t, fj ← t + tj t ← t + tj output intervalli [sj, fj] t ← 0 for j = 1 to n Assegna job j all intervallo [t, t + tj] sj ← t, fj ← t + tj t ← t + tj output intervalli [sj, fj] tempo fine job assegnati Esempio: 1 2 3 4 5 tj 3 2 1 4 3 6 2 dj 6 8 9 9 14 15 max ritardo = 1 d1 = 6 0 1 2 d2 = 8 3 4 d3 = 9 5 6 d4 = 9 7 8 d5 = 14 9 10 11 12 d6 = 15 13 14 49 Minimizzare Ritardo: Nessun tempo inattivo d=4 1 d=6 2 3 2 3 d=4 0 1 4 6 5 6 d=6 4 Exchange argument. Consideriamo una schedulazione ottimale Modifichiamola gradualmente, preservando l’ottimalità ad ogni passo L’ultima schedulazione modificata è quella greedy d = 12 5 7 50 Minimizzare Ritardo: Ottimalità Greedy Algorithm Osservazione. Vi è una schedulazione ottimale senza tempi inattivi. 0 15 8 9 10 11 8 9 10 11 d = 12 7 Osservazione. La schedulazione greedy non ha tempi inattivi. 51 52 Minimizzare Ritardo: Inversions Minimizzare Ritardo: Inversioni Definizione. Una inversione nella schedulazione S è una coppia di job i e j tale che: i < j ma j è schedulato prima di i. Definizione. Una inversione nella schedulazione S è una coppia di job i e j tale che: i < j ma j è schedulato prima di i. inversione inversione j prima dello scambio i dopo lo scambio j fi i i j f'j Osservazione. La schedulazione greedy non ha inversioni. Claim. Scambiando due job adiacenti ed invertiti, riduce il numero di inversioni di 1 e non incrementa il ritardo massimo. Osservazione. Se una schedulazione (senza tempi inattivi) ha una inversione, allora ne ha una con job invertiti schedulati consecutivamente. Prova. Sia il ritardo prima dello scambio, e sia ' dopo lo scambio. 'k = k per tutti k ≠ i, j 'i ≤ i ' j = f!j - d j (definizione) Se job j è in ritardo: = f -d (j finisce al tempo f ) ricorda: j = max {0,fj-dj} i j i ≤ fi - d i (i < j) ≤ i (definizione) 53 Minimizzare Ritardo: Analisi Algoritmo Greedy 54 Metodi per mostrare correttezza algoritmi greedy Teorema. La schedulazione greedy S è ottimale. L algoritmo greedy è sempre in vantaggio. Mostrare che dopo ogni passo dell algoritmo greedy, la sua soluzione è almeno tanto buona come quella Prova. Definiamo S* come una schedulazione ottimale con il minimo numero di inversioni. Possiamo assumere che S* non ha tempi inattivi. Se S* non ha inversioni, allora S = S*. Se S* ha almeno una inversione, sia i-j una inversione adiacente. – scambiando i e j non incrementiamo il ritardo massimo e diminuiamo il numero di inversioni. – questo contraddice la definizione di S* ▪ di ogni altro algoritmo. Argomento di scambio (Exchange argument). Trasformare gradualmente una soluzione ottima a quella dell’algoritmo greedy lasciando il suo valore ottimo. Strutturale. Trovare un semplice limite strutturale che ogni soluzione deve rispettare. Mostrare poi che l’algoritmo greedy raggiunge sempre quel limite. 55 56 Caching offline ottimale 4.3 Optimal Caching Caching. Cache con capacità di memorizzare k elementi. Sequenza di m richieste di elementi d1, d2, …, dm. Cache hit: elemento già nella cache quando richiesto. Cache miss: elemento non nella cache quando richiesto: è necessario portarlo nella cache e rimuovere un altro elemento (se la cache è piena). Obiettivo. Schedulazione rimozioni che minimizzano il numero di cache miss. Esempio: k = 2, cache all’inizio = ab, richieste: a, b, c, b, c, a, a, b. Scedulazione ottimale rimozione: 2 cache miss a a b a a b b a b b a b c c b c a c b c b b a b c c b c c b a a b a a b a a b a a b b a b b a b richieste cache 58 Caching offline ottimale: Farthest-In-Future Farthest-in-future. Rimuovere elemento nella cache che sarà richiesto il più tardi possibile nel futuro. occupazione cache: richieste future: a b c d e 4.4 Shortest Paths in a Graph f g a b c e d a b b a c d e a f a d e f g h ... cache miss rimuovere elemento f dalla cache Cammino minimo dal campus Fisciano alla stazione ferroviaria di Salerno Teorema. Farthest-In-Future è una schedulazione ottimale delle rimozioni. Prova. L’algoritmo ed il teorema sono intuitivi. Ma la prova non è immediata, richiede attenzione e comporta una distinzione di casi. La trovate nel libro. [L. Belady. A study of replacement algorithms for virtual storage computers. IBM Systems Journal 5 (1966), 78-101.] ©2009 Google - Immagini ©2009 DigitalGlobe, Cnes/Spot Image, GeoEye, European Space Imaging, Map data ©2009 Tele Atlas - Indicazioni stradali per Piazza Vittorio Veneto 14,5 km – circa 22 min 59 Problema cammino minimo Algoritmo di Dijkstra Dati input: Grafo diretto G = (V, E). Algoritmo di Dijkstra. Mantenere l’insieme dei nodi esplorati S per i quali abbiamo Sorgente s, destinazione t. e = lunghezza arco e. determinato le distanze dei cammini minimi d(u) da s ad u. Inizializzare S = { s }, d(s) = 0. Ripetutamente scegliere un nodo non esplorato v che minimizza Problema del cammino minimo: trovare cammino minimo diretto da s a t. π (v ) = costo cammino = somma costi archi del cammino 24 2 9 s 30 aggiungere v a S, e porre d(v) = π(v). Costo cammino s-2-3-5-t = 9 + 24 + 2 + 16 = 51. e d(u) Cammino minimo a qualche u nella parte esplorata, seguito da un singolo arco (u, v) v u S s 6 16 20 19 4 11 5 5 7 6 2 6 15 d (u ) + e , 3 18 14 min e = (u , v ) : u ∈ S t 44 61 Algoritmo di Dijkstra 62 Algoritmo di Dijkstra Algoritmo di Dijkstra. Mantenere l’insieme dei nodi esplorati S per i quali abbiamo determinato le distanze dei cammini minimi d(u) da s ad u. Inizializzare S = { s }, d(s) = 0. Ripetutamente scegliere un nodo non esplorato v che minimizza π (v ) = min e = (u , v ) : u ∈ S d (u ) + e , aggiungere v a S, e porre d(v) = π(v). d(u) e π (v ) = min e = (u , v ) : u ∈ S d (u ) + e , Cammino minimo a qualche u nella parte esplorata, seguito da un singolo arco (u, v) v u S s 63 64 Algoritmo di Dijkstra: Prova di correttezza Algoritmo di Dijkstra: Implementazione Invariante. Per ogni nodo u ∈ S, d(u) è la lunghezza del cammino minimo s-u. Per ogni nodo non ancora esplorato, calcola Prova. (per induzione su |S|) Caso base: |S| = 1 è banale. Ipotesi induttiva: Assumiamo vera per |S| = k ≥ 1. min e = (u,v) : u ∈ S d (u) + e . Prossimo nodo da esplorare = nodo con minimo π(v). Quando esploriamo v, per ogni arco incidente e = (v, w), aggiorna π (w) = min { π (w), π € (v) + e }. Sia v il prossimo nodo aggiunto ad S, e sia u-v l’arco scelto. π (v) = Il cammino minimo s-u più (u, v) è un cammino minimo s-v di lunghezza π(v). Sia P un cammino minimo s-v. Vediamo che non è più corto di π(v). Sia x-y il primo arco in P che lascia S, e sia P' il cammino da s a x (parte di P). P' u S v (P) ≥ (P') + (x,y) ≥ d(x) + (x, y) ≥ π(y) ≥ π(v) pesi non negativi ipotesi induttiva (P’) ≥ d(x) € y x s P è già troppo lungo appena lascia S. P definizione di π(y) Dijkstra sceglie v invece di y 65 66 Coda a priorità Algoritmo di Dijkstra: Implementazione Implementazioni: Per ogni nodo non ancora esplorato, calcola π (v) = 5 min 14 89 32 30 24 15 6 . . . . . 24 28 15 10 9 17 81 19 13 d (u) + e . Prossimo nodo da esplorare = nodo con minimo π(v). Quando esploriamo v, per ogni arco incidente e = (v, w), aggiorna €+ }. π (w) = min { π (w), π (v) e 31 11 min e = (u,v) : u ∈ S Implementazione efficiente. Mantenere una coda a priorità dei nodi non esplorati, sul campo π(v). ∅ € Head Priority Queue Operazione PQ Lista ordinata Lista non ordinata (a puntatori) (array) Binary heap Operazione PQ Dijkstra Array Binary heap Insert O(n) O(1) O(log n) Insert n n log n Min O(1) O(n) O(1) ExtractMin n 1 log n ExtractMin O(1) O(n) O(log n) ChangeKey m n log n ChangeKey O(n) O(1) O(log n) IsEmpty n 1 1 IsEmpty O(1) O(1) O(1) Total n2 m log n 67 68 Algoritmo di Dijkstra Algoritmo di Dijkstra Trovare cammino minimo da s a t. S={ } PQ = { s, 2, 3, 4, 5, 6, 7, t } ∞ ∞ 24 2 9 s 3 0 s 18 14 6 30 15 11 5 5 30 ∞ 11 5 5 6 16 t 7 distance label ∞ 4 19 6 16 20 44 6 2 19 15 20 7 ∞ 6 4 3 18 14 6 2 24 2 9 t 44 ∞ ∞ 69 70 Algoritmo di Dijkstra Algoritmo di Dijkstra S={ } PQ = { s, 2, 3, 4, 5, 6, 7, t } S={s} PQ = { 2, 3, 4, 5, 6, 7, t } decrease key minimo ∞ ∞ 0 s 24 2 9 ∞ 0 s 30 15 ∞ 11 5 5 7 ∞ 30 19 16 44 ∞ 11 5 5 6 16 20 t 7 distance label ∞ 71 ∞ 15 X 6 2 6 ∞ 4 3 18 X ∞ 14 14 15 20 24 2 9 6 2 6 distance label 3 18 14 ∞ ∞ 9 X 44 ∞ 4 19 6 t ∞ 72 Algoritmo di Dijkstra Algoritmo di Dijkstra S={s} PQ = { 2, 3, 4, 5, 6, 7, t } S = { s, 2 } PQ = { 3, 4, 5, 6, 7, t } minimo ∞ ∞ X 9 0 s 24 2 9 30 ∞ 11 5 5 30 ∞ 11 5 5 6 t 7 ∞ ∞ 15 X ∞ 4 19 6 16 20 44 6 2 6 19 3 18 X ∞ 14 14 ∞ 4 16 7 24 2 9 15 20 distance label 0 s 6 2 6 15 3 18 X ∞ 14 14 ∞ ∞ X 9 t 44 ∞ ∞ 15 X 73 74 Algoritmo di Dijkstra Algoritmo di Dijkstra S = { s, 2 } PQ = { 3, 4, 5, 6, 7, t } S = { s, 2 } PQ = { 3, 4, 5, 6, 7, t } decrease key ∞ 33 X ∞ X 9 0 s 24 2 9 30 ∞ 11 5 5 16 ∞ 15 X 44 24 2 9 18 X ∞ 14 14 30 19 ∞ 11 5 5 6 16 20 t 7 ∞ ∞ 15 X 75 6 2 6 ∞ 4 3 minimo 15 20 7 0 s 6 2 6 15 3 18 X ∞ 14 14 ∞ 33 X ∞ X 9 44 ∞ 4 19 6 t ∞ 76 Algoritmo di Dijkstra Dijkstra's Shortest Path Algorithm S = { s, 2, 6 } PQ = { 3, 4, 5, 7, t } S = { s, 2, 6 } PQ = { 3, 4, 5, 7, t } ∞ X 9 0 s 24 2 9 ∞ X 9 3 0 s 30 44 X ∞ ∞ 11 5 5 30 19 44 X ∞ ∞ 11 5 5 6 16 t 7 ∞ ∞ 15 X 4 19 6 16 20 44 6 2 6 4 3 18 X ∞ 14 14 15 20 7 24 2 9 6 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 32 ∞ 33 X X t 44 minimo ∞ 15 X ∞ 77 78 Dijkstra's Shortest Path Algorithm Dijkstra's Shortest Path Algorithm S = { s, 2, 6, 7 } PQ = { 3, 4, 5, t } S = { s, 2, 6, 7 } PQ = { 3, 4, 5, t } ∞ X 9 0 s 24 2 9 30 X 35 44 X ∞ 5 5 ∞ 15 X ∞ X 9 0 s 11 30 19 16 44 X 35 44 X ∞ 5 5 6 t 7 ∞ 15 X 79 ∞ 11 16 20 ∞ 59 X 6 2 6 4 3 18 X ∞ 14 14 6 ∞ 24 2 9 15 20 7 32 ∞ 33 X X 3 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 minimo 44 4 19 6 t ∞ 59 X 80 Dijkstra's Shortest Path Algorithm Algoritmo di Dijkstra S = { s, 2, 3, 6, 7 } PQ = { 4, 5, t } S = { s, 2, 3, 6, 7 } PQ = { 4, 5, t } ∞ X 9 0 s 24 2 9 ∞ X 9 3 0 s 30 X 34 X 35 44 X ∞ 5 5 ∞ 11 30 19 20 t 44 ∞ 11 4 19 6 16 minimo 7 ∞ 51 59 X X ∞ 15 X X 34 X 35 44 X ∞ 5 5 6 16 6 2 6 4 3 18 X ∞ 14 14 15 20 7 24 2 9 6 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 32 ∞ 33 X X t 44 ∞ 51 59 X X ∞ 15 X 81 82 Dijkstra's Shortest Path Algorithm Dijkstra's Shortest Path Algorithm S = { s, 2, 3, 5, 6, 7 } PQ = { 4, t } S = { s, 2, 3, 5, 6, 7 } PQ = { 4, t } ∞ X 9 0 s 24 2 9 30 X 34 X 35 44 X ∞ 5 5 ∞ 15 X 0 s 11 30 19 16 44 X 34 X 35 44 X ∞ 5 5 6 t 7 ∞ 15 X 83 ∞ 45 X 11 16 20 ∞ 50 51 X 59 X X 6 2 6 4 3 18 X ∞ 14 14 6 ∞ 45 X 24 2 9 15 20 7 ∞ X 9 3 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 32 ∞ 33 X X 44 4 19 minimo 6 t ∞ 50 51 X 59 X X 84 Dijkstra's Shortest Path Algorithm Dijkstra's Shortest Path Algorithm S = { s, 2, 3, 4, 5, 6, 7 } PQ = { t } S = { s, 2, 3, 4, 5, 6, 7 } PQ = { t } ∞ X 9 0 s 24 2 9 ∞ X 9 3 0 s 30 X 34 X 35 44 X ∞ 5 5 ∞ 45 X 11 X 34 X 35 44 X ∞ 5 5 6 16 7 30 19 t 7 ∞ 50 51 X 59 X X ∞ 15 X ∞ 45 X 11 4 19 6 16 20 44 6 2 6 4 3 18 X ∞ 14 14 15 20 24 2 9 6 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 32 ∞ 33 X X t 44 minimo ∞ 15 X ∞ 50 51 X 59 X X 85 86 Algoritmo di Dijkstra Algoritmo di Dijkstra S = { s, 2, 3, 4, 5, 6, 7, t } PQ = { } S = { s, 2, 3, 4, 5, 6, 7, t } PQ = { } ∞ X 9 0 s 24 2 9 30 X 34 X 35 44 X ∞ 5 5 ∞ 15 X 0 s 11 30 19 16 44 X 34 X 35 44 X ∞ 5 5 6 t 7 ∞ 15 X 87 ∞ 45 X 11 16 20 ∞ 50 51 X 59 X X 6 2 6 4 3 18 X ∞ 14 14 6 ∞ 45 X 24 2 9 15 20 7 ∞ X 9 3 2 6 15 32 ∞ 33 X X 18 X ∞ 14 14 32 ∞ 33 X X 44 4 19 6 t ∞ 50 51 X 59 X X 88 Edsger Wybe Dijkstra 4.5 Minimum Spanning Tree Rotterdam, 11 maggio 1930 – Nuenen, 6 agosto 2002 A note on two problems in connection with graphs Numerische Matematik, vol. 1, 1959, pp. 269-271 89 Minimum Spanning Tree Minimum Spanning Tree Abbiamo un insieme di locazioni e vogliamo costruire una rete di comunicazione tra loro: Dato un grafo connesso G = (V, E) con pesi a valori reali ce>0 sugli archi, trovare un insieme di archi T ⊆ E tale che il grafo (V,T) è connesso e la rete connessa: ci deve essere un cammino tra ogni coppia economicità: costo totale più basso possibile somma dei pesi degli archi in T è minimizzata. 24 4 23 6 16 18 5 9 14 10 9 6 5 11 8 7 24 4 4 8 6 11 16 7 18 5 9 14 9 6 5 11 8 10 21 4 23 7 8 11 7 21 Costo totale 50 G = (V, E) 91 T, Σe∈T ce = 50 92 Minimum Spanning Tree Minimum Spanning Tree (MST) Dato un grafo connesso G = (V, E) con pesi a valori reali ce>0 sugli archi, trovare un insieme di archi T ⊆ E tale che il grafo (V,T) è connesso e la Minimum spanning tree. Dato un grafo connesso G = (V, E) con pesi a valori reali ce sugli archi, un MST è un sottoinsieme degli archi T ⊆ E somma dei pesi degli archi in T è minimizzata. 24 4 16 18 5 9 14 10 9 6 5 11 8 7 24 4 4 23 6 tale che T è uno spanning tree la cui somma dei pesi sugli archi è minimizzata. 8 6 11 16 7 18 5 9 14 9 6 5 11 8 10 21 4 23 7 8 11 7 21 G = (V, E) G = (V, E) T, Σe∈T ce = 50 Lemma. Sia T la soluzione. Allora (V,T) è un albero. Prova. (V,T) è connesso. Facciamo vedere che non ha cicli. Per assurdo: se ci fosse un ciclo, prendiamo un arco in tale ciclo. Il grafo (V,T-{e}) è ancora connesso ed ha costo minore. Contraddizione. T, Σe∈T ce = 50 Teorema di Cayley. Ci sono nn-2 spanning tree di Kn. non si può risolvere con brute force 93 94 Applicazioni Algoritmi Greedy MST è un problema fondamentale con svariate applicazioni. Algoritmo di Kruskal. Inizia con T = φ. Network design. – telephone, electrical, hydraulic, TV cable, computer, road Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. Approximation algorithms for NP-hard problems. – traveling salesperson problem, Steiner tree Algoritmo di Reverse-Delete. Inizia con T = E. Considera archi in ordine decrescente di costo. Cancella l’arco da T se non disconnette T. Indirect applications. – max bottleneck paths – LDPC codes for error correction – image registration with Renyi entropy – learning salient features for real-time face verification – reducing data storage in sequencing amino acids in a protein – model locality of particle interactions in turbulent fluid flows – autoconfig protocol for Ethernet bridging to avoid cycles in a network Algoritmo di Prim. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. Nota bene. Tutti e tre gli algoritmi producono un MST. Cluster analysis. 95 96 Algoritmi di Prim e di Kruskal Algoritmo di Prim Algoritmo di Prim. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con il costo minimo. Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T=φ 24 2 9 s 3 18 14 30 15 11 5 5 Algoritmo di Kruskal. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. 6 2 6 4 19 7 16 20 7 t 44 97 98 Algoritmo di Prim Algoritmo di Prim Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T = { {s,2} } Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T = { {s,2}, {s,6} } 24 2 9 s 3 s 18 14 30 15 11 5 5 16 20 7 30 19 15 44 11 5 5 7 16 20 t 7 99 6 2 6 4 3 18 14 6 2 6 24 2 9 44 4 19 7 t 100 Algoritmo di Prim Algoritmo di Prim Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T = { {s,2}, {s,6}, {6,7} } T = { {s,2}, {s,6}, {6,7}, {6,3} } 24 2 9 s 3 s 30 11 5 5 11 5 5 7 16 20 7 30 19 15 t 4 19 7 16 20 44 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 15 Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. 7 t 44 101 102 Algoritmo di Prim Algoritmo di Prim Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T = { {s,2}, {s,6}, {6,7}, {6,3}, {3,5} } T = { {s,2}, {s,6}, {6,7}, {6,3}, {3,5}, {3,4} } 24 2 9 s 3 s 30 11 5 5 16 20 7 30 19 15 44 11 5 5 7 16 20 t 7 103 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 15 Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. 44 4 19 7 t 104 Algoritmo di Prim Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ e con un nodo radice s. Trovare Minimo Spanning Tree. Inizia con T = φ. Aggiungi arco a T che è incidente solo su un nodo in T e con costo minimo. T = { {s,2}, {s,6}, {6,7}, {6,3}, {3,5}, {3,4}, {4,t} } Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T=φ 24 2 9 s 3 s 18 14 30 15 11 5 5 11 5 5 7 16 20 7 30 19 15 t 4 19 7 16 20 44 6 2 6 4 3 18 14 6 2 6 24 2 9 7 t 44 105 106 Algoritmo di Kruskal Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ. Trovare Minimo Spanning Tree. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5} } Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5}, {6,7} } 24 2 9 s 3 s 18 14 30 15 11 5 5 16 20 7 30 19 15 44 11 5 5 7 16 20 t 7 107 6 2 6 4 3 18 14 6 2 6 24 2 9 44 4 19 7 t 108 Algoritmo di Kruskal Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ. Trovare Minimo Spanning Tree. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5}, {6,7}, {3,4} } T = { {3,5}, {6,7}, {3,4}, {4,t} } 24 2 9 s 3 s 30 11 5 5 11 5 5 7 16 20 7 30 19 15 t 4 19 7 16 20 44 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 15 Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. 7 t 44 109 110 Algoritmo di Kruskal Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ. Trovare Minimo Spanning Tree. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2} } T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2} } 24 2 9 s 3 s 30 11 5 5 16 20 7 30 19 15 44 11 5 5 7 16 20 t 7 111 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 15 Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. 44 4 19 7 t 112 Algoritmo di Kruskal Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ. Trovare Minimo Spanning Tree. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2}, {s,6} } T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2}, {s,6} } 24 2 9 s 3 s 30 15 11 5 5 11 5 5 7 16 20 7 30 19 15 t 4 19 7 16 20 44 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. 7 t 44 113 114 Algoritmo di Kruskal Algoritmo di Kruskal Trovare Minimo Spanning Tree. Inizia con T = φ. Trovare Minimo Spanning Tree. Inizia con T = φ. Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2}, {s,6} } T = { {3,5}, {6,7}, {3,4}, {4,t}, {s,2}, {s,6}, {3,6} } 24 2 9 s 3 s 30 15 11 5 5 16 20 7 30 19 15 44 11 5 5 7 16 20 t 7 115 6 2 6 4 3 18 14 6 2 6 24 2 9 18 14 Considera archi in ordine crescente di costo. Inserisci l’arco in T se non crea un ciclo. 44 4 19 7 t 116 Algoritmi Greedy Cicli e tagli Assunzione per semplificare. Tutti i costi degli archi ce sono distinti. Ciclo. Insieme di archi della forma a-b, b-c, c-d, …, y-z, z-a. Proprietà di taglio. Sia S un sottoinsieme di nodi, e sia e l’arco con il minimo costo che è incidente su esattamente un nodo in S. Allora l’MST contiene e. 1 2 3 6 4 Ciclo C = 1-2, 2-3, 3-4, 4-5, 5-6, 6-1 5 Proprietà del ciclo. Sia C un ciclo, e sia f l’arco con il massimo costo in C. Allora l’MST non contiene f. f S 8 7 Cutset (Insieme di taglio). Un cut (taglio) è un insieme di nodi S. L’insieme di taglio corrispondente D è il sottoinsieme di archi che sono incidenti su esattamente un nodo in S. C e 1 2 3 6 e è nell’MST Cut S = { 4, 5, 8 } Cutset D = 5-6, 5-7, 3-4, 3-5, 7-8 4 5 f non è nell’MST 7 8 117 118 Intersezione Ciclo-Taglio Algoritmi Greedy Claim. Un ciclo ed un cutset si intersecano in un numero pari di archi. 2 1 3 6 4 Assunzione per semplificare. Tutti i costi degli archi ce sono distinti. Proprietà del taglio. Sia S un sottoinsieme di nodi e sia e l’arco di costo minimo che incide su esattamente un nodo in S. Allora l’MST T* contiene e. Ciclo C = 1-2, 2-3, 3-4, 4-5, 5-6, 6-1 Cutset D = 3-4, 3-5, 5-6, 5-7, 7-8 Intersezione = 3-4, 5-6 5 Prova. (per assurdo, usando una argomentazione di scambio) Supponiamo che e non appartiene a T*. Aggiungere e a T* crea un ciclo C in T*. L’arco e è sia nel ciclo C e nel cutset D corrispondente ad S ⇒ esiste un altro arco, diciamo f, che è sia in C che in D. 8 7 Prova. C S f S V-S e 119 T* 120 Algoritmi Greedy Algoritmi greedy Assunzione per semplificare. Tutti i costi degli archi ce sono distinti. Assunzione per semplifare. Tutti i costi degli archi ce sono distinti. Proprietà del taglio. Sia S un sottoinsieme di nodi e sia e l’arco di costo minimo che incide su esattamente un nodo in S. Allora l’MST T* contiene e. Proprietà del ciclo. Sia C un ciclo in G, e sia f l’arco di costo massimo in C. Allora l’MST T* non contiene f. Prova. (per assurdo, usando una argomentazione di scambio) Supponiamo che f sia in T*. La cancellazione di f da T* crea un taglio S in T*. L’arco f è sia nel ciclo C sia nel cutset D corrispondente ad S ⇒ esiste un altro arco, diciamo e, che è sia in C che in D. Prova. (per assurdo, usando una argomentazione di scambio) Supponiamo che e non appartiene a T*. Aggiungere e a T* crea un ciclo C in T*. L’arco e è sia nel ciclo C e nel cutset D corrispondente ad S ⇒ esiste un altro arco, diciamo f, che è sia in C che in D. T' = T* ∪ { e } - { f } è ancora uno spanning tree. Dato che ce < cf, cost(T') < cost(T*). f Questa è una contraddizione. ▪ f S S e e T* T* 121 Algoritmi greedy 122 Algoritmo di Prim: Prova di correttezza Assunzione per semplifare. Tutti i costi degli archi ce sono distinti. Algoritmo di Prim. [Jarník 1930, Dijkstra 1957, Prim 1959] Initializza S = un nodo qualsiasi. Proprietà del ciclo. Sia C un ciclo in G, e sia f l’arco di costo massimo in C. Allora l’MST T* non contiene f. Prova. (per assurdo, usando una argomentazione di scambio) Supponiamo che f sia in T*. La cancellazione di f da T* crea un taglio S in T*. L’arco f è sia nel ciclo C sia nel cutset D corrispondente ad S ⇒ esiste un altro arco, diciamo e, che è sia in C che in D. T' = T* ∪ { e } - { f } è ancora uno spanning tree. Dato che ce < cf, cost(T') < cost(T*). Questa è una contraddizione. Applica la proprietà del taglio ad S. Aggiungi l’arco di costo minimo nel cutset corrispondente ad S a T, ed aggiungi un nuovo nodo esplorato u ad S. S f S e T* 123 124 Algoritmo di Prim: implementazione Algoritmo di Kruskal: Prova di correttezza Implementazione. Usare Coda a Priorità. Mantenere insieme di nodi esplorati S. Algoritmo di Kruskal. [Kruskal, 1956] Considera archi in ordine crescente di peso. Per ogni nodo non esplorato v, mantenere a[v] = costo minimo di un cammino per v con nodi in S. O(n2) con un array; O(m log n) con un binary heap. Prim(G, c) { foreach (v Initialize foreach (v Initialize Caso 1: Se l’aggiunta di e a T crea un ciclo, ignora e. Caso 2: Altrimenti, inserisci e = (u, v) in T (proprietà del taglio dove S = insieme di nodi nella componente connessa di u). ∈ V) a[v] ← ∞ an empty priority queue Q ∈ V) insert v onto Q set of explored nodes S ← φ v while (Q is not empty) { u ← delete min element from Q S ← S ∪ { u } foreach (edge e = (u, v) incident to u) if ((v ∉ S) and (ce < a[v])) decrease priority a[v] to ce e u Case 2 Case 1 } S e 125 126 Algoritmo di Kruskal: implementazione Lexicographic Tiebreaking Implementazione. Usa la struttura dati union-find. Costruisci insieme T di archi nel MST. Per rimuovere l’assunzione che tutti gli archi hanno costi distinti: perturba tutti i costi di piccolissime quantità per evitare lo stesso Mantenere insieme per ogni componente connessa. O(m log n) per ordinamento e O(m α(m, n)) per union-find. m ≤ n2 ⇒ log m è O(log n) costo. Impatto. Kruskal e Prim effettuano solo confronti tra costi. Se le perturbazioni sono molto piccole, l’MST con i costi perturbati è l’MST con i costi originali. essenzialmente una costante Kruskal(G, c) { Sort edges weights so that c1 ≤ c2 ≤ ... ≤ cm. T ← φ e.g., se tutti i costi fossero interi, perturba il costo di ei di i / n2 Implementazione. Possiamo gestire perturbazioni arbitrariamente piccole in modo implicito: lessicograficamente, secondo gli indici. foreach (u ∈ V) costruisci insieme con solo u Sono u e v in componenti connesse diverse? for i = 1 to m (u,v) = ei if (u e v sono in insiemi diversi) { T ← T ∪ {ei} merge insiemi contenenti u e v } merge due componenti connesse return T boolean less(i, j) { if (cost(ei) < cost(ej)) else if (cost(ei) > cost(ej)) else if (i < j) else } } 127 return return return return true false true false 128 Esercizio 8 pag. 192 4.8 Huffman Codes and Data Compression Sia G un grafo connesso in cui tutti gli archi hanno costi distinti. Allora G ha un unico MST. Prova. (per assurdo, usando una argomentazione di scambio) Supponiamo che G abbia due spanning tree minimi diversi: T1 e T2. Sia e l’arco di minimo costo che si trova in uno dei due spanning tree e non nell’altro. Supponiamo che l’arco e sia in T1 ma non in T2. Aggiungere l’arco e a T2 crea un ciclo C. Vi deve essere almeno un arco nel ciclo C che non è in T1. (Altrimenti T1 conterrebbe un ciclo). Sia f tale arco. T2' = T2 ∪ { e } - { f } è ancora uno spanning tree. Dato che ce < cf, cost(T2') < cost(T2). Questa è una contraddizione della minimalità di T2. 129 Codifica simboli usando bit Codice Morse Codifica di 32 caratteri: 26 lettere, spazio, ed i cinque simboli , . ?!’ 5 bit per un totale di 25=32 simboli 00000 a 00001 b … I simboli hanno diverse frequenze di occorrenza “e” occorre più frequentemente di “q” Samuel Finley Breese Morse (Apr. 27, 1791-Apr. 2. 1872) italiano 131 132 Codici Compressione Dati Spesso è importante trovare un modo efficiente per rappresentare i dati, cercando di minimizzare il numero di bit usati carattere a b c d e f si occupa meno spazio in memoria si risparmia sul tempo di trasferimento Frequenza su 100 45 13 12 16 9 5 Lunghezza fissa 000 001 010 011 100 101 100 101 111 1101 1100 Lunghezza variabile 0 Codice a lunghezza fissa (Tutti i caratteri sono codificati con lo stesso numero di bit) per 100.000 caratteri servono 300.000 bit Codice a lunghezza variabile (I caratteri sono codificati con un numero variabile di bit) per 100.000 caratteri servono solo 45.000x1 + 13.000x3 + 12.000x3 + 16.000x3 + 9.000x4 + 5.000x4 = 224.000 bit 133 134 Codifica e decodifica Codifica e decodifica carattere a b c d e f carattere a b c d e f Frequenza su 100 45 13 12 16 9 5 Frequenza su 100 45 13 12 16 9 5 Lunghezza fissa 000 001 010 011 100 101 Lunghezza fissa 000 001 010 011 100 101 100 101 111 1101 1100 Lunghezza variabile 0 100 101 111 1101 1100 Lunghezza variabile 0 Codice a lunghezza fissa: aac… Codice a lunghezza fissa: 000000010… Codice a lunghezza variabile: aac… 000000010… aac… Codice a lunghezza variabile: 00101… aac… Codice prefisso: nessuna parola codice è prefisso di altra parola codice 00101… 135 136 Codifica e decodifica Codifica e decodifica carattere a b c d e f carattere a b c d e f Frequenza su 100 45 13 12 16 9 5 Frequenza su 100 45 13 12 16 9 5 Lunghezza fissa 000 001 010 011 100 101 Lunghezza fissa 000 001 010 011 100 101 100 101 111 1101 1100 Lunghezza variabile 0 100 101 111 1101 1100 Lunghezza variabile 0 Codice a lunghezza fissa: aac… Codice a lunghezza variabile: aac… 000000010… Codice prefisso: nessuna parola codice è prefisso di altra parola codice 00101… Decodifica codici prefisso: Scorrendo la stringa di bit, Codice a lunghezza variabile: aac… o si leggono bit in sequenza fino a che non troviamo una parola codice, Codice prefisso: nessuna parola codice è prefisso di altra parola codice 00101… o scriviamo il carattere corrispondente. Se avessimo codificato a 1 Come si decodifica 1101 ? ac e 137 138 Esercizio decodifica Alberi binari e codici prefissi I codici prefisso possono essere rappresentati come alberi binari. A B C D E 0 11 100 1010 1011 11010010010101011 A B C D E A B C D E 00 01 10 110 111 00 010 011 100 101 0 0 1 0 A Ogni foglia rappresenta un carattere 100100101010 1 0 B 0 1 C 1 D E Ogni arco sinistro è etichettato con 0, ed ogni arco destro è etichettato con 1 Parola codice di ogni foglia è la sequenza di etichette del percorso dalla radice 139 140 Alberi binari e codici prefissi Lunghezza codifica Abbiamo: un file composto da caratteri nell alfabeto S un albero T che rappresenta la codifica Quanti bit occorrono per codificare il file con T ? Per ogni x∈S, sia dT(x) la profondità in T della foglia che rappresenta x La parola codice per x è lunga dT(x) bit f(x) è il numero di volte che x occorre nel file. La dimensione del file codificato è ∑ f (x)d T (x) x∈S 141 142 € Codici Problema: trovare il codice prefisso ottimo carattere a b c d e f Frequenza su 100 45 13 12 16 9 5 Lunghezza fissa 000 001 010 011 100 101 100 101 111 1101 1100 Lunghezza variabile 0 Problema del codice prefisso ottimo: Dato un alfabeto S e le frequenze dei caratteri f(x), per x∈S, trovare il codice prefisso T che minimizza ∑ f (x)d T (x) albero x∈S ∑ f (x)d T € (x) x∈S 45x3 + 13x3 + 12x3 + 16x3 + 9x3 + 5x3 = 300.000 bit 45x1 + 13x3 + 12x3 + 16x3 + 9x4 + 5x4 = 224.000 bit 143 € 144 Problema: trovare il codice prefisso ottimo Domanda Potrebbe essere ottimo per un alfabeto S con 6 caratteri e frequenze f(x)>0, per x∈S ? Problema del codice prefisso ottimo: Dato un alfabeto S e le frequenze dei caratteri f(x), per x∈S, trovare il codice prefisso T che minimizza ∑ f (x)d T albero (x) x∈S Vediamo qualche proprietà del codice/albero ottimale € A 000 B 001 C 010 D 011 E 100 F 101 145 146 Domanda Proprietà: gli alberi ottimi sono pieni Potrebbe essere ottimo per un alfabeto S con 6 caratteri e frequenze f(x)>0, per x∈S ? No! A 000 A 000 B 001 B 001 C 010 C D 011 D E 100 F 101 inutile L’albero binario corrispondente ad un codice ottimo è pieno (full). Ovvero, ogni nodo interno ha due figli. A 000 A 000 B 001 B 001 010 C 010 C 010 011 D 011 D 011 E 10 E 100 E 10 F 11 F 101 F 11 E’ migliore! 147 inutile E’ migliore! 148 Domanda Domanda Potrebbe essere ottimo questo codice prefisso? frequenza Potrebbe essere ottimo questo codice prefisso? No! parola codice frequenza parola codice A 25 00 A 25 00 B 25 010 B 25 010 C 6 0110 C 6 0110 D 6 0111 D 6 0111 E 13 10 E 13 10 F 25 11 F 25 11 Guadagno in lunghezza scambio ∑ f (x)d T x∈S (x) − ∑ f (x)dT$ (x) x∈S (25x3 + 13x2) – (25x2 + 13x3) = (75+26)-(50+39) = 101-89 = 12 149 150 Proprietà: associazione caratteri con parole codice Proprietà: associazione caratteri con parole codice Teorema. Sia T un albero prefisso ottimale per l’alfabeto S con frequenze f(x), per x∈S. Se dT(x) > dT(y) allora f(x) ≤ f(y). Teorema. Sia S un alfabeto con frequenze f(x), per x∈S. Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T* in cui x,y corrispondono a foglie che sono fratelli. Prova. (per assurdo) Supponiamo che f(x) > f(y). Scambiamo le parole codice. Il guadagno in lunghezza è: dT(x) f(x) + dT(y) f(y) – dT(x) f(y) - dT(y) f(x) = (dT(x) - dT(y)) (f(x) – f(y)) > 0 Esempio frequenza frequenza parola codice parola codice A 25 00 B 25 010 x 6 0110 y 6 0111 E 13 10 F 25 11 A 25 00 x 25 010 C 6 0110 D 6 0111 y 13 10 F 25 11 y scambio x 151 x y 152 Proprietà: scelta greedy Proprietà: scelta greedy Teorema. Sia S un alfabeto S con frequenze f(x), per x∈S. Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice Teorema. Sia S un alfabeto S con frequenze f(x), per x∈S. Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T* in cui x,y corrispondono a foglie che sono fratelli. ottimale con albero T* in cui x,y corrispondono a foglie che sono fratelli. Prova. Sia T un albero che rappresenta un codice ottimo. Costruiamo un albero T* ancora ottimo ma con i caratteri x,y foglie figlie dello stesso padre z e a profondità massima in T*. Prova. Sia T un albero che rappresenta un codice ottimo. Costruiamo un albero T* ancora ottimo ma con i caratteri x,y foglie figlie dello stesso padre z e a profondità massima in T*. Assumiamo f(u) ≤ f(v). Quindi f(x) ≤ f(u) e f(y) ≤ f(v). Assumiamo f(u) ≤ f(v). Quindi f(x) ≤ f(u) e f(y) ≤ f(v). y x Scambiamo x ed u. Il guadagno in lunghezza è: dT(x) f(x) + dT(u) f(u) – dT(x) f(u) – dT(u) f(x) = (dT(x) – dT(u)) (f(x) – f(u)) > 0 z u y u v x z u v x 153 Proprietà: scelta greedy 154 Sottoproblema Teorema. Sia S un alfabeto S con frequenze f(x), per x∈S. Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T* in cui x,y corrispondono a foglie che sono fratelli. Prova. Sia T un albero che rappresenta un codice ottimo. Costruiamo un albero T* ancora ottimo ma con i caratteri x,y foglie figlie dello stesso padre z e a profondità massima in T*. Assumiamo f(u) ≤ f(v). Quindi f(x) ≤ f(u) e f(y) ≤ f(v). Scambiamo x ed u. Il guadagno in lunghezza è: dT(x) f(x) + dT(u) f(u) – dT(x) f(u) – dT(u) f(x) = (dT(x) – dT(u)) (f(x) – f(u)) > 0 Scambiamo y e v. Il guadagno in lunghezza è: dT(y) f(y) + dT(v) f(v) – dT(y) f(v) – dT(v) f(y) = (dT(y) – dT(v)) (f(y) – f(v)) > 0 y u x v z u v x y 155 156 Esempio F:5 Esempio E:9 C:12 B:13 D:16 A:45 C:12 B:13 D:16 A:45 F:5 E:9 157 158 Esempio Esempio C:12 B:13 D:16 A:45 C:12 B:13 14 D:16 A:45 F:5 E:9 14 F:5 E:9 159 160 Esempio 14 Esempio D:16 A:45 14 F:5 E:9 D:16 F:5 E:9 25 A:45 C:12 B:13 25 C:12 B:13 161 162 Esempio Esempio 25 A:45 25 C:12 B:13 C:12 B:13 14 D:16 F:5 E:9 30 14 A:45 30 D:16 F:5 E:9 163 164 Esempio A:45 Esempio 100 55 25 A:45 30 C:12 B:13 D:16 14 55 25 F:5 E:9 C:12 B:13 30 14 D:16 F:5 E:9 165 Esempio 166 Algoritmo di Huffman 100 0 1 A:45 55 0 frequenza parola codice A 45 0 B 13 101 C 12 100 D 16 111 E 9 1100 F 5 1101 1 25 0 30 1 0 C:12 B:13 D:16 14 0 1 1 F:5 E:9 167 168 Algoritmo di Huffman: implementazione Codici di Huffman: correttezza Huffman(A, n) { Inizializza coda a priorità vuota Q for i=1 to n { insert A[i] in Q } for i=1 to n-1 { x ← estrai elemento minimo da Q y ← estrai elemento minimo da Q Crea nuovo albero con radice z e frequenza f(x)+f(y) e figli x e y Insert z in Q } } Teorema: L’algoritmo di Huffman produce un codice prefisso ottimo Prova. Dato che l algoritmo è ricorsivo, la prova è per induzione sulla cardinalità dell alfabeto. L asserto è vero per k=2, cioè per un alfabeto con due simboli. Supponiamo che sia ottimale per tutti gli alfabeti con k-1 simboli. Mostreremo che è ottimale per gli alfabeti con k simboli. Ricordiamo: Teorema. Sia S un alfabeto con frequenze f(x). Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T in cui x,y corrispondono a foglie che sono fratelli. Operazione PQ Huffman Array Binary Heap Insert 2n-1 n log n ExtractMin 2n-1 n log n ChangeKey 0 1 log n IsEmpty 0 1 1 O(n2) O(n log n) Total Mostreremo che: ∑ f (x)d T' (x) = ∑ f (x)dT (x) − f (z) x∈S c∈S Mostreremo che se T non fosse ottimale allora T' x∈S 170 x’ €Prova. ∑ f (x)d T (x) = f (x')dT (x') + f (y')dT (y') + x∈S Teorema: L algoritmo di Huffman produce un codice prefisso ottimo Prova. z x∈S ∑ f (x)d T Dato che l algoritmo è ricorsivo, la prova è per induzione sulla cardinalità dell alfabeto. L asserto è vero per k=2, cioè per un alfabeto con due simboli. y’ Supponiamo che sia ottimale per tutti gli alfabeti con k-1 simboli. Mostreremo che è ottimale per gli alfabeti con k simboli. (x) Ricordiamo: Teorema. Sia S un alfabeto con frequenze f(x). Siano x≠x',y' = ( f (x') + f (y'))(1+ dT (z)) + x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T in cui x,y corrispondono a foglie che sono fratelli. ∑ f (x)dT ' (x) x≠x',y' = f (z)(1+ dT ' (z)) + Abbiamo visto che: x≠x',y' ∑ f (x)d T' (x) ∑ f (x)d T' x≠x',y' x∈S (x) = ∑ f (x)dT (x) − f (z) c∈S Mostreremo che se T non fosse ottimale allora = f (z) + ∑ f (x)dT ' (x) z x’ y’ non lo sarebbe neanche T ‘. x∈S 171 € T Sia T ‘ =T U {z} - {x’,y’} ∑ f (x)dT ' (x) = f (z) + f (z)dT ' (z) + y’ Codici di Huffman: correttezza T (x) = ∑ f (x)dT (x) − f (z) x’ € Codici di Huffman: sottostruttura ottima ∑ f (x)d z non lo sarebbe neanche T ‘. 169 Lemma: Sia T ‘ =T U {z} - {x’,y’}. T Sia T ’ =T U {z} - {x’,y’} € 172 Codici di Huffman: correttezza Esercizio Teorema: L algoritmo di Huffman produce un codice prefisso ottimo frequenza Prova. A 22 Dato che l algoritmo è ricorsivo, la prova è per induzione sulla cardinalità dell alfabeto. B 12 L asserto è vero per k=2, cioè per un alfabeto con due simboli. C 24 Supponiamo che sia ottimale per tutti gli alfabeti con k-1 simboli. Mostreremo che è ottimale per gli alfabeti con k simboli. Ricordiamo: Teorema. Sia S un alfabeto con frequenze f(x). Siano x,y∈S caratteri con le frequenze più basse, f(x) ≤ f(y). Allora esiste un codice ottimale con albero T in cui x,y corrispondono a foglie che sono fratelli. T Sia T ‘ =T U {z} - {x’,y’} Abbiamo visto che: ∑ f (x)d T' 6 E 27 F 9 z (x) = ∑ f (x)dT (x) − f (z) x∈S D parola codice c∈S Assumiamo T non ottimale. Sia T* ottimale della forma x’ ∑ f(x)d y’ T (x) = ? xεS Allora T* =T* U {z} - {x’,y’} sarebbe migliore di T ‘. Contraddizione. € 173 174 Esercizio frequenza parola codice A 22 00 B 12 100 C 24 01 D 6 1010 E 27 11 F 9 ∑ f(x)d 1011 T Articolo di Huffman 100 David A. Huffman, ”A method for the construction of minimum-redundancy codes”, Proceedings of the I.R.E., settembre 1952, pagg. 1098-1102 54 27 46 15 1098 PROCEEDINGS OF THE I.R.E. September 1952 Huffman: A Method for the Construction of Minimum-Redundancy Codes 1099 A Method for the Construction of Minimum-Redundancy Codes* DAVID A. HUFFMAN+, ASSOCIATE, IRE 22 12 24 6 27 9 A B C D E F (x) = 22⋅2 + 12⋅3 + 24 ⋅2 + 6⋅ 4 + 27 ⋅2 + 9 ⋅ 4 = 242 xεS 175 176 Cambio monete (Cambio monete) Coin Changing (Cambio monete) Obiettivo. Dati i valori delle monete U.S.A. : 1, 5, 10, 25, 100, trovare un metodo per pagare un fissato ammontare ad un cliente usando il numero minore di monete. Esempio: 34¢. Algoritmo del cassiere. Ad ogni iterazione, aggiungere moneta con il maggior valore che non supera l’ammontare da pagare. Esempio: $2.89. 178 Cambio monete: Algoritmo greedy Cambio monete: Analisi algoritmo greedy Algoritmo del cassiere. Ad ogni iterazione, aggiungere moneta di maggior valore che non supera l’ammontare da pagare. Teorema. Greedy è ottimale per il conio U.S.A. : 1, 5, 10, 25, 100. Prova. (induzione su x) Sort coins denominations by value: c1 < c2 < … < cn. monete selezionate S ← φ while (x ≠ 0) { sia k più grande intero tale che ck ≤ x if (k = 0) return soluzione non trovata" x ← x - ck S ← S ∪ {k} } return S Considera il modo ottimale per ck ≤ x < ck+1 : greedy sceglie moneta k. Ogni soluzione ottimale contiene la moneta k. – altrimenti, ci sarebbero monete di tipo c1, …, ck-1 che sommano ad x – nessuna soluzione ottimale può farlo, come si vede dalla tabella k ck Tutte le soluzioni ottimali soddisfano Massimo valore delle monete 1, 2, …, k-1 in una sol. ottimale 1 1 penny ≤ 4 - 2 5 nickel ≤ 1 4 3 10 nickel + dime ≤ 2 4+5=9 4 25 quarter ≤ 3 20 + 4 = 24 5 100 Senza limiti 75 + 24 = 99 5 ≤ x < 10 Al massimo • 4 penny 5 ≤Riduzione x < 10 al cambio di x - ck centesimi, che per induzione, è risolto in Se ci fossero 5 penny potrei migliorare con “1 nickel” L algoritmo del cassiere è ottimale? modo ottimale dall’algoritmo greedy. ▪ 179 180 Cambio monete: Analisi algoritmo greedy Cambio monete: Analisi algoritmo greedy Teorema. Greedy è ottimale per il conio U.S.A. : 1, 5, 10, 25, 100. Prova. (induzione su x) Teorema. Greedy è ottimale per il conio U.S.A. : 1, 5, 10, 25, 100. Prova. (induzione su x) Considera il modo ottimale per ck ≤ x < ck+1 : greedy sceglie moneta k. Ogni soluzione ottimale contiene la moneta k. – altrimenti, ci sarebbero monete di tipo c1, …, ck-1 che sommano ad x – nessuna soluzione ottimale può farlo, come si vede dalla tabella Considera il modo ottimale per ck ≤ x < ck+1 : greedy sceglie moneta k. Ogni soluzione ottimale contiene la moneta k. – altrimenti, ci sarebbero monete di tipo c1, …, ck-1 che sommano ad x – nessuna soluzione ottimale può farlo, come si vede dalla tabella k ck Tutte le soluzioni ottimali soddisfano Massimo valore delle monete 1, 2, …, k-1 in una sol. ottimale k ck Tutte le soluzioni ottimali soddisfano Massimo valore delle monete 1, 2, …, k-1 in una sol. ottimale 1 1 penny ≤ 4 - 1 1 penny ≤ 4 - 2 5 nickel ≤ 1 4 3 10 nickel + dime ≤ 2 4+5=9 4 25 quarter ≤ 3 20 + 4 = 24 5 100 Senza limiti 75 + 24 = 99 10 ≤ x < 25 Al massimo • 4 penny e • 1 nickel 10 ≤ x < 25 Riduzione al cambio di x - ck centesimi, che per induzione, è risolto in Se ci fossero 5 penny potrei migliorare con “1 nickel” modo ottimale dall’algoritmo greedy. ▪ Se ci fossero 2 nickel potrei migliorare con “1 dime” 2 5 nickel ≤ 1 4 3 10 nickel + dime ≤ 2 4+5=9 4 25 quarter ≤ 3 20 + 4 = 24 5 100 Senza limiti 75 + 24 = 99 25 ≤ x < 100 Al massimo • 4 penny e • 2 dime 25 ≤ x < 100 Se ci fossero 3 dime potrei migliorare con “1 quarter + 1 nickel” nickel + dime ≤ 2 Se ci fossero 2 dime e 1 nickel potrei migliorare con “1 quarter” Se ci fossero 1 dime e 1 nickel avrebbe valore inferiore a “2 dime” 181 182 Cambio monete: Analisi algoritmo greedy Cambio monete: Analisi algoritmo greedy Teorema. Greedy è ottimale per il conio U.S.A. : 1, 5, 10, 25, 100. Prova. (induzione su x) Teorema. Greedy è ottimale per il conio U.S.A. : 1, 5, 10, 25, 100. Prova. (induzione su x) Considera il modo ottimale per ck ≤ x < ck+1 : greedy sceglie moneta k. Ogni soluzione ottimale contiene la moneta k. – altrimenti, ci sarebbero monete di tipo c1, …, ck-1 che sommano ad x – nessuna soluzione ottimale può farlo, come si vede dalla tabella Considera il modo ottimale per ck ≤ x < ck+1 : greedy sceglie moneta k. Ogni soluzione ottimale contiene la moneta k. – altrimenti, ci sarebbero monete di tipo c1, …, ck-1 che sommano ad x – nessuna soluzione ottimale può farlo, come si vede dalla tabella k ck Tutte le soluzioni ottimali soddisfano Massimo valore delle monete 1, 2, …, k-1 in una sol. ottimale k ck Tutte le soluzioni ottimali soddisfano Massimo valore delle monete 1, 2, …, k-1 in una sol. ottimale 1 1 penny ≤ 4 - 1 1 penny ≤ 4 - 2 5 nickel ≤ 1 4 2 5 nickel ≤ 1 4 3 10 nickel + dime ≤ 2 4+5=9 3 10 nickel + dime ≤ 2 4+5=9 4 25 quarter ≤ 3 20 + 4 = 24 5 100 Senza limiti 75 + 24 = 99 100 ≤ x Al massimo • 3 quarter 100 ≤x Riduzione al cambio di x - ck centesimi, che per induzione, è risolto in Se ci fossero 4 quarter potrei migliorare con “1 dollaro” 4 25 quarter ≤ 3 20 + 4 = 24 5 100 Senza limiti 75 + 24 = 99 Riduzione al cambio di x - ck centesimi, che per induzione, è risolto in modo ottimale dall’algoritmo greedy. ▪ modo ottimale dall’algoritmo greedy. ▪ 183 184 Cambio monete: Analisi algoritmo greedy Cambio monete: Esercizio Osservazione. L algoritmo greedy non è ottimo per i valori dei francobolli americani: 1, 10, 21, 34, 70, 100, 350, 1225, 1500. Conio euro: 1, 2, 5, 10, 20, 50, 100, 200. Controesempio. 140¢. Greedy: 100, 34, 1, 1, 1, 1, 1, 1. Ottimo: 70, 70. Greedy è ottimale? 185 186 Selecting Breakpoints Selecting Breakpoints Selecting breakpoints (scelta fermate). Viaggio in auto da Salerno a Mosca per una percorso fissato. Distributori di benzina a punti fissi lungo il percorso. Capacità serbatoio = C. Obiettivo: minimizzare numero di fermate per rifornimento benzina. Algoritmo Greedy. Viaggiare il più possibile prima del rifornimento. C Salerno C C C C 1 2 3 4 C C 5 6 Mosca 7 188 Selecting Breakpoints: Algoritmo Greedy Selecting Breakpoints: Correttezza Algoritmo greedy. Teorema. L’algoritmo greedy è ottimale. Prova. (per assurdo) Assumiamo che l’algoritmo greedy non sia ottimale. Sia 0 = g0 < g1 < . . . < gp = L insieme di breakpoints scelto da greedy. Sia 0 = f0 < f1 < . . . < fq = L insieme di breakpoints nella soluzione ottimale con f0 = g0, f1 = g1 , . . . , fr = gr per il massimo valore possibile per r. Nota: gr+1 > fr+1 per la scelta greedy dell’algoritmo. Sort breakpoints so that: 0 = b0 < b1 < b2 < ... < bn = L breakpoints selected current location S ← {0} x ← 0 while (x ≠ bn) let p be largest integer such that bp ≤ x + C if (bp = x) return "no solution" x ← bp S ← S ∪ {p} return S g0 g1 g2 gr f0 f1 f2 fr gr+1 Greedy: ... Ottimo: Implementazione. O(n log n) Usare ricerca binaria per scegliere ogni breakpoint p. fr+1 fq Perchè in questa soluzione ottimale non ci si ferma un pò dopo? 189 190 Selecting Breakpoints: Correttezza Fractional Knapsack problem Teorema. L’algoritmo greedy è ottimale. Prova. (per assurdo) Assumiamo che l’algoritmo greedy non sia ottimale. Sia 0 = g0 < g1 < . . . < gp = L insieme di breakpoints scelto da greedy. Sia 0 = f0 < f1 < . . . < fq = L insieme di breakpoints nella soluzione ottimale con f0 = g0, f1 = g1 , . . . , fr = gr per il massimo valore possibile per r. Nota: gr+1 > fr+1 per la scelta greedy dell’algoritmo. g0 g1 g2 gr f0 f1 f2 fr gr+1 Greedy: ... Ottimo: fq Altra soluzione ottimale con un valore di r maggiore ⇒ contraddizione 191 Fractional Knapsack problem Fractional Knapsack problem Fractional Knapsack problem (Problema dello zaino frazionato). n oggetti, ognuno con peso wi > 0 e valore pi > 0 Fractional Knapsack problem (Problema dello zaino frazionato). n oggetti, ognuno con peso wi > 0 e valore pi > 0 Zaino con capacità M Obiettivo: Riempire lo zaino con gli oggetti (presi anche in parte) massimizzando il valore totale Massimizzare Zaino con capacità M Obiettivo: Riempire lo zaino con gli oggetti (presi anche in parte) massimizzando il valore totale ∑ px knapsack i i 1≤i≤n ∑wx Vincoli i i ≤M con 0 ≤ xi ≤ 1, 1 ≤ i ≤ n 1≤i≤n oggetti parte frazionaria presa 1 2 3 4 5 peso: 4 ml 8 ml 2 ml 6 ml 1 ml valore: €12 €32 €40 €30 €50 10 ml 193 194 Fractional Knapsack problem Fractional Knapsack problem Fractional Knapsack problem (Problema dello zaino frazionato). n oggetti, ognuno con peso wi > 0 e valore pi > 0 Fractional Knapsack problem (Problema dello zaino frazionato). n oggetti, ognuno con peso wi > 0 e valore pi > 0 Zaino con capacità M Obiettivo: Riempire lo zaino con gli oggetti (presi anche in parte) massimizzando il valore totale Scelta greedy: selezionare l’oggetto con massimo valore relativo e prenderne la maggior quantità possibile Zaino con capacità M Obiettivo: Riempire lo zaino con gli oggetti (presi anche in parte) massimizzando il valore totale Scelta greedy: selezionare l’oggetto con massimo valore relativo e prenderne la maggior quantità possibile knapsack knapsack Soluzione oggetti 1 2 3 4 5 peso: 4 ml 8 ml 2 ml 6 ml 1 ml valore: €12 €32 €40 €30 €50 oggetti 10 ml 1 2 3 4 5 peso: 4 ml 8 ml 2 ml 6 ml 1 ml valore: valore: €12 €32 €40 €30 €50 3 4 20 5 50 (€ per ml) 195 10 ml • 1 ml di 5 • 2 ml di 3 • 6 ml di 4 • 1 ml di 2 • 0 ml di 1 x5=1 x3=1 x4=1 x2=1/8 x1=0 Valore totale = € 50+40+30+32/8 = € 124 196 Fractional Knapsack problem Connecting wires Algoritmo del cassiere. Ad ogni iterazione, aggiungere la massima parte dell’oggetto di maggior valore relativo senza superare W. Sort oggetti per valore relativo: p1/w1 < p2/w2 < … < pn/wn. Peso degli oggetti selezionati w ← 0 x1 ← 0; x2← 0; …; xn← 0 i ← 1 while (w < W) and (i < n){ if (wi < W - w) then xi ← 1 w ← w + wi else xi ← (W – w) / wi w ← W i ← i + 1 } return (x1, x2 …, xn) Running time O(n log n). Provare che l’algoritmo è ottimale (quale tecnica usare?) 197 Connecting wires (Fili di connessione) Connecting wires (Fili di connessione) Ci sono n punti bianchi ed n punti neri su una linea, equispaziati (cioè la Ci sono n punti bianchi ed n punti neri su una linea, equispaziati (cioè la distanza tra 2 punti consecutivi è sempre la stessa) distanza tra 2 punti consecutivi è sempre la stessa) Vogliamo connettere ogni punto bianco con uno nero minimizzando la lunghezza totale di fili Vogliamo connettere ogni punto bianco con uno nero minimizzando la lunghezza totale di fili Esempio: Esempio: Lunghezza totale 1 + 1 + 1 + 5 = 8 Lunghezza totale 1 + 1 + 1 + 5 = 8 Trovare un algoritmo greedy per risolvere il problema, analizzando le varie scelte greedy. Per ogni scelta greedy individuata, verificare se - è corretta (prova) - non è corretta (mostrare un controesempio) Un esempio di scelta greedy: Connettere tutte le coppie a distanza 1 Connettere tutte le coppie rimanenti a distanza 2 … 199 200 Connecting wires (Fili di connessione) Controesempio: Collecting coins Lunghezza totale 1 + 1 + 1 + 7 = 10 Lunghezza totale 1 + 3 + 1 + 3 = 8 Un esempio di scelta greedy: Connettere tutte le coppie a distanza 1 Connettere tutte le coppie rimanenti a distanza 2 … 201 Collecting coins Collecting coins Su una scacchiera ci sono alcune monete. Un robot parte dall’angolo in alto a sinistra e cammina fino all’angolo in basso a destra Il robot può muovere solo in 2 direzioni: destra ed in giù Il robot colleziona monete al suo passaggio Problema: collezionare tutte le monete usando il numero minimo di robot. Esempio: Su una scacchiera ci sono alcune monete. Un robot parte dall’angolo in alto a sinistra e cammina fino all’angolo in basso a destra Il robot può muovere solo in 2 direzioni: destra ed in giù Il robot colleziona monete al suo passaggio Problema: collezionare tutte le monete usando il numero minimo di robot. Esempio: 4 robot sono sufficienti a collezionare tutte le 10 monete 203 204 Collecting coins Collecting coins Su una scacchiera ci sono alcune monete. Un robot parte dall’angolo in alto a sinistra e cammina fino all’angolo in basso a destra Il robot può muovere solo in 2 direzioni: destra ed in giù Il robot colleziona monete al suo passaggio Problema: collezionare tutte le monete usando il numero minimo di robot. Esempio: Su una scacchiera ci sono alcune monete. Un robot parte dall’angolo in alto a sinistra e cammina fino all’angolo in basso a destra Il robot può muovere solo in 2 direzioni: destra ed in giù Il robot colleziona monete al suo passaggio Problema: collezionare tutte le monete usando il numero minimo di robot. Esempio: Un esempio di scelta greedy: • Il primo robot prende il maggior numero di monete • Il secondo robot prende il maggior numero delle restanti monete • … Trovare un algoritmo greedy per risolvere il problema, analizzando le varie scelte greedy. Per ogni scelta greedy individuata, verificare se - è corretta (prova) - non è corretta (mostrare un controesempio) 205 206 Collecting coins Collecting coins Controesempio: Controesempio: Un esempio di scelta greedy: • Il primo robot prende il maggior numero di monete • Il secondo robot prende il maggior numero delle restanti monete • … Scelta greedy: 3 robot • Il primo prende 7 monete • Il secondo prende 3 monete • Il terzo prende l’ultima moneta Ottimo: 2 robot Un esempio di scelta greedy: • Il primo robot prende il maggior numero di monete • Il secondo robot prende il maggior numero delle restanti monete • … Scelta greedy: 3 robot • Il primo prende 7 monete • Il secondo 3 monete • Il terzo l’ultima moneta 207 208 Collecting coins Collecting coins Scelta Greedy: “peeling the next leftmost strip from top to bottom” Scelta Greedy: “peeling the next leftmost strip from top to bottom” Celle disgiunte: una è sotto ed a sinistra dell’altra Lunghezza max catena di celle disgiunte è limite inferiore al problema Qual’è la lunghezza max della catena? Ogni coppia di celle consecutive è disgiunta Occorre un robot per ogni cella della catena 209 210 Riepilogo Capitolo 4, Greedy Algorithms Collecting coins 4.1 Interval Scheduling 4.1 Interval Partitioning Scelta Greedy: “peeling the next leftmost strip from top to bottom” 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 Celle disgiunte: una è sotto ed a sinistra dell’altra Lunghezza max catena di celle disgiunte è limite inferiore al problema … ed è anche uguale alla soluzione ottima! infatti, ogni robot decrementa di 1 la lunghezza max della catena Scheduling to Minimize Lateness Optimal Caching (senza prova correttezza) Shortest Paths in a Graph Minimum Spanning Tree The Union-Find Data Structure (no) Clustering (no) Huffman Codes and Data Compression Minimum-Cost Arborescences (no) Esercizi: Coin Changing Selecting Breakpoints Fractional Knapsack problem Connecting wires Collecting coins 211 212