Algoritmi e Strutture Dati - Prof. Roberto De Prisco A.A. 2004-2005 Seconda prova di verifica (4 Febbraio 2005) Laurea/Diploma in Informatica Università di Salerno Nome e Cognome: 1 /15 Matricola: 2 /20 3 /30 4 /15 5 /20 TOTALE /100 Spazio riservato alla correzione ISTRUZIONI D’USO Nessun materiale ammesso per consultazione Prima di iniziare la prova scrivere nome, cognome e matricola negli appositi spazi. Leggere attentamente il testo della prova e cercare di rispondere alle domande: Le risposte non vengono valutate in base al numero di parole scritte ma in base al contenuto. Spesso una risposta concisa è più efficace di una risposta elaborata, a patto che risponda alla domanda. Buon lavoro. 1. [15 pt] Cancellazione in un albero binario di ricerca Si consideri l’albero binario di ricerca riportato nella seguente figura. 4 2 9 7 10 5 8 6 Si mostri, disegnando l’albero risultante, l’effetto della cancellazione del nodo 4. Quindi si mostri, disegnando l’albero risultante, l’effetto della cancellazione del nodo 7. Ed infine si mostri, sempre diesgnando l’albero risultante, l’effetto della cancellazione del nodo 10. Soluzione: Le seguenti 3 figure mostrano l’albero dopo la cancellazione, rispettivamente, dei nodi 4, 7 e 10. 5 2 5 9 7 6 2 9 10 8 5 8 2 10 10 6 Algoritmi e Strutture Dati - Seconda prova di verifica (4 Febbraio 2005) 8 6 Pagina 1 2. [20 pt] Rotazione Si descriva con un disegno l’operazione di rotazione sinistra su un nodo x in un albero T . Si scriva lo pseudocodice della procedura Left-Rotate(T, x) che implementa tale operazione. Soluzione: x y y x Left−Rotate(T,x) α β γ γ α β Left-Rotate(T,k) y ← right [x] right [x] ← left [y] if (left[y] 6= nil) then p[right [y]] ← x p[y] ← p[x] if (p[x] 6= nil) then root (T ) = y else if (x = left[p[x]]) then left[p[x]] ← y else right[p[x]] ← y left [y] ← x p[x] ← y Algoritmi e Strutture Dati - Seconda prova di verifica (4 Febbraio 2005) Pagina 2 3. [30 pt] Il piastrellista Il signor Nello Matto ha il seguente problema: deve comprare almeno T mattonelle per pavimentare un garage ancora in costruzione. Poichè non gli interessa l’aspetto estetico è diposto anche ad utilizzare mattonelle diverse pur di risparmiare sul costo totale. Per comprare le mattonelle si reca in un grosso punto di vendita dove trova una svendita di mattonelle che vengono vendute in blocchi. Ci sono n blocchi in vendita; il blocco i contiene mi mattonelle e costa ci . Si noti che le mattonelle hanno tutte la stessa dimensione, che al signor Matto ne servono almeno T e che il costo ci del blocco i non è proporzionale la numero di mattonelle mi contenuto nel blocco in quanto le P mattonelle possono essere di vario tipo. Si assuma inoltre che ni mi ≥ T , cioè che ci siano abbastanza mattonella in vendita. Fornire un algoritmo di programmazione greedy che aiuti il signor Matto a decidere quali blocchi comprare in modo tale da avere almeno T mattonelle in totale e ovviamente spendere il meno possibile. Non è necessario fornire lo pseudocodice ma basta spiegare cosa fa l’algoritmo. L’algoritmo proposto calcola la soluzione ottima, cioè di costo minimo? Se si, fornire una prova, se no, fornire un controesempio. Soluzione: Una possibile scelta greedy è quella di comprare prima i blocchi per i quali il prezzo unitario delle mattonelle è minore. L’idea è che se ogni mattonella la paga al prezzo minore dovrei risparmiare. Quindi un possibile algoritmo greedy funziona in questo modo. (a) Ordina i blocchi in ordine decrescente di (b) Siano c1 m1 ≥ c2 mi ≥ ... ≥ cn mn ci . pi i blocchi ordinati. (c) Sia k il più piccolo intero tale che Pk i mi ≥ T (d) Compra i blocchi 1, 2, . . . , k Un tale algoritmo greedy può non generare la soluzione ottima. Il problema della scelta utilizzata è che il blocco di mattonelle il cui prezzo unitario è il più basso potrebbe contenere tantissime mattonelle costringendo il signor Matto a comprarne molte di più di quanto ne servano. Ad esempio si consideri la seguente situazione. Al Signor Matto servono T = 30 mattonelle. Il punto di vendita offre due blocchi, il primo con ci = 80 e mi = 80 ed il secondo con ci = 70 e mi = 35. L’algoritmo descritto sceglierebbe il primo blocco perchè il prezzo per ogni singola mattonella è 1 mentre il prezzo per ogni singola mattonella del secondo blocco è 2. Quindi l’algoritmo sceglie una soluzione di costo 80. Però la soluzione ottima, in questo caso, è quella di prendere il secondo blocco spendendo 70. Algoritmi e Strutture Dati - Seconda prova di verifica (4 Febbraio 2005) Pagina 3 4. [15 pt] Il castello misterioso Un castello ha n stanze s1 , s2 , . . . , sn collegate fra di loro sia da normali porte che mettono in comunicazione stanze adiacenti sia da passaggi segreti che mettono in comunicazione stanze non adiacenti. Vi viene fornita una lista di passaggi che contiene l’elenco completo (sia quelli normali che quelli segreti) nella forma (si , sj ), dove (si , sj ) indica un passaggio dalla stanza i alla stanza j. Dare un algoritmo che presi in input una stanza i ed un stanza j dica se le due stanze sono comunicanti (cioè esiste una serie di passaggi che permetta di andare dall’una all’altra stanza) oppure no. L’algoritmo deve essere espresso tramite pseucodice. Potrebbe essere necessario calcolare attraverso un algoritmo ausiliario una opportuna struttura dati. In tal caso si fornisca anche lo pseudocodice di tale algoritmo ausiliario. Si assuma di avere a siposizione gli algoritimi MakeSet,FindSet e Union studiati a lezione. Quindi non si deve scrivere il loro pseudocodice. Soluzione: Rappresento il castello con un grafo G = (V, E) in cui i vertici s1 , s2 , . . . , sn sono le n stanze, mentre gli archi E rappresentano i collegamenti (normali e segreti) fra le stanze e quindi sono dati dalla lista dei passaggi. Poi utilizzo la seguente procedura per calcolare una struttura dati che contiene tutte le stanze che sono collegate fra di loro utilizzando come subroutine gli algoritmi di MakeSet,FindSet e Union: CalcolaStruttura(V, E) for ogni stanza si ∈ V do MakeSet(si ) for ogni passaggio (si , sj ) ∈ E do if FindSet(si ) 6= FindSet(sj ) then Union(si , sj ) return A questo punto posso fornire l’algoritmo che risolve il mio problema: StanzeConnesse(si , sj ) if FindSet(si ) = FindSet(sj ) then return ”Le stanze sono connesse.” else return ”Le stanze non sono connesse.” Algoritmi e Strutture Dati - Seconda prova di verifica (4 Febbraio 2005) Pagina 4 5. [20 pt] Chiusura della classe P Si provi che la classe di problemi P è chiusa rispetto alle operazioni di intersezione e di complemento (un insieme è chiuso rispetto ad una operazione se applicando l’operazione ad elementi dell’insieme il risultato è anch’esso un elemento dell’insieme). Soluzione: Per la chiusura rispetto all’intersezione dobbiamo provare che se L1 e L2 sono due problemi appartenenti a P allora L = L1 ∩ L2 appartiene a P . Per provare che L ∈ P dobbiamo fornire un algoritmo che decide L in tempo polinomiale. Lo costruiamo nel seguente modo. Poichè L1 e L2 appartengono a P esistono due algoritmi, chiamiamoli A1 e A2 che decidono, rispettivamente, L1 e L2 . Quindi A1 (x) risponde SI se x ∈ L1 e NO se x 6∈ L1 , in tempo polinomiale. A2 fa lo stesso per in linguaggio L2 . Per decidere L costruisco il seguente algoritmo A: 1. Sia x l’input di A 2. Sia r1 l’output di A1 (x) 3. Sia r2 l’output di A2 (x) 4. Se (r1 =SI e r2 =SI) allora rispondi SI, altrimenti rispondi NO. Quindi A(x) risponde SI se e solo se x appartiene sia ad L1 che ad L2 e quindi ad L, mentre risponde NO se x non appartiene ad L. Cioè A decide L. Inoltre poichè sia A1 che A2 rispondono in tempo polinomiale anche A riesce a rispondere in tempo polinomiale. Per la chiusura rispetto all’intersezione dobbiamo provare che se L ∈ P allora L̄ ∈ P . Per provare che L̄ ∈ P dobbiamo fornire un algoritmo che decide L̄ in tempo polinomiale. Lo costruiamo nel seguente modo. Poichè L ∈ P esiste un algoritmo, chiamiamolo A che decide L. Quindi A(x) risponde SI se x ∈ L e NO se x 6∈ L, in tempo polinomiale. Per decidere L̄ costruisco il seguente algoritmo Ā: 1. Sia x l’input di A 2. Sia r l’output di A(x) 3. Se (r=SI) allora rispondi NO, altrimenti rispondi SI. Quindi Ā(x) risponde SI se e solo se x non appartiene ad L il che equivale a dire che Ā(x) risponde SI se e solo se x appartiene ad L̄ Cioè A decide L̄. Inoltre poichè sia A risponde in tempo polinomiale anche Ā risponde in tempo polinomiale. Algoritmi e Strutture Dati - Seconda prova di verifica (4 Febbraio 2005) Pagina 5