istruzioni d`uso - Dipartimento di Informatica

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