Esercizio - masterizzazione compatta di tracce su CD, scelta greedy e ottimalità (esercitazione greedy, es. 10.1)
In questa pagina 5
Testo (esercitazione sul paradigma greedy, dispense del corso di Algoritmi per l'Ingegneria, Ing. Informatica UniPD). Per si ha una stringa di canzoni , in cui la -esima ha durata . Le canzoni vanno masterizzate su una sequenza di CD, , in modo che:
- ogni canzone stia su un solo CD e la concatenazione dei CD per indici crescenti presenti le canzoni nello stesso ordine di ;
- la durata cumulativa delle canzoni di ogni CD non ecceda la durata massima di un CD.
Si assume per ogni , altrimenti non esiste soluzione. Una soluzione ammissibile è una successione : sul finisce, nell'ordine, la sottostringa . Si vuole la successione con il minimo , cioè il minimo numero di CD. Si chiede l'algoritmo greedy, la dimostrazione della scelta greedy e della sottostruttura ottima, e la complessità.
Verifica dell'ammissibilità: per ogni deve valere
Passo 1: la scelta greedy
La maniera più naturale di procedere è riempire il primo CD con più canzoni possibile: si mettono su le canzoni del più lungo prefisso con (cioè ), e poi si continua con il resto.
- Clean-up: nessuno. Non ci sono canzoni incompatibili da eliminare, perché le canzoni non masterizzate sono tutte ancora da sistemare. La sottoistanza residua è il suffisso delle canzoni rimaste, con lo stesso .
- Se tutte le canzoni stanno sul primo CD () e la residua è la stringa vuota . Si estende lo spazio delle istanze con l'istanza vuota, associata a una sequenza vuota di CD (zero CD).
Rispetto a un'istanza a canzoni la residua ha almeno una canzone in meno ( perché ): le taglie decrescono e la ricorsione termina (Paradigma greedy - scelta golosa, sottostruttura e selezione delle attivitàIl paradigma greedy compie subito una scelta localmente migliore (scelta greedy), pulisce l'istanza (clean-up) e risolve l'unica sottoistanza residua, con ricorsione di coda eliminabile; il codice è facile, la correttezza no e richiede due proprietà, la scelta greedy (esiste un ottimo che la contiene) e la sottostruttura ottima (cut-and-paste), da cui la correttezza segue per induzione. Caso di studio: la selezione delle attività, con l'algoritmo del primo che finisce, correttezza completa, complessità Theta(n) dopo l'ordinamento e controesempi per le scelte greedy sbagliate.Paradigma greedy - scelta golosa, sottostruttura e selezione delle attività →).
Passo 2: l'algoritmo
La ricorsione è di coda, quindi si scrive iterativo: si accumula in sumd la durata del CD corrente e, quando la canzone successiva non ci sta, si chiude il CD e se ne apre uno nuovo che comincia con quella canzone. Il vettore contiene le fini .
MIN_NUM_CD(d, dmax) {vincolo statico: d[i] <= dmax per ogni i}
n <- d.len
k <- 0; N[0] <- 0
sumd <- d[1] // il primo CD comincia con la canzone c_1
for i <- 2 to n do
if sumd + d[i] > dmax then
// individuata la scelta greedy: il CD corrente e' pieno
k <- k + 1
N[k] <- i - 1 // il CD k finisce con la canzone i-1
sumd <- d[i] // il prossimo CD comincia con la canzone i
else
sumd <- sumd + d[i]
N[k+1] <- n // l'ultimo CD termina sempre con l'ultima canzone
return N // i CD sono k + 1Ammissibilità. All'inizio di ogni iterazione sumd è la durata delle canzoni , cioè del CD in costruzione, ed è : all'inizio vale ; il ramo else somma solo se il totale resta ; il ramo then riparte da . Quando si fissa un valore , la sumd contiene la durata di , che quindi rispetta il limite.
Complessità. Il ciclo fa iterazioni, ciascuna con un confronto e una addizione (nel ramo then nessuna): confronti e al più addizioni, quindi , con spazio ausiliario oltre al vettore di uscita.
Esempio eseguito a mano
minuti, , .
sumd prima |
sumd + d_i |
? | azione | ||
|---|---|---|---|---|---|
| inizio | sumd , |
||||
| 2 | 3 | 4 | 7 | sì | sumd |
| 3 | 5 | 7 | 12 | no | , , sumd |
| 4 | 2 | 5 | 7 | sì | sumd |
| 5 | 6 | 7 | 13 | no | , , sumd |
| 6 | 1 | 6 | 7 | sì | sumd |
| 7 | 4 | 7 | 11 | no | , , sumd |
| 8 | 7 | 4 | 11 | no | , , sumd |
Alla fine : , quindi CD: , , , , (durate ). Con la programmazione dinamica esatta e con la forza bruta su tutte le frammentazioni il minimo è (verificato con Python anche su 3000 istanze casuali).
Passo 3: proprietà di scelta greedy
Enunciato. Esiste una soluzione ottima che contiene la scelta greedy, cioè in cui contiene le canzoni del più lungo prefisso con durata (in altre parole ).
Dimostrazione (cut-and-paste). Sia una soluzione ottima, con successione .
- Se , contiene già la scelta greedy.
- Altrimenti . Poiché è il massimo numero di canzoni che stanno su un CD partendo dalla prima, deve essere (un CD non può contenere un prefisso più lungo di ).
Si costruisce spostando le canzoni dal al . Controlli:
- Ammissibilità di : contiene ora , di durata totale per la definizione di .
- non si svuota. Deve essere : se fosse , tutte le canzoni del sarebbero tra e e lo spostamento lo svuoterebbe, ottenendo una soluzione con un CD in meno di , contro l'ottimalità. (Per lo stesso motivo deve essere : se fosse sarebbe .)
- Ammissibilità di : contiene , un sottoinsieme di quelle che conteneva prima, quindi la durata non supera .
- Ordine: la concatenazione dei CD presenta ancora le canzoni nell'ordine originale.
La nuova successione è con per , ha lo stesso numero di CD di : è ottima e contiene la scelta greedy.
Passo 4: proprietà di sottostruttura ottima
Enunciato. Sia una soluzione ottima che contiene la scelta greedy. Allora formano una soluzione ottima per la residua .
Dimostrazione. Non c'è clean-up, quindi la sottostruttura è semplice. La disposizione delle canzoni su è una soluzione ammissibile per , con la successione , e usa CD. Se non fosse ottima, esisterebbe una soluzione della residua con meno di CD; componendola con la scelta greedy (le canzoni su , poi quella soluzione) si avrebbe una soluzione dell'istanza originale con meno di CD, contraddicendo l'ottimalità di .
In formula: .
Passo 5: correttezza dell'algoritmo
Per induzione sul numero di canzoni , con le due proprietà (Paradigma greedy - scelta golosa, sottostruttura e selezione delle attivitàIl paradigma greedy compie subito una scelta localmente migliore (scelta greedy), pulisce l'istanza (clean-up) e risolve l'unica sottoistanza residua, con ricorsione di coda eliminabile; il codice è facile, la correttezza no e richiede due proprietà, la scelta greedy (esiste un ottimo che la contiene) e la sottostruttura ottima (cut-and-paste), da cui la correttezza segue per induzione. Caso di studio: la selezione delle attività, con l'algoritmo del primo che finisce, correttezza completa, complessità Theta(n) dopo l'ordinamento e controesempi per le scelte greedy sbagliate.Paradigma greedy - scelta golosa, sottostruttura e selezione delle attività →). Base: (istanza vuota), zero CD. Passo: MIN_NUM_CD mette su le canzoni (il ciclo si ferma esattamente quando la canzone successiva non ci sta) e poi procede, con le stesse istruzioni, sulla residua , per ipotesi induttiva in modo ottimo. Il numero di CD è per la sottostruttura.
Perché qui il greedy basta. L'ordine delle canzoni è fisso: la soluzione è una frammentazione della stringa, e riempire il primo CD non può mai far perdere, perché ogni altra frammentazione chiude il primo CD prima o allo stesso punto. Se invece le canzoni si potessero riordinare, il problema sarebbe il bin packing, che è NP-difficile (osservazione fuori programma): nessun algoritmo efficiente esatto è noto.
Versione ripasso
- Problema: canzoni di durate , ordine fisso, ognuna su un solo CD, minimo numero di CD. Soluzione: con per ogni .
- Scelta greedy: su il più lungo prefisso con . Clean-up vuoto; residua suffisso (istanza vuota zero CD), con almeno una canzone in meno (Paradigma greedy - scelta golosa, sottostruttura e selezione delle attivitàIl paradigma greedy compie subito una scelta localmente migliore (scelta greedy), pulisce l'istanza (clean-up) e risolve l'unica sottoistanza residua, con ricorsione di coda eliminabile; il codice è facile, la correttezza no e richiede due proprietà, la scelta greedy (esiste un ottimo che la contiene) e la sottostruttura ottima (cut-and-paste), da cui la correttezza segue per induzione. Caso di studio: la selezione delle attività, con l'algoritmo del primo che finisce, correttezza completa, complessità Theta(n) dopo l'ordinamento e controesempi per le scelte greedy sbagliate.Paradigma greedy - scelta golosa, sottostruttura e selezione delle attività →).
- Algoritmo:
k <- 0; N[0] <- 0; sumd <- d[1]; per : sesumd + d[i] > dmaxallorak <- k+1; N[k] <- i-1; sumd <- d[i], altrimentisumd <- sumd + d[i]; alla fineN[k+1] <- n. I CD sono . Invariante:sumdè la durata del CD in costruzione, sempre . Costo confronti e al più addizioni, . - Esempio , : ( fa , chiudo), ( fa ), ( fa ), ( fa ), . Quindi , CD con durate ; coincide con il minimo esatto (DP e forza bruta).
- Scelta greedy (prova): ottima con ; se allora , perché è il massimo. Si spostano da a : ha durata per definizione di ; non si svuota (, altrimenti un CD in meno, assurdo) e tiene un sottoinsieme delle canzoni di prima, quindi è ammissibile; l'ordine è conservato; il numero di CD è sempre .
- Sottostruttura (prova): se è ottima con la scelta greedy, (successione ) sono ammissibili per ; se esistesse una soluzione con meno di CD, con si avrebbe un'istanza con meno di CD, assurdo. Quindi .
- Correttezza: induzione su (base istanza vuota); il ciclo chiude il CD esattamente quando la canzone successiva non ci sta, cioè dopo il prefisso massimo , e continua con la stessa regola sul suffisso.
- Perché basta il greedy: l'ordine è fisso, la soluzione è una frammentazione e riempire il primo CD non fa perdere nulla; con canzoni riordinabili sarebbe il bin packing (NP-difficile).
- Errori tipici: far ripartire
sumdda invece che da quando si apre un CD; scrivere invece di come numero di CD; non motivare perché non si svuota; dimenticare l'ammissibilità di dopo lo spostamento; credere che il greedy valga con le canzoni riordinabili.