Informatica Teorica
Seconda prova in itinere e appello del corso del Vecchio ordinamento
29 Giugno 2004
Coloro che sostengono la seconda prova in itinere svolgano gli esercizi 1,2,3 in un’ora e un
quarto. Chi sostiene l’appello completo (o la parte di Informatica teorica del corso integrato
Algebra + Inf. Teorica) svolga gli esercizi 1, 3 e 4 nello stesso tempo.
NB I punteggi assegnati agli esercizi 1,2,3 hanno valore solo con riferimento alla II prova in
itinere.
Si suggerisce di affrontare per primo l’esercizio 3.
Esercizio 1 (Punti 6)
Si dica, giustificando brevemente la risposta, se le seguenti affermazioni sono vere o false:
a)
Il problema di stabilire se un generico programma P, codificato in C, eseguito su un
generico dato di ingresso x, non terminerà mai la sua esecuzione è semidecidibile.
b)
Il problema di stabilire se un generico programma P, codificato in C, eseguito su un
generico dato di ingresso x, “andrà in loop”, nel senso stretto del termine, ossia ripeterà
indefinitamente una stessa sequenza di “mosse” ritornando ogni volta nello stesso stato
di memoria, è semidecidibile.
Esercizio 2 (Punti 4)
Il signor Furbetti sta realizzando un archivio mediante una tabella hash. I record dell’archivio hanno
una chiave costituita da sequenze di al più 30 caratteri e la tabella ha una dimensione di 5 MB.
Furbetti è particolarmente soddisfatto perché ha trovato una funzione di hash h “perfetta” (ossia è
riuscito a dimostrare che la sua funzione h è tale che x  y implica h(x)  h(y)). Accingendosi però a
implementare un algoritmo per il calcolo di h non riesce a trovarne uno. Egli viene allora assalito
dal dubbio che la sua h non sia calcolabile.
Potete aiutare Furbetti a risolvere il suo dubbio?
Esercizio 3 (Punti 8)
a) Si descriva sinteticamente –senza necessariamente codificarlo in modo completo- un
algoritmo per la macchina RAM per riconoscere il linguaggio L = {anbncn | n >=1}. Se ne
valutino complessità spaziale e temporale –a meno della relazione -mediante il criterio di
costo logaritmico.
b) E’ possibile ottenere le stesse complessità (sia spaziale che temporale) mediante una
macchina di Turing? Giustificare brevemente la risposta.
Esercizio 4
Si scriva una grammatica che generi il linguaggio L = {anw | w  {b,c}*  #(b,w) = #(c,w) = n, n
>=1}, dove la funzione #(i,x) denota il numero di occorrenze del carattere i nella stringa x.
La grammatica così ottenuta è a potenza minima, ossia non esiste una grammatica ad essa
equivalente appartenente ad una classe di minor potenza generativa? Giustificare brevemente la
risposta.
Soluzioni
Esercizio 1
a) Falsa. Infatti il problema complementare è notoriamente non decidibile ma semidecidibile.
Quindi non può essere semidecidibile anche il problema della non-terminazione.
b) Vera. E’ concettualmente possibile registrare ogni stato dell’esecuzione del programma e
verificare se lo stato attuale è identico a uno già attraversato. Se ciò accade, da quel
momento in poi l’esecuzione si ripeterà identicamente all’infinito.
Esercizio 2
h è certamente calcolabile perché ha un dominio finito. Ciò però aiuta solo in parte Furbetti perché
non fornisce indicazioni su come trovare l’algoritmo di calcolo di h.
Esercizio 3
a) La RAM aggiorna un contatore per ogni a letto (costo (i), i = 1, …, n). Salva il valore del
contatore al termine della lettura degli a in due celle diverse. Decrementa la prima copia per
ogni b letto e la seconda copia per ogni c letto successivamente. Al termine entrambi i
contatori devono contenere esattamente 0. Ne deriva una complessità spaziale, a criterio
logaritmico, (log(n)) e una temporale (n.log(n))
b) Sì. Una MdT può simulare il comportamento della RAM esattamente allo stesso modo,
usando un nastro per ogni contatore e codificandone il contenuto in numerazione binaria.
Per ogni carattere letto l’incremento o il decremento del nastro contatore richiede un numero
di mosse al più proporzionale alla lunghezza del nastro, ossia (log(n)). Perciò complessità
spaziale e temporale coincidono con quelle della RAM.
Si noti che un MdT potrebbe riconoscere lo stesso linguaggio con complessità (n) sia
spaziale che temporale.
Esercizio 4
S  aSH | aH
H  BC
BC  CB
CB  BC
Bb
Cc
La grammatica di cui sopra non è non-contestuale (appartiene però alla classe delle grammatiche
contestuali, una classe non considerata in questo corso di minor potenza delle grammatiche generali
e di maggior potenza di quelle non-contestuali; questa classe genera linguaggi decidibili al contrario
delle grammatiche generali). Non è possibile generare lo stesso linguaggio mediante una
grammatica non-contestuale perché per riconoscere L occorre tenere aggiornati i conteggi sia delle b
che delle c per confrontarli con il numero di a letto inizialmente.
Informatica Teorica
Sezione Mandrioli
Appello del 20 Luglio 2004
Coloro che recuperano la I prova risolvano gli esercizi 1 e 2 tra quelli indicati qui sotto entro
un’ora.
Coloro che recuperano la II prova risolvano gli esercizi 3 e 4 tra quelli indicati qui sotto entro
un’ora.
Coloro che recuperano entrambe le prove o che sostengono l’appello della semiunità di
Informatica Teorica VO risolvano tutti gli esercizi entro due ore.
Coloro che sostengono l’esame del corso integrato con Algebra risolvano uno a scelta tra gli
esercizi 1, 2, e l’esercizio 3 entro un’ora.
NB: i punteggi indicati per i vari esercizi fanno riferimento esclusivamente al corso di
Informatica Teorica; non hanno valore per il corso integrato.
Attenzione!!!
I voti proposti verranno pubblicati sul sito seguente (e affissi nella bacheca del Dip. di
Elettronica e Informazione in forma cartacea):
http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html
Aggiornando il file originariamente esistente dopo le prove in itinere.
Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della
pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere
comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato!
Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria.
La rinuncia al voto proposto è definitiva e totale: chi rinuncerà dovrà sostenere il recupero
dell’intero esame a settembre.
Così pure, chi risulterà insufficiente dopo il recupero di luglio dovrà sostenere a settembre il
recupero dell’intero esame.
Esercizio 1 (punti 9/15)
Si specifichi, mediante una formula del prim’ordine un apparato che funziona nel modo seguente:
All’istante 0 esso emette un segnale s, che può essere uno 0 o un 1. Se, dopo l’emissione di s e
prima dello scadere di 3 secondi, viene ricevuto lo stesso segnale in risposta, allora allo scadere del
terzo secondo viene emesso un nuovo segnale invertendone il valore (0 se prima si era emesso 1 e
viceversa); in caso contrario viene riemesso lo stesso segnale inviato in precedenza. Il
comportamento dell’apparato si ripete poi periodicamente con periodo di 3 secondi applicando
sempre la stessa regola.
L’apparato emette un segnale soltanto in istanti che sono multipli di 3 secondi.
Si suggerisce di usare i predicati emette(s,t) e riceve(s,t) per indicare, rispettivamente l’emissione e
la ricezione del segnale s all’istante t.
NB: il domino temporale può essere sia discreto (ad esempio, l’insieme dei naturali) che continuo
(ad esempio, l’insieme dei reali).
Esercizio 2
(punti 8/15)
Con riferimento all’esercizio precedente, si assuma un tempo discreto (la cui unità sia il secondo. Si
costruisca un’opportuna macchina astratta, preferibilmente a potenza minima, che abbia come
alfabeto di ingresso (rispettivamente, di uscita) la ricezione (risp., emissione) di 0, la ricezione
(risp., emissione) di 1, oppure l’assenza di segnale e si comporti come specificato nell’esercizio 1.
NB: essendo il comportamento dell’apparato periodico, senza che sia prevista una sua terminazione,
la macchina astratta, di conseguenza, non dovrà prevedere una situazione di arresto, a meno che non
debba bloccarsi a causa di errori.
Esercizio 3 (punti 7/15)
Si dica, giustificando brevemente la risposta, quali di queste affermazioni sono vere e quali false:
1. La funzione g(y,x) = (1 se fy(x) è pari, 0 altrimenti) è calcolabile.
2. La funzione g(y,x) = (1 se fy(x) è pari,  altrimenti) è calcolabile
3. La funzione g(y) = (1 se fy(x) è pari x, 0 altrimenti) è calcolabile
4. La funzione g(y) = (1 se fy(x) è pari x,  altrimenti) è calcolabile
NB: Nel caso la risposta a qualcuna delle domande precedenti fosse “Falsa” e se ne fornisse
una dimostrazione mediante tecnica diagonale, il punteggio acquisito verrebbe maggiorato di
punti 3.
Esercizio 4
(punti 8/15)
Si descriva con sufficiente precisione, ma senza necessariamente specificare ogni dettaglio, come
una Macchina di Turing a nastro singolo deterministica (si ricordi che una Macchina “a nastro
singolo” è diversa da una macchina a k nastri con k = 1) possa riconoscere il linguaggio L = {ww, w
 {a,b}*} analizzandone la complessità spaziale e temporale (a meno dell’ordine di grandezza
determinato dalla –equivalenza).
Soluzioni
Esercizio 1
ts(emette( s, t )  (
( s  0  s  1)  (k (k  N  t  3k )) 
t1 (t  t1  t  3  riceve( s, t1 ))  emette(neg( s), t  3) 
t1 (t  t1  t  3  riceve( s, t1 ))  emette( s, t  3)
)))  (emette(0,0)  emette(1,0))
dove la lettera funzionale neg, che inverte i valori 0 e 1, è definita così:
neg(s)  (s  1) mod 2 .
(mod è il ben noto operatore “resto della divisione intera”).
Esercizio 2
La figura sottostante descrive parzialmente un automa a stati finiti che si comporta secondo le
specifiche. La parte omessa, cui si accede attraverso la freccia tratteggiata, tratta il caso
dell’emissione iniziale di uno 0 in modo simmetrico.
*/1
*/1
_,0/_
_,0/_
*/0
1/_
1/_
*/_
*/0
Legenda: * indica un qualsiasi simbolo; _ indica assenza di segnale; a, b/ etichetta una transizione che avviene in
conseguenza dll’input a o dell’input b.
Esercizio 3
1. Falsa. E’ possibile ridurre il problema della terminazione al problema dato assegnando al
risultato della funzione il valore 2 a valle del calcolo di una funzione generica fz(w)di cui
si voglia stabilire la terminazione.
Si può sfruttare per la dimostrazione anche il teorema di Rice nel seguente modo: si fissi
ad arbitrio un valore intero k, e si definisca la funzione h(y) = (1 se g(y,k) è pari, 0
altrimenti). h(x) è la funzione caratteristica dell'insieme delle macchine di Turing che
calcolano funzioni con valore pari nel punto k. Questo insieme non è né l'insieme vuoto,
né l'insieme universo, e non è dunque decidibile, quindi la sua funzione caratteristica
non è calcolabile. Se g(y,x) fosse calcolabile, lo sarebbe anche h(y), il che porterebbe a
una contraddizione.
La dimostrazione può anche essere costruita in forma diretta usando la tecnica diagonale
nel modo seguente:
Si definisca h(x) = Se fx(x) non è pari allora 2,  altrimenti. Se g fosse calcolabile lo
sarebbe anche h. Quindi h dovrebbe essere = fx0 per qualche x0. Ma h(x0) non pari
implicherebbe h(x0) = 2 e h(x0) = 2 implicherebbe h(x0) non pari.
2. Vera: basta fare il run di fy(x).
3. Falsa grazie al teorema di Rice: infatti la g(y) è la funzione caratteristica dell'insieme di
tutte (e sole) le macchine di Turing che computano funzioni totali con valore sempre
pari. Questo insieme non è né l'insieme vuoto, né l'insieme universo, non è quindi
decidibile, e la sua funzione caratteristica non è computabile.
4. Falsa. Infatti questa è la funzione semicaratteristica dell'insieme di tutte (e sole) le
macchine di Turing che computano funzioni totali con valore sempre pari. Se tale
funzione fosse calcolabile, ciò vorrebbe dire che tale insieme di funzioni è RE. Questo è
tuttavia impossibile. Si prenda infatti una funzione calcolabile f(x) generica; si può
facilmente calcolare la funzione f’(x) = 2f(x), la quale ha lo stesso dominio di f(x) ed ha,
laddove è definita, valore pari. Di conseguenza, a partire dall’insieme di tutte le funzioni
computabili a valori solo pari è possibile costruire l’insieme di tutte le funzioni
computabili semplicemente dividendo per 2 le immagini. Da questo deriva che se
l’insieme di tutte e sole le funzioni totali a valori pari fosse RE, anche l’insieme di tutte
e sole le funzioni totali lo sarebbe. E’ tuttavia ben noto (da lezione) che l’insieme di tutte
e sole le funzioni totali non è RE, di conseguenza non lo è neanche l’insieme di funzioni
di partenza.
Esercizio 4
La macchina M deve in primo luogo individuare la metà della stringa in ingresso. Per ottenere ciò,
mediante una prima passata memorizza – ad esempio in unario – la lunghezza della stringa, alla sua
destra (durante questa passata la macchina dovrà tenere traccia del carattere fino a dove si è contato,
per esempio cambiandolo da a ad a', e da b a b', e riconvertendolo nel carattere originale prima di
passare a contare il prossimo carattere). Ciò richiede un tempo (n) per ogni carattere letto e quindi
(n2) per l’intera stringa. Indi, per ogni coppia di caratteri della stringa che memorizza la lunghezza
dell’input, sposta di una posizione un’opportuna marca all’interno della stringa di input (ad esempio
sostituendo il carattere a con il carattere a’ e b con b’). Al termine la marca si troverà a metà della
stringa di ingresso. Anche questa macro-operazione richiede un tempo (n2) ((n) per ogni coppia
di caratteri).
A questo punto M può procedere a confrontare, uno per uno il primo carattere dell’input con il
carattere in corrispondenza della marca che segna la metà; il secondo con il successivo. Anche
questo confronto richiede un tempo (n) per ogni carattere e quindi (n2) per l’intera stringa.
In conclusione l’intero procedimento ha una complessità temporale (n2) e spaziale (n).
Informatica Teorica
Sezione Mandrioli
Appello del 15 Settembre 2004
Attenzione!!!
I voti proposti verranno pubblicati sul sito seguente:
http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html
Aggiornando il file originariamente esistente dopo le prove in itinere.
Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della
pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere
comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato!
Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria.
Per evitare il ripetersi di recenti disguidi, probabilmente dovuti a malfunzionamenti del
servizio di posta elettronica, il docente spedirà a ogni studente “rinunciatario” un esplicito
messaggio di “ricevuta”. In caso di mancata ricezione di tale ricevuta si consiglia di contattare
il docente telefonicamente o di avvisare la segreteria didattica del DEI.
Chi risulterà insufficiente dopo il recupero di settembre o rinuncerà al voto proposto dovrà
sostenere il recupero dell’intero esame nella sessione invernale, oppure ri-iscriversi al corso
per l’anno accademico 2004/05.
Esercizio 1 (punti 8)
Si specifichi, mediante una formula del prim’ordine il ripetersi periodico di un segnale istantaneo
(ossia che si verifica in un istante di tempo isolato) con periodo 2 unità di tempo a partire
dall’istante 5. Prima dell’istante 5 e in tutti gli altri istanti il segnale non si verifica.
Esercizio 2
(punti 9)
Si costruisca un automa a pila equivalente alla grammatica seguente (ossia che riconosca il
linguaggio da essa generato):
S  aAB
A  aAA | bAB | c
B  bBB | aBA | c
L’automa così costruito è deterministico? In caso negativo, è possibile costruirne uno equivalente
deterministico?
Esercizio 3 (punti 7)
Si dica, giustificando brevemente la risposta, quali delle seguenti affermazioni sono vere e quali
false:
1. L’insieme dei programmi C la cui terminazione è garantita a priori per ogni valore dei dati in
ingresso è ricorsivamente enumerabile.
2. L’insieme dei programmi C la cui terminazione è garantita a priori per ogni valore dei dati in
ingresso è ricorsivo.
Esercizio 4
(punti 7)
In passato alcuni studenti, nello svolgimento di prove d’esame, hanno costruito una valutazione di
complessità per macchine di Turing dichiarando di utilizzare il criterio di costo logaritmico. Si
spieghi brevemente perché ciò è un errore e perché invece tale criterio è utile e spesso necessario
nella valutazione di complessità relativa a un modello di calcolo come la RAM.
Soluzioni
Esercizio 1
Codificando l’occorrenza del segnale all’istante t mediante il predicato s(t), la formula seguente
specifica il comportamento desiderato:
s(5) 
t ((t  5)  s(t ) 
(t  5  ( s(t )  (k (k  N  t  5  2k )))))
Si noti che i primi termini possono essere omessi, dal momento che sono implicati dall’ultimo,
ottenendo così la formula equivalente e più sintetica:
t (s(t)  (k (k  N  t = 2k + 5)))
Esercizio 2
La figura sottostante descrive un automa a pila (deterministico) equivalente alla grammatica fornita.
b,A/AB
a,A/AA
, Z0/SZ0
a,S/AB
c,B/
a,B/BA
c,A/
, Z0/
b,B/BB
Legenda: la stringa a destra del carattere / viene depositata sulla pila mettendo il carattere più a sinistra in alto.
Esercizio 3
Entrambe le affermazioni sono false. Infatti è noto (Teorema 2.10 del testo) che un insieme di indici
di Macchine di Turing che calcolino tutte e sole le funzioni calcolabili e totali non è ricorsivamente
enumerabile. Se perciò l’insieme suddetto di programmi C fosse ricorsivamente enumerabile,
potremmo automaticamente calcolare per ogni tale programma un corrispondente indice di MT che
calcola la stessa funzione del programma, e quindi ricavare da una enumerazione ricorsiva
dell’insieme dei programmi una corrispondente enumerazione ricorsiva di un insieme di indici di
MT che calcolano tutte e sole le funzioni calcolabili e totali.
A maggior ragione, se tale insieme non è ricorsivamente enumerabile, non può essere ricorsivo.
Esercizio 4
Le operazioni astratte della MT (transizioni) sono effettivamente elementari e possono essere
realizzate a “risorse costanti” con qualunque tecnologia di base. Al contrario le operazioni astratte
della RAM, più di alto livello, sono realizzate mediante opportuno HW la cui complessità, intermini
di circuiteria e utilizzata e tempo impiegato è funzione –appunto logaritmica- della dimensione dei
dati in ingresso.
Informatica Teorica
Sezione Mandrioli
Appello del 5 Febbraio 2005
Attenzione!!!
I voti proposti verranno pubblicati sul sito seguente:
http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html
Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della pubblicazione per
rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere comunicato via email, facendo
uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato! Trascorsi i due giorni, i voti verranno
registrati e trasmessi alla segreteria.
Per evitare il ripetersi di recenti disguidi, probabilmente dovuti a malfunzionamenti del servizio di posta elettronica, il
docente spedirà a ogni studente “rinunciatario” un esplicito messaggio di “ricevuta”. In caso di mancata ricezione di tale
ricevuta si consiglia di contattare il docente telefonicamente o di avvisare la segreteria didattica del DEI.
Chi risulterà insufficiente dopo il recupero di febbraio o rinuncerà al voto proposto dovrà ri-iscriversi
al corso per l’anno accademico 2004/05.
_______________________________________________________________________________
Esercizio 1
(punti 8)
Si specifichi, mediante una formula del prim’ordine il seguente comportamento di un ipotetico sistema:
Tutte le volte che, in un certo istante, si verifica l’evento A, dopo esattamente k unità di tempo si verifica
l’evento B, a meno che, contemporaneamente ad A, non si verifichi anche l’evento C. In tal caso, B non si
verifica dopo k unità di tempo, bensì dopo k+1.
Esercizio 2
(punti 8)
Si considerino i seguenti linguaggi:
L1 = {anb2m| n, m >= 1}, L2 = {anb3n| n >= 0}
Si costruisca una grammatica G che generi il linguaggio L = L1  L2. E’ preferibile una grammatica a
potenza minima, ossia regolare se ne esiste una, non contestuale se ne esiste una ma non ne esiste una
regolare, ecc. Nel caso, si spieghi brevemente perché non esstono grammatiche appartenenti a classi
inferiori a quella proposta.
Esercizio 3
(punti 6)
Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se il linguaggio L di cui
all’esercizio 2 è vuoto o no.
Esercizio 4
(punti 8)
Si dica, giustificando brevemente la risposta, qual è l’ordine di grandezza minimo per il riconoscimento del
linguaggio L di cui all’esercizio 2 nei due casi in cui si usi
a)
Una macchina di Turing.
b)
Una RAM, assumendo il criterio di costo logaritmico.
Soluzioni
Esercizio 1
Codificando l’occorrenza di un generico evento E all’istante t mediante il predicato E(t), la formula
seguente specifica il comportamento desiderato:
t (( A(t )  C (t ))  B(t  k )) 
(( A(t )  C (t ))  (B(t  k )  B(t  k  1)))
Si noti che la formula di cui sopra porta ad una contraddizione se non solo all'istante t, ma anche
all'istante t-1 accadono sia A che C (cosa che la specifica a parole in principio non vieta). In questo
caso, infatti, il secondo congiunto applicato a t-1 vincola B ad accadere a t+k, mentre lo stesso
congiunto riferito all'istante t proibisce che B accada a t+k. Una formula che evita questo fenomeno,
reinterpretando la specifica a parole è la seguente:
t (( A(t )  C (t ))  B(t  k )) 
(( A(t )  C (t ))  B(t  k  1))
Esercizio 2
Il linguaggio L = L1  L2 è l’insieme {a2nb6n| n >= 1}. Infatti, L1 è il linguaggio delle stringhe con
un numero pari di ‘b’ che seguono un numero qualunque di ‘a’. Tra le stringhe di L2, del tipo
‘anb3n’, quelle che appartengono anche a L1 sono esattamente quelle con un numero pari di ‘b’,
ossia quelle nella forma ‘a2nb3(2n) = a2nb6n’.
L è generato dalla seguente grammatica non contestuale (e da nessuna grammatica regolare essendo
necessaria una pila per il suo riconoscimento):
S  AB | ASB
A  aa
B  bbbbbb
Esercizio 3
L non è vuoto: contiene aabbbbbb, ecc. Quindi il problema L =  è deciso e perciò decidibile.
Esercizio 4
Una MT che simuli un automa a pila deterministico può facilmente riconoscere L in tempo lineare.
Una RAM deve necessariamente aggiornare un contatore (il cui contenuto è un numero
proporzionale ad n) per ogni carattere letto. Perciò, a criterio di costo logaritmico, la sua
complessità è necessariamente (n.log(n)).
Informatica Teorica
Prima prova in itinere - 5 Maggio 2005
Esercizio 1
(5/13 punti)
Si consideri il linguaggio:
L  {a,b,c}* costituito dalle stringhe in cui il numero di a sia uguale al numero di b + 5 e il numero
di c sia pari.
Si costruisca una macchina astratta che riconosca L. Tra le diverse macchine astratte che
riconoscono L sono preferite macchine “a potenza minima” ossia appartenenti alla categoria di
automi a minor potenza riconoscitiva possibile.
Esercizio 2
(4/13 punti)
E’ noto che le due seguenti definizioni di grammatica regolare sono equivalenti, ossia generano la
stessa classe di linguaggi:
1)
    P, || = 1,   VN .VT  VT
2)
    P, || = 1,   VT.VN  VT
La seguente ulteriore modifica della definizione è anch’essa equivalente alle precedenti?
3)
    P, || = 1,   VT.VN VN .VT  VT
Giustificare brevemente la risposta.
Esercizio 3 (5/13 punti)
Si definisca in maniera matematicamente precisa la seguente versione arricchita di automa a pila.
L’automa, oltre a tutte le caratteristiche dei normali automi a pila (nondeterministici), può anche, ad
ogni mossa, esaminare il simbolo contenuto nel fondo della pila e sostituirlo con un altro simbolo.
Se ne formalizzino anche le regole di funzionamento (per esempio mediante le normali nozioni di
configurazione e transizione tra configurazioni) e di riconoscimento di stringhe.
NB: nel caso la precedente definizione informale non risulti sufficientemente precisa in alcuni
dettagli, si operino opportune scelte, spiegandone le ragioni, per giungere ad una formalizzazione
precisa.
Si dica poi, giustificando brevemente la risposta, se l’automa, così arricchito aumenta la potenza
riconoscitiva rispetto agli automi a pila tradizionali. In caso positivo, raggiunge la potenza delle
macchine di Turing?
Soluzioni
Esercizio1
Il linguaggio L è riconosciuto dal seguente automa a pila deterministico:
a,H/
b,P/
b, H/H
a,M/
, Z0/HHHHMZ0
a, P/PP
b, N/
a, Z0/NZ0
b, Z0/MZ0
a, N/P
b, M/M
c, Q/ Q
c, Q/ Q
a,H/
c, Q/ Q
c, Q/ Q
c, Q/ Q
b,P/
b, H/H
a,M/
c, Q/ Q
a, P/PP
b, N/
a, Z0/NZ0
b, Z0/MZ0
b, M/M
a, N/P
Legenda: il simbolo Q indica un qualsiasi simbolo  
Evidentemente non è possibile riconoscere L con una macchina a stati finiti, a causa della necessità
di conteggio illimitato sul numero di a e b.
Esercizio2
No
La grammatica seguente soddisfa la nuova definizione ma genera il linguaggio
{anbn | n >= 1} che notoriamente non è regolare.
S  aA
A  Sb | b
Esercizio 3
Un automa riconoscitore nondeterministico a pila, che possa accedere e modificare anche il fondo
della pila può essere formalizzato mediante una 7-pla
<Q, I, , , q0, Z0 , F >in cui tutti i simboli hanno lo stesso significato di quelli relativi agli automi a
pila tradizionali, con l’unica differenza che la funzione  viene estesa nel modo seguente:
 : Q  ( I  { })      F (Q   *  )
dove  (q, i, A, B) = {<q’, , C>} significa che l’automa, trovandosi nello stato q, leggendo i dal
nastro di ingresso (oppure  nel caso di  –mossa), A dalla cima della pila, B dal fondo della
medesima, in maniera nondeterministica tra le diverse terne possibili, si porta in q’, scrive  sulla
cima della pila al posto di A e C sul fondo al posto di B.
Una configurazione c dell’automa è una 3-pla c = <q, x, >, come per l’automa a pila tradizionale;
la relazione di transizione è, parzialmente, definita dalle regole seguentise |   2
< q, i.y, A> |-- <q’, y, > se e solo se <q’, , M>   (q, i, A, H)
se |  = 1
<q, i.y, A> |-- <q’, y, > se e solo se <q’, , M>   (q, i, A, A)
NB: se <q’, , M>   (q, i, A, A) con   M, la transizione non è applicabile. Sono però
possibili anche altre definizioni: ad esempio che la macchina dia priorità alla riscrittura sulla cima
della pila rispetto a quella sul fondo; oppure che comunque la transizione sia possibile solo se il
contenuto della pila contiene almeno due caratteri.
(la parte rimanente della definizione della relazione di transizione viene data per scontata).
Infine x è accettata dall’automa se e solo se
< q0, x, Z0 > |-- <q’, , >, per qualche con q’  F, come nel caso dell’automa a pila tradizionale.
La potenza dell’automa non aumenta rispetto all’automa a pila tradizionale, poiché l’informazione
aggiuntiva che esso può trattare è un’informazione finita (il simbolo in fondo alla pila) e può quindi
essere memorizzata attraverso gli stati finiti dell’organo di controllo.
Informatica Teorica
Seconda prova in itinere - 29 Giugno 2005
Esercizio 1
(punti 6/17-esimi)
Si specifichi, mediante opportune pre- e post-condizioni il seguente requisito per un frammento di programma FP:
Sia dato un array a di n < NMAX interi positivi; gli n interi sono memorizzati nelle prime posizioni di a, a partire da
a[0]; dopo di essi si trova il valore convenzionale 0 usato come “terminatore”.
FP deve produrre un nuovo array b, che sia il risultato dell’ordinamento di a in ordine crescente e dell’eliminazione di
eventuali ripetizioni. FP usa a come variabile “read-only”. Anche la sequenza dei valori di b deve essere terminata da
uno 0.
Suggerimento: si consiglia di introdurre la funzione lungh(z) definita su array di NMAX interi che fornisce il numero di
valori di z diversi da 0 che precedono il primo 0 (in caso di assenza di uno 0, lungh(z) = -1 per convenzione).
Esercizio 2
(punti 7/17-esimi)
Si consideri il programma seguente, codificato in un ipotetico linguaggio ispirato al C.
int g(int p); int f(char t);
main ()
{
char a[20]; int i, z;
scanf(a); z = 0
while (i = 0; g(i) != 20; i++) do z = z + f(a[i]);
printf(z);
}
Si assuma che f e g siano due sottoprogrammi “esterni” la cui terminazione sia garantita per ogni valore dei parametri di
ingresso.
Si dica, motivando brevemente la risposta, se è decidibile il problema di stabilire se il programma main di cui sopra
terminerà o meno la sua esecuzione in corrispondenza di un generico –non fissato!- valore del dato di input a.
Esercizio 3 (punti 7/17-esimi)
Si consideri una sequenza S di elementi che contengano informazione codificabile in un numero limitato a priori di celle
di memoria. Si assuma che S si trovi già memorizzata nella memoria di una macchina RAM secondo una delle due
tradizionali tecniche:
a)
come array di celle consecutive
b) come lista di elementi collegati tra loro mediante puntatori
Si valuti la complessità asintotica sia spaziale che temporale, a meno della relazione , di un algoritmo di ricerca
sequenziale nei due casi, facendo uso sia del criterio di costo costante che del criterio di costo logaritmico; si spieghi
brevemente come si giunge ai risultati proposti, senza bisogno peraltro di codificare in dettaglio l’algoritmo. Si indichi
con precisione il parametro rispetto al quale viene misurata la dimensione dei dati di ingresso, in funzione della quale
viene fornita la funzione di complessità.
Esercizio 3-bis, Facoltativo (punti 4/17-esimi, valido solo se preceduto da soluzione corretta
della parte obbligatoria)
Come cambiano le valutazioni di complessità di cui sopra immaginando che il medesimo algoritmo venga eseguito da
una Macchina di Turing?
Soluzioni
Esercizio 1
In primo luogo si definisca la funzione lungh(z) mediante una formula del tipo
lungh(z) = n  ( (0  n < NMAX  z[n]=0  i(0  i < n  z[i] = 0)) 
(n = -1  i(0  i < NMAX  z[i] = 0)) )
A questo punto il requisito richiesto può essere specificato dalla seguente coppia per-post-condizione:s
{n (lungh (a)  n  i (0  i  n  ai   0))}
FP
{m (lungh (b)  m

i (0  i  m  1  b[i ]  b[i  1])

i (0  i  lungh (a)  j ((0  j  m)  (a[i]  b[ j ])))
j (0  j  m  i ((0  i  lungh (a))  (a[i]  b[ j ]))))}

Esercizio 2
La risposta è positiva
Premessa. Perché il quesito sia significativo occorre ovviamente assumere una macchina astratta che presupponga un
dominio totale di dati infinito: in questo caso, il tipo int deve essere l’insieme matematico degli interi. Altrimenti, come
noto, la macchina astratta diventa automaticamente un automa a stati finiti e quindi la sua terminazione decidibile.
Il dominio dei dati di ingresso del programma in oggetto è però finito, essendo l’insieme degli array di 20 caratteri. Per
ognuno dei possibili valori di ingresso la risposta al quesito è semplicemente un sì o un no; esiste quindi una macchina
di Turing che fornisce tale risposta, per ogni valore del dato di ingresso a; di conseguenza esiste un numero finito di
macchine di Turing, che, opportunamente combinate tra loro, forniscono la risposta corretta per ogni valore del dato di
ingresso a; la combinazione di tali macchine può dar luogo ad un’unica macchina che, sul dominio finito dei possibili
valori di a, fornisce l’insieme finito delle risposte corrette. Ovviamente, ciò non garantisce la conoscenza di tale
macchina; ne garantisce esclusivamente l’esistenza.
Equivalentemente e più sinteticamente si può osservare che il problema posto (la decidibilità dell’halt del programma
rispetto ai diversi valori di ingresso) è formalizzato da una funzione a dominio finito (l’insieme degli array di 20
caratteri) e codominio {T, F}. Tale funzione è quindi riducibile a una tabella finita, e quindi calcolabile.
Si noti anche che la terminazione del programma, essendo garantita la terminazione di una singola esecuzione del corpo
del ciclo, dipende solo dalla valutazione della funzione g, che, o non produce mai 20, oppure prima o poi deve produrre
il valore 20 per qualche valore di i. Ciò è indipendente dal valore del dato di ingresso a. Quindi la tabella di cui sopra,
non dipendendo dai dati di ingresso sarà costituita da tutti T o tutti F.
Esercizio 3
Si indichi con n il numero di elementi della sequenza. Poiché ogni elemento contiene informazione codificabile in un
numero limitato a priori di celle di memoria, ossia in un numero fissato di byte, è del tutto indifferente assumere come
parametro di dimensione dei dati in ingresso il numero n di elementi di S o le celle di memoria utilizzate per
memorizzare S.
La memorizzazione mediante array richiede una quantità di memoria (n) sia a criterio di costo costante che a criterio
logaritmico. La memorizzazione mediante puntatori invece richiede di memorizzare un intero come puntatore per ogni
elemento di S. Essendo il numero di elementi di S illimitato, una quantità di memoria richiesta sarà (n) a criterio di
costo costante ma (n·log(n)) a criterio logaritmico.
La complessità temporale risulterà invece (n) a criterio di costo costante e (n·log(n)) a criterio logaritmico per
entrambi i tipi di memorizzazione.
Esercizio 3 bis (parte facoltativa)
Simulare un array mediante un nastro di macchina di Turing richiede ovviamente uno spazio (n). (n) risulta pure la
complessità temporale di un algoritmo di ricerca sequenziale.
La memorizzazione di un puntatore in un nastro di macchina di Turing richiede la codifica (ad esempio in binario) di un
numero i e quindi un numero (log(i)) di celle. La complessità spaziale risulta perciò (n·log(n)) e l’accesso a un
generico elemento richiede pure (n·log(n)), rendendo perciò la complessità totale (n2·log(n))
Informatica Teorica
Recupero della prima prova in itinere - 29 Giugno 2005
Esercizio 1
(punti 6+3/13-esimi)
Si scrivano degli automi che riconoscano i seguenti linguaggi (k è fissato e > 1):
L1 = { x  {a,b}* | x = anbkn, n > 0}
k
L2 = { x  {a,b}* | x = anbn , n > 0}
Parte facoltativa. Si scriva un automa che riconosca il seguente linguaggio (k è fissato e > 1):
L3 = { x  {a,b}* | x = anblogk(n), n > 0}
NB: non è necessario che gli automi vengano disegnati completamente. Essi devono però essere descritti con sufficiente
dettaglio da poter capire quali sono i loro stati e le loro transizioni.
Esercizio 2
(punti 6/13-esimi)
Si scriva una grammatica che generi il seguente linguaggio:
L = { x  {a,b,c}* | #xa = 2n, #xb = 4, #xc = n, n > 0}
dove con la scrittura #x si intende il numero di occorrenze del carattere  nella stringa x.
La grammatica scritta è a potenza minima tra quelle che riconoscono L? Si giustifichi la risposta.
Soluzioni
Esercizio 1
Per riconoscere il linguaggio L1 è sufficiente un automa a pila deterministico che funziona in questa maniera: per ogni a
letta, esso mette k A sulla pila. Quando poi arriva a leggere le b, per ogni b letta cancella una B dalla pila. Se l'automa
arriva in fondo alla stringa con solo il carattere Z0 sulla pila, la stringa viene accettata, altrimenti viene rifiutata.
Per riconoscere il linguaggio L2, invece, è necessaria una MT. Una MT (a 2 nastri) che riconosce L2 può essere fatta in
questa maniera.
Essa innanzi tutto legge le a e memorizza nel primo nastro un numero di A pari al numero di a lette, mette nel secondo
nastro altrettante B. Quindi ripete le seguenti operazioni k-1 volte:

ad ogni B del secondo nastro sostituisce un numero di B pari al numero di A nel primo nastro (creando per
ogni B da "moltiplicare" ogni volta lo spazio necessario nel secondo nastro, spostando le celle di n posti a
partire dal fondo).
A questo punto legge le b dal nastro di ingresso, cancellando una B dal terzo nastro per ogni b letta. Se alla fine, quando
si è letta l'ultima b, il terzo nastro è vuoto, la MT accetta la stringa, portandosi in uno stato finale.
Parte facoltativa.
Anche per riconoscere il linguaggio L3 è necessaria una MT. La MT (a 2 nastri) può essere fatta in questa maniera.
Essa innanzi tutto legge le a e memorizza nel primo nastro un numero di A pari al numero di a lette. Quindi esegue
passate successive sul primo nastro fino a che il primo nastro rimane vuoto, e ad ogni passata fa quanto segue:

ad ogni k A del primo nastro sostituisce una sola A; se in fondo al nastro rimane un numero di A minore di k, le
ultime A vengono eliminate e basta (di fatto ciò corrisponde a dividere il numero di A per k);

scrive una B nel secondo nastro (a meno che nel primo nastro ci fossero meno di k A).
A questo punto legge le b dal nastro di ingresso, cancellando una B dal terzo nastro per ogni b letta. Se alla fine, quando
si è letta l'ultima b, il terzo nastro è vuoto, la MT accetta la stringa, portandosi in uno stato finale.
Una maniera alternativa di risolvere il problema poteva essere di memorizzare sul primo nastro il numero di a lette
codificando il numero in base k. logk(n) a questo punto è banalmente il numero di cifre necessarie per codificare n in
base k (meno uno), e quindi per verificare che ci siano logk(n) b basta cancellare una cifra della codifica in base k per
ogni b letta.
Esercizio 2
Una grammatica che genera il linguaggio L è la seguente:
S  AACS | X
X  BBBB
AC  CA
CA  AC
AB  BA
BA  AB
CB  BC
BC  CB
Aa
Bb
Cc
Tale grammatica non è a potenza minima. Il linguaggio può essere riconosciuto da un automa a pila (deterministico), per
cui la grammatica a potenza minima che lo genera è una grammatica non contestuale.
Una possibile grammatica non contestuale che genera il linguaggio L è la seguente:
S  Saac | Saca | Scaa | aSac | aSca | cSaa | aaSc | acSa | caSa | aacS | acaS | caaS | bS 1
S1  S1aac | S1aca | S1caa | aS1ac | aS1ca | cS1aa | aaS1c | acS1a | caS1a | aacS1 | acaS1 | caaS1 | bS2
S2  S2aac | S2aca | S2caa | aS2ac | aS2ca | cS2aa | aaS2c | acS2a | caS2a | aacS2 | acaS2 | caaS2 | bS3
S3  S3aac | S3aca | S3caa | aS3ac | aS3ca | cS3aa | aaS3c | acS3a | caS3a | aacS3 | acaS3 | caaS3 | b
Informatica Teorica
Appello del 7 – 7 2005
Esercizio 1
(punti 15)
Si consideri il seguente linguaggio Lstud formato dalle parole p così formate: {p = N6Vk | N  0..9, V
 {a, b, c, d}, k <= 30} (cioè composte da 6 cifre, seguite da al massimo 30 caratteri, in cui ogni
carattere è o a, o b, o c, o d), in cui le 6 cifre rappresentato i numeri di matricola degli studenti
immatricolati al Politecnico di Milano nell'anno 2001/2002, e i caratteri seguenti i voti conseguiti
negli esami superati (d per un voto da 18 a 21, c per uno da 22 a 24, b per uno da 25 a 27, a per uno
da 28 a 30).
Si dica, giustificando brevemente la risposta:
a. quale è l'automa a potenza minima in grado di riconoscere il linguaggio Lstud;
b. se è decidibile il problema di stabilire se ci sono 2 studenti diversi con gli stessi voti;
c. quale è la complessità minima per risolvere il problema di appartenenza di una stringa al
linguaggio Lstud.
Esercizio 2
(punti 8)
Si specifichi mediante opportune formule del prim’ordine il seguente comportamento di un
ipotetico sistema.
Tutte le volte che, in un certo istante, si riceve il segnale Start, per i 10 istanti istanti successivi
viene emesso un segnale intermittente (con intermittenza di 1 istante) Blink (per esempio, se viene
ricevuto il segnale Start all'istante 6, il segnale Blink viene emesso agli istanti 8, 10, 12, 14 e 16).
Due segnali di Start successivi sono a distanza l'uno dall'altro di almeno 15 istanti di tempo.
Esercizio 3
(punti 7)
Si costruisca una grammatica G che generi il seguente linguaggio L:
L = {an(bc)m| n, m >= 1, m < n/2}
E’ preferibile una grammatica a potenza minima, ossia regolare se ne esiste una, non contestuale se
ne esiste una ma non ne esiste una regolare, ecc. Nel caso, si spieghi brevemente perché non
esistono grammatiche appartenenti a classi inferiori a quella proposta.
Soluzioni
Esercizio 1
a. Il inguaggio è formato da un numero finito di parole, quindi può essere riconosciuto da un automa
a stati finiti (addirittura, da un automa senza cicli).
b. Essendo il linguaggio finito, il problema è decidibile.
c. Il problema del riconoscimento di può risolvere con complessità O(1) (cioè costante) in quanto il
linguaggio è finito.
Esercizio 2
Codificando la ricezione/emissione di un segnale S all'istante t con il predicato S(t), le formule
seguenti specificano il comportamento desiderato:
t ( Start(t )  t1 (1  t1  5  Blink (t  2t1 )))

t 2 , t 3 ( Start(t 2 )  Start(t 3 )  t 2  t 3  15)
Esercizio 3
L è generato dalla seguente grammatica non contestuale (e da nessuna grammatica regolare essendo
necessaria una pila per il suo riconoscimento):
S  aaaabc | ASB
A  aa
B  bc | 
Informatica Teorica
Prova d'esame - 13 Luglio 2005
Esercizio 1
(punti 8/30-esimi)
Si scriva un automa che riconosca il linguaggio L le cui stringhe sono costruite sull'alfabeto A={0,
1} e sono fatte nella seguente maniera: le stringhe hanno lunghezza dispari; se il primo e l'ultimo
carattere della stringa sono entrambi uguali ad '1', il carattere di centro è anch'esso uguale ad '1',
altrimenti il carattere di centro è uguale a '0'.
NB: il punteggio massimo verrà assegnato solo se l'automa ideato sarà a potenza riconoscitiva
minima tra quelli che riconoscono il linguaggio desiderato.
Esercizio 2
(punti 8/30-esimi)
Descrivere (senza necessariamente codificarla nei dettagli) una macchina RAM che riconosce il
linguaggio L descritto nell'esercizio 1, e se ne dia la complessità spaziale e temporale a costo
costante e a costo logaritmico.
Esercizio 3
(punti 8/30-esimi)
Scriva una formula logica che descrive un segnale fatto nella seguente maniera: dal momento in cui
il segnale viene emesso la prima volta (che potrebbe anche non essere l'istante 0), esso viene emesso
ad intervalli che si raddoppiano continuamente. L'intervallo tra i primi due istanti di emissione può
essere qualunque.
In altre parole, se la distanza fra la (k-1)-esima emissione e la k-esima emissione è d, la distanza tra
la k-esima e la (k+1)-esima emissione è 2d.
Un esempio possibile tra i tanti di evoluzione temporale del segnale è la seguente (vengono indicati
gli istanti in cui il segnale viene emesso; si noti che l'intervallo tra le prime due emissioni è pari a 3
istanti di tempo):
2, 5, 11, 23, 47, 95, 191, ...
Esercizio 4 (punti 8/30-esimi)
parte a.
Siano date le seguenti pre- e post- condizioni di un metodo Java che ha un parametro in ingresso
arg di tipo String, ritorna un int, e può sollevare un'eccezione ComputationException:
Pre: arg  null  1  length(arg)  50 
 i, j(1  i < j  length(arg)  arg[i]  arg[j])
Post: result > 0  raise ComputationException
laddove result indica il valore ritornato dal metodo (se questo ritorna senza sollevare eccezioni) e
raise ComputationException indica il fatto che viene sollevata un'eccezione ComputationException;
inoltre, length(arg) indica la lunghezza della stringa arg, e arg[i] indica l'i-esimo carattere della
stringa.
E' decidibile il problema di stabilire se un'implementazione I soddisfa la specifica data sopra?
Si motivi adeguatamente la risposta.
parte b.
Sia data la seguente implementazione
int myImpl(String arg) throws ComputationException {
int sum = 0, i = 1;
try {
while(sum < (int)Math.pow(23.5, 4.21)){
int diff = (int)(arg.charAt(i-1)-arg.charAt(0));
sum += (int)(diff*Math.pow(4.67, 2.9));
if (i == arg.length()) i = 1;
else i++;
}
} catch (Exception e) {
throw new ComputationException();
}
return sum;
}
E' decidibile il problema di stabilire se myImpl soddisfa la specifica descritta sopra?
Soluzioni
Esercizio 1
Il linguaggio L è riconosciuto dal seguente automa a pila nondeterministico:
1,Z0/Z0
0,Z0/Z0
1,A/
0,A/
1,A/
0,A/
, Z0/AZ0
q0
0,A/
q1
q2
, Z0/Z0
qF
1,A/
0,A/
1,Z0/
1,A/
q4
q3
1,A/
q6
,Z0/Z0
0,A/
0,A/
1,A/
0,A/
q5
0,A/
1,A/
Evidentemente non è possibile riconoscere L con una macchina a stati finiti, visto che le stringhe di
L possono essere arbitrariamente lunghe, nè con un automa a pila deterministico, che non e’ in
grado di “indovinare” il punto centrale della stringa.
Esercizio 2
Una semplice macchina RAM che riconosce il linguaggio è fatta nella seguente maniera.
Innanzi tutto, essa legge una volta i caratteri in ingresso; ogni carattere letto viene memorizzato, e
contemporaneamente si incrementa un contatore che mi dice quanti caratteri ho letto fino a quel
momento. Alla fine della lettura, se ho contato un numero di caratteri pari, segnalo su nastro di
uscita che la stringa non è accettata. Se invece ho contato un numero di caratteri dispari, vado a
leggere il primo carattere, l'ultimo, e quello di mezzo (per recuperare l'offset del quale rispetto al
primo carattere basta dividere per 2 il numero di caratteri letti). Se questi sono tutti uguali ad 1,
oppure se quello di centro ed almeno uno tra il primo e l'ultimo sono uguali a 0, accetto la stringa,
segnalandolo sul nastro di uscita, altrimenti rifiuto.
A costo costante, sia la complessità spaziale che quella temporale sono (n).
A costo logaritmico, la complessità spaziale è ancora (n), mentre quella temporale è (n·log(n)).
Esercizio 3
Indicando, come al solito, col predicato e(t) che il segnale viene emesso al tempo t, una possibile
soluzione è:
 t1, t2 ( t1 < t2  e(t1)  e(t2)   t’ ( t1 < t’ < t2   e(t’) )

e(t2 + 2 (t2  t1))   t’ ( t2 < t’ < t2 + 2 (t2  t1)   e(t’) ) )
Esercizio 4
parte a.
Non è decidibile.
Una maniera per dimostrarlo potrebbe essere tramite il Teorema di Rice: l'insieme delle
implementazioni (cioè delle MT, visto che si può tradurre un programma Java in una MT
equivalente) che soddisfano la specifica non è certamente l'insieme vuoto (esiste almeno una
funzione che soddisfa la specifica), e non è certamente neanche l'insieme universo (è banale pensare
ad una funzione che non soddisfa la specifica), quindi il problema di stabilire se una data MT
appartiene all'insieme non è decidibile.
Una maniera alternativa potrebbe riducendo il problema della terminazione al problema del
soddisfacimento della specifica. Preso un programma qualunque P (facendo attenzione che in P non
compaia il parametro arg) basta in effetti costruire un metodo siffatto:
int Pridotto(String arg) throws ComputationException {
P
return 1;
}
Tale metodo soddisfa la specifica se e solo se P termina.
Se sapessi risolvere il problema di partenza, saprei anche risolvere il problema della terminazione di
un programma qualunque, che è un assurdo.
parte b.
In questo caso, il problema è banalmente decidibile.
Infatti, l'implementazione è in questo caso fissata a myImpl, quindi si danno 2 soli casi: o myImpl
soddisfa le specifiche, oppure non le soddisfa. La risposta è quindi in questo caso binaria, o sì o no,
e la MT che risolve il problema o è quella costante uguale ad 1, oppure è quella costante uguale a 0.
In entrambi i casi essa è banalmente calcolabile.
Informatica Teorica (Sez. Mandrioli)
Appello del 13 Settembre 2005
Esercizio 1
(punti 10/30-esimi)
Si scrivano un automa e una grammatica che, rispettivamente, riconosca e generi il linguaggio L =
{anamaman | n, m >= 1, n pari, m dispari}.
NB: il punteggio massimo verrà assegnato solo se l'automa ideato sarà a potenza riconoscitiva
minima tra quelli che riconoscono il linguaggio desiderato e la grammatica avrà il minimo numero
di produzioni.
Esercizio 2
(punti 10/30-esimi)
Si scriva una formula logica che descrive la seguente regola per controllare atterraggi e decolli in un
aeroporto:

Se c’è un aereo in fase di decollo nessun altro aereo può decollare entro 3 minuti dall’inizio
del decollo e nessun altro aereo può atterrare entro 5 minuti dall’inizio del decollo dell’aereo
precedente;

Se c’è un aereo in fase di atterraggio nessun altro aereo può atterrare entro 3 minuti
dall’inizio dell’atterraggio e nessun altro aereo può decollare entro 5 minuti dall’inizio
dell’atterraggio dell’aereo precedente.
Esercizio 3
(punti 10/30-esimi)
Dire, giustificando brevemente la risposta, se la seguente funzione f: N  N è:
a)
Computabile
b)
Totale.
f(n) = n-esimo numero primo. Per convenzione, si assuma f(0) = 1, e, di conseguenza, f(1) = 2, f(2)
= 3, f(3) = 5, …
Soluzioni
Esercizio 1
La definizione di L equivale a L = {a2n| n dispari e >= 2}, ossia L = {a6 , a10, a14, a18, …}, ossia,
detto in altra maniera L = { a2(2l+1) | l  1 } = { a4l+2 | l  1 }. Quindi L può essere riconosciuto
mediante il seguente semplice automa a stati finiti:
a
a
a
a
a
a
a
a
a
a
Da esso si può ricavare immediatamente una grammatica regolare equivalente, che può essere
“compattata” nella seguente grammatica (non contestuale!) per minimizzare il numero di
produzioni:
S  a4A
A  a4A| a2
Esercizio 2
Si definscano i predicati StartTakeOff (x, t) e StartLand(x, t) per indicare, rispettivamente, che
l’aereo x ha iniziato il decollo o l’atterraggio all’istante t.
Il requisito richiesto è allora formalizzato dalla formula seguente:
t , x( StartTakeOff ( x, t ) 
y, t1 ( y  x  (t  t1  t  3)  StartTakeOff ( y, t1 )) 
y, t1 ( y  x  (t  t1  t  5)  StartLand ( y, t1 )) )

t , x( StartLand ( x, t ) 
y, t1 ( y  x  (t  t1  t  3)  StartLand ( y, t1 )) 
y, t1 ( y  x  (t  t1  t  5)  StartTakeOff ( y, t1 )) )
Altri predicati e formule, non strettamente necessari ai fini della formalizzazione del requisito ma
utili a chiarire il significato dei termini potrebbero definire la fase di atterraggio/decollo dell’aereo x
come quella compresa tra i relativi inizio (Start) e fine (End).
Esercizio 3
La funzione f è computabile: essendo infatti decidibile se un numero sia primo o no, dopo aver
costruito l’n-esimo numero primo si può ottenere l’n+1-esimo enumerando tutti i numeri ad esso
successivi fino ad ottenere il prossimo numero primo.
f è anche totale perché i numeri primi sono infiniti. Quindi, per ogni n, esiste l’n+1-esimo numero
primo che verrà individuato dall’algoritmo suddetto.
Informatica Teorica (Nuovo e Vecchio Ordinamento)
Appello del 6 Febbraio 2006
Esercizio 1 (Punti 15)
Si formalizzino mediante formule logiche del prim’ordine le regole del gioco “Sudoku”.
Informalmente le regole sono le seguenti:
E’ dato un quadrato di 9 * 9 caselle, ognuna delle quali deve contenere un numero intero compreso
tra 1 e 9. Il quadrato è suddiviso in 9 “sottoquadrati” di 3 * 3 caselle (il primo “copre” le caselle
[1..3 * 1..3]; il secondo [4..6* 1..3], ecc.)
Occorre riempire le caselle del quadrato in modo che:

Ogni riga e ogni colonna contenga tutti i numeri tra 1 e 9

Ogni “sottoquadrato” contenga tutti i numeri tra 1 e 9.
Facoltativamente (ulteriori punti 1): potrebbe il problema essere generalizzato rispetto alle
dimensioni del quadrato? Se sì, come?
Esercizio 2 (punti 7)
Si dica, giustificando brevemente la risposta, se il suddetto problema del Sudoku, ossia stabilire se,
assegnati alcuni valori ad alcune caselle esiste un modo di riempire le altre in modo da soddisfare le
regole, è decidibile o no.
Come cambia la risposta (se cambia), se il problema è espresso nella sua forma generalizzata?
Esercizio 3 (punti 8)
Si descrivano brevemente (senza necessariamente "codificarli" in dettaglio) algoritmi per il
riconoscimento del linguaggio {anbn | n >= 1} con le seguenti caratteristiche:
 Una macchina di Turing che minimizzi la complessità temporale
 Una macchina di Turing che minimizzi la complessità spaziale
 Una RAM che minimizzi la complessità temporale
 Una RAM che minimizzi la complessità spaziale
E si confrontino le funzioni di complessità così ottenute.
Soluzioni
Esercizio 1
Si formalizzi la tabella del Sudoku mediante un array (si ricordi che, in termini matematici, un array
altro non è che una funzione). Le regole del gioco sono allora formalizzate dalla formula seguente:
i, j (1  i, j  9  1  a i, j   9)

i, j, k (1  i, j, k  9  a i, j   a i, k 

i, j, k (1  i, j, k  9  a i, j   a  k , j 

i, j, k , h((1  i, j, k , h  9  i / 3  k / 3  j / 3  h / 3   i  k  j  h )  a i, j   a k , h 
NB. il simbolo '/' indica la divisione a risultato intero.
La generalizzazione al caso di un quadrato k*k è banale se si ha l'accortezza di scegliere un valore
di k che sia un quadrato perfetto. In tal caso k rimpiazza il numero 9 e k rimpiazza il numero 3
nella formula precedente.
Esercizio 2
Il problema è chiaramente decidibile in quanto è riconducibile del tutto a un problema finito. Infatti,
ogni griglia 9 * 9 può essere riempita con numeri da 1 a 9 (rispettando le regole) in un numero finito
di modi diversi. (Contare il numero esatto di schemi diversi non è banale, ma è sufficiente capire
che esso è finito. Per curiosità, tale numero è stato calcolato essere uguale a 6 670 903 752 021 072
936 960). Pertanto un algoritmo che provi esaustivamente tutte le possibili soluzioni termina
sicuramente.
Anche nal caso generalizzato, il problema rimane decidibile. Per ogni n fissato, ogni schema di n2 *
n2 celle ha un numero finito di possibili completamenti (sicuramente meno di n2n^4), per cui possono
essere provati esaustivamente tutti.
Il problema è però computazionalmente oneroso, NP-completo per la precisione, come mostrato in:
T. Yato, "Complexity and completeness of finding another solution and its application to puzzles".
Master's thesis, University of Tokyo, Department of Information Sciences, 2003.
Esercizio 3
1. Macchina di Turing che minimizzi la complessità temporale.
E' sufficiente "simulare" con la macchina di Turing un automa a pila, usando un nastro di
memoria come una pila. La complessità temporale risultante sarebbe (n), che è facile
capire essere il meglio ottenibile.
2. Macchina di Turing che minimizzi la complessità spaziale.
In questo caso conviene contare in codifica binaria (o equivalentemente, in altra base > 1) il
numero di 'a' ricevute e poi decrementare il contatore binario per ogni 'b' ricevuta. La
complessità spaziale sarebbe così (log n), ottenuta però al prezzo di un peggioramento di
un fattore logaritmico della complessità temporale.
3. RAM che minimizzi la complessità temporale.
Si può replicare la soluzione della macchina di Turing al punto 1 con una RAM, scrivendo
un marker in n celle adiacenti. La complessità temporale risultante è la stessa (n), con
criterio di costo costante. Con criterio di costo logaritmico essa sale invece a (n log n), dal
momento che anche se scrivo un valore costante (il marker) nelle celle adiacenti, ad ogni
accesso devo manipolare un puntatore all'elemento corrente, che è un numero maggiorato da
n.
4. RAM che minimizzi la complessità spaziale.
In questo caso conviene utilizzare un singolo contatore intero in una singola cella di
memoria. In questo modo il costo a criterio di costo costante è semplicemente (1) (uso di
un numero costante di celle di memoria), mentre a costo logaritmico diventa (log n), che è
una caratterizzazione del fatto che la RAM di fatto "implementa" una codifica binaria del
dato.
Informatica Teorica
Prima prova in itinere - 12 Maggio 2006
Si svolgano i seguenti esercizi. Il tempo complessivo a disposizione è di 1h e 30 minuti.
Esercizio 1 (Punti 6/13-esimi senza la parte opzionale c), che comporta ulteriori 3 punti)
Si consideri la seguente variante di automa a pila, detto automa a pila visibile (APV). L’alfabeto di
ingresso I dell’automa è partizionato in tre sottoinsiemi Ipush, Ipop, Ilocal, che determinano
indirettamente come la pila viene gestita durante il riconoscimento: se il carattere letto appartiene a
Ipush, allora l’automa deve effettuare una push (ossia aggiungere esattamente un carattere alla cima
della pila, senza rimuoverne alcuno); se il carattere letto appartiene a Ipop, allora l’automa deve
effettuare una pop (ossia rimuovere il carattere in cima alla pila, senza aggiungerne altri); se infine il
carattere appartiene a Ilocal, l’automa non deve modificare il contenuto della pila. Si noti che ad ogni
mossa è possibile modificare al più un carattere della pila. Per il resto l’automa si comporta come
un normale automa a pila.
a)
Si formalizzi l’automa a pila visibile in versione nondeterministica, nonché le regole
di funzionamento e di riconoscimento di stringhe (mediante le usuali nozioni di
configurazione, transizione, accettazione, ecc.). Per semplicità non si considerino le
mosse.
b)
Si confronti poi la potenza riconoscitiva degli APV con quella degli automi a stati finiti.
c)
Opzionale: si confronti la potenza riconoscitiva degli APV con quella degli automi a
pila standard. (E’ sufficiente una argomentazione non pienamente formale)
Esercizio 2 (Punti 4/13-esimi)
Si consideri il linguaggio L su alfabeto  = {a,b,c,p,q, z}, composto da tutte e sole le stringhe che:
se iniziano per ‘a’, hanno ‘z’ come penultimo carattere (in questo caso sono lunghe almeno 3
caratteri), e se hanno ‘c’ come terzo carattere, allora hanno ogni occorrenza di ‘p’, successiva al
terzo carattere, seguita immediatamente da una occorrenza di ‘q’. Si scriva un automa a potenza
minima tra quelli noti che accetta il linguaggio L.
Esercizio 3 (Punti 4/13-esimi)
Si scriva una grammatica che genera il linguaggio L1 definito sull’alfabeto  = {(, ),*}; le stringhe
di L1 o contengono esclusivamente parentesi tonde, e, in tal caso, devono essere ben parentetizzate,
oppure, se contengono almeno un *, sono del tutto libere, cioè sono sequenze arbitrarie di (, ),*.
Anche in questo caso è preferibile una grammatica a potenza minima tra quelle che generano L1.
Soluzioni
Esercizio 1
Un automa riconoscitore nondeterministico a pila visibile (APV) è definito come una 7-pla
< Q, I, , , q0, Z0, F >
con tutti i simboli col significato degli automi a pila tradizionali. In più I è partizionato nei tre
sottoinsiemi Ipush, Ipop, Ilocal, ossia
I = Ipush  Ipop  Ilocal
e
Ipush  Ipop = Ipop  Ilocal = Ipush  Ilocal = 
La funzione di transizione  è definita
: Q  I    (Q  Q  )
Transizione di configurazione:
c = (q, a.x, c' = (q', x', '), con a I, x I*, 
 se a Ipush e <q', >  (q, a, ), allora ' = 
 se a Ipop e q'  (q, a, ),
allora ' = 
 se a Ilocal e q'  (q, a, ),
allora ' = 
La configurazione dell’automa, le relazione di transizione e la condizione di accettazione sono
definite in maniera del tutto analoga al caso degli automi a pila standard (senza mosse .
La potenza espressiva degli APV è strettamente maggiore di quella degli automi a stati finiti;
infatti, il linguaggio non regolare {anbn | n > 0} è accettato da un APV con Ipush = {a}, Ipop = {b},
Ilocal = , con l’accorgimento di avere un carattere extra di pila per poter accettare a pila non vuota.
D’altro canto è evidente che ogni automa a stati finiti può essere espresso come un banale automa
APV.
Il confronto con gli automi a pila standard è più complesso. Consideriamo il linguaggio {wcwR |
w{a,b}*}, riconosciuto da un automa a pila deterministico standard (e dunque a maggior ragione
da uno nondeterministico), mediante la seguente tecnica: si impilano i caratteri letti finchè si
incontra il carattere c; a questo punto verifica che i rimanenti caratteri letti (ossia quelli di wR) siano
esattamente quelli che sono in pila, togliendoli dalla cima. Siccome ciascun carattere viene
incontrato due volte – uno in w e uno in wR – e per la prima occorrenza è necessario fare una push,
mentre per la seconda una pop, non è possibile partizionare l’alfabeto di pila secondo quanto
richiesto dagli APV per effettuare il riconoscimento richiesto.
In conclusione gli APV sono meno espressivi degli automi a pila standard (anche solo
deterministici).
Gli APV (in inglese, visibly pushdown automata), sono stati introdotti in: Alur e Madhusadan:
“Visibly pushdown languages”, Proceedings of the 36th ACM Symposium on Theory of Computing
(STOC’04), pp. 202-211, 2004.
Esercizio 2
Un automa a stati finiti è sufficiente per accettare L; eccone una versione nondeterministica (gli stati
in grigio sono di accettazione).
\{p}

a
c
p
q
\{c}
z
z
\{p}
z
\{a}


\{p}
p

c
q

\{c}
Si noti che la definizione informale del linguaggio poteva ammettere anche un’interpretazione più
complicata ma comunque corretta, ossia che la condizione “e se hanno ‘c’ come terzo carattere,
allora hanno ogni occorrenza di ‘p’, successiva al terzo carattere, seguita immediatamente da una
occorrenza di ‘q’.” si applicasse alle sole stringhe che iniziano per ‘a’.
Esercizio 3
La seguente grammatica noncontestuale genera L1.
S → B | Q
B → BB | (B) | 
Q → A*A
A → *A | (A | )A | 
Anche in questo caso, sono ammissibili interpretazioni leggermente diverse, in particolare se la
stringa nulla appartenga a L1 e se una stringa ben parentetizzata debba comunque avere un’unica
coppia di parentesi più esterna.
Informatica Teorica
Seconda prova in itinere  5 Luglio 2006, Sezione Mandrioli
Il problema della Torre di Hanoi è così definito. Vi sono n dischi simili ma di dimensioni diverse inseriti in un piolo,
in modo tale che il disco più grande sia nel punto più basso e tutti gli altri siano sopra di esso in ordine decrescente.
Esistono altri due pioli inizialmente liberi (si veda la Figura (a)).
Si vogliono trasportare tutti i dischi su un altro piolo, spostandoli uno alla volta da un piolo all’altro, e operando in
modo tale che mai un disco sia appoggiato sopra uno più piccolo (ovviamente, per spostare un disco da un piolo
all’altro occorre aver rimosso quelli sovrastanti, sempre rispettando le regole precedenti). Le Figure (b) e (c)
completano l’illustrazione del problema.
Figure (a), (b), (c) Il problema della torre di Hanoi: (a) situazione iniziale, (b) situazione finale richiesta,
(c) situazione inammissibile.
Esercizio 1
(punti 8/17-esimi)
Si formalizzi mediante formule del prim’ordine una generica situazione ammissibile della posizione dei dischi nei pioli:
ad esempio le figure (a) e (b) rappresentano due situazioni ammissibili al contrario della figura (c).
Esercizio 1.bis(da svolgere facoltativamente solo dopo aver svolto tutti gli altri esercizi.
L’esercizio vale ulteriori punti 3/17-esimi)
Si formalizzi, sempre mediante formule del prim’ordine, la relazione che deve sussistere tra due diverse situazioni
ammissibili perché l’una sia ottenibile dall’altra mediante una mossa lecita.
Esercizio 2
(punti 4/17-esimi)
Si dica se il seguente problema è decidibile: Dato un algoritmo A qualsiasi, stabilire se A risolve correttamente il
problema della Torre di Hanoi. Giustificare brevemente la risposta.
Esercizio 3 (punti 5/17-esimi)
Dovendo valutare la complessità di un algoritmo per la soluzione del problema della Torre di Hanoi da eseguire
mediante un normale calcolatore basato sulla classica architettura di von Neumann (macchina RAM), quale criterio di
costo risulterebbe più adeguato e conveniente? Giustificare brevemente la risposta.
Esercizio 3bis, facoltativo (ulteriori punti 2/17-esimi)
Che relazione è “naturale” aspettarsi tra complessità (sia spaziale che temporale) di un algoritmo per la soluzione del
problema, valutata a criterio costante e a criterio logaritmico? NB. Non si chiede di descrivere un algoritmo né di
valutarne le complessità; bensì di stabilire come cambia la valutazione di complessità cambiando il criterio di costo.
Avvisi importanti
1.
Il tempo disponibile per lo svolgimento della prova è 1 ora e 30 minuti.
2.
L’eventuale soluzione dell’Esercizio 1.bis sarà presa in considerazione e valutata solo se tutti gli
altri esercizi saranno stati risolti in maniera ritenuta soddisfacente.
3.
Si ricorda che possono svolgere questa prova in itinere solo coloro che abbiano ottenuto almeno 5
punti nella prima prova.
Eccezionalmente sono ammessi anche gli studenti laureandi, che devono indicare esplicitamente
la loro situazione nella testata del loro elaborato. Come già comunicato, in caso di esito positivo
nella presente prova, verranno loro comunicate le modalità di recupero della prima prova.
4.
Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di
accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale di Dino Mandrioli
sul sito ufficiale del Dipartimento. Verrà data precedenza alla correzione dei compiti dei laureandi
(che risultino tali dall’archivio ufficiale del CEDA)
Soluzioni
Esercizio 1
Si indichi
d) con Di l’i-esimo disco: 1 <= i <= n;
e)
con dim(Di) la dimensione del disco i-esimo;
(i ((1 <= i <= n )  (1 <= dim(Di) <= n))) 
(i,j (((1 <= i, j <= n )  (i  j))  (dim(Di)  dim(Dj))))
f)
con pos(Di) la posizione del disco i-esimo:
pos(Di) = <h,p>; 1 <= h <= n; 1 <= p <= 3; che indica che il disco si trova ad altezza h nel piolo p.
g) la funzione pos deve sottostare ai seguenti vincoli:
h) i,j (pos(Di) = pos(Dj)  Di = Dj)

i)
i,h, k, p ((pos(Di) = <h,p>  k < h)  j (pos(Dj) = <k,p>))

j)
i,j, h, k, p ((pos(Di) = <h,p>  pos(Dj) = <k,p>  k < h)  (dim(Dj) > dim(Di)))
Esercizio 1.Bis
Si indichino con pos1 e pos2, rispettivamente, due funzioni che definiscono la posizione del disco i-esimo prima e dopo
l’esecuzione di una mossa. Ovviamente sia pos1 che pos2 devono soggiacere ai vincoli formalizzati precedentemente.
Inoltre esse soddisfare la relazione espressa dalle formule seguenti:

Se un disco qualsiasi non si trova in cima a un piolo, la sua posizione rimane invariata nel passaggio da pos1 a
pos2:
i,h, p ((pos1(Di) = <h,p>   k, j (k > h  pos1(Dj) = <k,p>))  (pos2(Di) = <h,p>))

Se (per ogni tripla di dischi Di1, Di2, Di3 e posizioni):
i1,i2, i3, h1, h2, h3, p1, p2, p3
o
il disco Di1 si trova in cima al piolo p1:
( (pos1(Di1) = <h1,p1>   k, j (k > h1  pos1(Dj) = <k,p1>))
o
e il disco Di2 si trova in cima al piolo p2:
 (pos1(Di2) = <h2,p2>   k, j (k > h2  pos1(Dj) = <k,p2>))
o
e il disco Di3 si trova in cima al piolo p3:
 (pos1(Di3) = <h3,p3>   k, j (k > h3  pos1(Dj) = <k,p3>))
o
e i tre dischi Di1 sono diversi tra loro, e stanno sui tre pioli diversi
 (i1  i2  i2  i3  i1  i3  p1  p2  p2  p3  p1  p3) )

allora:

o
uno (e uno solo) tra Di1, Di2, e Di3 cambia piolo in pos2 (e, necessariamente per i vincoli su pos,
viene a trovarsi in cima al nuovo piolo)
 h, p ( (pos2(Di1) = <h,p>  p  p1  pos2(Di2) = pos1(Di2)  pos2(Di3) = pos1(Di3))
 (pos2(Di2) = <h,p>  p  p2  pos2(Di1) = pos1(Di1)  pos2(Di3) = pos1(Di3))
 (pos2(Di3) = <h,p>  p  p3  pos2(Di1) = pos1(Di1)  pos2(Di2) = pos1(Di2))
)
Soluzione alternativa
Definiamo che la differenza tra pos1 e pos2 riguarda un solo disco, che deve essere in cima ad un piolo in pos1 (e che
sarà in cima ad un piolo in pos2 per i vincoli sui pioli):
 Di, h, p ( pos1(Di) = <h,p>  pos2(Di)  <h,p> 
 j (pos1(Dj) = <h+1,p>) 
j ( j  i  pos1(Dj) = pos2(Dj) )
)
/* Di cambia posizione */
/* Di è in cima ad un piolo in pos1 */
/* tutti gli altri dischi rimangono fermi */
Si noti che potremmo semplificare la condizione eliminando il vincolo che Di in pos1 sia in cima ad un piolo, in quanto
ciò è garantito dal fatto che in pos2 non ci possono essere "buchi", e dal fatto che l'unico disco ad essere spostato è D i:
 Di, h, p ( pos1(Di) = <h,p>  pos2(Di)  <h,p> 
j ( j  i  pos1(Dj) = pos2(Dj) )
)
/* Di cambia posizione */
/* tutti gli altri dischi rimangono fermi */
Se invece volessimo specificare, per maggiore chiarezza, che nella nuova posizione D i deve essere in cima ad un piolo,
potremmo modificare la condizione come segue:
 Di, h, p ( pos1(Di) = <h,p>  pos2(Di)  <h,p> 
 j (pos1(Dj) = <h+1,p>) 
h', p' ( pos1(Di) = <h',p'>)

 j (pos2(Dj) = <h'+1,p'>) ) 
j ( j  i  pos1(Dj) = pos2(Dj) )
)
/* Di cambia posizione */
/* Di è in cima ad un piolo in pos1 */
/* Di è in cima ad un piolo anche in pos2 */
/* tutti gli altri dischi rimangono fermi */
Le due seguenti ulteriori soluzioni alternative descrivono in maniera completa non solo i vincoli
sul posizionamento dei dischi nei pioli e sul loro movimento, ma anche l’obiettivo del gioco.
Esercizio 1 + 1.Bis, alio modo
Si introduca la seguente funzione:

piolo(p, h, t) = d se e solo se d è la dimensione del disco che si trova ad altezza h sul piolo p al tempo t
Una possibile formalizzazione del problema della Torre di Hanoi è la seguente (con implicite quantificazioni universali
esterne):

vincoli sui domini:
piolo(p, h, t) = d  1  p  3  1  h  n  1  d  n

unicità del disco:
piolo(p1, h1, t) = piolo(p2, h2, t)  p1 = p2  h1 = h2

assenza di "buchi" sul piolo:
piolo(p, h, t) = d  h > 1  d1(piolo(p, h-1, t) = d1)

vincolo sull'ordinamento dei dischi sul piolo:
piolo(p, h1, t) > piolo(p, h2, t)  h1 < h2
Si introducano poi i seguenti predicati e funzioni:

altezza(p, t) = h se e solo se h è l'altezza del piolo p al tempo t

muovi(p1, p2, t) se e solo se all'istante t il disco che si trova in cima al piolo p 1 è spostato in cima al piolo p2
Una possibile formalizzazione dell'evoluzione del gioco della Torre di Hanoi è la seguente (con implicite
quantificazioni universali esterne):

definizione della funzione "altezza", che deriva da "piolo":
altezza(p, t) = h 
(h > 0  d(piolo(p, h, t) = d)  d(piolo(p, h+1, t) = d)) 
(h = 0  d(piolo(p, 1, t) = d)))

una è mossa possibile solo se il piolo di partenza non è vuoto e se il piolo di arrivo è diverso da quello di
partenza:
muovi(p1, p2, t)  altezza(p1, t) > 0  p1  p2

non è possibile effettuare 2 mosse contemporaneamente:
muovi(p1, p2, t)  muovi(p3, p4, t)  p1 = p3  p2 = p4

effetto di una mossa sullo stato di un piolo:
piolo(p, h, t) = d 
(p = 1  h = n - d +1  t1, p1, p2(t1 < t  muovi(p1, p2, t1)))

t1 (t1 < t  altezza(p, t1) = h-1 
p1( muovi(p1, p, t1) 
piolo(p1, altezza(p1, t1), t1) = d 
t2 (t1 < t2 < t  altezza(p, t2) = h

p1 (muovi(p, p1, t2)) )))

stato iniziale del gioco:
i(1  i  n  piolo(1, i, 0) = n - i + 1)  altezza(2, 0) = 0  altezza(3, 0) = 0
o

si noti che la seconda e terza condizione sono superflue, in quanto se tutti i dischi sono sul primo
piolo, sugli altri non ci può essere nulla
stato finale del gioco:
t (i(1  i  n  piolo(3, i, t) = n - i + 1)  altezza(1, t) = 0  altezza(2, t) = 0)
Esercizio 1 + 1.Bis, yet another
Insiemi: D = {1,2,..,n} dischi; P = {1,2,3} pioli; tempo N.
Variabili: t  N; d,d',d"  D; p,p',p"  P.
Predicati:
piolo(p,d,t): il disco d è sul piolo p al tempo t
mossa(p,p',t): si muove dal piolo k a k' al tempo t
on(d,d',t): il disco d è immediatamente sopra d' al tempo t (serve solo per descrivere la situazione iniziale)
Formule:
unicità dischi su pioli:
piolo(p,d,t)  p' (p'  p  piolo(p',d,t))
definizione di disco più in alto:
top(p,d,t) 
(piolo(p,d,t)  d' (d' < d  piolo(p,d',t))

d = n+1  d' piolo(p,d',t))
situazione iniziale:
init(t) 
(1 =< d < n  on(d,d+1,t)) 
(on(d,d',t)  piolo(1,d,t)  piolo(1,d,t'))
situazione finale:
end(t)  d piolo(3,d,t)
mossa:
mossa(p,p',t) 
top(p,d,t)  top(p',d',t)  d' > d 
piolo(p',d,t+1) 
d",p" (d"  d  piolo(p",d",t)  piolo(p",d",t+1))
partita:
init(0)  t (end(t)  p,p' mossa(p,p',t))
Esercizio 2
Si tratta di un classico caso di applicazione del teorema di Rice. Infatti, il problema può essere visto come una specifica
funzione (il cui valore, per una data configurazione iniziale, potrebbe essere la sequenza di mosse, se esiste, che porta
alla desiderata configurazione finale). Tale funzione è ovviamente calcolabile. Quindi considerando l’insieme costituito
esattamente da tale funzione, non è decidibile, in base al teorema di Rice, se un generico algoritmo calcola esattamente
la funzione considerata.
Esercizi 3 e 3 bis
Ovviamente il criterio di costo logaritmico fornisce sempre la garanzia di risultati realistici. In questo caso, tuttavia esso
risulterebbe superfluo e quindi inutilmente oneroso da applicare. Si osservi infatti che una quantità di memoria limitata
linearmente dal numero n di dischi è sufficiente per rappresentare qualsiasi configurazione del sistema (ad esempio un
array che indichi la posizione di ogni disco costerebbe  (n) a criterio di costo costante e  (n.log(n)) a criterio
logaritmico). L’applicazione di ogni mossa richiederebbe perciò un tempo costante a criterio di costo costante e al più 
(log(n)) a criterio di costo logaritmico. Ne consegue che qualsiasi sia la complessità T(n) di un algoritmo (ovviamente
che non usi la memoria in modo scioccamente inefficiente) calcolata a criterio di costo costante, la corrispondente
complessità calcolata a criterio di costo logaritmico sarebbe automaticamente  (T(n).log(n)).
Si noti tuttavia che la funzione T(n) invece sarà probabilmente di un ordine di grandezza molto elevato data la natura “a
ricorsione fortemente nidificata” dei normali algoritmi per risolvere il problema.
Informatica Teorica
Appello del 19 Luglio 2006
Esercizio 1 (Punti 10)
Si consideri il linguaggio seguente:
L = {wcW | w, W  {a, b}*; W essendo una stringa che differisce dalla stringa riflessa, wR, di w per
al più 3 caratteri}
Si scrivano una grammatica e un automa, preferibilmente a potenza minima (ossia appartenenti a
una categoria di grammatiche e automi tale che una categoria di minor potenza generativa non possa
definire L) che generi e riconosca L, rispettivamente.
Esercizio 2 (Punti 13)
Si consideri il seguente problema: data una f(x) qualsiasi (con dominio e codominio l’insieme N) di
cui sia noto a priori che è computabile, stabilire se esistono un polinomio P a coefficienti interi non
negativi e un valore x  N tali che P( x)  f ( x) .
Si dica, giustificando brevemente la risposta, se il problema è decidibile, semidecidibile, o neanche
semidecidibile.
Come cambia, se cambia, la risposta assumendo di sapere a priori che f non è totalmente indefinita
(ossia indefinita per ogni valore del suo dominio)?
Esercizio 3 (Punti 10)
Si consideri il linguaggio L presentato nell'esercizio 1. Si descriva nel dettaglio un algoritmo per
una macchina basata sull’architettura di Von Neumann (ad es. la macchina RAM), che restituisca in
uscita la stringa wcwR, se la stringa in ingresso x = wcW appartiene a L, cc altrimenti. Si supponga
che
la
stringa
in
ingresso
NON
sia
già
disponibile
in
memoria.
Se ne valuti la complessità (spaziale e temporale, con entrambi i criteri di costo).
Soluzioni
Esercizio 1
L è evidentemente un linguaggio non contestuale.
Una G che genera L è la seguente:
S  c | aSa | bSb | aAb | bAa
A  c | aAa | bAb | aBb | bBa
B  c | aBa | bBb | aCb | bCa
C  c | aCa | bCb
Similmente, un automa a pila che riconosca L può operare nel modo seguente:
Inizialmente impila i caratteri di w fino ad incontrare c.
Dopo aver letto c inizia a svuotare la pila rimanendo nello stesso stato finché il simbolo letto
corrisponde al simbolo in cima alla pila. Se la pila si svuota quando si giunge a fine stringa in
questo stato l’ingresso viene accettato.
Non appena viene letto un carattere no corrispondente al carattere in pila si cambia stato una prima
volta; indi si prosegue lo svuotamento della pila nel modo usuale.
Sono possibili al più 3 cambiamenti di stato durante la lettura di W.
Esercizio 2
E’ noto che per qualsiasi valore y esistono un polinomio P e un valore z tale che P(z) = y (ad
esempio il polinomio costante y). Quindi il fatto che esistano un polinomio P a coefficienti interi
non negativi e un valore x  N tali che P( x)  f ( x) è equivalente a stabilire se esiste un x  N
tale che f (x) sia definito, ossia se f sia totalmente indefinita o meno.
Questo è un problema notoriamente indecidibile (tra i tanti modi di dimostrarlo si può utilizzare il
teorema di Rice); tuttavia esso è semidecidibile: infatti se un tale x esiste, mediante una tipica
enumerazione diagonale (simulo x mosse di una macchina che calcola f sul valore y, ecc.) esso
viene individuato.
Se invece si sapesse a priori che f non è totalmente indefinita, allora l’esistenza di x sarebbe già
garantita e quindi anche il problema di partenza sarebbe risolto.
Esercizio 3
Un semplice algoritmo che risolve il problema utilizza una lista di caratteri la cui lunghezza
massima sarà pari alla lunghezza di w, una struttura dati LIFO (cioè una pila) ed un contatore che
memorizza il numero di “errori” commessi dalla stringa W rispetto alla wR (quest’ultimo è
inizializzato a zero). Ogni volta che un carattere viene letto dall’input, si procede in questa maniera:
1. se non si è ancora letto il separatore ‘c’, si copia il carattere letto in coda alla lista e si
impila lo stesso carattere sulla pila
2. se si legge il carattere ‘c’, si procede al carattere successivo
3. se si è già letto il separatore ‘c’, allora
a. se il carattere appena letto corrisponde a quello in cima alla pila, si elimina
quest’ultimo dalla pila e si procede alla lettura del carattere successivo
b. altrimenti, si incrementa il contatore degli errori e
i. se il contatore errori è maggiore di 3, si scrive ‘cc’ in output e si termina,
ii. altrimenti, si procede con la lettura del carattere successivo
4. se la stringa è stata letta completamente dall’input e la pila è vuota, si utilizza la lista
riempita al passo 1. per scrivere in output wcwR. Per fare ciò, si scrive prima w scorrendo la
lista a partire dalla testa, si inserisce ‘c’ , e si ripercorre la lista in direzione opposta,
ottenendo quindi wR in output. Altrimenti, si scrive ‘cc’ in output.
Chiamando n la lunghezza della stringa in ingresso, l’occupazione in memoria dell’algoritmo
proposto è proporzionale a questa lunghezza. Infatti, per ciascun carattere letto, è necessario un
numero costante di celle di memoria (nel caso peggiore, una posizione nella lista e una posizione
sulla pila). Per cui, la complessità spaziale dell’algoritmo sarà (n) sia a costo costante che a costo
logaritmico. Per quanto riguarda la complessità temporale, i passi 1., 2. e 3. hanno un costo
costante per singola esecuzione. Nel caso peggiore, 1. e 3. vengono eseguiti n volte. Analogamente,
il passo 4. richiede un numero di operazioni direttamente proporzionale ad n nel caso peggiore. Di
conseguenza, la complessità temporale dell’algoritmo valutata a costo costante sarà (n), mentre
valutata a costo logaritmico sarà (n log(n)).
Informatica Teorica
Sezione Mandrioli
Appello del 13 Settembre 2006
Attenzione
I voti proposti verranno pubblicati sul sito seguente:
http://www.elet.polimi.it/upload/mandriol/Didattica/sitoinfteor1.html
Verrà data precedenza ai laureandi, che devono indicare questa loro qualifica nel proprio
elaborato.
Gli studenti avranno tempo due giorni (48 ore, per la precisione) dalla data della
pubblicazione per rifiutare il voto proposto, se sufficiente. L’eventuale rifiuto deve essere
comunicato via email, facendo uso dell’indirizzo ufficiale del Poliself, non di indirizzo privato!
Trascorsi i due giorni, i voti verranno registrati e trasmessi alla segreteria.
Il docente spedirà a ogni studente “rinunciatario” un esplicito messaggio di “ricevuta”. In
caso di mancata ricezione di tale ricevuta si consiglia di contattare il docente telefonicamente
o di avvisare la segreteria didattica del DEI.
Il tempo a disposizione per lo svolgimento del tema d’esame è 1h e 30 minuti.
Esercizio 1 (punti 12)
Si considerino le seguenti regole di attraversamento di un incrocio regolato da un semaforo.

Il semaforo è verde per 4 unità di tempo; poi passa a giallo per un’unità di tempo e rosso per
4 ulteriori unità.

Se un veicolo attraversa l’incrocio con semaforo verde o giallo nessuna azione viene
eseguite nei suoi confronti.

Se un veicolo attraversa l’incrocio con semaforo rosso entro 1 unità di tempo da quando è
diventato rosso, viene elevata contravvenzione per Euro 50.

Se un veicolo attraversa l’incrocio con semaforo rosso dopo 1 unità di tempo da quando è
diventato rosso, viene elevata contravvenzione per Euro 200.

Per semplicità si consideri un solo veicolo alla volta; si può anche assumere che la
contravvenzione sia contemporanea all’infrazione.
Si formalizzino le suddette regole in una sola delle versioni proposte nel seguito.
Versione A
Si utilizzi un’opportuna macchina astratta assumendo un tempo discreto in cui l’unità corrisponde
all’unità di tempo indicata sopra.
Versione B
Si utilizzino formule del primo ordine. In tal caso si può adottare un dominio temporale sia discreto
che continuo.
NB
E’ vietato consegnare entrambe le soluzioni che in tal caso non sarebbero valutate.
Esercizio 2
(punti 10)
Si consideri il sottoinsieme del linguaggio C in cui siano escluse tutte le istruzioni di controllo del
flusso dell’esecuzione ad eccezione dell’istruzione condizionale if e dell’istruzione ciclica for.
Si dica, giustificando brevemente la risposta, se è decidibile o no il problema di stabilire se un
generico programma scritto in tale sottoinsieme del C terminerà sempre la sua esecuzione (ossia per
ogni valore dei dati di ingresso) o no.
Esercizio 3 (punti 10)
Si supponga di implementare un algoritmo di merge-sort mediante una macchina RAM (non è
necessario scrivere effettivamente il codice!).
Quale sarebbe la sua complessità temporale valutata a criterio di costo costante e a criterio di costo
logaritmico? Giustificare brevemente la risposta. Per semplicità si può assumere che i dati da
ordinare occupino singolarmente una quantità limitata di memoria (ad esempio, 32 bit).
Parte facoltativa (ulteriori punti 5)
Si valutino anche la complessità spaziale dell’implementazione mediante RAM e la complessità sia
spaziale che temporale di una possibile implementazione mediante macchina di Turing, assumendo
la stessa ipotesi semplificativa della parte precedente.
Soluzioni
Esercizio 1
Versione A (traccia per la costruzione di un automa)
Assumendo un dominio temporale discreto, conviene associare ogni scatto di transizione a un’unità
di tempo. Quindi si può costruire un automa a 9 stati per descrivere l’evoluzione del semaforo. Ogni
transizione è etichettata da un input attr (“il veicolo attraversa durante l’unità di tempo corrente”)
oppure n_attr (“il veicolo non attraversa durante l’unità di tempo corrente”). La transizione
etichettata attr uscente dal primo stato rosso comporta l’uscita multa50 e le successive transizioni
uscenti dagli stati rossi comportano l’uscita multa200.
Versione B
Si introducano i seguenti predicati:
 v(t), (g(t), r(t), s(t))
Il semaforo è verde (rispettivamente, giallo, rosso, spento) all’istante t
 attr(t)
Il veicolo attraversa l’incrocio all’istante t
 multa50(t)
Viene elevata contravvenzione per 50 euro all’istante t
 multa200(t)
Viene elevata contravvenzione per 200 euro all’istante t
La formula seguente formalizza le regole richieste, assumendo che il semaforo inizi a funzionare
all’istante 0 (con il verde) e che la multa venga notificata immediatamente.
t
(t  0  s(t ))  (0 mod 9  t  4 mod 9  v(t )) 
(4 mod 9  t  5 mod 9  g (t ))  (5 mod 9  t  9 mod 9  v(t ))

((attr (t )  0 mod 9  t  4 mod 9)  (multa 50(t )  multa 200 (t ))

((attr (t )  4 mod 9  t  5 mod 9)  (multa 50(t )  multa 200 (t ))

((attr (t )  5 mod 9  t  6 mod 9)  (multa 50(t )  multa 200 (t ))

((attr (t )  6 mod 9  t  9 mod 9)  (multa 50(t )  multa 200 (t ))
Commento
Si noti che le formule di cui sopra, semplici e sistematiche, in realtà non formalizzano esattamente
le regole enunciate; bensì formalizzano un insieme di “comportamenti” che garantiscono la
soddisfazione delle regole: da queste formule, usate come assiomi, è possibile derivare come
teorema, ad esempio, il fatto che Se un veicolo attraversa l’incrocio con semaforo rosso dopo 1
unità di tempo da quando è diventato rosso, viene elevata contravvenzione per Euro 200.
Esercizio 2
In C, diversamente da altri linguaggi, come il Pascal, il ciclo for ha sufficiente generalità da
permettere di simulare anche il ciclo while. E’ noto che istruzione if e ciclo while (oppure
l’istruzione if e la possibilità di usare la ricorsione nella chiamata di sottorpogrammi) permettono a
un normale linguaggio di programmazione di avere la stessa potenza delle Macchine di Turing.
Quindi il problema posto è equivalente a stabilire se una generica MT calcola una funzione totale o
no. Questo problema è notoriamente indecidibile.
Esercizio 3
La normale analisi di complessità temporale dell’algoritmo di merge-sort assume implicitamente un
criterio di costo costante. E’ noto che essa produce un risultato (n.log(n)). Assumendo il criterio di
costo logaritmico occorre tener presente che ogni accesso a un singolo elemento costa un fattore
log(n) (in questa valutazione interviene solo il costo dell’indirizzamento, poiché la memorizzazione
dei singoli dati richiede un numero di bit limitato a priori). Quindi la complessità temporale valutata
a criterio di costo logaritmico è (n.log2(n)).
Parte facoltativa
Per valutare la complessità spaziale dell’implementazione mediante RAM occorre tener presente
che sono possibili diverse realizzazioni –ricorsive e non- dell’algoritmo di merge-sort. La più
efficiente dal punto di vista della complessità spaziale fa uso alternato di due array (o file) e risulta
quindi (n) in entrambi i criteri.
Un’analoga implementazione mediante MT richiederebbe anch’essa una quantità di memoria (n),
mentre avrebbe una complessità temprale (n.log(n)) grazie alla natura tipicamente sequenziale sia
dell’algoritmo di merge-sort che della MT (risparmiando così il fattore log(n) per l’accesso al
singolo dato).
Informatica Teorica
Appello dell’8 Febbraio 2007
Il tempo a disposizione per lo svolgimento del tema d’esame è 1h e 30’.
Esercizio 1 (punti 10)
Sia dato il linguaggio L sull'alfabeto {a, b, c} contenenti tutte e sole le stringhe che hanno le
seguenti caratteristiche:
k) la stringa inizia e termina con esattamente lo stesso numero di 'a'
l) la stringa contiene almeno un carattere diverso da 'a'
Per esempio, le seguenti stringhe appartengono a L:
aabcaa, aca, aacabbabaa, aaaacaaaa, ...
Le seguenti stringhe, invece, non appartengono ad L:
aaabaa, aaaa, aaacaccaaaaaa, ecc.
Si scriva un automa oppure una grammatica che riconosca o generi il linguaggio L.
NB1: il punteggio massimo verrà dato se il formalismo scelto è a potenza minima tra quelli che
riconoscono/generano L.
NB2: si scelga una sola tra le due possibilità: si scriva o un automa, oppure una grammatica, ma
non entrambi.
Esercizio 2 (11)
L'algoritmo di ordinamento per conteggio serve ad ordinare un array di valori interi fornito in
ingresso. Esso per funzionare si basa sulla ipotesi fondamentale che i valori da ordinare siano degli
interi appartenenti all'insieme [0..k], con k prefissato. L'algoritmo sfrutta per funzionare un array
ausiliario C di k+1 elementi, che serve a contenere il conteggio effettuato dall'algoritmo: in pratica
C[j] contiene il numero di elementi presenti nell'array in ingresso con valore pari a j.
Si implementi un algoritmo di ordinamento per conteggio, sapendo che ogni singolo dato da
ordinare è sempre un intero non negativo memorizzabile in 8 bit. Quali sono le sue complessità
temporale e spaziale valutate a criterio di costo costante e a criterio di costo logaritmico?
Giustificare brevemente la risposta.
NB: Si consiglia per comodità di descrivere l’algoritmo in pseudocodice, o mediante un linguaggio
di alto livello.
Esercizio 3 (punti 11)
Il professor Touring ha preparato, per il prossimo appello del suo esame di Informatica 1, i 3
seguenti esercizi:

Sia dato il seguente frammento di codice C:
1. void DivisoreComune (int i1, int i2){
2.
int min, max;
3.
4.
if(i1 <= i2){
5.
min = i1;
6.
max = i2;
7.
} else {
8.
min = i2;
9.
max = i1;
10.
}
11.
12.
for(d = 1; d <= min; d++){
13.
if(min % d == 0 && max % d == 0)
14.
return d;
15.
}
16.
17.
return 0;
18. }
Dire se ci sono errori di sintassi e, se ce ne sono, indicare quali.

Si scriva un sottoprogramma che prende in ingresso due parole p1 e p2 di al massimo 20 caratteri l'una, e
ritorna true se sono una l'anagramma dell'altra, false altrimenti.

Siano P, Q, R, tre puntatori a interi e x, y due variabili intere. Si dica quanto valgono rispettivamente x, y, *P,
*Q,
*R
dopo
l’esecuzione
della
seguente
sequenza
di
istruzioni.
x = 3; y = 5;
P = &x; Q = &y; R = P;
*R = 10; y = x + *Q; x = x + *P;
Q = R; P = Q
Per ognuno di questi esercizi dire, motivando adeguatamente la risposta, se è decidibile il problema
di stabilire se la soluzione proposta da uno studente è corretta oppure no.
Soluzioni
Esercizio 1
La seguente grammatica noncontestuale genera il linguaggio L.
S → aSa | BXB | B
X → aX | bX | cX | 
B → b|c
Esercizio 2
L’algoritmo puo’ operare come segue. Si mantengono due puntatori a, c rispettivamente
all’elemento corrente dell’array A da ordinare e all’elemento corrente dell’array C dei contatori.
1. Fase di input, che supponiamo venga terminata dalla lettura di -1, e di scrittura dei contatori:
for (c = 0 to 255)
C[c] := 0
c := read();
a := 0;
while( c ≠ -1 ) {
A[a] := c;
C[c] := C[c]+1;
c := read();
a := a+1;
}
A[a] := -1;
2. Fase di scrittura dell’output, che scandisce C e sovrascrive A:
a := 0
for (c = 0 to 255) {
while ( C[c] > 0 ) {
A[a] := c;
C[c] := C[c]-1;
a := a+1; }}
Sia n il numero di elementi dell’array da ordinare.

A costo costante, la complessita’ spaziale e’ (n) in quanto memorizzo un array di
dimensione n e uno di dimensione costante (infatti considero interi a 8 bit, quindi 256
possibili
valori).
La complessita’ temporale e’ pure (n). Infatti il passo 1 consta di 1 ciclo eseguito (n)
volte. Nel passo 2, invece, il ciclo piu’ interno e’ eseguito un numero costante di volte,
mentre quello esterno e’ eseguito al piu’ n volte. Quindi tutti i passi sono di complessita’
temporale (n), e lo stesso e’ la loro composizione sequenziale.

A costo logaritmico, il costo di memorizzazione dell’array da ordinare e’ sempre (n), in
quanto in ogni cella ho un valore limitato da 256. L’array di contatori consta invece di 256
celle, ognuna delle quali costa (log(n)). Quindi in tutto la complessita’ spaziale e’ ancora
limitata
superiormente
da
(n).
Per quanto riguarda la complessita’ temporale, si manipolano dei contatori che sono limitati
superiormente da n. Dunque, in costo logaritmico, questo implica in fattore log(n) in
ciascuna esecuzione dei cicli, che si traduce in una complessita’ temporale complessiva di
(n log(n)).
Esercizio 3
1. La risposta si riduce a una lista, sicuramente finita visto che il frammento di programma e’
finito, di potenziali errori di sintassi. Pertanto verificare la risposta corrisponde
semplicemente a confrontare due liste di dimensioni finita, problema chiaramente decidibile.
2. Verificare la correttezza della risposta corrisponde a decidere se il programma/soluzione
fornito dallo studente implementa la funzione richiesta oppure no. Come noto, decidere se
un dato programma implementa una certa funzione e’ un problema non decidibile. Si noti
che il fatto che l’input del programma e’ ristretto ad un numero finito di elementi (le
stringhe di 20 caratteri) non cambia la risposta, dal momento che il formalismo usato per
descrivere la soluzione (il codice) e’ comunque Turing-completo.
3. In questo caso la risposta consiste semplicemente in 3 valori interi per *P, *Q, e *R.
Controllare la validita’ della risposta e’ pertanto decidibile, in quanto si riduce al confrontro
tra 3 coppie di interi.
Informatica Teorica
Prima prova in itinere - 11 Maggio 2007
Tempo a disposizione: 1h 45’
Esercizio 1
(punti 5/13)
Scrivere una grammatica che genera il linguaggio costruito sull'alfabeto {a,b,c} fatto di tutte e sole
le stringhe x tali che esistano 2 sottostringhe disgiunte w e w', di lunghezza multiplo di 3, e w' = wR
(es. w = ccacbb, w’ = bbcacc).
NB: Il punteggio massimo verrà dato se la grammatica scritta sarà a potenza minima tra quelle che
generano il linguaggio desiderato.
Esercizio 2
(punti 5/13)
Si abbia un impianto manifatturiero che produce 2 tipi di prodotti, p1 e p2, tali che ogni pezzo di tipo
p1 vale 20000 euro, ed ogni pezzo di tipo p2 vale 30000 euro. L'impianto può produrre pezzi p1 e p2
in qualunque sequenza, fatto salvo che, ad ogni punto della sequenza di produzione, il valore totale
dei pezzi p2 prodotti deve essere maggiore o uguale del valore totale dei pezzi p1 prodotti, e
comunque la differenza tra i 2 valori totali non deve essere mai superiore ai 90000 euro.
Si scriva un automa che accetta tutte e sole le sequenze di produzione ammissibili dell'impianto
sopracitato.
NB: Il punteggio massimo verrà dato se l’automa scritto sarà a potenza minima tra quelli che
riconoscono le sequenze desiderate.
Esercizio 3 (punti 6/13)
E’ noto che ogni automa trasduttore definisce una traduzione : I* → O*. Per ogni famiglia di
automi trasduttori (a stati finiti, a pila –deterministici e non–, di Turing) si dica, giustificando
brevemente la risposta, se essa è chiusa rispetto alla composizione di traduzioni, ossia se, dati due
automi A1 e A2 che definiscano rispettivamente le traduzioni 1 e 2, esista nella stessa famiglia un
automa A che definisca la traduzione (x) = 2(1(x)).
Soluzioni
Esercizio1
Una grammatica (non-contestuale) che genera il linguaggio desiderato è la seguente.
S  QR1Q
Q  aQ | bQ | cQ | 
R1  aR2a | bR2b | cR2c
R2  aR3a | bR3b | cR3c
R3  aR1a | bR1b | cR1c | aQa | bQb | cQc
Esercizio2
Un automa a stati finiti che accetta tutte e sole le sequenze di produzione desiderate è il seguente
(laddove ogni stato rappresenta la differenza fino ad ora accumulata tra il totale del valore dei pezzi
p2 ed il totale del valore dei pezzi p1):
p2
p1
D10k
D20k
D0k
p1
D30k
D90k
p1
p1
p2
p2
D80k
p2
D40k
p1
p1
D70k
D50k
p2
p1
p2
p1
D60k
p2
Esercizio 3
1.
Le traduzioni a stati finiti sono chiuse rispetto alla composizione: un procedimento che, dati due
traduttori T1 = <Q1, I1, 1, q01, F1, 1, O1> e T2 = <Q2, I2, , q02, F2, , O2> (con O1 = I2) produca
un traduttore T che definisca (x) = 2(1(x)) può essere intuitivamente descritto con la seguente
costruzione, derivata dalla costruzione per l’intersezione di automi.
T è una tupla <Q, I1, , q0, F, , O2> in cui Q = Q1  Q2 e le funzioni di transizione e output di T,
<, >, sono definite secondo la seguente regola: se in T1 esiste una coppia
<1, 1>(q1, a) = <q1’, w1>, con a  I1 e w1  O1*, e per T2 si ha
<2*, 2*>(q2, w1) = <q2’, w2>, con w2  O2*
si definisca la coppia <, >(<q1,q2>, a) = <<q1’ q2’>, w2>.
L’insieme di stati di accettazione F di T sono tutti e soli quelli nella forma < q1, q2 > tali che q1  F1
e q2  F2. Lo stato iniziale di T è infine lo stato <q01, q02>.
2.
Le traduzioni a pila (sia deterministiche che non) non sono chiuse rispetto alla composizione.
Infatti la traduzione (w·c) = w·c·w, può essere ottenuta componendo le due traduzioni
1(w·c) = w·c·wR·d e 2(w1·c·w2·d) = w1·c·w2R. Essa però non può essere ottenuta da un solo
automa a pila, rigorosamente legato alla disciplina LIFO nella gestione del proprio input.
Un altro controesempio possibile è il seguente: la traduzione (an·bn·cn) = d può essere ottenuta
componendo le due traduzioni 1(an·bn·c*) = bn·c* e 2(bn·cn) = d. Anche in questo caso la
traduzione, che necessita dell’accettazione del linguaggio {an·bn·cn}, non può essere effettuata da un
automa a pila semplice.
Più in generale, si osserva che componendo “in serie” due trasduttori a pila è possibile fare in modo
che la composizione dei due accetti un linguaggio uguale all’intersezione dei due linguaggi accettati
da ognuno dei due trasduttori di partenza. Poiché è noto che la classe dei linguaggi accettati dagli
automi a pila non è chiusa rispetto all’intersezione, in generale non esiste quindi un automa a pila
equivalente alla composizione dei due di partenza.
3.
La composizione di due traduzioni effettuate da macchine di Turing può essere banalmente ottenuta
da una macchina che memorizzi in un nastro di memoria l’output della prima e poi lo usi come
fosse l’input della seconda.
Informatica Teorica
Seconda prova in itinere - 3 Luglio 2007
Avvisi importanti



Il tempo disponibile per lo svolgimento della prova è 1 ora e 30 minuti.
Gli studenti laureandi devono indicare esplicitamente la loro situazione nella testata del
loro elaborato.
Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità
di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del
docente sul sito ufficiale del Dipartimento. Verrà data precedenza alla correzione dei
compiti dei laureandi (che risultino tali dall’archivio ufficiale del CEDA)
Esercizio 1
(punti 4/17)
La successione 2  1 , per n numero naturale, è detta dei numeri di Fermat. Il matematico Pierre de Fermat fu il
primo a notare come i primi termini della successione (per n=0, 1, 2, 3) siano primi, dunque congetturò che lo siano
tutti.
2n
Si risponda alle seguenti domande, fornendo delle brevi, ma esaurienti, spiegazioni:
1.1. E’ decidibile il problema “tutti i numeri di Fermat sono primi?”?
1.2. E’ decidibile il problema “dato un numero naturale n, il numero 22  1 è primo?”?
n
1.3. (nel caso si sia risposto positivamente alla domanda 1.2) E’ decidibile l’insieme delle macchine
di Turing che risolve il problema della domanda 1.2?
Esercizio 2
(punti 6/17)
2.1
Si descriva un algoritmo che, dato un numero naturale n, determini se l’n-esimo numero di Fermat è
primo.
Si noti che:
m) non è necessario che l’algoritmo sia efficiente o elegante, l’importante è che sia semplice;
n) per descrivere l'algoritmo è possibile usare pseudocodice oppure un linguaggio ad alto
livello.
2.2.
Se l'algoritmo definito al punto 2.1 viene eseguito su una macchina RAM, quale è il criterio di costo
più opportuno per valutare la complessità di tale macchina RAM? Si motivi la risposta.
2.3.
Si usi il criterio individuato al punto 2.2 per valutare la complessità spaziale e temporale di una
macchina RAM che esegue l'algoritmo definito.
Esercizio 3
(punti 9/17)
Si vuole usare la logica del prim'ordine (con il predicato di uguaglianza) per descrivere giocatori e
squadre di uno sport a squadre (per esempio il calcio).
Si assuma quanto segue:

le variabili (x, y, w, ...) denotano giocatori;
 viene introdotto il predicato SameTeam(x,y) il quale è vero se i giocatori x e y sono nella
stessa squadra (laddove “essere nella stessa squadra” è una relazione di equivalenza).
3.1.
Si scrivano, usando esclusivamente i predicati di uguaglianza (=), disuguaglianza () e SameTeam,
delle formule logiche che formalizzano i seguenti vincoli:
a)
tutte le squadre hanno almeno 3 giocatori;
b)
esistono almeno 3 squadre.
3.2.
Si consideri una relazione di “rivalità personale” tra alcuni dei giocatori. A questo scopo si
introduca il predicato PersRivalry(x,y), il quale rappresenta il fatto che i giocatori x e y sono
rivali (si assuma pure che PersRivalry sia simmetrica).
Si scriva una formula che formalizzi il fatto che non ci possono essere rivalità all’interno di una
stessa squadra.
3.3.
Si assuma che periodicamente (per esempio ogni mese) si svolga un torneo tra le squadre, e che sia
le squadre che le rivalità personali possano cambiare da un torneo all’altro.
Si assuma inoltre quanto segue:
le variabili t, t’, t’’ denotano i momenti di svolgimento dei tornei, rappresentati come numeri
interi.

per descrivere squadre e rivalità si usano delle varianti temporizzate dei predicati introdotti
in precedenza, SameTeam(x,y,t) e PersRivalry(x,y,t), che indicano appartenenza
alla stessa squadra / rivalità di x e y al momento del torneo t.

Si scrivano delle formule che formalizzino i seguenti vincoli:
a)
due giocatori sono nella stessa squadra durante un torneo solo se non erano rivali in alcuno
dei precedenti k tornei;
b)
se, per un certo torneo, due giocatori della stessa squadra sono rivali, essi non saranno nella
stessa squadra per i prossimi h tornei.
Soluzioni
Esercizio 1
1.1. Sì, si tratta di una domanda “chiusa” (la risposta è sì oppure no). Tra l’altro si conosce anche la
risposta: Eulero dimostrò che per n=5 si ottiene un numero non primo.
1.2. Sì, basta scrivere una semplice procedura che, dato n, calcoli 22  1 e poi ne controlli la
primalità.
n
1.3. No, è una conseguenza del teorema di Rice (l'insieme delle MT che risolvono il problema 1.2
non è l'insieme vuoto, né tantomeno quello universo).
Esercizio 2
2.1
boolean primeNthFermat(int n){
1. x = 2
2. for i from 1 to n do x = x*x
3. x = x+1
4. for i from 2 to squareRootOf(x) do
5.
if (x/i)*i==x then return false
6. return true
2.2-2.3.
Per il calcolo del numero di Fermat (righe 1-3) è necessario usare il criterio di costo logaritmico, per
ottenere una valutazione di complessità realistica. Quindi si ottiene:
∑k=1, ..., n 2k =(2n) per il tempo e (2n) anche per lo spazio.
Il fattore di complessità dominante è però il secondo ciclo (righe 4-5): la complessità temporale che
si ottiene per esso (naturalmente sempre a costo logaritmico) è:
(
2n  22
n
) = ( 2 n  2 2
n1
) = ( 2 2
n 1
n
).
Infatti la singola iterazione costa log (22n) ed il calcolo della radice quadrata non impatta sul
comportamento asintotico della complessità.
Esercizio 3
3.1.
a) xyz(xy  yz  xz  SameTeam(x,y)  SameTeam(y,z))
b) xyz(xy  yz  xz  SameTeam(x,y)  SameTeam(y,z)  SameTeam(x,z))
3.2.
xy(xy  SameTeam(x,y)  PersRivalry(x,y))
3.3.
a) xyt(SameTeam(x,y,t)  t’(t-kt’<t  PersRivalry(x,y,t’)))
b) xyt(PersRivalry(x,y,t)  SameTeam(x,y,t)  t’(t<t’t+h  SameTeam(x,y,t’)))
Informatica Teorica
Appello del 17 Luglio 2007
Avvisi importanti


Il tempo disponibile per lo svolgimento della prova è 2 ore.
Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità
di accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del
docente sul sito ufficiale del Dipartimento.
Esercizio 1 (punti 12)
Parte A
Si considerino le grammatiche seguenti:
G1:
S  SS | ASB | BSA | 
Aa
Bb
G2:
S  SBA | 
BA  AB
AB  BA
Aa
Bb
G3:
S  ABCS | e tutte le permutazioni della stringa ABCS | 
Aa
Bb
Cc
G4:
S  ABCS | 
BA  AB
AB  BA
CB  BC
BC  CB
AC  CA
CA  AC
Aa
Bb
Cc
Si dica, motivando brevemente la risposta, se G1 e G2, e G3 e G4 sono tra loro equivalenti.
Parte B
Si dica, motivando brevemente la risposta, se i linguaggi generati da G1, G2, G3 e G4 sono
riconoscibili da automi a pila (anche nondeterministici).
(continua sul retro)
Esercizio 2 (Punti 12)
Per una funzione F:NN, un elemento x del suo dominio di definizione è detto mimimo globale di
F se F(x) è definita e, per ogni valore y in cui F(y) è definita, F(x)  F(y), dove  definisce l’usuale
relazione di “minore o uguale” tra numeri naturali.
1. Si determini se il problema di trovare se una generica funzione computabile f ha un minimo
globale è decidibile.
2. Si determini se lo stesso problema è semidecidibile.
3. Come cambia, se cambia, la risposta ai quesiti precedenti se si considerano solo funzioni
totali e computabili?
Esercizio 3 (Punti 10)
Si consideri il problema della ricerca di un elemento x in un array S di lunghezza n. In tutto
l’esercizio, consideriamo solo la complessità temporale e il criterio di costo costante.
Come noto, l’algoritmo più immediato per risolvere il problema è quello della ricerca sequenziale,
che scandisce tutto l’array sequenzialmente alla ricerca dell’elemento x, e raggiunge una
complessità di (n) nel caso pessimo.
Si consideri ora il problema di trovare un algoritmo per risolvere lo stesso problema che sia
asintoticamente peggiore della ricerca sequenziale, ossia raggiunga una qualche complessità
n
0.
(p(n)), con p(n) funzione totale e computabile, tale che lim
n   p ( n)
1. Si descriva un algoritmo di ricerca asintoticamente peggiore della ricerca sequenziale, e se
ne valuti la complessità temporale, mostrando che è effettivamente asintoticamente
peggiore.
2. Un algoritmo A che risolve un problema P con complessità TA(n) è detto pessimo se ogni
altro algoritmo B che risolve P con complessità TB(n) è tale che: o A è asintoticamente
peggiore
di
B,
oppure
TA(n)
(TB(n)).
Per un generico problema P, esiste sempre un algoritmo pessimo che lo risolve? Esiste un
problema P che ammette un algoritmo pessimo per la sua soluzione? Motivare brevemente
le risposte.
Soluzioni
Esercizio 1
Parte A
G1 e G2 sono equivalenti. Infatti entrambe generano tutte e sole le stringhe con ugual numero di a e
b.
G3 e G4 non lo sono. Infatti G3, pur generando stringhe con ugual numero di a, b, c non può
generare, ad esempio stringhe del tipo anbncn.
Parte B
Poiché G1 e G3 sono non contestuali, i linguaggi da esse generati sono certamente riconoscibili da
automi a pila. Essendo G2 equivalente a G1, lo stesso vale per L(G2).
Invece G4 richiede il riconoscimento di stringhe del tipo anbncn che devono essere distinte, ad
esempio, da stringhe come anbnc2n. Ciò richiede una capacità di “conteggio illimitato doppio” che,
come ben noto, non rientra tra le possibilità dell’automa a pila.
Esercizio 3
1. Il problema non è decidibile, in quanti riducibile al problema di determinare se una generica
funzione computabile è definita per almeno un valore del suo dominio, problema che
notoriamente non è decidibile.
Infatti, sulla base della definizione data, tenendo conto che l’insieme dei numeri naturali è
discreto e limitato inferiormente, una funzione computabile f: N  N ha minimo globale se
e solo se è definita in almeno un punto.
2. Sia f una funzione totale e computabile, e sia I  N la sua immagine. Essendo I un insieme
limitato inferiormente (da 0), è sicuramente definito l’estremo inferiore i = inf I. Inoltre,
essendo I un insieme discreto, i appartiene a I, quindi i = min I. Il valore x tale che f(x) = i è
il minimo di f, che dunque esiste sempre per funzioni totali e computabili a valori in N.
Dunque il problema è deciso, e quindi a maggior ragione decidibile.
Per ripassare un pò di matematica, ecco un’altra giustificazione che I ha sicuramente
minimo. Un insieme S è detto ben ordinato (well-ordered) sse ogni suo sottinisieme non
vuoto ha un elemento minimo. Per assurdo, sia I non ben ordinato. Allora esiste un suo
sottoinsieme  J  I che non ammette minimo. Sia K il complemento, rispetto a N, di J.
Se 0  J, esso è anche minimo; quindi 0  J e dunque 0  K. Per induzione, tutti i naturali
appartengono a K e dunque J è vuoto, contrariamente all’ipotesi. Dunque I è ben ordinato, e
dunque ha minimo.
Esercizio 4
1.
n
 0 , si può generare un algoritmo
p ( n)
di ricerca che abbia complessità (p(n)) semplicemente “peggiorando” un normale algoritmo di
ricerca sequenziale aggiungendo l’esecuzione di un numero di istruzioni pari a p(n), ove n è la
lunghezza dell’array ove si sta cercando. In pseudocodice:
Data una qualunque funzione computabile p(n) tale che lim
n 
ricerca_p_peggiore(x, S):
1
n = |S|
2
max = p(n)
3
for i:=1 to max do
4
5
continue;
return ricerca_sequenziale(x, S)
end
La complessità dell’istruzione 5 è chiaramente pari a (n). Sia c(n) la complessità dell’istruzione 2,
ossia il costo di calcolare p(n). Infine il ciclo for delle istruzioni 3-4 ha complessità (p(n)). In
totale quindi, ricordando che p(n) cresce asintoticamente più di n, si ha una complessità (c(n) +
p(n)) che è (p(n)).
2.
Nella soluzione di 1. abbiamo mostrato come la complessità si possa “peggiorare” arbitrariamente.
Dunque per qualsiasi problema non ha senso cercare la complessità pessima perchè è sempre
possibile scegliere una funzione che cresce più velocemente e peggiorare l’algoritmo di quel fattore.
Informatica Teorica
Appello dell’11 Settembre 2007
Avvisi importanti

Il tempo disponibile per lo svolgimento della prova è 2 ore.

Come in altre occasioni i risultati e le successive comunicazioni (in particolare le modalità di
accettazione/rifiuto del voto proposto) saranno pubblicati nella pagina personale del docente sul sito ufficiale
del Dipartimento.
Esercizio 1 (punti 14)
Si consideri un modello di calcolo consistente in una Macchina di Turing a nastro singolo e dotata
di h testine di lettura/scrittura.
1. Si formalizzi tale modello.
NB, non è necessario formalizzarne il comportamento, ossia la relazione di transizione; è
sufficiente formalizzare la struttura della macchina ed eventualmente la configurazione.
2. Si dica, spiegandone brevemente i motivi, se una tal macchina dotata di k > h testine ha una
potenza di calcolo (e.g. capacità di riconoscere linguaggi) maggiore di quella dotata di sole h
testine.
3. Si dica, spiegandone brevemente i motivi, se una tal macchina dotata di k > h testine ha la
capacità di risolvere problemi (e.g. di riconoscere linguaggi) con complessità strettamente
inferiori (secondo la relazione ) rispetto a quella dotata di sole h testine.
Esercizio 2 (punti 10)
Si considerino le due grammatiche seguenti:
G1:
G2:
S  ADaCD | DAbDC
S  aADCD | DbADC
DC  CD | AA
DC  CD | AA
A  a | SSAD
A  a | SSAD | 
C  ADC | c
C  ADC | c
SA  AS | 
SA

AS
|

Si dica, giustificando brevemente le risposte, se i seguenti problemi sono decidibili:
1) G1 è equivalente a G2?
2) Data una generica grammatica regolare G, G è equivalente a G1?
Esercizio 3 (punti 10)
Si formalizzi mediante una formula del prim’ordine il linguaggio L costituito da stringhe del tipo
wcu, in cui w e u denotano stringhe non nulle consistenti dei soli caratteri ‘a’ e ‘b’ tali che almeno
in una posizione a partire dal loro inizio si trovi lo stesso carattere.
Per esempio la stringa ababcaabaaa appartiene a L, aaaaacbb non vi appartiene, ecc.
Soluzioni
Esercizio 1
1. Partendo dalla normale formalizzazione delle macchina a nastro singolo basta modificare la
funzione  nel modo seguente:
: Q  Ah  Q  Ah  Mh | M  {R, L, S}
La definizione di configurazione dovrà tener conto della posizione delle h testine, ad
esempio mediante apposite marche.
2. La potenza di calcolo ovviamente non aumenta, essendo già massima la potenza della
macchina con una sola testina.
3. Aumenta invece la capacità di riconoscere linguaggi con minor complessità, come
dimostrato dal seguente ragionamento intuitivo:
Il linguaggio {wcw | w  {a,b}*} non è riconoscibile in tempo lineare da una macchina a
nastro singolo con una sola testina ma è facilmente riconoscibile con 2 testine in tempo
O(n); con una naturale estrapolazione il linguaggio
{wcwcw … | w  {a,b}* ripetuto h volte }
può essere riconosciuto in tempo lineare mediante h+ 1 testine ma non con sole h testine.
Esercizio 2
1) Senza bisogno di rispondere al quesito se le due grammatiche siano equivalenti o meno, si
può comunque affermare che il problema di trovare tale risposta è decidibile, dato che la
risposta non può che essere SI o NO indipendentemente da qualsiasi altro fattore. Quindi
una tra le macchine di Turing che forniscono risposta costante SI e quella che forniscono
risposta costante NO risolve il problema di stabilire se le due grammatiche siano equivalenti.
2) Senza analizzare la regolarità del linguaggio di G1, o G1 genera un linguaggio regolare,
oppure non lo genera. Se non lo genera, la risposta è sempre negativa, dunque decidibile. Se
lo genera, allora il problema si riconduce all’equivalenza tra automi a stati finiti, che è
decidibile.
Esercizio 3
Seguendo una schema consueto si usino simboli di variabili per indicare generiche stringhe o
generici caratteri, a, b, c essendo invece simboli di costanti corrispondenti ai caratteri dell’alfabeto.
Usando inoltre le normali abbreviazioni ‘.’ e ‘| |’ per rappresentare la funzione binaria
concatenazione e la funzione “lunghezza di una stringa” la cui definizione viene data qui per
scontata, la formula seguente caratterizza tutte e sole le strnghe del linguaggio:
x  L   w, u, v, z (x = wfucvfz  |w| = |v|  (f = a  f = b)  (w,u,v,z  {a,b}*)).
Informatica Teorica
Prova d'esame - 13 Febbraio 2008
Esercizio 1
(punti 10/30-esimi, 7 se l’automa non è a potenza minima)
Si consideri la seguente grammatica G:
S  AB
A   | CAC | D
D  aDa | 
C  cC | Cc | 
B  bbB | b
Si scriva un automa, preferibilmente a potenza minima, che riconosca il linguaggio L generato da G.
Esercizio 2
(punti 10/30-esimi)
Descrivere (senza necessariamente codificarla nei dettagli) una macchina RAM che riconosce il
linguaggio L descritto nell'esercizio 1, e se ne dia la complessità spaziale e temporale a costo
costante e a costo logaritmico. E’ preferita una macchina che minimizzi entrambe le complessità, a
meno della relazione di equivalenza .
Esercizio 3
(punti 10/30-esimi)
 Dire se è decidibile il problema di stabilire se, data una generica macchina RAM, questa
riconosce il linguaggio generato dalla grammatica G dell'esercizio 1.
 Dire se è decidibile il problema di stabilire se la macchina RAM definita nell’esercizio 2
riconosce il linguaggio L generato dalla grammatica G dell’esercizio 1 oppure no.
Soluzioni
Esercizio 1
Il linguaggio L(G) è l’insieme
{c*a2nc*b2m+1 | n, m >= 0 }
che è un linguaggio regolare, anche se G non lo è. Quindi un automa a potenza minima che
riconosce L(G) è il seguente automa a stati finiti.
Esercizio 2
Una macchina RAM può simulare un automa a stati finiti con complessità spaziale (K) e
complessità temporale (n) sia a cirterio di costo costante che a criterio di costo logaritmico.
Esercizio 3
1. Il problema è indecidibile in quanto è il calassico problema della correttezza.
2. Il problema è decidibile, in quanto la macchina RAM in questione è fissata (e quindi la risposta è
chiusa, o SI, o NO).
Informatica Teorica
Prima prova in itinere - 8 Maggio 2008
NB: il punteggio è espresso in 13-esimi e riflette il peso relativo della prova rispetto all’intero
esame il cui punteggio è in 30-esimi. Come già in altre occasioni è tuttavia possibile ottenere un
punteggio complessivo superiore a 13/13.
Esercizio 1
(10/13 punti)
Parte 1
Si formalizzi la nozione di automa trasduttore finito deterministico FT1 che, al contrario del
modello di trasduttore finito presentato a lezione (chiamiamolo FT), può anche effettuare -mosse
ma può emettere, a ogni transizione, al più un solo simbolo sul nastro di uscita.
Dimostrare che il modello FT1 è almeno altrettanto potente del modello FT deterministico (ossia
che qualsiasi FT può essere simulato da un opportuno FT1).
Parte 2
Formalizzare poi la nozione di automa finito deterministico a due ingressi, 2FA, tratteggiato in
figura a sinistra.
I1
a, 
CD
a, a
I2
2FA può fare -mosse, non facendo avanzare la testina di ingresso su uno o entrambi i nastri di
ingresso I1 e I2. L’automa 2FA può essere visto come traduttore nel modo seguente: la stringa di
ingresso x viene accettata e tradotta in (x) se e solo se la coppia di stringhe <x, (x)> sui due nastri
I1 e I2 è accettata. Per esempio, l’automa 2FA nella figura a destra definisce la traduzione (an)=an/2
per n0 e pari. Mostrare che il modello 2FA è almeno altrettanto potente di FT deterministico, nel
senso che se un FT deterministico accetta una stringa x e la traduce nella stringa (x), allora esiste
un opportuno 2FA che accetta la coppia di stringhe <x, (x)> sui due nastri I1 e I2.
Valutare se il modello 2FA ha esattamente la stessa potenza espressiva di FT, cioè se qualsiasi
traduzione definita da un 2FA nel modo sopra indicato può essere calcolata da un opportuno FT.
Esercizio 2 (4/13 punti)
Scrivere una grammatica G che generi il linguaggio {anbn se n è pari >= 0, ancn se n è dispari}
Soluzioni
Esercizio 1
 Un FT1 è una tupla (Q, I, O, δ, q0, F) dove Q, I, O, q0, e F hanno lo stesso significato che
negli automi trasduttori tradizionali. La funzione di transizione δ: Q × I  {}  Q × O 
{} definisce, per ogni coppia (q, i) di stato corrente e carattere in input (oppure ) lo stato
prossimo q’ e il singolo carattere scritto in output (oppure ), cioè δ(q,i) = (q’, o). Affinchè
sia deterministico si richiede che se δ(q,) è definito, allora δ(q,i) è indefinito per tutti gli i 
I.
Conviene poi fornire la definizione di configurazione, transizione tra configurazioni, e
trasduzione seguendo la prassi standard usata per automi a pila e macchine di Turing.
 Dato un FT = (Q, I, O, δ, q0, F) deterministico, è sempre possibile definite un FT1 = (Q’, I,
O, δ’, q0, F) che definisce la stessa traduzione facendo in modo che, quando FT emette una
stringa di lunghezza >1, l’FT1 corrispondente emetta in sequenza i caratteri della stringa,
uno alla volta, mediante una serie di -mosse che lo fanno passare attraverso una serie di
stati aggiuntivi, diversi da tutti gli altri, introdotti a questo scopo. Q’ e δ’ sono quindi
definiti in questo modo. Q’ contiene tutti gli stati che sono in Q. Inoltre, per ogni δ(q,i) =
(q’, s) con s  O*, se |s|  1 si ha semplicemente δ’(q,i) = (q’, s); se |s| > 1si aggiungono |s|
stati qs1, qs2, ..., qs|s| a Q’ e si pone: (1) δ’(q,i) = (qs1, s[1]); (2) per ogni 2  k  |s|: δ’(qsk-1,)
= (qsk, s[k]); (3) δ’(qs|s|,) = (q’, );.
 Un 2FA è una tupla (Q, I1, I2, δ, q0, F) dove I1 e I2 sono gli alfabeti dei due nastri di
ingresso, Q, q0, e F hanno il significato convenzionale. La funzione di transizione δ: Q × I1
 {} × I2  {}  Q definisce per ogni tupla (q, x, y) di stato corrente q, carattere sul
primo nastro x (o ), e carattere sul secondo nastro y (o ) lo stato prossimo δ(q, x, y). Si
richiede per il determinismo che se δ(q, x, ) (rispettivamente δ(q, , y)) è definito allora δ(q,
x, y) è indefinito per ogni y  I2 (rispettivamente per ogni x  I1).
La definizione di configurazione e transizione tra configurazioni sono definite di
conseguenza nel solito modo (includendo nella configurazione il contenuto dei due nastri
dalla posizione della testina in poi).
 Il modello 2FA è almeno altrettanto potente del modello FT1 (e quindi, transitivamente, del
modello FT): dato un qualsiasi FT1, esiste un 2FA che simula ogni sua transizione,
leggendo dal secondo nastro di ingresso lo stesso carattere che l’FT1 emette sul nastro di
uscita ed effettuando -mosse sul primo o sul secondo nastro di ingresso quando,
rispettivamente, l’FT1 fa una -mossa (i.e., non consuma ingresso) o non emette alcun
simbolo in uscita. Formalmente, dato un FT1 = (Q, I, O, δ, q0, F) si definisce il
2FA = (Q, I, O, δ’, q0, F) dove ’(q, x, y) = q’ se e solo se (q, x)=(q’,y), q,q’Q e
xI{} e yO{}.
 Il modello 2FA è strettamente più potente del modello FT, perchè permette di definire una
traduzione, accettandola come stringa in ingresso sul secondo nastro, anche nel caso in cui la
traduzione dipenda da una proprietà della stringa di ingresso (quella sul primo nastro) che
può essere decisa solo al termine della scansione, dopo un numero di passi illimitato a priori.
Ciò non può essere fatto dal modello FT, a causa del vincolo di memoria finita che lo
obbliga a emettere la traduzione “in tempo reale”, durante la scansione della stringa in
ingresso. Come esempio di cìò si consideri la seguente traduzione: (an)=bn se n è pari,
(an)=cn se n è dispari. Nessun FT può calcolare questa traduzione, perchè il riconoscimento
della stringa come avente lunghezza pari o dispari avviene solo al termine della scansione,
mentre l’emissione della traduzione deve avvenire durante la scansione. Il 2FA mostrato in
figura invece definisce la traduzione in questione accettando il linguaggio L={( an,bn) | n0,
n pari }{( an,cn) | n dispari }
.
a,b
a,b
a,c
a,b
a,c
a,c
Esercizio 2
SX|Y
X  aAb | 
A  aXb
Y  aBc
B  aYc | 

Theoretical Computer Science
(English version, with slightly more detailed solutions)
Midterm exam – May 8th 2008
NB: the total score is 13, reflecting the relative weight of this part of the exam w.r.t. the total of 30 for the whole course.
Just like in previous occasions it is possible, however, to get a grade higher than 13.
Exercise 1
(10/14 points)
Part 1
Please formalize the notion of a deterministic finite transducer FT1 that, unlike the finite
transducer model presented at lesson (let us call that one FT), can also have -moves but can emit,
at every transition step, at most one symbol on the output tape.
Prove that the FT1 model is at least as powerful as the deterministic FT (i.e., any possible
deterministic FT can be simulated by a suitable FT1).
Part 2
Please formalize the notion of a two-input deterministic finite automaton 2FA, outlined in the figure
on the left.
I1
a, 
CD
a, a
I2
The 2FA may make -moves, i.e., it may leave the scanning head still on one or both of the input
tapes I1 and I2. The 2FA automaton can be viewed as a transducer in the following way: the input
string x is accepted and translated into (x) if and only if the string pair <x, (x)> is accepted on the
two input tapes I1 and I2. For instance, the 2FA automaton in the figure on the right defines the
translation (an)=an/2 for n0 and n even.
Please show that the 2FA model is at least as powerful as the deterministic FT, i.e., if a
deterministic FT accepts a string x and translates it into the string (x), then there exists a suitable
2FA that accepts the string pair <x, (x)> on the two input tapes I1 and I2.
Please determine if the 2FA model has exactly the same expressive power as the FT model, i.e., if
any translation defined by a 2FA in the manner indicated above can be computed by a suitable FT.
Exercise 2 (4/14 points)
Write a grammar G that generates the language {anbn if n is even >= 0, ancn if n is odd}
Solutions
Exercise 1
 An FT1 is a tuple (Q, I, O, δ, q0, F) where Q, I, O, q0, and F have the same meaning as in
traditional finite transducers. The transition function δ: Q × I  {}  Q × O  {} defines,
for each pair (q, i) of current state and input character (or ) the next state q’ and the unique
character written on the output (or ), i.e., δ(q, i) = (q’, o). To make the automaton
deterministic it is required that, if δ(q, ) is defined, then δ(q, i) is not defined for all i  I.
Following the usual notations adopted for Stack automata and Turing machines, the
configuration of a FT1 is defined as a tuple (q, x, y)Q × I* × O*, q being the current state,
x the string still to be read on the input, and y the string output so far. The transition relation
|-- among configurations is defined as follows. If (q, )=(q’, o) then (q, x, y)|--(q’, x, y.o); if
(q, i)=(q’, o) then (q, i.x, y)|--(q’, x, y.o); the relation |-*- is defined as the reflexive
transitive closure of |--; a string xI1 is accepted if and only if, for some qfF and yO*, (q0, x, ) |-*- (qf, , y); in that case the translation performed by FT1 on x is define as (x) = y.
 Given a deterministic FT = (Q, I, O, δ, q0, F), it is always possible to define a
FT1 = (Q’, I, O, δ’, q0, F) that defines the same translation by making sure that, when the
FT emits a string of length >1, the corresponding FT1 emits in a sequence the characters
composing the string, one at the time, by means of a series of -moves that make it go
through a sequence of additional states, different from all the other ones and suitably
introduced for this purpose. Q’ and δ’ are hence defined as follows. Q  Q’ and besides, for
each δ(q,i) = (q’, s) with s  O*, if |s|  1 then simply δ’(q,i) = (q’, s); if |s| > 1 the |s| new
states are added to Q’, qs1, qs2, ..., qs|s| and: (1) δ’(q,i) = (qs1, s[1]); (2) for each 2  k  |s|:
δ’(qsk-1,) = (qsk, s[k]); (3) δ’(qs|s|,) = (q’, ).
 A 2FA is a tuple (Q, I1, I2, δ, q0, F) where I1 and I2 are the alphabets of the two input tapes,
Q, q0, and F have the usual meaning. The transition function δ: Q × I1  {} × I2  {}  Q
defines, for each tuple (q, x, y) of current state q, input character on the first tape x (or ),
and input character on the second tape y (or ) the next state δ(q, x, y). To make the device
deterministic it is required that if δ(q, x, ) (respectively, δ(q, , y)) is defined, then δ(q, x, y)
is not defined for every y  I2 (respectively, for every x  I1).
The configuration of a 2FA is defined as a tuple (q, x, y)Q × I1* × I2*, q being the current
state, x and y the strings still to be read on the first and second input. The transition relation
|-- among configuration is defined as follows. (q, x, y) |-- (q’, w, z) in the following cases:
(q, ) = q’ and w=x and z=y, or (q, i1, )=q’ with i1I1 and x=i1.w and z=y, or (q, ,
i2)=q’ with i2I2 and w=x and y = i2.z, or (q, i1, i)=q’ with i1I1 and with i2I2 and x=i1.w
and y = i2.z. The relation |-*- is defined as the reflexive transitive closure of |--; a pair of
strings (x, y) is accepted if and only if, for some qfF, (q0, x, y) |-*- (qf, , ).
 The 2FA model is at least as powerful as the FT1 model (and hence, transitively, as the FT
model): given any FT1, there exists a 2FA that simulates all its transitions, by reading from
the second input symbol the same character that the FT1 writes on its output tape, and
performs -moves on the first or second input tape when, respectively, the FT1 makes an moves (i.e., it does not consume its input) or it does not emit any output symbol. Formally,
given an FT1 = (Q, I, O, δ, q0, F) one can define the 2FA = (Q, I, O, δ’, q0, F) where
’(q, x, y) = q’ if and only if (q, x)=(q’,y), q,q’Q and xI{} and yO{}.
 The 2FA model is strictly more powerful than the FT model, because it allows one to define
a translation, by accepting the string result of the translation as input on the second tape, also
in the case when the translation depends on a property of the input string (the string on the
first input tape) that can be decided only at the end of its scanning, after a number of steps
that is a priori unlimited. This cannot be done by the FT, due to the finite memory constraint
that forces it to emit the translation “in real time”, during the scanning of the input string. As
an example, let us consider the following translation: (an)=bn if n is even and n0, (an)=cn
if n is odd. No FT can compute this translation, because the decision that the string has even
or odd length can be taken only at the end of the scanning of the input, while the translation
must be written during the scanning of the input. Instead, the 2FA shown in the figure below
defines the translation by accepting the language L={( an,bn) | n0, n even }{( an,cn) | n
odd}.
.
a,b
a,b
a,c
a,b
a,c
a,c
Exercise 2
SX|Y
X  aAb | 
A  aXb
Y  aBc
B  aYc | 

Informatica Teorica
Seconda prova in itinere  30 Giugno 2008, Sezione Mandrioli
Il tempo a disposizione è di 2 ore e 30 minuti
Esercizio 1
(punti 8/17-esimi)
Si formalizzi mediante formule del prim’ordine il seguente comportamento di un sistema di allarme
a tempo continuo:

L’allarme si attiva e disattiva inserendo la chiave nell’apposito alloggiamento; mentre la
disattivazione è immediata, l’attivazione avviene dopo 12 secondi dall’introduzione della
chiave; un eventuale reinserimento della chiave durante questo periodo non ha effetto;
l’estrazione della chiave dall’alloggiamento non ha alcun effetto e può essere trascurata.

Ad allarme attivato l’ingresso di un corpo estraneo nel volume sotto controllo determina lo
scatto dell’allarme dopo 12 secondi, a meno che durante tale intervallo non venga inserita la
chiave nell’alloggiamento per disinserirlo.
Si suggerisce di usare i seguenti predicati logici (dall’ovvio significato), tutti quanti aventi un
parametro a valori reali: attiva_allarme(t), disattiva_allarme(t), allarme_attivo(t),
inserimento_chiave(t), rilevamento_corpo_estraneo(t), scatto_allarme(t).
Esercizio 2
(punti 6/17-esimi)
Si dica, giustificando brevemente la risposta, se i seguenti problemi sono decidibili o semidecidibili:
o) Stabilire se, data una generica macchina di Turing a nastro singolo e due configurazioni
della medesima, le due configurazioni sono tra loro in relazione di transizione immediata.
p) Stabilire se, data una generica macchina di Turing a nastro singolo e due configurazioni
della medesima, le due configurazioni sono tra loro in relazione di transizione non
necessariamente immediata.
Esercizio 3 (punti 6/17-esimi)

Si supponga che una macchina di Turing deterministica simuli il comportamento di un
automa a stati finiti nondeterministico nel seguente modo: ricevendo in ingresso una stringa,
essa riproduce, una dopo l’altra, tutte le possibili esecuzioni che l’automa nondeterministico
può svolgere su tale stringa. Si indichi la complessità minima (col criterio del caso pessimo)
che tale simulazione richiede, sia per il tempo che per lo spazio, in funzione della lunghezza
n della stringa in ingresso x.

Si supponga che una macchina di Turing deterministica abbia in ingresso la descrizione di
un automa a stati finiti nondeterministico, e una stringa, da intendere come ingresso per
l’automa, e scriva in uscita il valore 1 se la stringa appartiene al linguaggio accettato
dall’automa, 0 altrimenti. Si valutino, giustificando brevemente la risposta:
o la complessità temporale e quella spaziale minime (col criterio del caso pessimo)
come funzione del numero m degli stati dell’automa in ingresso;
o la complessità temporale e quella spaziale minime (sempre col criterio del caso
pessimo) come funzione della lunghezza n della stringa in ingresso x.
Soluzioni schematiche
Esercizio 1
inserimento_chiave,
attiva_allarme,
disattiva_allarme,
rilevamento_corpo_estraneo,
scatto_allarme sono definiti a priori come eventi, ossia istantanei, allarme_attivo è invece definito a
priori come uno stato che ha quindi una durata.
La formula seguente esprime i requisiti richiesti mediante la sintassi del calcolo dei predicati.
attiva_allarme(t) 



t
inserimento_chiave(t 12)allarme_attivot
( 12)


t1(t 12t1 t attiva_allarme(t1))



tdisattiva_allarme(t) inserimento_chiave(t)allarme_attivot
( )

( )
allarme_attivot



t
t1 t attiva_allarme(t1)

t1


t2(t1 t2 t disattiva_allarme(t2))


scatto_allarme(t) 



t
rilevamento_corpo_estraneot
( 12)allarme_attivot
( 12)


t1(t 12t1 t inserimento_chiave(t1))


Esercizio 2
Quesito 1
Il problema è sicuramente decidibile: è infatti immediato costruire un semplice algoritmo che
scandisca la configurazione iniziale e determini il simbolo in lettura e lo stato della macchina,
individui la mossa definita dalla funzione  della macchina e verifichi se la seconda configurazione
coincide con quella che si otterrebbe applicando la .
Quesito 2
Questo problema è invece non decidibile. Infatti il classico problema dell’HALT è un caso
particolare del problema posto: stabilire cioè se da una configurazione iniziale si può giungere a una
configurazione di HALT. NB: per la precisione, visto che in generale vi possono essere diverse di
configurazioni di HALT, per ricondurre il problema dell’HALT esattamente al problema in
questione è necessario modificare la macchina in modo tale che essa abbia un’unica configurazione
di HALT (ad esempio, nastro vuoto e stato qF.)
Il problema è invece semidecidibile in quanto è sufficiente “far girare” la macchina a partire dalla
prima configurazione: se la seconda è raggiungibile, prima o poi la si raggiunge e si risolve il
problema. Non vale ovviamente il viceversa.
Esercizio 3
Quesito 1
Il meccanismo di simulazione della MT è quello classico di visita dell’albero delle computazioni;
quindi la complessità temporale è nel caso pessimo (2n) (per semplicità assumiamo che l’albero
sia binario). Se la macchina costruisce l’intero albero delle computazioni anche la complessità
spaziale è dello stesso ordine. Tuttavia la macchina potrebbe limitarsi a memorizzare solo l’ultimo
cammino visitato, ad esempio, in preordine sinistro; in tal modo potrebbe generarli ed esaminarli
tutti in sequenza (ad esempio:
S, S, S, S, S - S,S,S,S,D  S, S, S, D, S  S, S, S, D, D  S, S, D, S, S ….)
senza costruire l’intero albero. In tal caso la complessità spaziale risulta (n).
Quesito 2
Consideriamo una macchina di Turing che costruisce l’automa deterministico equivalente a quello
non deterministico di partenza, e quindi effettua il riconoscimento della stringa simulando
direttamente l'automa deterministico.
a.
E’ noto che nel caso pessimo l'automa deterministico, equivalente a quello in input di m stati, ha
(2m) stati e quindi la complessità spaziale della macchina è dominata da questo fattore. Allo stesso
modo, la complessità temporale è dominata dalla costruzione di tale automa.
b.
Una volta costruito l’automa deterministico la MT può semplicemente simulare quest’ultimo con la
stessa sua complessità, ossia (n) per la complessità temporale e (1) per quella spaziale, tenendo
conto ovviamente che la memoria finita costituita dagli (2m) stati non è funzione della lunghezza
della stringa di ingresso x.
Soluzione alternativa del Quesito 2:
Considerando i quesiti a e b come indipendenti, possiamo scegliere un algoritmo diverso in
ciascuno dei due casi, puntando unicamente a minimizzare la complessità rispetto al parametri
considerato nel punto in questione.
Per il punto b la soluzione basata sulla determinizzazione suggerita nella soluzione precedente
rimane la migliore dal punto di vista della complessità ottenibile.
Per il punto a, invece, possiamo utilizzare di nuovo l'algoritmo di simulazione del punto 1. La
complessità spaziale è quella necessaria a memorizzare l'ultimo cammino visitato; essendo un
cammino lungo n ed essendo necessari log m bit per memorizzare (sinteticamente in binario)
l'informazione su uno degli m stati, abbiamo una complessità spaziale di (log(m)) visto che n non
è funzione di m. Similmente, la complessità temporale è quella necessaria ad esplorare l'albero delle
2n computazioni, dove ogni passo costa l'aggiornamento dello stato corrente, ossia log(m). Quindi
anche la complessità temporale è (log(m)). Ovviamente questa valutazione di complessità è
formalmente corretta ma irrealistica perchè ignora completamente la dimensione di parte dell'input
(e i suoi effetti sulla complessità).
Informatica Teorica
Appello d'esame del
16 luglio 2008, Sezione Mandrioli
Si consideri la grammatica G seguente:
S  BAcB | 
A  aAa | acBa
B  CcB | 
C  aC | a
Esercizio 1 (punti 11)
Si fornisca un automa che riconosca il linguaggio L(G) generato da G.
L’automa deve appartenere alla classe di minima potenza riconoscitiva possibile per riconoscere
L(G).
Si spieghi brevemente perché la classe dell’automa scritto è quella a potenza minima possibile.
Esercizio 2 (punti 12)
q) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se L(G)
intersecato con il linguaggio {(a*c)*} produce il linguaggio vuoto o no.
r) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se, dato
un generico automa a stati finiti A, il linguaggio L(A) riconosciuto da A è uguale al
linguaggio L(G) oppure no.
s) Si dica, giustificando brevemente la risposta, se, fissata una grammatica G', è decidibile il
problema di stabilire se, dato un generico automa a stati finiti A, il linguaggio L(A)
riconosciuto da A è uguale al linguaggio L(G’) generato da G’ oppure no.
t) Si dica, giustificando brevemente la risposta, se è decidibile il problema di stabilire se, dati
una generica grammatica G’ ed un generico automa a stati finiti A, il linguaggio L(A)
riconosciuto da A è uguale al linguaggio L(G’) generato da G’ oppure no.
Esercizio 3 (punti 10)
Si descrivano a grandi linee il funzionamento di una macchina di Turing deterministica e di una
RAM che riconoscano L(G) e se ne valutino le complessità secondo la classe , usando per la RAM
il criterio di costo logaritmico.
Soluzioni schematiche
Esercizio 1
La grammatica genera il linguaggio:
L(G) = { (a+c)*anc(a+c)*anc(a+c)* | n > 0 }  ,
dove x+ = x* – {}.
Per riconoscere L(G) è necessario e sufficiente un automa a pila nondeterministico. La pila è
necessaria per effettuare il conteggio delle sottostringhe an. Anche il nondeterminsmo è necessario
perchè con il solo determinismo non è possibile stabilire in quale punto delle sottostringhe fatte di
‘a’ è necessario iniziare ad usare la pila per contare tali ‘a’. In altre parole, il nondeterminismo serve
a discernere le sottostringhe del tipo (a+c)*, per le quali è sufficientemente un riconoscimento a stati
finiti senza pile, da quelle del tipo an per le quali la pila è invece ovviamente necessaria.
Un possibile ND PDA che riconosce L(G) è il seguente:
c,Z0/Z0
a,Z0/Z0
a,Z0/Z0A
c,A/A
a,Z0/Z0
a,A/A
a,Z0/Z0
a,A/AA
a,Z0/Z0A
a,A/A
a,A/
a,A/A
a,Z0/Z0
c,Z0/Z0
c,A/A
a,A/
c,Z0/Z0
a,Z0/Z0
a,A/
Esercizio 2



Decidibile, la risposta è chiusa (Si/No). Anzi, in questo caso il problema è deciso, in quanto
l'intersezione non è vuota.
Decidibile: L(G) non è un linguaggio regolare, quindi la risposta sarà sempre No, qualunque
sia A.
Decidibile: se L(G') non è un linguaggio regolare la risposta sarà sempre No; se invece L(G')
è regolare, siccome è decidibile il problema di stabilire se FSA riconoscono lo stesso
linguaggio, ci sarà sempre una MT che, fissato un linguaggio regolare, determina se questo è
uguale a quello riconosciuto da un FSA in input. Ora, fissato L(G'), non è detto che io sappia
esattamente quale è questa MT (i linguaggi regolari sono un'infinità enumerabile, e non è

detto che io capisca quale di questi è quello generato da G'), ma essa di certo esiste,
rendendo il problema decidibile.
Indecidibile, in quanto riconducibile al problema di stabilire se una generica MT calcola una
certa funzione (in questo caso, quella corrispondente all'FSA), oppure no.
Esercizio 3
Una macchina di Turing (deterministica) che riconosce L(G) può operare nella seguente maniera (al
solito indichiamo con n la lunghezza dell'input):
 In primo luogo effettua una scansione completa dell'input per verificare che sia una stringa
del tipo (a+c)k con k > 1. Questa è una condizione necessaria perchè sia in L(G), e può essere
verificata in tempo (n).
 Se il test precedente è passato con successo, l'input appartiene a L(G) se e solo se esistono
due sottostringhe (massimali, ossia racchiuse tra due 'c') di sole 'a' della stessa lunghezza.
Questa verifica può essere fatta nella seguente maniera: per ogni sottostringa di 'a' incontrata
sequenzialmente nell'input:
o la sottostringa di 'a' viene ricopiata su un nastro di memoria;
o si prosegue la scansione dell'input confrontando ogni successiva sottostringa di 'a' con
quella presente sul nastro di memoria.
Nel caso pessimo questo comporta una scansione completa dell'input per ogni sottostringa di
'a' incontrata. Possono esservi fino a (n) sottostringhe di questo tipo, quindi la complessità
temporale di caso pessimo è (n2), che è anche la complessità complessiva dell'algoritmo.
La complessità spaziale è invece chiaramente (n).
Una macchina RAM può usare un algoritmo simile a quello descritto per la macchina di Turing,
usando ad esempio dei contatori per memorizzare lunghezza delle sottostringhe di 'a' incontrate. Si
avrebbero dunque (n) contatori, ciascuno memorizzante un intero (n). Adottando il criterio di
costo logaritmico, i (n2) confronti da effettuare porterebbero pertanto a una complessità temporale
complessiva di (n2 log n). La complessità spaziale, secondo le stesse considerazioni, sarebbe di
(n log n).
Informatica Teorica
Appello d'esame dell’8 Settembre 2008, Sezione Mandrioli
Il tempo a disposizione è di 2 ore
Esercizio 1 (Punti 13)
Si considerino le seguenti regole relative al funzionamento di un apparecchio per l’uso del
Bancomat:
1. L’apparecchio si trova inizialmente in uno stato di riposo
2. L’introduzione della tessera provoca la transizione in uno stato di immissione codice
3. Il codice consta di 5 cifre
4. L’immissione del codice è ultimata se l’utente ha digitato 5 cifre e successivamente premuto il
tasto ENTER, oppure dopo che sono trascorsi 5 secondi dall’immissione della quinta cifra.
5. Una volta ultimata l’immissione del codice l’apparecchio passa in uno stato di verifica.
6. Se, nello stato di immissione, trascorrono più di 5 secondi senza che si digiti una cifra e non è
stata ancora digitata la quinta cifra, viene espulsa la tessera e l’apparecchio torna nello stato di
riposo.
Si formalizzino mediante formule del prim’ordine solo le regole 4, 5 e 6 (le altre servono da
contesto ma non è necessario che vengano formalizzate esplicitamente). Si suggerisce di utilizzare i
seguenti predicati che denotano possibili stati in cui l’apparecchio si trova in un generico istante t:
 Riposo(t)
 ImissioneDati(t)
 Verifica(t)
 CifreImesse(t, k) indica che all’istante t le cifre immesse sono k; lo stato ha senso solo
durante lo stato ImmissioneDati.
e i seguenti predicati che denotano possibili eventi che si verificano in un generico istante t:
 PremiCifra(t)
 PremiEnter(t)
 EspulsioneTessera(t)
Esercizio 2
(Punti 11)
Dire se i seguenti problemi sono decidibili, solo semidecidibili, o né uno né l'altro:
1. Stabilire se, data una generica Macchina di Turing M, il linguaggio riconosciuto da M è
vuoto.
2. Stabilire se, data una generica Macchina di Turing M che non ha cicli (cioè il cui grafo
corrispondente è aciclico), il linguaggio riconosciuto da M è vuoto.
3. Stabilire se, data una generica Macchina di Turing M che non ha autoanelli (cioè il cui grafo
corrispondente non ha archi che puntano al nodo da cui originano; un autoanello è un caso
particolare di ciclo), il linguaggio riconosciuto da M non è vuoto.
Esercizio 3
(Punti 10)
Si consideri la traduzione di una stringa di ingresso w  {a,b,c}+ in una stringa an/2bm, dove n è il
numero di a nella stringa w e m è il numero di b nella stringa w.
1. Si descriva a parole una Macchina di Turing a k nastri che realizza la traduzione indicata, e
se ne diano le complessità spaziale e temporale.
2. Si descriva a parole una Macchina RAM che realizza la traduzione indicata, e se ne diano le
complessità spaziale e temporale usando il criterio di costo logaritmico.
3. Si descriva a parole una Macchina di Turing a nastro singolo che realizza la traduzione
indicata, e se ne diano le complessità spaziale e temporale.
NB: Il punteggio conseguito sarà tanto più alto tanto migliori saranno le complessità delle macchine
ideate.
Soluzioni
Esercizio 1
Come già in altre occasioni, per un generico stato S, Up_to_now_S(t) è una notazione abbreviata
per la formula seguente
 (t1 (t    t1  t )  S (t1 ))
(sottintes o :   0)
Similmente From_now_on_S(t) è una notazione abbreviata per la formula seguente:
 (t1 (t  t1  t   )  S (t1 ))
Ciò premesso le regole 4 e 6 possono essere formalizzate nel modo seguente, sottintendendo per
ognuna la quantificazione universale t, k:
Regole 4 e 5
(
Up_to_now_CifreImmesse(t, 5)  PremiEnter(t)

From_now_on_ImmissioneDati(t)  From_now_on_Verifica(t)
)

(
Up_to_now_CifreImmesse(t, 5)  PremiCifra(t-5) 
(t1 (t-5 < t1 < t)  (PremiEnter(t)   PremiCifra(t)))

From_now_on_ImmissioneDati(t)  From_now_on_Verifica(t)
)
Regola 6
Up_to_now_ImmissioneDati(t)  Up_to_now_CifreImmesse(t, k)  (0  k <5)

(t1 (t-5 < t1 < t)  (PremiEnter(t)   PremiCifra(t)))

From_now_on_ImmissioneDati(t)  From_now_on_Riposo(t)  EspulsioneTessera(t)
Esercizio 2
1.
Il problema non è né decidibile, né semidecidibile. Non è decidibile per il teorema di Rice
(l’insieme delle MT che riconoscono il linguaggio vuoto non è l’insieme vuoto, né è l’insieme
universo).
Non è neanche semidecidibile, in quanto è semidecidibile il suo complemento: enumerando
opportunamente le stringhe in ingresso, con la solita tecnica diagonale è possibile simulare le
esecuzioni della MT in modo che, se una stringa viene accettata, prima o poi questa viene trovata; in
caso contrario, la computazione prosegue all’infinito.
2.
Il problema è decidibile (e quindi anche semidecidibile). Il numero di computazioni di una MT
senza cicli è finito ed ognuna di esse è fatta di un numero finito di passi. E’ quindi possibile
enumerarle tutte, e determinare se almeno una di queste si porta in stato finale oppure no.
3.
Il problema non è decidibile, ma è semidecidibile. Data una MT qualunque (anche con autoanelli) è
possibile costruirne in modo algoritmico una che sia invece priva di autoanelli (è sufficiente
“sdoppiare” gli stati su cui ci sono autoanelli). Di conseguenza, è facile ridurre il problema della
emptiness del linguaggio di una MT generica (cioè il determinare se il linguaggio accettato è vuoto
o no) a quello di una MT senza autoanelli.
Se quindi fosse decidibile il problema in oggetto, lo sarebbe anche quello della emptiness di una MT
generica (che è in effetti il complemento di quello in oggetto), che non è decidibile per quanto detto
al punto 1.
Il problema è invece semidecidibile, in quanto, sempre per quanto detto al punto 1, per una generica
MT (e quindi a maggior ragione per una senza autoanelli) è possibile, enumerando le stringhe in
ingresso e le varie computazioni con meccanismo diagonale, determinare se questa accetta almeno
una stringa (in caso contrario il procedimento algoritmico non termina).
Esercizio 3
1.
E’ possibile scrivere una MT che effettua la traduzione desiderata senza fare uso di nastri di
memoria, e in tempo (n).
Tale macchina deve semplicemente scorrere il nastro di input 2 volte: una per produrre in uscita an/2,
ed una per produrre in uscita bm. Più precisamente, nella prima passata, la macchina produce, ogni 2
a incontrate, una a in uscita. Arrivata in fondo al nastro di input, essa lo scorre al contrario,
producendo una b per ogni b letta.
2.
Una macchina RAM, non potendo scorrere al contrario il nastro di input, dovrà necessariamente
ricorrere alla memoria per effettuare la traduzione desiderata.
Più precisamente, essa si può comportare nella seguente maniera: legge la stringa in ingresso e, per
ogni a (risp. b) letta, incrementa un opportuno contatore memorizzato in M[1] (risp. M[2]). Alla
fine della lettura divide M[1] per 2, quindi ripete M[1] volte la scrittura in uscita di a, ed M[2] volte
la scrittura in uscita di b.
Le complessità (a criterio di costo logaritmico) di una simile macchina sono (n log(n)) per quella
temporale, e (log(n)) per quella spaziale.
3.
Una Macchina di Turing a nastro singolo può realizzare la traduzione desiderata con un
meccanismo simile a quello dell’insertion sort per portare prima tutte le a in testa alla stringa, farle
seguire dalle b, e quindi chiudere con le c.
Una volta fatto questo, è sufficiente cancellare le c in coda per ottenere la traduzione desiderata.
La complessità temporale di una simile macchina di Turing è, come per l’algoritmo di insertion sort,
(n2); quella spaziale è (n).
Informatica Teorica
Appello d’esame del 3 febbraio 2009, Sezioni Mandrioli-Pradella
Il tempo a disposizione è di 1h30.
Esercizio 1 (punti 8)
Sia data la seguente grammatica G1:
S  AcS | bBS | bac
A  ba
B  ac
1) Si dica quale è il linguaggio generato da G1.
2) Si scriva un automa che riconosce il linguaggio generato da G1. L’automa deve appartenere alla
classe di potenza riconoscitiva minima tra quelle che riconoscono il linguaggio generato da G1.
Esercizio 2 (punti 12)
Si dica, giustificando brevemente la risposta, se è decidibile l’equivalenza tra:
1. Un automa a stati finiti e una macchina di Turing.
2. Una grammatica non contestuale e una macchina di Turing.
3. Una macchina di Turing e la grammatica G1 dell’esercizio 1.
4. Due automi a stati finiti.
5. Un automa a stati finiti e un automa a pila determinitico.
(Suggerimento: si tenga presente che l’intersezione tra il linguaggio riconosciuto da un automa
a stati finiti e quello riconosciuto da un automa a pila deterministico è riconoscibile da un
automa a pila deterministico costruibile algoritmicamente sulla base dei due automi dati.)
Esercizio 3 (punti 11)
Si descriva a grandi linee il funzionamento di una macchina di Turing deterministica che riconosce
il linguaggio L = {w4 | w  {a, b, c}+} (laddove w4 = wwww).
Si valutino le complessità spaziale e temporale della macchina di Turing descritta.
La macchina di Turing deve essere tale da minimizzare la complessità spaziale.
Soluzioni schematiche
Esercizio 1
La grammatica genera il linguaggio:
L(G1) = { (bac)+ }
L(G1) è un linguaggio regolare, cioè riconoscibile da un automa a stati finiti.
Un automa a stati finiti che riconosce il linguaggio è il seguente:
b
a
b
c
c
a
Esercizio 2
Le prime 3 domande hanno risposta negativa sulla base di normali ragionamenti in applicazione al
teorema di Rice.
La domanda 4 ha risposta positiva, grazie alla chiusura del formalismo rispetto alle operazioni
booleane: L1  L2  ( L1   L2) =   ( L1  L2) = .
Alla stessa maniera, sfruttando l’informazione fornita nel suggerimento e il fatto che sia i linguaggi
regolari che quelli noncontestuali deterministici sono chiusi rispetto al complemento, si dimostra
decidibile anche il quesito 5.
Esercizio 3
Una macchina di Turing (deterministica) a 2 nastri che riconosce il linguaggio desiderato può
operare nella seguente maniera (al solito indichiamo con n la lunghezza dell'input):
1- conta gli elementi dell'input in binario (usando il nastro T1)
2- se il numero su T1 è divisibile per 4 (deve terminare con 2 zeri), allora elimina gli ultimi 2
zeri per dividere per 4
3- torna all'inizio dell'input
4- copia il contenuto di T1 nel nastro T2, tenendo traccia nello stato del simbolo letto
5- si sposta sul nastro di input decrementando T2 ad ogni mossa
6- quando T2 è a zero, confronta il simbolo sotto la testina con quello memorizzato, se sono
diversi, si blocca
7- si sposta di una cella in avanti sul nastro di input; se è in fondo al nastro, stop con successo
8- torna indietro di T1 elementi sul nastro (usando ancora T2 come contatore)
9- ripete dal passo 4
La complessità spaziale della macchina è log(n).
La complessità temporale, invece, è n2log(n).
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere
18 Novembre 2011
Il tempo a disposizione è di 2 ore
Esercizio 1 (punti 7/12)
Si considerino le seguenti definizioni:
1.
Una grammatica si dice lineare a destra se le sue produzioni sono del tipo
A ----> Bx, x  VT*, oppure, A ----> x, x  VT*.
2.
Una grammatica si dice lineare a sinistra se le sue produzioni sono del tipo
A ----> xB, x  VT*, oppure, A ----> x, x  VT*.
3.
Una grammatica si dice lineare a destra o a sinistra se le sue produzioni sono del tipo
A ----> Bx, x  VT*, oppure, A ----> xB, x  VT*,
oppure, A ----> x, x  VT*.
4.
Una grammatica si dice lineare se le sue produzioni sono del tipo
A ----> yBx con y, x  VT*, oppure, A ----> x, x  VT*.
Si confrontino tra loro le potenze generative (le famiglie di linguaggi generati) delle suddette classi
di grammatiche tra loro e con quelle dei seguenti formalismi:
Nota.
a.
Automi a stati finiti
b.
Automi a pila deterministici
c.
Automi a pila nondeterministici
d.
Reti di Petri (senza archi inibitori)
Ogni relazione tra le diverse potenze generative deve essere accompagnata da una breve
giustificazione; non è necessario che essa sia una rigorosa dimostrazione matematica ma
deve essere sufficientemente chiara e convincente.
Esercizio 2 (punti 6/12)
Nel "problema delle 8 regine" si vogliono posizionare 8 regine su una scacchiera 88 (inizialmente
vuota) in modo che nessuna regina "attacchi" (ossia si trovi sulla stessa riga, colonna o diagonale di)
un'altra regina.
Formalizzare tramite logica del prim'ordine una formula che specifichi tutti i requisiti del problema
(e quindi sia vera se e solo se i pezzi sulla scacchiera corrispondono a una soluzione).
Suggerimento: si consiglia di adottare un predicato relativo al posizionamento di una regina sulla
scacchiera, ad esempio il predicato ternario p(N, X, Y) i cui argomenti sono numeri tra 1 e 8 e che
indica che la regina numero N si trova alla colonna X e alla riga Y della scacchiera.
Soluzione dell'esercizio 1
a.
b.
d.
c.
e.
f.
g.
Le grammatiche lineari a sinistra (GLS) sono una sorta di abbreviazione delle grammatiche regolari:
infatti, ad esempio la produzione
A ----> acB
può essere trasformata nella coppia di produzioni regolari equivalenti
A ----> aA1; A1 ---> cB
con A1 simbolo nuovo.
Quindi le GLS sono equipotenti agli automi a stati finiti.
Gli automi a stati finiti sono equivalenti non solo alle grammatiche regolari le cui produzioni sono del
tipo A ---> aB, ma anche a quelle con produzioni del tipo A ---> Ba (che a loro volta sono equivalenti
alle lineari a destra con ragionamento analogo al punto a.), purché esse non contengano
contemporaneamente produzioni dei due tipi:
Basta infatti associare ad una transizione del tipo (A, a) = B una produzione del tipo B ----> Aa,
invece che A ---> aB e "invertire stati finali con assioma: la derivazione parte dalla fine della stringa
invece che dall'inizio.
Quindi GLS, GLD, grammatiche regolari e automi a stati finiti sono tutti equipotenti.
Le grammatiche lineari a destra o a sinistra sono equipotenti alle grammatiche lineari: infatti esse ne
sono un caso particolare (quindi non sono più potenti); inoltre ogni produzione del tipo A ----xBy può
essere trasformata nella coppia A -----> x A1, A1 ---> by, con A1 simbolo nuovo.
La grammatica lineare S ---->aSb|ab genera il linguaggio anbn che non è regolare. Quindi le
grammatiche lineari e le lineari a destra o a sinistra sono più potenti di quelle lineari solo a sinistra o
solo a destra.
Le grammatiche lineari sono un caso particolare di quelle non contestuali. Tuttavia esse non possono
generare linguaggi come {anbncmdm}. Questo fatto però, pur avendo una certa evidenza intuitiva non
è di facile dimostrazione in termini rigorosi. Di conseguenza esse sono anche strettamente meno
potenti degli automa a pila nondeterministici.
La seguente G lineare
S ---> aAb | aBbb
A ---> aAb | ab
B ---> aBbb | abb
invece genera il linguaggio {anbn}  {anb2n} notoriamente nondeterministico. Siccome il precedente
linguaggio {anbncmdm} è invece deterministico, se ne deduce che le potenze delle grammatiche
lineari e degli automi a pila deterministici non sono confrontabili.
E' noto che le PN senza archi inibitori, usate come riconoscitori di linguaggi hanno una potenza non
comparabile con quella delle grammatiche non contestuali: accettano ad esempio {a nbncn} ma non
sono in grado di riconoscere {wcwR}. Siccome quest'ultimo linguaggio è facilmente generabile
mediante una G lineare, se ne conclude che le PN non sono comparabili neanche con le G lineari.
Soluzione dell'esercizio 2
Risolviamo l'esercizio imponendo che ogni regina occupi esattamente una posizione sulla
scacchiera, ogni riga e ogni colonna contengano al più una regina e che non ci siano due regine sulla
stessa diagonale.
In questa prima soluzione utilizziamo un predicato ternario p(N, X, Y) che indica che la regina
numero N si trova alla colonna X e alla riga Y della scacchiera
n(1≤nn≤8  xy(p(n,x,y)  1≤xx≤8  1≤yy≤8)
(almeno una posizione sulla scacchiera per la regina n)

nx1x2y1y2 (p(n,x1,y1)  p(n,x2,y2)  x1=x2  y1=y2)
(al più una posizione sulla scacchiera per la regina n)

xn1n2y1y2 (p(n1,x,y1)  p(n2,x,y2)  n1=n2  y1=y2)
(al più una regina in colonna x)

yn1n2x1x2 (p(n1,x1,y)  p(n2,x2,y)  n1=n2  x1=x2)
(al più una regina in riga y)

n1n2x1x2y1y2 (p(n1,x1,y1)  p(n2,x2,y2)  n1n2  x1+y2  x2+y1)
(due regine diverse non sono mai sulla stessa diagonale NW-SE)

n1n2x1x2y1y2 (p(n1,x1,y1)  p(n2,x2,y2)  n1n2  x1+y1  x2+y2)
(due regine diverse non sono mai sulla stessa diagonale NE-SW)
Soluzione alternativa che fa uso di un predicato binario p(X,Y) che indica che c'è una regina in
colonna X e riga Y.
x(1≤xx≤8  y(p(x,y)  1≤yy≤8)
(almeno una regina in colonna x)

xy1y2 (p(x,y1)  p(x,y2)  y1=y2)
(al più una regina in colonna x)

y(1≤yy≤8  x(p(x,y)  1≤xx≤8)
(almeno una regina in riga y)

yx1x2 (p(x1,y)  p(x2,y)  x1=x2)
(al più una regina in riga y)

x1x2y1y2 (p(x1,y1)  p(x2,y2)  (x1x2  y1y2)  x1+y2  x2+y1)
(due regine diverse non sono mai sulla stessa diagonale NW-SE)

x1x2y1y2 (p(x1,y1)  p(x2,y2)  (x1x2  y1y2)  x1+y1  x2+y2)
(due regine diverse non sono mai sulla stessa diagonale NE-SW)
Algoritmi e principi dell’Informatica
Seconda prova in itinere  24 Gennaio 2012, Sezione Mandrioli
Avvisi importanti
I punteggi attribuiti ai singoli esercizi hanno valore solo per chi sostiene la II prova completa
del corso integrato.
Per chi deve sostenere solo il modulo di Informatica 3 o l’intero appello (riservato ai
laureandi) il punteggio sarà diverso e valutato caso per caso.
Chi deve sostenere solo l’esame di Informatica 3 deve risolvere gli esercizi 2, 3, 4 in 2 ore.
Chi deve sostenere la II prova del corso integrato deve risolvere gli esercizi 1, 2, 3, 4 in 2 ore e
15 minuti.
Chi deve sostenere l’intero appello deve risolvere tutti gli esercizi in 3 ore e 30 minuti.
Su ogni foglio consegnato devono essere indicati chiaramente:
Cognome, nome, numero di matricola
Quale dei tre tipi di prova di cui sopra si sta sostenendo
Esercizio 1 (punti 4/18-esimi)
Si dica, giustificando brevemente ma precisamente la risposta, se la seguente funzione è calcolabile:
Per i compreso tra 1 e 1000, j compreso tra 1 e 10000 f(i, j) = 1 se la i-esima MT si ferma
computando il dato j, 0 altrimenti.
Esercizio 2 (punti 6/18-esimi)

Si descrivano, mediante opportuno pseudocodice, due algoritmi che simulino il
comportamento di due rispettivi automi a pila che riconoscano i seguenti linguaggi:
o L1 = { an bn }  { an b2n }| n  1
o L2 = {wwR | w  {a,b}*} ( wR indica, al solito, la stringa speculare di w)
NB1: gli algoritmi non devono semplicemente decidere se una stringa appartiene al
linguaggio dato, ma simulare completamente il comportamento dell’automa, ossia
ripercorrere –senza necessariamente fornirle in output- le stesse computazioni che
eseguirebbe l’automa.
NB2: si può assumere che l’input dell’algoritmo sia una stringa di caratteri seguita da un
terminatore di “fine stringa”.
NB3: la scelta dello pseudocodice è lasciata allo studente: può essere un linguaggio di tipo
“mini-Pascal” o “mini-C” o in stile RAM; o anche in “linguaggio naturale strutturato”. E’
però importante che la descrizione degli algoritmi sia sufficientemente precisa da non
lasciare dubbi sulla semantica delle operazioni elementari, sul loro costo e sul fatto che esse
corrispondano alle operazioni astratte dei corrispondenti automi a pila.

Si valuti la complessità temporale di entrambi gli algoritmi nel caso pessimo, adottando il
criterio di costo ritenuto più opportuno (e spiegandone brevemente la scelta)

E’ possibile costruire MT deterministiche che riconoscano gli stessi linguaggi con
complessità asintotica migliore di quella dei due rispettivi algoritmi? In caso positivo, quali
complessità sono ottenibili? Spiegare brevemente le risposte fornite.
Esercizio 3 (punti 2/18-esimi)
Si consideri una tabella di hash con 18 posizioni. Si vuole gestirla usando il double hashing
(h1(n)+i*h2(n)) mod 18 (con n numero da inserire e i numero del tentativo).
Dire quale tra queste coppie di funzioni si adotterebbe motivando brevemente la risposta
1) h1=n mod 9 e h2=n mod 3
2) h1=n mod 13 e h2=n mod 7
Esercizio 4
(punti 7/18-esimi)
Si ha un array di n liste; ognuna delle quali contenente al più m elementi che descrivono gli stipendi
di una società. Ogni lista contiene i dati di uno dei reparti della società. Supponendo che ognuna
delle liste contenga gli elementi in ordine crescente di stipendio, si progetti un algoritmo capace di
generare un'unica lista ordinata per stipendio di tutti i dipendenti della società cercando di ottenere
la miglior complessità temporale possibile e se ne fornisca una valutazione.
NB: si noti che n e m sono due parametri indipendenti che determinano la dimensione del
problema.
Esercizio per il recupero della prima prova
1. Si progetti un automa A1 che riconosca il linguaggio
L1 = { an bn | n  3 }
L'automa deve appartenere ad una classe C (tra FSA, PDA, TM) di automi a potenza minima
tra quelli che riconoscono L1.
2. Si progetti quindi a partire dall'automa A1, un automa A2 a potenza minima che riconosca il
linguaggio L2 = L1+.
3. La classe C è chiusa rispetto all'operazione "+" di chiusura transitiva ("più di Kleene")?
4. In caso affermativo, descrivere sinteticamente il procedimento che, dato un automa A
appartenente alla classe C, consente di sintetizzare l'automa che riconosce il linguaggio
L(A)+. In caso negativo, dire come si può determinare se nessun automa della classe C può
riconoscere L(A)+.
5. Si dia la specifica logica del linguaggio L2.
6. (Parte opzionale, da svolgere solo dopo aver completato le precedenti)
Costruire una rete di Petri che accetti L1.
Soluzioni schematiche
Esercizio 1
La funzione proposta ha un dominio finito (o, se la si volesse definire sull’intero N X N , sarebbe
decidibile stabilire se una coppia <i,j> appartiene al suo dominio di definizione.).
Quindi essa è esprimibile come una matrice 1000 X 10000 in ogni elemento della quale si trova un
1 o uno 0. Esiste un numero finito di tali matrici; ognuna delle quali può essere calcolata da
un’opportuna MT; quindi la funzione data è sicuramente calcolabile (anche se il ragionamento
suddetto non porta a costruire la MT che la calcola.)
Esercizio 2
Entrambi i linguaggi sono nondeterminisitici.
a.
Nel primo caso l’automa riconoscitore compie una sola scelta nondeterministica (come prima
mossa) e successivamente si comporta in modo deterministico.
Quindi un algoritmo può simularne il comportamento simulando inizialmente il riconoscimento
mediante pila di { an bn } (o viceversa); se questo primo tentativo fallisce –assumendo che la stringa
di ingresso sia stata memorizzata preliminarmente- passa alla simulazione dell’automa che
riconosce { an b2n }.
Ovviamente in tal caso la complessità temporale dell’algoritmo (a costo costante) è (n) (e
(n.log(n)) a costo logaritimico).
b.
Nel caso di L2 invece l’automa a pila “naturale” che lo riconosce decide nondeterministicamente ad
ogni passo se impilare il simbolo letto o iniziare a confrontarlo con quello in cima alla pila;
ovviamente, una volta deciso di iniziare il confronto il comportmento diventa deterministico e si
conclude con successo solo se la pila viene completamente svuotata esattamente in corrispondenza
della lettura dell’ultimo carattere.
Un algoritmo che simuli tale comportamento può consistere di due cicli: il primo scandisce e mette
in pila ogni simbolo letto; un secondo ciclo, interno al primo, per ogni simbolo “impilato”:

Copia l’attuale contenuto della pila

Riprende la lettura dal simbolo successivo a quello appena impilato e procede
verificando deterministicamente l’eguaglianza tra ogni simbolo letto e quello in pila
(ovviamente eliminandolo di volta in volta dalla pila).

Se la pila viene svuotata esattamente in corrispondenza della lettura dell’ultimo
carattere (all’uopo un normale algoritmo può usufruire di un carattere apposito
(ETX)) la stringa viene accettata e l’esecuzione interrotta.

Altrimenti si esce dal ciclo interno e si riprende l’esecuzione dall’ultimo carattere
letto nell’esecuzione del ciclo esterno.
Per fare ciò può essere necessario –se l’unità di I/O non lo permette- aver inizialmente
memorizzato l’intera stringa.
La complessità di un tale algoritmo è quadratica (a criterio di costo costante) perché nel caso
pessimo il ciclo esterno viene eseguito n volte e quello interno i volte (più la copiatura della stringa
impilata fino all’entrata, a sua volta lunga i) per l’i-esimo carattere letto nel ciclo esterno.
Anche in questo caso, l’uso del criterio di costo logaritmico non fa che aggiungere un fattore log(i)
a ogni memorizzazione o eliminazione di un carattere dalla pila, producendo quindi una complessità
(n2.log(n))
3.
Essendo la complessità asintotica del primo algoritmo lineare essa non è ovviamente migliorabile.
Al contrario un semplice macchina di Turing che riconosca L2 in tempo lineare può operare nel
modo seguente:

Memorizza la stringa di ingresso su due nastri;

Pone le due testine, rispettivamente all’inizio e alla fine della stringa;

Verifica che i caratteri letti dalle due testine coincidano, spostandole successivamente a
destra e sinistra, rispettivamente;

NB: ai fini della complessità asintotica non è necessario –ma è possibile per migliorare la
costante di proporzionalità- verificare che le testine giungano a metà stringa.
Esercizio 3
Nella scelta 1) sia h1 che h2 sono divisori di 18, quindi favoriscono una “clusterizzazione” dei dati
con rischio di rapida saturazione di alcune posizioni.
E’ quindi preferibile la seconda coppia di funzioni proposta.
Si noti tuttavia che anche quest’ultima non offre buoni risultati in termini di distribuzione nelle
varie posizioni: ad esempio per n = 9 si ottiene solo una sequenza di numeri dispari:
9, 11, 13, 15, 17, 1, 3, ….
Esercizio 4
Un algoritmo “banale” potrebbe costruire incrementalmente l’unica lista globale “fondendo”
(operazione di merge) le varie liste ad una ad una. Il merge di due liste lunghe al più h richiede un
tempo O(h); quindi la complessità totale di un tale algoritmo sarebbe
n
O( (i.m  m))  O(n 2 .m)
i 1
Un algoritmo un po’ meno banale, invece, potrebbe trarre ispirazione dal merge-sort e fondere le
liste a due a due in diverse passate:
La prima passata produrrebbe quindi n/2 liste di lunghezza (al più) 2.m ciascuna, in tempo O(n.m);
la seconda n/4 liste di lunghezza 4.m, sempre in tempo O(n.m), ecc.
Il numero di passate, risulterebbe, al solito O(log(n)) per una complessità totale O(n.m.log(n)).
Esercizio per il recupero della prima prova
Quesito 1
Per riconoscere il linguaggio L1 occorre la capacità di “contare” numeri arbitrariamente grandi. Il
formalismo degli automi a stati finiti non è pertanto sufficiente (come si può dimostrare, ad
esempio, tramite il pumping lemma).
Un semplice automa a pila che riconosce L1 è il seguente.
La classe degli automi a pila (deterministici) è pertanto a potenza minima, per il problema dato, tra
quelle specificate nel testo.
Quesito 2
Mostriamo ora un automa a pila che riconosce L2.
Quesiti 3 e 4
La classe dei linguaggi riconosciuti da automi a pila deterministici non è chiusa rispetto
all’operazione “+”: si consideri ad esempio il linguaggio { anbn c amb2m | n, m  0}
Lo è invece quella riconosciuta da automi a pila nondeterninistici. Il procedimento consiste,
generalizzando la costruzione dell’esempio, nel “cortocircuitare” gli stati finali con lo stato iniziale,
ripristinando contemporaneamente la situazione di pila iniziale (eventualmente mediante una serie
di -mosse.
Quesito 5
Specifica di L1:
Specifica di L2:
x(xL1n(n3x=an.bn))
x(xL2xL1yz(yL1zL2x=y.z))
Soluzione alternativa (senza ricorrere alla specifica intermedia di L1):
x(xL2n(n3x=an.bn)zn(zL2n3x=an.bn.z))
Quesito 6
Un esempio di rete di Petri che riconosce il linguaggio L1 è il seguente, in cui la marcatura iniziale è
mostrata in figura e l’insieme di marcature finali è F={MF} con MF(P6)=1 e MF(Pi)=0 per i=1,…,5.
Si noti che la classe delle reti di Petri è a potenza minimale – non minima – rispetto alle precedenti
perché le due classi PDA e PN sono tra loro non confrontabili.
A titolo di approfondimento si osservi che non si può costruire una rete di Petri che riconosca L2.
L’unica possibilità è di utilizzare archi inibitori, raggiungendo pertanto il potere espressivo delle
MT. Una rete di Petri con archi inibitori che riconosce L2 è mostrata di seguito.
Più in generale, è stato dimostrato che la classe dei linguaggi riconosciuti da rete di Petri non è
chiusa rispetto all’operazione “+”, se non facendo ricorso agli archi inibitori. La dimostrazione
formale di questo fatto è complessa. Dal punto di vista intuitivo, con riferimento all’esempio in
questione, oltre a spostare il gettone da P6 a P1, occorre anche sincerarsi che il posto P5 sia vuoto, il
che richiede un arco inibitore.
English version
Delivery time: 2 hours and 15 minutes after start.
Exercise 1 (max score: 4/18 points)
Consider the function f defined as follows:
for 1  i  1000, 1  j  10000,
f(i, j) = if the i-th Turing machine halts when computing on the input j then 1
else 0
Is f computable? Give a short but precise explanation for your answer.
Exercise 2 (max score: 6/18 points)
Consider the following languages:
o L1 = { an bn }  { an b2n }| n  1
o L2 = {wwR | w  {a,b}* (as usual, wR denotes the mirror image of w)

For each one of L1 and L2, provide an algorithm that simulates the behavior of a pushdown
automaton recognizing L. The algorithm should not –only- accept a string iff it is accepted by
the corresponding automaton, but should execute a sequence of steps corresponding to the
automaton single transitions; in particular it should use its memory as a stack and manage it just
as the formal automaton would do, by means of suitable push and pop –abstract- operations.
You are free to describe the language in any pseudo-code you feel appropriate: could be a
“mini-C” or a RAM, or even “structured natural language”, provided your description is precise
enough.

Evaluate the asymptotic time complexity of both algorithms by applying the cost criterion you
feel more appropriate; briefly explain your answer.

Is it possible to build deterministic Turing machines that accept the same languages with a
better time complexity? In the positive case, how? Which complexities can you obtain? Briefly
explain your answer.
Exercise 3 (max score: 2/18 points)
Consider a hash table with 18 placeholders. We want to manage it in a double-hashing fashion:
(h1(n)+i*h2(n)) mod 18 (where n denotes the value of the key to be inserted and i denotes the
iteration of the attempt to insert the element.
Which one between the following pairs of functions would you choose? Why?
1) h1=n mod 9 e h2=n mod 3
2) h1=n mod 13 e h2=n mod 7
Exercise 4 (max score: 7/18 points)
Assume you have an array consisting of n linked lists. Each list contains at most m elements (say,
describing the salaries of the employees of a section of a firm). Assume also that each list is ordered
in increasing order. Design an algorithm that, starting from the above data structure produces a
single ordered list containing –all and only- the elements of the n original lists; try to optimize the
time complexity of your algorithm and evaluate it (with respect to the order of magnitude ).
Notice that the complexity function depends on two unrelated parameters, n, and m.
Supplement exercise for those who must repeat the first midterm test
1. Build an automaton A1 that recognizes the following language
L1 = { an bn | n  3 }
A1 must belong to a class C (among FSA, PDA, TM) of automata with minimal power
among those that recognize L1.
2. Starting from A1, build a new automaton A2 (with minimal power) that recognizes the
language L2 = L1+.
3. Is class C closed under transitive closure (a.k.a. “+” or “Kleene plus”)?
4. If it is, you should sketchily describe the procedure allowing you to build the automaton that
recognizes the language L(A)+, given an automaton A belonging to class C. Otherwise you
should explain how you can determine whether no automaton of class C can recognize
L(A)+.
5. Specify language L2 in first-order logic.
6. Optional part, to be executed only after having completed the previous parts and the
other exercises.
Build a Petri net that recognizes L1.
Algoritmi e Prinicipi dell’Informatica
(Sez. Mandrioli)
Appello del 20 Febbraio 2012
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 h e 30 minuti
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere le parti a), b) e c)
dell’Esercizio 1 e l’Esercizio 2 in 1 ora.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere la parte d) dell’esercizo 1 e
l’esercizio 3 in 1 h e 30 minuti.
Esercizio 1
(punti 12/30-esimi)
Si consideri il seguente linguaggio:
L1 = { ab, abab, ababab, ...,
aabb, aabbaabb, aabbaabbaabb, …,
…,
an bn, an bn an bn, an bn an bn an bn, …,
…}
a) Fornire una specifica logica del linguaggio L1.
b) Sintetizzare un automa a potenza minima (tra FSA, PDA, TM) in grado di riconoscere L1.
c) Si consideri il linguaggio L2={ anbn }+. I linguaggi L1 e L2 sono equivalenti?
d) Si valutino le seguenti complessità relative al riconoscimento di L1:
1. Complessità spaziale minima ottenibile mediante una macchina di Turing a k nastri
2. Complessità temporale minima ottenibile mediante una macchina di Turing a k nastri
3. Complessità spaziale minima ottenibile mediante una RAM, a criterio di costo
logaritmico
4. Complessità temporale minima ottenibile mediante una RAM, a criterio di costo
logaritmico
Si giustifichino brevemente le risposte date
Esercizio 2
(punti 8/30-esimi)
Si considerino le seguenti funzioni:
(si rammenta che il simbolo
y denota il massimo intero  y e y il minimo intero  y;
|y| denota il valore assoluto di y; Z denota l’insieme dei numeri interi.)
f1: Z  Z, f1(x) = e|x|
f2: Z  Z, f2(x) = e x
f3: Z  Z, f3(x) = x2 + 1
f4: Z  Z, f4(x) = log (|x|)
Siano poi T l’insieme delle funzioni totali Z
 Z, e
H  {f: Z  Z | x(f(x) = 0)}
Dire, giustificando la risposta, se sia decidibile il problema di stabilire se, dato un generico
programma C o Java, esso computi una delle funzioni appartenenti all’insieme
F = { f1, f2, f3, f4}  T  H
Esercizio 3
(punti 10/30-esimi)
Si abbiano due alberi rosso-neri, rispettivamente di cardinalità m e n, con m << n. Si definisca,
mediante opportuno pseudocodice un algoritmo che costruisca una lista (monodirezionale) ordinata
in ordine crescente contenente tutti e soli gli elementi appartenenti ad entrambi gli alberi, cercando
di ottenerne la miglior complessità temporale possibile. Si valuti tale complessità in funzione dei
due parametri m e n.
Tracce di Soluzioni
Esercizio 1
a)
Indichiamo con L(k) il sottolinguaggio { ak bk, ak bk ak bk, ak bk ak bk ak bk, …}
Specifica di L(k): xk (xL(k)x=akbk  y(yL(k)x= akbk.y))
(si sottintende la definizione di wk per una generica stringa w e un generico intero k)
Specifica di L1: x(xL1 k(xL(k)))
b)
Il linguaggio non può essere riconosciuto da un automa a pila, in quanto richiede la capacità di
ricontare lo stesso numero più volte.
Una macchina di Turing che riconosce L1 è definita come segue:
c)
Il linguaggio L1 non è equivalente al linguaggio L2, bensì ne è un sottoinsieme proprio. Un esempio
di stringa di L2 che non appartiene a L1 è abaabb.
d.1) Una MT può riconoscere L1 con complessità spaziale O(log(n)), n essendo la lunghezza
della prima sequenza di a, e quindi  della lunghezza dell’intera stringa di ingresso. Essa può infatti
memorizzare il valore di n in binario (ad esempio su due nastri); ad ogni successiva scansione di
una serie di a o di b usa questo contatore decrementandolo di un’unità per ogni carattere letto; al
passaggio alla sequenza successiva lo risetta al valore originario (copiandolo dall’altro nastro.
d.2) La MT di cui al precedente punto d.1) ha una complessità O(m.log(n)), dove m è la
lunghezza dell’intera stringa. Un’analisi più raffinata potrebbe evidenziare che ogni conteggio di n a
o b può essere fatto in O(n) (perché l’aggiornamento del contatore richiede:
log(n ) 
O(n

h 0
h
)  O(n)
2h
); posto poi k = m/n sono necessarie k copiature di log(n) = log(m/k) bit; in ogni caso la complessità
temporale totale sarebbe O(m).
Una tale analisi è però superflua perché è sufficiente constatare che la semplice MT di cui al punto
b) ha evidentemente complessità temporale (e spaziale) O(m).
d.3 e d.4)
Una RAM che riconosca L1 deve necssariament memorizzare il valore di n in un
contatore (meglio in due) e poi procedere in modo analogo alla precedente MT; ogni aggiornamento
del contatore però costa alla RAM O(log(n)). Quindi nel caso pessimo la complessità spaziale è
O(log(n)) e quella temporale O(m.log(m)) (quando n è O(m)).
Esercizio 2
L’insieme F è vuoto. Infatti l’insieme immagine di f1, f2 e f3 non contiene lo 0 (i loro valori sono
tutti > 0) e f4 non è totale. Quindi nessun algoritmo può computare una funzione di F e il problema
posto è banalmente decidibile.
Esercizio 3
Uno schema di algoritmo per risolvere il problema posto è il seguente:

Siano Tm e Tn rispettivamente i due alberi di cardinalità m e n;

Si individui il massimo elemento di Tm (Questa operazione, per un albero rosso-nero costa
O(log(m)));

Si verifichi se questo elemento si trova in Tn (costo O(log(n)));
o Se l’elemento corrente si trova anche in Tn lo si inserisca in testa alla lista,
inizialmente vuota (costo O(1));

Si ripeta il ciclo precedente per tutti i successivi nodi di Tm in ordine decrescente.
Si noti che per fare ciò occorre tenere traccia del nodo esaminato nella precedente iterazione
del ciclo: indicando con N tale nodo, occorre quindi individuare il nodo a valore massimo a
sinistra di N (assumendo che i nodi a valore minore siano a sinistra), ricerca che può
comunque essere eseguite in tempo O(log(m)).
La complessità totale è quindi O(m.(log(m)+log(n))), che, essendo m < n è anche O(m.log(n)).
Un altro algoritmo a complessità sostanzialmente equivalente potrebbe “linearizzare” Tm in una lista
ordinata in ordine crescente (a costo O(m)) e successivamente, per ogni lemento della lista verifcare
se si trova in Tn (costo (O(log(n)) e in caso negativo eliminarlo dalla lista con costo O(1).
Si noti che la scelta di un tale algoritmo è giustificata dall’ipotesi che m << n. In caso contrario, ad
esempio se n ed m fossero sostanzialmente vicini, converrebbe linearizzare entrambi gli alberi in
O(n) e poi calcolarne l’intersezione sempre in O(n). Tuttavia, se, ad esempio, m fosse O(log(n)),
una complessità O(log2(n)) sarebbe nettamente preferibile.
Si noti anche che in caso di ripetizioni entrambi gli algoritmi manterrebbero nella lista risultante il
numero di occorrenze in Tm, non quello delle occorrenze in Tn.
English version
For the complete exam, the candidate must answer to all the exercises in 2h, 30’.
For the first module (Informatica Teorica), the candidate must answer to parts a), b) and c) of
Exercise 1, and to Exercise 2 in 1h.
For the second module (Informatica 3), the candidate must answer to part d) of Exercise 1,
and to Exercise 3 in 1h, 30’.
Exercise 1
(points 12/30)
Consider the following language:
L1 = {ab, abab, ababab, ...,
aabb, aabbaabb, aabbaabbaabb, …,
…,
an bn, an bn an bn, an bn an bn an bn, …,
…}
e) Give a logic specification of L1.
f) Define a minimal expressive power automaton (chosen among FSA, PDA, TM) that accepts
L1.
g) Consider language L2 = { anbn }+. Are languages L1 and L2 equivalent?
h) Assess the following complexities for recognizing L1:
5. Minimal space complexity obtainable with a k-tape Turing Machine.
6. Minimal time complexity obtainable with a k-tape Turing Machine.
7. Minimal space complexity obtainable with a RAM machine, considering the
logaritmic cost criterion.
8. Minimal time complexity obtainable with a RAM machine, considering the
logaritmic cost criterion.
Please, give a brief motivation of the given answers.
Exercise 2
(points 8/30)
Consider the following functions:
(Reminders: notation y denotes the maximal integer  y, and y the minimum integer  y;
|y| denotes the absolute value of y; Z is the set of all integer numbers.)
f1: Z  Z, f1(x) = e|x|
f2: Z  Z, f2(x) = e x
f3: Z  Z, f3(x) = x2 + 1
f4: Z  Z, f4(x) = log (|x|)
Let then T be the set of all total functions Z
 Z, and
H  {f: Z  Z | x(f(x) = 0)}
Is it decidable the problem of stating if, given a generic program written in C or Java, it computes
one of the functions in the following set?
F = {f1, f2, f3, f4}  T  H
Exercise 3
(points 10/30)
Consider two red-black trees, having cardinality m and n, respectively, with m << n.
Define an algorithm in pseudo-code that builds a mono-directed list that is ordered in a nondecreasing way. Such list must contain all and only the elements that belong to both the given trees.
This algorithm must exhibit a time complexity as good as possible, and it must be provided as a
function of the two parameters m and n.
Algoritmi e Principi dell’Informatica
Appello del 12 Luglio 2012
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 h 30’
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere l’Esercizio 1 e
l’Esercizio 2 in 1 ora 15’.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere l’esercizio 3 e l’esercizo 4 in 1
h 15’.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1
(punti 7/30-esimi)
Si consideri la seguente macchina di Turing M, dove q0 è stato iniziale e q4 finale:
(q0,a,Z0,Z0) = <q1,Z0,Z0,S,R,S>
(q1,a,_,Z0) = <q1,A,Z0,R,R,S>
(q1,b,_,Z0) = <q2,_,Z0,S,L,R>
(q2,b,A,_) = <q2,A,B,R,S,R>
(q2,c,A,_) = <q3,C,_,R,L,L>
(q3,c,A,B) = <q3,C,B,R,L,S>
(q3,_,Z0,B) = <q4,Z0,B,S,S,S>
Si definisca un automa a potenza minima che accetti lo stesso linguaggio di M.
Esercizio 2
(punti 9/30-esimi)
Siano A e G, rispettivamente una generica famiglia di automi e una di grammatiche; siano poi
L(A) e L(G) le rispettive classi di linguaggi definiti da esse. Di esse si sappia che:

L(A) è ricorsivamente contenuta in L(G); ossia esiste un algoritmo che dato un automa A in A
costruisce una G in G ad esso equivalente, ossia tale che L(A) = L(G).

L(A) è ricorsivamente chiusa rispetto al complemento; ossia esiste un algoritmo che dato un
automa A in A costruisce un automa A’ in A che accetta il complemento di L(A).

L(G) è ricorsivamente chiusa rispetto all’intersezione; ossia esiste un algoritmo che date due
grammatiche G e G’ in G costruisce una grammatica G” in G tale che L(G”) = L(G) L(G’).
Sulla base di queste e solo queste informazioni è possibile concludere che il segente problema:
Dati una generica G in G e un generico A in A, tutte le stringhe generate da G sono accettate da
A?
è decidibile?
Nel caso di risposta positiva si fornisca una breve descrizione di un algoritmo per risolvere il
suddetto problema (NB: in un caso estremo si potrebbe anche dimostare la decidibilità del problema
senza per questo essere in grado di produrre un tale algoritmo). E’ anche opportuno fornire qualche
esempio di famiglie A e G che, soddisfacendo le ipotesi di cui sopra, godano della relativa
proprietà di decidibilità.
In caso di risposta negativa:
Si fornisca una convincente spiegazione per essa; un modo semplice, sempre che ciò sussista,
sarebbe fornire un adeguato controesempio, ossia un caso specifico di A e G che soddisfano le
ipotesi ma tali per cui il problema indicato non sia decidibile.
Sempre in caso di risposta negativa, è possibile individuare una nuova condizione, da aggiungere
alle precedenti, che sia sufficiente per rendere decidibile il problema? Anche in questo caso si
fornisca qualche giustificazione: uno schema di algoritmo, qualche esempio, …
Esercizio 3 (punti 8)
Si considerino alberi binari, in cui ciascun nodo contiene come informazione un numero intero. Si
progetti un algoritmo che, ricevendo in input un albero e un intero TOT, restituisce 1 se esistono
almeno due cammini distinti dalla radice alle foglie in cui la somma dei numeri contenuti nei nodi è
uguale a TOT e 0 altrimenti. Due cammini sono distinti se differiscono anche solo per un nodo.
Si calcoli l’ordine di grandezza () della complessità temporale dell'algoritmo proposto in funzione
del numero n di nodi dell'albero.
Esercizio 4 (punti 8)
Si consideri il linguaggio L={ uu | u(a, b)+ }
1. Si definisca in maniera sufficientemente precisa e dettagliata una MT deterministica M che
riconosca L, preferibilmente con complessità temporale nella classe (n), dove al solito n = |x| è
la lunghezza della stringa di ingresso. Si calcoli anche la funzione di complessità temporale
TM(n) di M in modo preciso, non solo con riferimento alla sua classe .
2. Si stabilisca se una MT nondeterministica N possa riconoscere lo stessso linguaggio L con una
complessità temporale TN(n) tale che TN(n) < TM(n) per ogni n. Nel caso positivo si descriva,
anche a grandi linee ma in maniera sufficientemente precisa da poterne ricavare con esattezza la
funzione di complessità temporale, una tale macchina N. Altrimenti si spieghi il motivo per cui
una tale macchina N non può esistere1.
3. Si delinei poi una macchina RAM che riconosca lo stesso linguaggio e se ne stimi la
complessità temporale TR(n) facendo riferimento sia al criterio di costo uniforme che a quello
logaritmico.
1
Per comodità si richiama qui la Definizione 9.11. del testo in cui si definisce la funzione di complessità temporale di
una MT nondeterministica.
Definizione 9.11
Sia M una MT multinastro non deterministica che accetta il linguaggio L. M ha complessità temporale TM (e,
rispettivamente, complessità spaziale SM) con dominio I* se, per ogni stringa di ingresso x, x  L se e solo se
esiste almeno una computazione di M che accetta x in TM(x) mosse (rispettivamente, usando SM(x) celle di
memoria) e nessun’altra computazione accetta x in meno di TM(x) mosse (rispettivamente, usando meno di
SM(x) celle del nastro di memoria). TM(n) (rispettivamente, SM(n)) viene definita come il massimo di TM(x)
(rispettivamente, SM(x)) su tutte le x  L di lunghezza n.
Tracce di Soluzioni
Esercizio 1
Il linguaggio riconosciuto dalla MT è { anb+cn, n>0}
Quindi esso è riconosciuto anche da un automa a pila deterministico facilmente costruibile.
Esercizio 2
Sulla base delle sole ipotesi indicate il problema non è a priori decidibile. Ad esempio si scelga
come A la classe degli automi a stati finiti e come G la classe delle grammatiche non ristrette: le
due famiglie soddisfano le ipotesi; tuttavia stabilire se per una generica G in G L(G)  L(A), A
essendo un generico automa a stati finiti, è evidentemente indecidibile (altrimenti sarebbe decidibile
stabilire se un generico L(G) è vuoto).
Viceversa è proprio la decidibilità della emptiness per i linguaggi L(G) che, aggiunta alle ipotesi
precedenti, rende il problema decidibile. Infatti, dati G e A, L(G)  L(A) se e solo se
L(G)  L(A) = : le due operazioni insiemistiche sono effettive e la nuova ipotesi garantisce la
decidibilità dell’uguaglianza.
Purtroppo, tra le famiglie di automi e grammatiche di uso più comune le uniche che soddisfano tutte
queste ipotesi sono automi e grammatiche regolari, tra l’altro equipotenti tra loro;infatti è su questa
classe fondamentale che si appoggiano moderni algoritmi di verifica basati su questa decisione. A
meno di non ricorrere a classi decisamente più specialistiche …
Esercizio 3
int cerca(Tree t, int totale) {
if(t==null)
return 0;
if(cercaAux(t, totale)>=2)
return 1;
else
return 0;
}
int cercaAux(Tree t, int totale) {
if(t==null)
return 0;
if(t->left==null && t->right==null) {
if(totale==t->info)
return 1;
else
return 0;
} else
return cercaAux(t->left, totale - t->info) + cercaAux(t->right, totale - t->info);
}
E’ facile constatare che la complessità temporale dell’algoritmo proposto è (n).
Esercizio 4
Punti 1 e 2 (Impostazione)
Un MT “naturale” deterministica M che riconosca L può operare nel modo seguente:
1. Scandisce l’intera stringa x: n mosse (+ un numero limitato di eventuali mosse extra per
inizializzazione e riconoscimento di fine stringa). Nel fare ciò memorizza
contemporaneamente il valore di n/2 in unario in un nastro di memoria e ricopia il valore di
x in un altro nastro
2. mediante n/2 mosse; riporta la testina del nastro di ingresso a metà stringa.
3. Mediante ulteriori n/2 mosse da destra a sinistra verifica che la prima metà della stringa nel
nastro di ingresso coincida con la seconda metà della stringa nel nastro di memoria. In caso
di confronto positivo la stringa è accettata.
Il totale delle mosse impiegate da M è dunque 2.n + c (c essendo una costante piccola indipendente
da n).
Una MT nondeterministica N può invece “indovinare” la metà della stringa di ingresso e operare
quindi nel modo seguente:
1. Scandisce e copia la stringa di ingresso in un nastro di memoria, finché
nondeterministicamente “indovina” di essere giunta alla sua metà: ciò comporta quindi n/2
mosse.
2. Mediante altre n/2 mosse riporta la testina del nastro di memoria a inizio stringa.
3. Mediante ulteriori n/2 mosse verifica che la parte restante della stringa di ingresso coincida
con la stringa contenuta nel nastro di memoria.
Il numero di mosse complessivo è perciò 3/2.n + c’.
Punto 3 (Impostazione)
La RAM, essendo deterministica, deve operare secondo le stesse linee di M (tenendo però presente
che la definizione normale della RAM non permette alla macchina di riposizionare la testina di
lettura); precisamente:
1. Legge e memorizza la stringa di ingresso, calcolandone la lunghezza mediante un contatore
intero;
2. Dimezza il valore del contatore.
3. Per ogni valore di i, 1 <= i <= n/2 verifica che M[i] sia uguale a M[i+n/2].
Il costo complessivo, a criterio uniforme è dunque k1.n + 1 + k2.n/2 + k3, ki essendo costanti piccole
che indicano il numero di operazioni elementari (READ, LOAD, STORE, …) all’interno dei vari
cicli.
A criterio di costo logaritmico l’esporessione precedente diventa k1.n.log(n) + log(n) + k2.n/2.log(n)
+ k3.
Algoritmi e Principi dell’Informatica
July 12th 2012 (English version)
Exercise 1
(pts 7)
Consider the following Turing machine M, where q0 and q4 are the initial and the final state,
respectively:
(q0,a,Z0,Z0) = <q1,Z0,Z0,S,R,S>
(q1,a,_,Z0) = <q1,A,Z0,R,R,S>
(q1,b,_,Z0) = <q2,_,Z0,S,L,R>
(q2,b,A,_) = <q2,A,B,R,S,R>
(q2,c,A,_) = <q3,C,_,R,L,L>
(q3,c,A,B) = <q3,C,B,R,L,S>
(q3,_, Z0,B) = <q4, Z0,B,S,S,S>
Write an automaton of minimum expressive power (among those seen in class) which accepts the
same language accepted by M.
Exercise 2
(pts 9)
Let A and G be a generic family of automata and a generic family of grammars, respectively; let
L(A) and L(G) be the classes of languages defined from A and G, respectively, and with the
following properties:

L(A) is recursively contained in L(G), that is, for each automaton A in A, there exists an
algorithm that builds an equivalent grammar G in G (recall that G is equivalent to A if and only
if L(A) = L(G)).

L(A) is recursively closed under complement, i.e. for each automaton A in A, there exists an
algorithm that builds an automaton A’ in A which accepts the complement of L(A).

L(G) is recursively closed under intersection, i.e. given two grammars G and G’ in G, there
exists an algorithm that builds a grammar G” in G, such that L(G”) = L(G) L(G’).
Given the above information, is the following problem decidable?
Problem P: Given a generic G in G and a generic A in A, does A accept all the strings
generated by G?
If the answer is yes, do the following:
1. Sketch an algorithm that solves P. (Note that, even if you cannot provide such algorithm,
you can still prove the decidability of P.)
2. Provide some examples of families A and G that satisfy the above properties and, therefore,
guarantee the decidability of the problem.
If the answer is no, do the following:
1. Provide a convincing explanation of why the problem is not decidable. A simple way to do
so is to provide a suitable counterexample, that is, two families A and G that satisfy the
hypotheses, but for which the above problem is not decidable.
2. Find, if possible, an additional property that, together with the ones listed above, makes the
problem decidable. If such a property exists, also sketch an algorithm that solves P and
provide some examples of families A and G that satisfy the above properties plus the
additional one you identified.
Exercise 3 (pts 8)
Consider a binary tree data structure BT, in which each node contains an integer. Design an
algorithm, that, given a BT T and an integer TOT, returns:

1 if there are at least two distinct paths, from the root to any leaf, in which the sum of the data
in the nodes is equal to TOT;

0, otherwise.
Two paths are distinct if they contains at least one different node.
Compute the time complexity (according to the class Θ) in terms of n, the number of nodes in T.
Exercise 4 (pts 8)
Consider the language L={ uu | u(a, b)+ }
4. Define, in a precise and detailed way, a deterministic Turing machine M that recognizes the
language with a time complexity preferably in the class (n), where n=|x| is the length of the
analyzed string. Provide also a precise evaluation of the time complexity TM(n) of the machine
M, still as a function of the string length n=|x|.
5. Determine whether a nondeterministic Turing machine N can recognize the same language with
a time complexity function TN(n) such that TN(n)<TM(n). In the positive case describe the
nondeterministic Turing machine, preferably in a precise, detailed way; otherwise, explain why
the nondeterministic Turing machine cannot be more time efficient than the deterministic one.
6. Sketch a RAM machine that recognizes the language, and estimate its time complexity TR(n) as
a function of the analyzed string, using both the uniform and the logarithmic cost criterion.
Algoritmi e Principi dell’Informatica
Appello del 10 Settembre 2012
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in
1h e 45 min.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3,4 e 5 in 1h e 45
min.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1
(punti 7/30-esimi)
Si considerino le seguenti grammatiche e i linguaggi da esse generati; si indichi, per ognuna di esse,
qual è il tipo di automa a potenza minima (all’interno delle “famiglie” tradizionali: a stati finiti, a
pila deterministici, a pila nondeterministici, macchine di Turing) che riconosce il linguaggio.
1. S  a X b | b X a
XaXb|bXa|c
2. S  X | Y
X  a Y b | ab
Y  b X a | ba
3. S  a X b | b Y a
X  a S b | ab
Y  b S a | ba
4. S  X | Y
XaYb|bYa
YbXa|aXb
Esercizio 2 (punti 8/30-esimi)
Dire se le seguenti funzioni sono calcolabili, motivando adeguatamente la risposta:
1) f(x,y) è indefinita, se la y-esima MT (sia essa a nastro singolo) termina e durante tutta la
computazione con ingresso x non esce mai dalle celle utilizzate per memorizzare la stringa x
e le due celle contenenti blank immediatamente prima e dopo x, altrimenti è pari a 0;
2) g(z) = 1 se la funzione calcolata dalla z-esima MT è diversa dalla f del punto 1, 0
altrimenti.
Esercizio 3 (punti 3/30-esimi)
Si descriva a grandi linee una MT che accetti il Linguaggio 3 dell’Esercizio 1 e se ne valuti la
complessità temporale. La descrizione della macchina può essere anche informale ma
sufficientemente precisa da permettere la valutazione della complessità (asintotica) senza dubbi o
ambiguità.
Esercizio 4
(punti 7/30-esimi)
Si considerino gli algoritmi RB-INSERT e RB-DELETE per l’inserimento e la cancellazione di
nodi in e da alberi red-black. E' possibile, usando solo tali algoritmi, costruire un albero red-black
fatto di esattamente 3 nodi, tutti neri?
Se sì, scrivere una sequenza di invocazioni di RB-INSERT e RB-DELETE che crea l’albero
desiderato, motivando il perché la sequenza scritta produce la struttura richiesta.
Esercizio 5
(punti 8/30-esimi)
1. Definire un algoritmo che, dato in input un array A, restituisce il sottoarray [i,j] di A di lunghezza
massima tale che, per ogni i ≤ k ≤ j, si ha A[i] ≤ A[k] ≤ A[j].
Per esempio, nel caso dell’array [5, 18, 2, 12, 4, 7, 13, -2, -5, 12] il sottoarray cercato è [2, 12, 4, 7,
13].
2. Dire quale è la complessità temporale dell'algoritmo ideato.
NB1: L'algoritmo può essere descritto in pesudocodice, oppure anche in modo informale, purchè la
descrizione sia sufficientemente precisa per determinare la complessità dell’algoritmo.
NB2: Il punteggio dato sarà tanto più alto quanto migliore sarà la complessità dell'algoritmo ideato.
Soluzioni (parziali e schematiche)
Esercizio 1
1. Il linguaggio è costituito da stringhe di lunghezza dispari, con al centro una c, tali che se in una
posizione prima della c si trova una a (rispettivamente, una b) allora dopo la c, in posizione
simmetrica, si trova una b (rispettivamente, una a), e viceversa. Il linguaggio è riconoscibile da
un semplice automa a pila deterministico, ma non da una automa a stati finiti.
2. Il linguaggio è composto da stringhe di lunghezza pari, con simboli a e b alternati, ed è regolare.
3. Il linguaggio è costituito da stringhe di lunghezza multipla di 4, che sono sequenze di coppie di
tipo aa e bb, tali che se in una posizione prima del centro della stringa si trova una a
(rispettivamente, una b) allora dopo il centro, in posizione simmetrica, si trova una b
(rispettivamente, una a) , e viceversa. Il linguaggio è riconoscibile da un automa a pila non
deterministico, perché uno deterministico non avrebbe la possibilità di identificare la posizione
centrale.
4. Il linguaggio è vuoto, quindi regolare.
Esercizio 2
1) f è calcolabile, infatti il numero di configurazioni da considerare per la MT y è finito, quindi
simulando la computazione possiamo controllare se si passa due volte per la stessa configurazione
(loop) o se si esce dalla porzione di nastro fissata: in questo caso si restituisce 0. Se si arriva in
fondo alla simulazione, si va in loop.
2) Non è calcolabile per il teorema di Rice: g è la funzione caratteristica dell'insieme degli indici di
MT che non calcolano f, sicuramente né vuoto né coincidente con N (v. risposta del punto 1).
Esercizio 3
Un MT che riconosca L3 può essere ottenuta mediante una semplice modifica della macchina che
riconosce {wwR}: un prima scansione copia la stringa di ingresso in un nastro di memoria; durante
al scansione la macchina verifica anche che la stringa appartenga a {aa, bb}* e che abbia lunghezza
multipla di 4; successivamente una delle due testine viene riposizionata all’inizio della stringa e
facendo procedere quest’ultima da sinistra e destra e l’altra da destra a sinistra si verifica che
quando una legge ‘a’ l’altra legga ‘b’ e viceversa.
La complessità temporale di una tale macchina è evidentemente (n).
Esercizio 4
Per ottenere l'albero desiderato è sufficiente inserire 4 valori nell’albero. Questo crea un albero in
cui i nodi ai primi 2 livelli sono neri, e sul terzo livello c’è un solo nodo di colore rosso, per
esempio l’albero seguente (la posizione del nodo rosso dipende dai valori inseriti, comunque è poco
rilevante):
Per ottenere l’albero desiderato, è a questo punto sufficiente cancellare, mediante RB-DELETE, il
nodo rosso.
Esercizio 5
E’ abbastanza facile costruire algoritmi a complessità duadratica per sisolvere il problema. Volendo
cercare soluzioni più efficianti si osservi che l’algoritmo seguente ha complessità lineare.
MaxSubarray(A)
1 l_max := l := 1
2 u_max := u := 1
3 for i := 2 to A.length
4
if A[i] >= A[u]
5
u := i
6
elsif A[i] < A[l]
7
if u-l > u_max–l_max
8
l_max := l
9
u_max := u
10
l := u := i
11 if u-l > u_max – l_max
12
l_max := l
13
u_max := u
14 return <l_max,u_max>
Esso però non sempre produce la soluzine desiderata. Ad esempio, nel caso proposto [5, 18, 2, 12,
4, 7, 13, -2, -5, 12] viene correttamente prodotta la soluzione [2, 12, 4, 7, 13]. Tuttavia se l’array
originario fosse [5, 18, 2, 12, 4, 7, 13, 3, 6, 5, 8, 4, 7, 10, 12], l’algoritmo produrrebbe ancora [2, 12,
4, 7, 13] invece della più lunga [3, 6, 5, 8, 4, 7, 10, 12]. Ciò è dovuto al fatto che, dopo il valore 13
l’indice u rimane inalterato perché non vi sono più valori > 13.
Si osservi però che, se l’array viene scandito in maniera simmetrica ossia da destra verso sinistra e
invertendo i confronti ( e.g., elsif A[i] > A[l],)la sequenza più lunga sarebbe individuata;
ovviamente una scansione da destra a sinistra avrebbe il difetto opposto; tuttavia all’accopiata dei
due attraversamenti non sfuggirebbe nessuna sequenza, ragion per cui basterebbe fare questa doppia
passata nei due sensi e poi scegliere la maggiore delle due sequenze massime. Ad esempio, si
consideri la sequenza
[3 --- 20] [2 --- 25] [3 ---22] [-1 --- 28] [2 ----20], dove i trattini indicano un numero qualsiasi di
valoro compresi tra i due estremie della sottosequenza.
La passata <sinistra-destra> non riesce a individuare le sottosequenze [3 ---22] e [2 ----20] mentre
quella <destra-sinsitra> non coglie la [3 --- 20], indipendentemente dalla loro lunghezza. Tuttavia i
due attraversamenti congiunti prendono in esame tutte le possibili sequenze; quindi non resta che
individuare quella di lunghezza masima tra tutte.
Si ottiene dunque una soluzione del problema a complessità (n) (e lineare).
.
Algoritmi e Principi dell’Informatica
Appello del 27 Settembre 2012
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere l’Esercizio 1 e
l’Esercizio 2 in 1 ora e 30 minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere l’Esercizio 3 e l’Esercizio 4 in
1 ora e 30 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1
le righe)
(punti 7/30-esimi se si compilano solo le prime 3 righe, 9/30 se si compilano tutte
Si considerino i seguenti linguaggi:
L1 = {anbn| n  1} {anb2n| n  1}
L2 = {1anbn| n  1} {2anb2n| n  1}
L3 = {an1bn| n  1} {an2b2n| n  1}
L4 = {anbn1| n  1} {anb2n2| n  1}
e le seguenti famiglie di macchine astratte, usate come riconoscitori di linguaggi:
AF: automi a stati finiti
APD: automi a pila determinstici
APN: automi a pila nondeterministici
ARP: reti di Petri
Si riempia la seguente tabella indicando in ogni casella se la famiglia indicata nella riga è in grado
di riconoscere il linguaggio indicato nella corrispondente colonna; giustificare brevemente le
risposte.
L1 L2 L3 L4
AF
APD
APN
ARP
Esercizio 2
(punti 9/30-esimi)
All’inizio di ogni anno accademico ogni studente deve compilare il proprio piano di studi. Si
formalizzino mediante formule del prim’ordine le seguenti regole (semplificate) relative alla
compilazione del proprio piano di studi da parte degli studenti.

Il piano di studi di uno studente consiste in un numero di insegnamenti non inferiore a 3 e
non superiore a 10 tra quelli ancora disponibili nel proprio corso di studi (si assuma che
esista una tabella con l’elenco degli insegnamenti che ogni studente può ancora scegliere;
non si prendano in considerazioni eventuali obbligatorietà e mutue esclusioni; né viene
chiesto di specificare come la tabella viene aggiornata ogni anno).

Ad ogni insegnamento è associato un numero di crediti. Il totale dei crediti “acquistati” nel
piano di studi non deve essere inferiore a 50 e non può essere superiore a 80.
NB: la formalizzazione deve specificare anche le regole intrinsecamente connesse con l’uso e il
significato delle tabelle utilizzate: ad esempio, un piano di studi non può contenere più occorrenze
dello stesso esame; …
Suggerimento
Si definiscano adeguate variabili per rappresentare studenti, insegnamenti e crediti, nonché
opportune funzioni e/o predicati per rappresentare l’elenco degli insegnamenti offerti, il piano di
studi, i crediti associati a ogni insegnamento, …
NB: potrebbe essere conveniente, anche se non necessario, che le liste degli insegnameti contenute
sia nella tabella di quelli disponibili che nel piano di studi siano costituite da elementi “adiacenti”,
…
Esercizio 3 (punti 8/30)
Si consideri un modello di Macchina di Turing a nastro singolo (usato sia come ingresso che come
memoria ed eventuale output) ma dotata di due testine di lettura-scrittura (che all’inizio della
computazione sono posizionate entrambe sul primo carattere significativo del nastro).
Si delineino due MT di tal fatta che riconoscano, rispettivamente il linguaggio L1 ={wwR | w 
{a.b}+} (al solito wR denota la stringa speculare di w) e il linguaggio L2 = {ww | w  {a.b}+}.
Se ne forniscano le rispettive funzioni di complessità temporale (a meno dell’ordine di grandezza
definito dalla classe ). Non è necessario fornire una definizione completa delle due macchine, ma
essa deve essere sufficientemente precisa da permettere una valutazione inequivoca della funzione
di complessità.
Il punteggio attribuito alla soluzione sarà tanto maggiore quanto migliore la complessità ottenuta.
NB: tra i diversi modi, tra loro sostanzialmente equivalenti, per definire la funzione  di questo tipo
di macchina si propone il seguente, dall’interpretazione ovvia:
: Q  A  Q  (A  {R, L, S})2;
Si noti che ciò potrebbe creare una situazione di conflitto nel caso le due testine si trovassero nella
stessa posizione; questo dettaglio è irrilevante ai fini dell’esercizio; si può comunque assumere che
in una situazione del genere venga convenzionalmente scelto come simbolo da scrivere sul nastro al
posto di quello letto, quello indicato per la testina 1.
Esercizio 4 (punti 8/30)
Si stabilisca quali sono i rapporti minimo e massimo tra il numero di nodi interni rossi e neri in un
generico albero rosso-nero. Si giustifichi brevemente la risposta.
Soluzioni (parziali e schematiche)
Esercizio 1
L1
AF
L2
L3
L4
NO NO NO NO
APD NO SI
SI
NO
APN SI
SI
SI
SI
ARP SI
SI
SI
SI
La ARP seguente riconosce L1assumendo come marcatura iniziale quella indicata in figura e come
marcature di accettazione quella con un solo token in B22 e S2 (rispettivamente in B1 e S1) e
nessun token in tutti gli altri posti; essa è facilmente modificabile in modo da riconoscere anche gli
altri linguaggi.
A
S2



a
B1
B21
A2n
An
b
b
S1
B22

b
Breve illustrazione
Un numero arbitrario n di scatti della transizione etichettata ‘a’ deposita n token nel posto An e 2n
token in A2n. Dopo tali scatti in maniera nondeterministica una delle due transizioni uscenti da A
ed etichettate  inizia il deconteggio dei token accumulati in An e A2n rispettivamente: la
transizione ‘b’ uscente da B1 può scattare esattamente n volte lasciando un token in B1 e nessun
token in An; simmetricamente per le transizioni uscenti da B21 e B22.
Perché la stringa sia riconosciuta è però necessario che alla fine degli scatti tutti i posti diversi da
B22 e B1 siano vuoti (e solo uno di essi contenga un token). All’uopo le due transizioni  usenti da
A innescano anche un “percorso ausiliario” segnato in modo tratteggiato in figura, con il compito di
svuotare rispettivamente i posti An e A2n quando diventano irrilevanti ai fini del conteggio.
Esercizio 2
Si definiscano i seguenti simboli di variabili, funzioni e di predicati:

st: variabile studente

es: variabile esame

cr: variabile crediti

CR(es): numero di crediti dell’esame es

Tab(st, i): l’i-esimo esame nella tabella di esami disponibile per lo studente st (NB: la tabelle
non contiene ripetizioni). Se per un certo valore di i non esiste un esame nella tabella il
valore Tab(st, i) è  (indefinito).

P_S(st, i): l’i-esimo esame inserito nel piano di studi dello studente st. Se per un certo valore
di i non esiste un esame nel piano di studi il valore P_S (st, i) è  (indefinito).

N_Es(st) Numero di esami nel pianodi studi dello studente st.
Le formule seguenti formalizzano le regole specificate dall’esercizio:

st, i,j (i  j  Tab(st, i)  Tab(st, j)  P_S(st, i)  P_S(st, j)

st, i , es (es = P_S(st, i)   j Tab(st, j) = es)

st, i(Tab(st, i)     j(j  i  Tab(st, i)  )

/*idem per P_S*/

st  i (Tab(st, i) = )

st,i (N_Es(st) = i  (P_S(st, i+1) =    k( 1 k  i  P_S(st, i)  ))

st (3  N_Es(st)  10)

st ( 50 

/* la formalizzazione della sommatoria può essere omessa in quanto ben nota*/

N _ Es( st)
i 1
CR( P_S(st, i))  80)
Esercizio 3
Una macchina a nastro singolo che riconosca L1 può operare nel modo seguente:

Inizialmente tiene ferma la testina 1 mentre la 2 si sposta fino alla fine della stringa (al
termine di questa fase la seconda testina si riposiziona sull’ultimo carattere della stringa);

Successivamente le due testine si spostano una a destra e l’altra sinistra verificando ad ogni
passo di leggere lo stesso carattere; ciò finché entrambe non raggiungono
contemporaneamente la fine della stringa di ingresso;

NB : in questo modo la machina riconosce tutte e sole le stringhe palindrome in
{a, b}+; questo insieme però contiene anche stringhe non in L1: precisamente quelle a
lunghezza dispari; occorre quindi anche verificare che la lunghezza della stringa sia pari.
La complessità di questa macchina è evidentemente (n).
Una macchina a nastro singolo che riconosca L2 può operare invece nel modo seguente:

Inizialmente le due testine si spostano verso destra, una a “velocità” doppia dell’altra, finché
la prima non giunge a fine stringa; alla fine di questa fase –che, en passant, verifica anche
che la lunghezza della stringa sia pari- entrambe le testine si spostano di una posizione a
sinistra; quella più a sinistra marca anche la sua posizione con un carattere apposito che sarà
riconosciuto dall’altra testina.

Successivamente le due testine ripercorrono la stringa a ritroso e alla stessa “velocità”
verificando di leggere sempre lo stesso carattere finché la testina di sinistra non legge un
blank e quella di destra non trova la marca lasciata dall’altra.
Anche in questo caso la complessità è evidentemente (n).
Esercizio 4
Un albero può essere totalmente nero (si noti che normalmente ciò avviene solo attraverso qualche
cancellazione che trasformi un nodo rosso in uno nero, perché ogni nuova inserzione in un albero
totalmente nero inserisce un nodo rosso; quindi l’unico modo per avere un albero totalmente nero
senza operare cancellazioni è che esso consista della sola radice). In tal caso il rapporto minimo è
evidentemente 0.
Al contrario, il massimo numero di nodi rossi lo si può ottenere se ogni nodo nero ha entrambi i
figli rossi e tutti i nodi “pseudofoglie”, ossia interni ma puntanti al NIL, sono rossi. In tal caso con
una semplice induzione si dimostra che il rapporto massimo è 2.
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere
20 Novembre 2012
Il tempo a disposizione è di 2 ore
Esercizio 1 (punti 7/15-esimi)
Il funzionamento delle reti di Petri (PN) è normalmente definito attraverso la cosiddetta “semantica
interleaving” in cui si assume che una sola transizione per volta, tra quelle abilitate in una certa
marcatura, possa scattare. La letteratura però ha proposto anche definizioni diverse della semantica
delle PN. Tra queste la semantica “true concurrency”, con lo scopo di evidenziare che alcune
attività modellate dalle PN possono avvenire in parallelo, ammette lo scatto contemporaneo di più
transizioni, tra quelle abilitate (purché ciò non violi proprietà di mutua esclusione). Un caso
particolare di tale semantica è quella a “parallelismo massimo”, che assume che tutte le transizioni
abilitate in una certa marcatura scattino contemporaneamente, sempre rispettando eventuali vincoli
di mutua esclusione.
Esercizio 1.1
Si forniscano definizioni precise, preferibilmente ricorrendo a notazioni formali (abilitazione, scatto
delle transizioni, ecc.) della semantica “true concurrency” generale e di quella a “parallelismo
massimo”. Per semplicità si assuma che ogni transizione possa scattare una sola volta ad ogni passo,
ossia che non siano ammessi scatti multipli e contemporanei della stessa transizione, anche se il
numero di token nei posti di ingresso lo permetterebbe.
Esercizio 1.2
Si dica, giustificando brevemente la risposta, se le affermazioni seguenti sono vere o false:
a) Nella semantica “true concurrency” il comportamento della rete è deterministico
b) Nella semantica “a parallelismo massimo” il comportamento della rete è deterministico
c) Se una marcatura è raggiungibile da una marcatura iniziale secondo la semantica
"interleaving" lo è anche secondo la semantica "true concurrency" e viceversa
d) Se una marcatura è raggiungibile da una marcatura iniziale secondo la semantica
"interleaving" lo è anche secondo la semantica a “parallelismo massimo” e viceversa.
Esercizio 2 (punti 5/15-esimi)
Si forniscano opportune pre- e post-condizioni, codificate mediante formule del prim'ordine, per
specificare il comportamento desiderato di un (frammento di) programma che, avendo in memoria
due array non vuoti di caratteri, A e B di lunghezza rispettivamente n e m, con m < n, stabilisca se
tutti i caratteri presenti in B compaiono anche in A con lo stesso numero di ripetizioni.
Esercizio 3 (punti 5/15-esimi)
Data una classe C di automi, un automa A in C viene detto minimo nella classe C se non esistono
altri automi in C che riconoscano il linguaggio L(A) riconosciuto da A e che abbiano un numero
inferiore di stati rispetto ad A.
Rispondere ai quesiti seguenti fornendo un’opportuna giustificazione:
1. E’ decidibile il problema di stabilire se un generico automa a stati finiti è minimo nella
classe degli automi a stati finiti?
2. E’ decidibile il problema di stabilire se, fissati l'alfabeto  della pila e la lunghezza massima
della stringa che ad ogni mossa l'automa può mettere in cima alla pila, un generico automa
a pila deterministico è minimo nella classe degli automi a pila deterministici?
Suggerimento: può essere di aiuto tenere presente che il problema dell’equivalenza tra
automi a pila deterministici è stato recentemente dimostrato decidibile (si veda la Tabella
8.1 a pagina 352 del testo)
3. E’ decidibile il problema di stabilire se la macchina di Turing mostrata sotto è minima nella
classe delle macchine di Turing?
a, _ / M, <R, R>
a, Z0/Z0, <S, R>
q0
q1
b, M / M, <R, L>
b, _ / _, <S, L>
q2
c, Z0/Z0, <S, R>
_, _ / _, <S, S>
qF
q3
c, M / M, <R, R>
!" #
$J #
Tracce di Soluzioni
Esercizio 1.1
In primo luogo si può estendere la definizione di transizione abilitata a un insieme di transizioni
abilitate. Escludendo il caso più generale in cui una transizione possa scattare diverse volte in un
colpo solo, si definisce, per una marcatura M:
Enab(M) = {t1, t2, … tk} se per tutte e sole le transizioni t1, t2, … tk i corrispondenti posti in ingresso
(Preset) sono marcati.
Successivamente, la true concurrency definisce lo scatto multiplo e nondeterministico di un set di
transizioni abilitate nel modo seguente
M |---- {ti1 …tir} M’ se e solo se {ti1 …tir}  Enab(M)

token_sufficienti(ti1 …tir)
/* ossia P contiene abbastanza token da far scattare tutte le transizioni in {ti1 …tir} da esso uscenti;
ciò evidentemente implica una scelta nondeterministica ma vincolata su quali transizioni possano
scattare concorrentemente tra quelle abilitate. */

/* la marcatura di M’ è definita nel modo tradizionale sommando gli effetti di eventuali transizioni
concorrenti*/
dove
token_sufficienti(ti1 …tir)
è definita come
 P   Preset {ti1 …tir}
M(P)  |{ tj1 … tjk}| dove { tj1 … tjk} = {ti1 …tir}  Postset(P)
dove Postset(P) indica l’insieme di transizioni uscenti da P.
La semantica a parallelismo massimo è un caso particolare di quella true concurrency, per ottenere
la quale basta aggiungere la clausola
 {ti1’ …tir’} tale che
({ti1 …tir}  {ti1’ …tir’}  Enab(M)

token_sufficienti(ti1’ …tir’))
Si noti che anche con questa restrizione il comportamento della rete rimane nondeterministico e
sarebbe anzi più corretto parlare di parallelismo massimale piuttosto che massimo.
Esercizio 1.2
Da quanto sopra le affermazioni a) e b) sono false.
La c) è vera perché la semantica interleaving non fa che mettere in sequenza scatti di transizioni
“impacchettati” in un unico scatto globale dalla semantica true concurrency.
La d) invece è falsa: la semantica interleaving (vedi anche punto precedente) può “sviluppare”
qualsiasi sequenza di scatti multipli, ma obbligando a far scattare sempre in parallelo tutte le
transizioni abilitate non è detto che si possano produrre tutte le marcature ottenibili con la
semantica interleaving, come mostrato dal controesempio seguente:
Nella semantica a parallelismo massimo i due token continuano a "rincorrersi" in modo sincrono
senza mai raggiungersi né superarsi; cosa che non avviene nella semantica interleaving.
Esercizio 2
Usando la notazione del metodo di Hoare la specifica del programma desiderato può essere espressa
nel modo seguente:
{n > m > 0}
P
{OK   x (Carattere(x)  i (0 < i  m  B[i] = x)  CountB(x) = CountA(x))}
dove le funzioni CountA(x) e CountB(x) sono definite nel modo seguente:
CountA(x) = Count_Aux_B(x, n) e
CountB(x) = Count_Aux_B(x, m).
Count_Aux_B(x, y) è a sua volta definita da:
Count_Aux_B(x, 0) = 0

y(0 < y  m  ( B[y] = x  Count_Aux_B(x, y) = Count_Aux_B(x, y - 1) + 1)

( B[y] = x  Count_Aux_B(x, y) = Count_Aux_B(x, y - 1)))
La definizione di Count_Aux_A(x, y) è analoga.
Esercizio 3
1. Il primo problema è decidibile, in quanto è sufficiente enumerare tutti gli automi a stati finiti
(costruibili sull’alfabeto di simboli di A), in ordine crescente rispetto al numero di stati, fino
al primo automa (escluso) con un numero di stati pari al numero di stati in A. Questo tipo di
enumerazione è certamente possibile ed è simile a quello utilizzato per enumerare le
macchine di Turing. A questo punto, per ciascun automa in questa enumerazione è
sufficiente verificarne l’equivalenza con A, proprietà decidibile grazie alle proprietà di
chiusura della famiglia e della decidibilità della emptiness di un linguaggio regolare: se
l’equivalenza sussiste, A non è minimo, altrimenti lo è.
NB: In alternativa e in maniera più immediata il problema può essere dimostrato decidibile
facendo ricorso alla procedura di minimizzazione per gli automi a stati finiti e quindi
semplicemente confrontando il numero di stati dell'automa di partenza e dell'automa minimo
corrispondente.
2. Con un procedimento del tutto simile al precedente (e mantenendo fissato l'alfabeto di pila
dell'automa) risulta decidibile anche il secondo problema (tenendo conto, come stabilito
nella tabella 8.1, che è decidibile anche l’equivalenza tra automi a pila deterministici e che
limitando la lunghezza della stringa depositabile in pila esiste solo un numero finito di
automi con un determinato numero di stati, a meno di una irrilevante ridenominazione degli
stati).
Si noti che se l'alfabeto di pila non fosse fissato sarebbe sempre possibile ridurre il numero
di stati (fino a due) memorizzando l'informazione in essi contenuta in opportuni simboli
depositati sulla pila.
Si noti inoltre che ogni automa a pila può essere trasformato in uno equivalente che non
depositi in pila più di k caratteri per ogni mossa, purché k sia > 1 e al prezzo di un aumento
del numero di stati.
3. Il quesito del terzo problema è una domanda chiusa, che non dipende da alcun parametro,
pertanto il problema è certamente decidibile.
Algoritmi e Principi dell'Informatica
Seconda Prova in Itinere
8 Febbraio 2013
Il tempo a disposizione è di 2 ore
Esercizio 1 (punti 5/15-esimi)
Esercizio 1.a
Si delinei una macchina di Turing M a nastro singolo che riconosca il linguaggio L  {a,b}*
consistente di tutte e sole le stringe con un numero di occorrenze di 'a' uguale a quello di 'b'. La
descrizione non deve necessariamente scendere in tutti i dettagli ma deve essere sufficientemente
chiara e precisa da permettere di calcolare la complessità temporale asintotica della macchina: si
spieghi con precisione quale sia tale complessità.
E' possibile trovare un altro modello di calcolo a potenza risolutiva minore della macchina a nastro
singolo (ossia non in grado di riconoscere tutti i linguaggi riconoscibili dalla MT) che riconosca L
con complessità inferiore a quella di M? Si motivi brevemente la risposta.
Esercizio 1.b
Si risolva lo stesso esercizio del punto 1.a con riferimento al linguaggio L'  {a, b, c}* le cui
stringhe hanno ugual numero di 'a', 'b' e 'c'.
Esercizio 2 (punti 8/15-esimi)
Si consideri un array che sia il risultato della visita in post-ordine sinistro di un Binary Search Tree
(BST) i cui nodi contengano numeri interi ordinati in ordine crescente (figlio di sinistra < del padre
≤ del figlio di destra; linearizzato in: figlio di sinistra, figlio di destra, padre).
Assumendo l'ipotesi che il BST di partenza avesse entrambi i figli per ogni nodo interno, si delinei,
mediante opportuno pseudocodice, un algoritmo che, partendo dall'array linearizzato ricostruisca il
BST originario. Indi se ne valuti la complessità asintotica.
NB: il punteggio attribuito alla soluzione terrà conto della complessità asintotica dell'algoritmo.
Esercizio 3 (punti 3/15-esimi)
Si vuole progettare una tabella di hashing in cui memorizzare numeri primi, usando gli stessi come
chiave. La tabella è lunga 2n elementi, si sceglie di utilizzare la funzione
h(x) = x mod 2n come funzione di hash. E' una buona scelta? Motivare brevemente la risposta.
Esercizio 4 (punti 2/15-esimi)
Si stabilisca l’ordine di grandezza (classe di -equivalenza) della soluzione della seguente
equazione alle ricorrenze:
T(n) = 7 T(n/5) +  (n2)
Tracce di soluzioni
Esercizio 1
1.a
Una M a nastro singolo non può far altro che scorrere l'intero nastro, o una sua porzione ad esso
proporzionale, nel caso pessimo, per ogni carattere letto alla ricerca di un suo corrispondente;
alternativamente aggiornando un contatore che dovrebbe trovarsi in una diversa porzione di nastro
rispetto a quella dove è memorizzata la stringa di ingresso. Quindi la sua complessità temporale
deve essere almeno (n2).
Un automa a pila deterministico invece può facilmente riconoscere L in (n).
1.b
La precedente macchina M può facilmente essere modificata in modo da riconoscere L' con la stessa
complessità asintotica.
L' però non è riconoscibile da alcun automa a pila; è tuttavia riconoscibile da una rete di Petri,
sempre in tempo lineare, che però non ha la potenza computazionale delle MT.
Esercizio 2
Un esempio di BST che soddisfi l'ipotesi dell'esercizio e della sua linearizzazione in post-ordine
sinistro è fornito in figura.
13
11
8
5
3
15
12
14
18
8
6
(a) esempio di BST
(b) array risultante dalla visita in post-odine sinistro del BST in figura (a):
3, 6, 5, 8, 8, 12, 11, 14, 18, 15, 13.
Si noti che (per un certo valore) non possono esistere più di due nodi contenenti quel valore,
altrimenti si dovrebbe violare l'ipotesi che ogni nodo interno ha entrambi i figli.
Un modo semplice di riottenere il BST di partenza consiste nel percorrere l'array da destra a sinistra
ed eseguire una serie di inserimenti in ordine dei vari elementi. In questo modo però la complessità
risulta (O(n.log(n)) nel caso di BST bilanciato e O(n2) nel caso pessimo.
Un algoritmo più efficiente invece può fare uso di una struttura ausiliaria a pila e procedere nel
modo seguente, da sinistra a destra, sfruttando la proprietà che gli elementi dell'array sono in ordine
crescente tranne quando si passa da figlio (necessariamente di destra) a padre:
push a[0]; crea un nodo per a[0]
for i := 1, …,n
do
while a[i-1] < a[i] push a[i]; crea un nodo per a[i]
crea un nodo per a[i]; assegna al suo campo figlio di destra il puntatore al nodo creato per
l'elemento in cima alla pila e al figlio di sinistra il puntatore al nodo creato per l'elemento
sottostante; pop; pop; push a[i];
L'algoritmo visita ogni elemento una sola volta e quindi ha complessità O(n).
Esercizio 3
La funzione di hash proposta non è una buona funzione: i numeri primi, fatto salvo 2, sono tutti
dispari; quindi i posti di posizione pari verranno utilizzati solo in caso di conflitti e la tabella
risulterà fortemente sbilanciata e/o sottooccupata.
Esercizio 4
Applicando il teorema dell’esperto (Master theorem) abbiamo:
a = 7, b = 5, f(n) =  (n2) >  (nlogb(a) + )
Quindi la soluzione è  (n2).
Algoritmi e Principi dell’Informatica
Appello del 21 Febbraio 2013
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1
ora e 30 minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5, 6 e in 1 ora e
30 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1 (punti 5)
Si considerino i seguenti linguaggi
L1 =
abaaabbbabd, … aabbabaaabbbd, …}
= {abd, aabbabd, aabbaabbd, abaabbd, …
L2 =
= {abcad, … aaabbcaad, aaabbbcaaad,
aabbbcaaabcad, …}
1. Definire una grammatica non contestuale che generi L1 e un automa a pila deterministico che lo
accetti.
2. Definire una grammatica non contestuale che generi L2 e un automa a pila, preferibilmente
deterministico, che lo accetti.
3. Definire una grammatica non contestuale che generi L1L2. Se possibile, definire un automa a
pila deterministico che lo accetti; altrimenti argomentare in modo informale ma convincente che
il linguaggio L1L2 non può essere accettato da un automa a pila deterministico, e definire un
automa a pila nondeterministico che accetti L1L2.
Esercizio 2 (punti 5)
Si specifichi in logica del prim’ordine una funzione f : A*  N  A, dove A è un alfabeto di
simboli e N è l’insieme dei numeri naturali, che, data una stringa costruita sull’alfabeto A e un
numero i, restituisce il carattere in posizione (i+1)-esima nella stringa (cioè il carattere con indice i
nella stringa, dove 0 è l’indice del primo carattere, 1 del secondo, e così via). Nella specifica, è
consentito l’uso delle seguenti funzioni:
st
(concatenazione delle stringhe s e t)
|s|
(lunghezza di una stringa s)
e del predicato = (uguaglianza). Ovviamente non è consentito l’uso della notazione s[i], che indica
l’i-esimo carattere della stringa s.
Esercizio 3 (punti 5)
Si dica, giustificando brevemente la risposta, se la seguente funzione è calcolabile o no:
f : N  N N  {0, 1}
f (0, 0, 0) = 0;
f (x, y, z) =
se z è pari allora 0 se x è la radice quadrata intera esatta di y, altrimenti ;
se z è dispari allora 1 se
( x dispari y pari e k, h  N tali che kx = hy,

 x pari  y dispari e k, h  N tali che kx = hy )
 altrimenti.
Esercizio 4 (punti 6)
Si risolva la seguente equazione alle ricorrenze (a meno della relazione O):
T(n) = 2T(n-4) + O(log(n))
Esercizio 5 (punti 6)
Scrivere un algoritmo che, dato un array A, determina se esiste un sottoarray (per sottoarray si
intende una sequenza di elementi consecutivi dell’array base) di A che sia a sua volta scomponibile
in 2 sottoarray tali che la somma degli elementi nel primo sia uguale alla somma degli elementi del
secondo. L'algoritmo deve restituire il sottoarray più lungo tra quelli che soddisfano la condizione di
cui sopra, se esiste.
Indicare la complessità temporale asintotica dell’algoritmo scritto.
Esercizio 6 (punti 5)
Si definisca (senza necessariamente codificarne tutti i dettagli) un macchina di Turing a nastro
singolo che riconosca il linguaggio delle stringhe del tipo x#y con x,y{a, b}* e (i) |x|  |y| e (ii) |x|
pari e |y| dispari o viceversa, minimizzando la complessità temporale della macchina; se ne valuti la
complessità spaziale e temporale a meno della relazione .
Tali complessità cambierebbero se si rimuovesse il vincolo (ii)?
Cosa cambierebbe se si usasse una macchina a k nastri invece di una macchina a nastro singolo?
Tracce di soluzione
Esercizio 1
1. La grammatica seguente, con assioma S1, genera L1
S 1  A S1 | A d
AaAb|ab
L’automa deterministico seguente accetta L1.
2. La grammatica seguente, con assioma S2, genera L2
S2 a S2 | a X d
XCX|C
CbCa|bca
L’automa deterministico seguente accetta L2.
3. La grammatica, con assioma S, genera L1L2
bZ0/BZ0
aZ0/Z0
aZ0/Z0
S  S1 | S2
dZ0/Z0
cB/B
bZ0/BZ0
i2
bB/BB
aB/
… più le regole per i linguaggi L1ed L2 …
L’automa a pila che accetta L1L2 non può essere deterministico: mentre legge il primo gruppo di
simboli a, l’automa deve memorizzare nella pila un conteggio unario del numero di a e poi, mentre
legge il primo gruppo di b, deve usare la pila per verificare (nel caso che la stringa L1) che il
numero delle bsia uguale al numero delle a. Ma facendo ciò il contenuto della pila va perso, quindi
la pila non può essere usata per verificare (nel caso la stringa L2) che il numero delle ache seguono
la successivaceguagli il numero delle bche la precedono. Un automa nondeterministico che accetti
L1L2 può essere ottenuto come semplice composizione dei due automi che accettano L1ed L2.
Esercizio 2
x y i ( f(x, i) = y w z (x = w  y  z  |y| = 1  |w| = i) )
Esercizio 3
f è calcolabile perché :

è decidibile se z sia pari o dispari

nel primo caso è decidibile stabilire se x sia la radice quadrata intera esatta di yo no e
produrre 1 o, rispettivamente, nei due casi;

nel secondo caso la domanda è chiusa (non importa stabilire se la condizione indicata sia
vera o falsa: la funzione di fatto non dipende da x e y in quanto quantificate) e quindi una
delle due macchine che per z dispari producono in output 1 oppure non terminano è la
macchina che computa questa parte della funzione.
Esercizio 4
Mediante il metodo dell’albero di ricorsione si ottiene il guess O(2n/4∙log(n)): il costo di ogni livello
è O(2k log(n – 4k)); quindi la profondità dell’albero è k = n/4.
Poi si verifica che, con opportune costanti, T(n) ≤ c∙2n/4∙log(n).
In effetti, per arrivare a concludere che T(n) ≤ c∙2n/4∙log(n), è utile mostrare un vincolo leggermente
più stretto, e cioè che T(n) ≤ c∙2n/4∙log(n) - bn2. Infatti si ha:
T(n) = 2∙T(n-4) + d∙log(n) ≤ 2c2((n-4)/4)log(n-4) -2b(n-4)2 + d∙log(n) =
= c2n/4log(n-4) - bn2 - bn2 + 16bn -32 + d∙log(n) ≤
≤ (c2n/4log(n) - bn2) - bn2 + 16bn -32 + d∙log(n) ≤
≤ c2n/4log(n) - bn2
per b ed n sufficientemente grandi.
Esercizio 5
Un modo naturale per risolvere il problema consiste nell’elencare tutti gli n2 sottoarray di A (lungo
n), e controllare se questi hanno la proprietàdesiderata;tale verifica si può fare in tempo O(n) per
ogni sottoarray.
Di conseguenza, la complessità temporale complessiva è  (n3).
Più precisamente, uno schema algoritmico per risolvere il problema è il seguente:



Si calcola la somma di tutti gli elementi dell’array, S; costo O(n);
Si inizializzano tre indici, i, j, k che delimitano rispettivamente inizio e fine del sottoarray corrente e
la separazione tra i due sottoarray del medesimo: ad esempio, i, k, = 0, j = n-1; di conseguenza,
inzialmente il primo sottoarray A1 ha somma A[0] e il secondo, A2 S – A[0];
Per ogni coppia i, j si fa variare k da i a j e per ogni incremento si aggiunge A[k] a A1 e lo si sottrae
ad A2; se i due valori coincidono si è risolto il problema. Per ogni valore di k questa operazione
costa O(1).
Quindi complessivamente l’algoritmo ha complessità temporale O(n3).
Esercizio 6
Una MT di Turing a nastro singolo che riconosce il linguaggio descritto opera con complessità
temporale e spaziale (n). Il linguaggio descritto è, infatti, un linguaggio regolare e il controllo
sulla condizione (ii) (che implica la condizione (i)) può essere fatto usando solo gli stati come nella
macchina seguente.
#|# <R>
a|a <R>
b|b <R>
a|a <R>
b|b <R>
a|a <R>
b|b <R>
a|a <R>
b|b <R>
-|- <S>
#|# <R>
a|a <R>
b|b <R>
#|# <R>
a|a <R>
b|b <R>
a|a <R>
b|b <R>
-|- <S>
a|a <R>
b|b <R>
-|- <S>
La
complessità spaziale è data dal fatto che l’unico nastro contiene la stringa di ingresso.
Se si rimuovesse il vincolo (ii) il linguaggio non sarebbe più regolare e una macchina che
minimizza la complessità temporale potrebbe operare nel seguente modo:
a|a <R>
b|b <R>
#|# <R>
a|X <R>
b|X <R>
X|X <L>
-|- <L>
#|# <S>
a|X <R>
b|X <R>
a|X <R>
b|X <R>
X|X <R>
#|# <R>
a|a <L>
b|b <L>
#|# <L>
a|a <S>
b|b <S>
#|# <R>
La complessità temporale diventerebbe quindi (n2), mentre quella spaziale rimarrebbe pari a (n).
Se invece che una macchina a nastro singolo si usasse una macchina a k nastri le complessità
cambierebbero nel seguente modo.
Nel primo caso la macchina a k nastri opererebbe esattamente come la macchina a nastro singolo,
mantenendo quindi una complessità temporale (n), mentre la complessità spaziale diventerebbe
(1), poiché i nastri di memoria e ingresso sono distinti e quindi la memoria in questo caso, non
viene usata.
Rimossa la condizione (ii), una macchina con un nastro di memoria può riconoscere il linguaggio
scorrendo la prima parte della stringa e copiandola nel nastro di memoria. Una volta raggiunto il
simbolo # legge la seconda parte della stringa, avvolgendo indietro il nastro in cui è stata copiato la
prima parte della stringa. Se il nastro raggiunge Z0 prima che la stringa sia finita o la stringa finisce
prima di arrivare a Z0 sul nastro, la parola viene accettata.
La complessità temporale diventa quindi (n), così come quella spaziale.
Algoritmi e Principi dell’Informatica
Appello del 25 Giugno 2013
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2, in 1
ora e 30 minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3, 4, 5 in 1 ora e
30 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1 (punti 7)
Nel gioco Reversi ci sono due giocatori (“bianco” e “nero”), ciascuno dotato di 32 dischi bicolori
(neri da un lato, bianchi dall'altro) da piazzare su una scacchiera di 8x8 caselle inizialmente vuota.
Si muove alternativamente (inizia il nero) piazzando ogni volta un nuovo disco (girato dalla parte
del proprio colore) in una casella vuota. Se tra il disco appena piazzato e quelli del proprio colore
già presenti sulla scacchiera sono presenti orizzontalmente, verticalmente o diagonalmente solo
dischi avversari senza caselle vuote nel mezzo, tali dischi vengono rovesciati e diventano del colore
di chi ha eseguito la mossa. La figura sottostante mostra un esempio di mossa del nero che produce
il rovesciamento di un disco bianco.
Per semplicità rispetto alla versione ufficiale del gioco, si assuma che sia sempre possibile muovere,
ossia piazzare nuovi dischi, fino a che la scacchiera non sia piena. A fine partita, vince il giocatore
con il maggior numero di dischi del proprio colore.
Scopo dell’esercizio è specificare alcune (non tutte!) regole del gioco mediante formule del
prim’ordine.
Si considerino i predicati seguenti, che fanno riferimento al tempo (discreto) in cui avviene una
mossa (ossia al numero d’ordine della mossa all’interno della partita, partendo da 1):
scacchiera(X,Y,C,T)
// c’è un disco di colore C al tempo T in posizione (X,Y)
mossa(X,Y,C,T) // il giocatore di colore C piazza un disco del suo colore al tempo T in posizione
(X,Y)
1. Si specifichino le condizioni seguenti:
a. inizialmente (al tempo 0) la scacchiera è vuota e la prima mossa viene eseguita dal
nero al tempo 1.
b. in ogni casella c’è sempre al massimo un solo disco.
2. Si specifichi ora la seguente regola, supponendo che sia già stato definito un predicato
daRibaltare(X,Y,T) che indica che un disco in posizione (X,Y) in conseguenza di una mossa
effettuata al tempo T deve essere ribaltato nello stesso istante T:
All’istante T viene eseguita una mossa (se nell’istante precedente esistevano caselle vuote);
se la mossa produce l’effetto che qualche casella sia ribaltabile, contestualmente, ossia nello
stesso istante T, avvengono tutti i ribaltamenti possibili. NB: non è necessario formalizzare
quale sia il giocatore che effettua la mossa.
3. [Opzionale: questa parte, se risolta in maniera corretta comporta 3 punti aggiuntivi; tuttavia
essa verrà valuatata solo se le parti precedenti dell’esercizio saranno state risolte
correttamente].
Specificare il predicato daRibaltare(X,Y,T) (Suggerimento: si prenda in considerazione
questa proprietà a partire dall’istante 1) . In tal caso si consideri inoltre già specificata la
seguente definizione di avversario mediante la funzione avv (avversario): avv(bianco) =
nero; avv(nero) = bianco
NB: Si ribadisce che non è richiesta la specifica di ulteriori regole del gioco (e.g.: una sola mossa
per volta, alternanza tra giocatori, …).
Esercizio 2 (punti 8)
Si risponda ai seguenti quesiti, giustificando brevemente ma con chiarezza la risposta:
1. Si consideri l’insieme S = { y | x ( fy(x)⊥fy(x)=x2) }. S è ricorsivo? S è ricorsivamente
enumerabile?
2. Si consideri la funzione seguente:
g(x, y) = 1, se z ( fx(z)⊥fy(z)⊥fx(z)= fy(z)), 0 altrimenti
g è computabile?
3. Si consideri ora la funzione g’, variazione della precedente g:
g’(x, y, z) = 1, se fx(z)⊥fy(z)⊥fx(z)= fy(z), ⊥ altrimenti
g’ è computabile?
Esercizio 3 (punti 7)
Si consideri il linguaggio
n
m
n
m
n
m
L = {b 1a 1b 2 a 2… b h a h|
(1) k>0, (2) ni ni+1 i=1, …, k-1,
(3) 1 ni 10, i=1,…, h
(4) mi+1 mi i=1, …, k-1,
(5) 1 mi 5, i=1,…, h}.
1) Quale è la complessità di una MT a k nastri che riconosce L?
2) Che cosa cambierebbe con una MT a nastro singolo?
3) È possibile ottenere la stessa complessità con una RAM usando il criterio di costo logaritmico?
4) Le risposte ai punti precedenti cambierebbero se venisse rimosso il vincolo (5)? Se sì, come?
Per tutti i punti, si descriva anche solo schematicamente il comportamento della MT o della RAM
usata per risolvere il problema, in modo da motivare la complessità fornita.
Esercizio 4 (punti 5)
a. Dato un albero binario di interi, memorizzato mediante una struttura dati che prevede che ogni
nodo punti ai propri figli ma non al padre e che può contenere elementi ripetuti, si vogliono
cancellare tutte le foglie che contengono un valore uguale a quello del padre. Si fornisca una
breve traccia di un algoritmo per questo scopo e se ne valuti la complessità asintotica; essa è
ottima?
NB: non è richiesto il codice e neanche lo pseudocodice dell’algoritmo: è sufficiente una
sintetica ma precisa descrizione che permetta di valutarne la complessità in modo evidente.
b. Si voglia estendere l’algoritmo in modo tale da ottenere un albero in cui non ci siano foglie che
contengono il valore del padre. Fornire una traccia e la relativa complessità del nuovo
algoritmo.
Esercizio 5 (punti 5)
Si consideri il seguente problema (versione semplificata di un classico problema per la
classificazione di dati):
Dato un insieme N di punti in uno spazio m-dimensionale partizionarli in un numero k – assegnato
e minore di N – di cluster (sottoinsiemi disgiunti) così che ogni punto appartenga ad un solo cluster,
ed ogni cluster contenga almeno un punto. Ogni cluster ha un centroide definito come la media,
nello spazio euclideo m-dimensionale, dei punti che appartengono al cluster stesso (ad esempio, se
il cluster è costituito da due punti, il suo centroide è il punto di mezzo tra essi).
Un semplice metodo greedy (che non garantisce di trovare la migliore separazione possibile fra i
cluster, che nella presente versione semplificata non è defintia) consiste nello scegliere casualmente
k punti come centroidi iniziali dei k clusters. Quindi ogni altro punto dell’insieme viene assegnato
al cluster il cui centroide è il più vicino ad esso e subito dopo viene ricalcolato il centroide di quel
cluster per tenere conto del nuovo valore; si procede in tal modo fino ad esaurimento dei punti.
Si dettagli la precedente traccia di algoritmo mediante opportuno pseudocodice fino a un livello di
dattaglio tale da poterne definire con precisione la complessità asintotica (temporale e spaziale).
Informazione di completamento culturale, irrilevante allo scopo di risolvere l’esercizio:
l’algoritmo completo procede per iterazioni successive fino a quando il calcolo dei centroidi e la
clusterizzazione non raggiungono un opportuno criterio di ottimalità.
Tracce delle soluzioni
Esercizio 1
1.
a. X Y C scacchiera(X,Y,C,0)mossa(X,Y, C, 0)
 Z,W mossa(Z,W, nero, 1)
b. X Y T (scacchiera(X,Y,bianco,T) scacchiera(X,Y,nero,T))
2.
T (T > 0  X,Y(C scacchiera(X,Y,C,T-1))
Z,W,H
mossa(Z,W,H,T) 
(K scacchiera(Z,W,K,T-1) )
scacchiera(Z,W,H,T)

(Z W daRibaltare (Z,W,T) scacchiera(Z,W,H,T) )
)
//se c’è almeno una casella libera a T-1, a T si fa una mossa che consiste nel mettere un disco in una
della caselle libere (a T-1); di conseguenza tutte le caselle divenute ribaltabili sono ribaltate.
Esercizio opzionale
X YT daRibaltare (X,Y,T)
(T >0 
(Z,W,P mossa(Z,W,P,T)N (N>0)M (M>0)
// 1° caso: orizzontale: X e Y si trovano sulla stessa linea orizzontale del punto di una
mossa e internamente a un “segmento” che parte dal punto della mossa e termina nel
primo punto di uguale colore della mossa(alla sua destra); inoltre tutti i punti interni
del segmento, inclusi X e Y, sono di colore opposto.
scacchiera(Z+M,W,P,T-1)
Z<X  X<Z+M  W = Y
(I(Z < I  I< Z+M)scacchiera(I,Y,avv(P),T-1))

//analogamente il caso in cui il segmento parta dal punto di uguale colore della
mossa (alla sua sinistra) e termini nel punto della mossa
….
// analogamente per i casi verticali e diagonali
….
))
Formulazione alternativa
X YT ribaltabile(X,Y,T) 
T>0 N N>0 M M>0 P
(
// 1° caso: orizzontale
(mossa(X-N,Y,P,T)  scacchiera(X+M,Y,P,T-1)

mossa(X+M,Y,P,T)  scacchiera(X-N,Y,P,T-1) )

I (X-N<II<X+M scacchiera(I,Y,avv(P),T-1)) )

// analogamente per i casi verticali e diagonali
…
)
Esercizio 2
1. S non è ricorsivo: ciò è una diretta conseguenza del toerema di Rice. D’altro canto il
complemento di S, S’:
S’ = { y | x ( fy(x)⊥fy(x)x2) }
è ricorsivamente enumerabile: i suoi elementi possono essere enumerati mediante una classica
tecnica “diagonale” (su 3 dimensioni) che consideri nell’ordine tutte le funzioni computabili, per
tutti i valori dei dati di ingresso e per numero crescente di passi di computazione individuando
quindi i valori di y per i quali la condizione fy(x)x2sussiste. Di conseguenza S non è
ricorsiviamente enumerabile altrimenti S e S’ sarebbero entrambi ricorsivi.
2. Sia K il numero di Godel di una MT che calcola la funzione f(x)=x2: risulta allora g(x, K)=p(x),
dove p è la funzione caratteristica dell’insieme S di cui al punto 1; quindi g(x, K) non è
computabile, ed a maggior ragione non lo è g(x,y).
3. g’ è computabile: una MT può calcolareg’simulandoil calcolo difx(z) efy(z) e, se entrambe le
computazioni terminano, verifica sefx(z)= fy(z), altrimenti continua con la sua simulazione
indefintamente.
Esercizio 3
Il linguaggio L è regolare, grazie ai vincoli (3) e (5); quindi, potendo ognuna delle macchine prese
in considerazione simulare il funzionamento di un automa a stati finiti con il proprio organo di
controllo, ognuna di esse può riconoscere L con complessità temporale O(n) e spaziale O(1), con
l’eccezione della macchina di Turing a nastro singolo che deve usare n celle per la stringa di
ingresso.
Se si rimuove il vincolo (5) L non è più regolare (e neanche context-free). Una MT a 2 nastri può
memorizzare i vari mi su un nastro e mi+1 sull’altro in alternanza, contestualmente verificando che
sia soddisfatta la diseguaglianza; ciò richiede evidentemente complessità spaziale e temporale O(n).
Una macchina RAM può procedere in maniera analoga usando 2 contatori, ottenendo una
complessità temporale O(n log n) col criterio di costo logaritmico. Una macchina a nastro singolo
invece deve scandire ogni gruppo di mi ‘a’ mi volte, ciò che comporta una complessità temporale
O(n2).
Esercizio 4
a. E’ sufficiente una visita in preordine dell’albero. Quando si raggiunge una foglia si verifica
se il padre ha lo stesso valore e in tal caso la si elimina. Quindi la complessità è lineare nel
numero dei nodi.
b. La soluzione più naturale consiste nell’ iterare l’algoritmo precedente. Ogni iterazione ha
quindi complessità lineare nel numero dei nodi; il numero di iterazioni al massimo è dato
dalla profondità dell’albero. Quindi nel caso pessimo la complessità è O(n2).
Tuttavia, un algoritmo più sofisticato può tenere traccia, ovviamente in maniera ricorsiva,
durante la visita dell’albero, del fatto che un nodo sia diventato foglia a seguito della
cancellazione dei suoi figli: in tal caso esso viene cancellato e, al momento di ritornare il
controllo al proprio padre gli notifica il fatto di essere stato cancellato; se un nodo riceve
questa ionformazione da ambo i figli sa di essere a sua volta diventato foglia e il
meccanismo può essere iterato durante la seuqnze di ritorno alle varie chiamate ricorsive,
ottenendo quindi una complessità O(n).
Esercizio 5
Complessità temporale:
considerando costante il tempo per calcolare la distanza del punto dai k centroidi (in realtà dipenda
da m ma non da k né da N), ognuna delle N iterazioni richiede k confronti ed il calcolo del nuovo
centroide, quindi O(N) nel caso pessimo dal momento che tutti i punti potrebbero essere assegnati
ad un unico cluster. La complessità temporale totale è perciò O(N2).m. Si noti tuttavia che il
ricalcolo della media dei punti (centroide) a causa dell’inserimento del nuovo punto potrebbe essere
fatto anche in O(1) moltiplicando la media precedente per il numero s di punti precedente;
aggiungendo le coordinate del nuovo punto e ridividendo per s+1. In tal modo la complessità
diventerebbe O(N.k.m)
Complessità spaziale
occorre tenere in memoria i punti ed i centroidi, quindi O((N + k)m)
Algoritmi e Principi dell’Informatica
Appello dell’11 Settembre 2013
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3, in 1
ora e 30 minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5, 6 in 1 ora e
30 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e
hanno valore puramente indicativo.
Esercizio 1 (punti 4)
Sia data la seguente grammatica G:
S→BSa|C
BC → C b b
C→c
1.
2.
Si dica quale è il linguaggio generato da G.
Si scriva un automa che riconosce il linguaggio generato da G. L’automa deve appartenere alla
classe di potenza riconoscitiva minima tra quelle che riconoscono il linguaggio generato da G.
Esercizio 2 (punti 5)
Si consideri il seguente programma (in pseudocodice), il cui scopo è ordinare un generico array A di
lunghezza variabile il cui valore è memorizzato nel campo length (si supponga che il campo key dei vari
elementi sia un intero in valore assoluto  100):
INSERTION-SORT(A)
1 for j := 2 to A.length
2 key := A[j]
3 //Inserisce A[j] nella sequenza ordinata A[1..j−1]
4 i := j − 1
5 while i > 0 and A[i] > key
6 A[i + 1] := A[i]
7 i := i − 1
8 A[i + 1] := key
1. E’ decidibile il problema di stabilire se il programma suddetto ordina correttamente un generico
array di lunghezza  100?
2. E’ decidibile il problema di stabilire se il programma suddetto ordina correttamente un generico
array di lunghezza qualsiasi?
Esercizio 3
Prima parte (obbligatoria:punti 6)
Si consideri un sistema costituito da un processo che gestisce una risorsa R utilizzata da due processi utenti
U1 e U2.




Ognuno dei due utenti richiede di tanto in tanto l’accesso alla risorsa R, in mutua esclusione.
Né U1 né U2 possono chiedere nuovamente l’uso di R se la loro precedente richiesta non è stata
prima soddisfatta.
Il processo gestore assegna R ai richiedenti, in mutua esclusione e in alternanza.
Al termine dell’uso di R il processo utente rilascia la risorsa.
Si formalizzi questo comportamento del sistema mediante una rete di Petri.
Seconda parte (facoltativa: ulteriori punti 4. NB: la parte facoltativa verrà valutata solo se
sarà stata svolta correttamente la parte obbligatoria.)
La versione precedente ha il difetto di imporre una rigida alternanza tra il servizio di U1 e quello di U2, con
l’effetto di bloccare entrambi i processi se uno dei due, pur potendo effettuare una richiesta, non la esegue
quando è il proprio turno. Ad esempio non sarebbe possibile la seguente sequenza, assumendo che
inizialmente né U1 né U2 abbiano richiesto la risorsa:
U1 richiede la risorsa e la ottiene; successivamente la risorsa viene rilasciata e U1 la chiede nuovamente; U2
però nel frattempo non l’ha ancora richiesta e quindi la risorsa viene nuovamente assegnata a U1 (mentre se
U2 nel frattempo l’avesse richiesta, essa dovrebbe essere obbligatoriamente assegnata ad U2).
Si modifichi la precedente rete di Petri in modo da permettere che la risorsa venga assegnata anche più volte
di seguito allo stesso processo ma solo se l’altro non l’ha richiesta.
Esercizio 4 (punti 5)
Si consideri il problema di cercare un elemento x compreso tra 0 e 9 in una sequenza ordinata S di
lunghezza n che contiene solo i numeri fra 0 e 9 (ciascun elemento può apparire più volte in S).
Si descriva a grandi linee il comportamento di una macchina di Turing a k nastri che, ricevendo in
ingresso la stringa x$S, sia in grado, facendo uso di un algoritmo di ricerca binaria, di stabilire se x
appartiene a S e se ne calcolino la complessità temporale e spaziale. Sono preferibili soluzioni che
minimizzano la complessità temporale.
Esercizio 5 (punti 6)
Si descriva un algoritmo, mediante opportuno pseudocodice, che calcoli il determinante del
prodotto tra due matrici A e B nn, sotto l’ipotesi che A e B siano entrambe triangolari superiori
(ossia abbiano tutti 0 al di sotto della diagonale principale) o, simmetricamente, triangolari inferiori.
Si valuti la complessità asintotica dell’algoritmo in funzione della dimensione n delle matrici.
Suggerimento (per chi avesse qualche difficoltà a richiamare alla memoria gli elementi
basilari di algebra lineare)
Ricavare proprietà e algoritmi generali estrapolandoli da esempi relativi a matrici “piccole”: e.g.,
22, 33, …
Esercizio 6 (punti 5)
Si risponda alle seguenti domande, motivando opportunamente le risposte.
1. Si considerino alberi red-black che ammettono l’esistenza di chiavi duplicate:
a. è possibile che ci siano due elementi con la stessa chiave che non sono uno il padre
dell'altro?
b. è possibile che ci siano due elementi con la stessa chiave che non sono uno antenanto
dell'altro?
2. Modificare gli algoritmi di RB-INSERT-RB e RB-DELETE visti a lezione in modo da
impedire che ci possano essere in un albero chiavi duplicate.
Dire come cambia (se cambia) la complessità degli algoritmi modificati rispetto alle versioni
originali.
Tracce di soluzioni
Esercizio 1
Il linguaggio generato dalla grammatica è L(G) = {c b2n an | n >= 0}, che è riconosciuto da un
semplice automa a pila deterministico.
Esercizio 2
La risposta è positiva in entrambi i casi. Infatti il problema può essere deciso, dimostrando in effetti
la correttezza dell’algoritmo codificato dal programma: in letteratura si trovano diverse
dimostrazioni matematiche della sua correttezza, ma anche una semplice analisi informale del
codice può portare alla decisione che esso effettivamente ordina correttamente un qualsiasi array.
Ovviamente, una volta deciso il problema nel caso generale ne consegue la stessa decisione nel caso
particolare.
Tuttavia nel primo caso è possibile constatare immediatemente la decidibilità del problema posto,
anche senza deciderlo: basta infatti constatare che in tal caso il dominio del problema è finito
(l’insieme degli array di lunghezza  100 e i cui elementi siano a loro volta interi compresi tra -100
e + 100): di conseguenza il problema può essere risolto alla peggio mediante testing esaustivo –
posto che a sua volta il problema di stabilire se un array è ordinato è decidibile-.
Esercizio 3
Prima parte (obbligatoria)
U2 richiede R
U1 richiede R
R
A1
A2
A1 e A2 impongono l’alternanza tra il servizio di U1 e quello di U2
Seconda parte (opzionale)
Aggiungendo alla rete precedente le parti in rosso della rete seguente si ottiene l’effetto che, ad
esempio, Gr1a (ossia grant di R a U1 avvenga solo se “è il turno di U1”; ma se fosse il turno di U2 e
U2 non avesse richiesto la risorsa – e solo in tal caso!-, essa sarebbe ugualmente assegnata ad U1
tramite la transizione Gr1b. In sostanza il comportamento della rete viene reso deterministico in
ambo i casi, ma nel primo caso imponendo un’alternanza obbigatoria, nel secondo determinando la
scelta tra la concessione di tipo a e quella di tipo b a seconda che sia il proprio turno oppure no ma
in assenza di richiesta da parte dell’altro processo.
U2 richiede R
U1 richiede R
R
Gr1a
Gr2a
A1
A2
Gr1b
Gr2b
Esercizo 4
Una soluzione banale consiste nel codificare l’algoritmo tradizionale di ricerca binaria che effettua
log(n) accessi alla sequenza S. Tale algoritmo può essere codificato dalla MT con complessità
temporale O(nlogn); infatti poiché nelle macchine di Turing l’accesso è sequenziale ciascun accesso
richiede fino a n passi.
È però possibile ottenere una complessità lineare nel seguente modo, con una macchina di Turing
con 3 nastri.
1) Copiare x sul nastro 1 e spostare la testina all’inizio di S.
2) Salvare la lunghezza di S sul nastro 2 (alla fine del procedimento la testina sul nastro di
ingresso sarà alla fine di S così come la testina sul nastro 2).
3) Scandire il nastro 2 da sinistra verso destra. Ogni due passi sul nastro 2, muovere di una
posizione a sinistra la testina sul nastro di ingresso e scrivere un simbolo sul nastro 3. (alla
fine la testina sul nastro in ingresso sarà sul simbolo centrale di S, la testina sul nastro 2 sarà
all’inizio del nastro e quella sul nastro 3 sarà alla fine del nastro).
4) Confrontare il simbolo centrale con x (salvato nel nastro 1):
a. Se coincidono, l’esecuzione termina.
b. Se x è maggiore del simbolo centrale, ripetere i passi 3 e 4 usando il nastro 3 al posto
del 2 e il 2 al posto del 3 e muovendosi a destra invece che a sinistra sul nastro di
ingresso a partire dalla posizione corrente (si considera come S la seconda metà della
sequenza corrente).
c. Se x è minore del simbolo centrale, ripetere i passi 3 e 4 usando il nastro 3 al posto
del 2 e il 2 al posto del 3 (si considera come S la prima metà della sequenza
corrente).
Con questo procedimento la complessità diventa lineare in quanto la macchina effettua al più log(n)
operazioni che costano rispettivamente n, n/2, n/4, … , cioè
.
In entrambe le soluzioni la complessità spaziale è lineare.
Esercizo 5
Si rammenti che il prodotto tra una matrice nm e una matrice mp è una matrice np il cui
generico elemento in osizione i, j è datto dalla
.
Si constata allora facilmente che il prodotto tra due matrici triangolari (ad esempio, superiori) è a
sua volta una matrice triangolare superiore i cui elementi sulla diagonale principale sono il prodotto
a[i, i]. b[i,i]. Notoriamente il determinante di una matrice triangolare è il prodotto degli elementi
sulla diagonale principale; esso è quindi dato dalla formula
che evidentemente può essere calcolata in O(n) a criterio di costo costante.
NB: allo stesso risultato si giunge anche ricordando che il determinante del prodotto tra due matrici
è il prodotto dei due detereminanti.
Esercizo 6
1.a E’ possibile, per esempio inserendo le seguenti chiavi: 3, 2, 5, 3
1.b E’ possibile, per esempio inserendo 3 volte la stessa chiave (2 sono foglie)
2. E’ da modificare solo l’algoritmo di RB-NSERT; la modifica può essere fatta in diverse maniere,
per esempio ricercando, prima di inserire l’elemento, se c’è già nell’albero la chiave da inserire. La
complessità dell’algoritmo modificato non cambia in termini di comportamento asintotico.
Si può modificare l’algoritmo in modo anche da controllare se esiste già la chiave da inserire mentre
si effettua l’inserimento.
Algoritmi e Principi dell’Informatica
Appello del 20 Settembre 2013
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 3 ore.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 30
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3, 4, e 5 in 1 ora e 30
minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 8)
Il programma P riceve in ingresso due stringhe x e y costruite sull’alfabeto italiano tali che l’insieme dei
caratteri di x coincida con l’insieme dei caratteri di y.
Il programma P verifica se una delle due stringhe in ingresso sia una sottostringa dell’altra. In caso positivo,
il programma pone a 1 il valore della variabile ESITO, altrimenti a 0.
Ecco alcuni esempi. Se x è basso e y è asso, le stringhe x e y non soddisfano le precondizioni. Se x è
sasso e y è asso, le precondizioni sono soddisfatte e P pone ESITO=1. Infine, se x è sasso e y è ossa, le
precondizioni sono soddisfatte e P pone ESITO=0.
Formulare in logica del prim’ordine le precondizioni e postcondizioni di P servendosi esclusivamente dei
seguenti predicati e funzioni:
 il predicato unario char che è vero se e solo se il suo argomento è una stringa costituita da un unico
carattere dell’alfabeto italiano;
 il predicato (binario) = che rappresenta la classica uguaglianza;
 la funzione binaria  che rappresenta la concatenazione di stringhe.
Esercizio 2 (punti 8 escludendo la domanda 4.b, 10 includendo anche essa)
Si consideri il gioco del "forza 4", in cui ci sono 2 giocatori, uno con pedine rosse ed uno con pedine gialle,
in cui vince chi per primo mette in fila (orizzontalmente, verticalmente, o diagonalmente) 4 pedine del
proprio colore in uno schema di dimensione 7 colonne per 6 righe. Una mossa del gioco consiste nello
scegliere una colonna, e nel fare scendere una pedina lungo la colonna: se la colonna al momento della
mossa contiene k pedine, in seguito alla mossa la nuova pedina occuperà la posizione k+1 (assumendo che
la prima posizione sia la #1); non si possono depositare pedine in una colonna piena e inzialmentetutte le
colonne sono vuote.
1.
E' decidibile il problema di stabilire se, data una configurazione del gioco (cioè una distribuzione di
pedine nello schema), esiste una sequenza di mosse che portano un giocatore a vincere?
2.
E' decidibile il problema del punto 1 se lo schema di gioco, invece che essere 67, è di dimensione
arbitraria hk?
3.
E' decididibile il problema del punto 1 se lo schema di gioco, invece che essere 67, non ha limiti né
nelle righe né nelle colonne?
4.
Si consideri di avere a disposizione una funzione che, date 2 configurazioni del gioco ed un colore,
dice quale delle 2 è la "migliore" per quel colore (una configurazione potrebbe essere "migliore"
perché, per esempio, rende più probabile al giocatore del colore dato di vincere la partita):
4.a E' decidibile il problema di stabilire se, dato un generico programma che prende in ingresso una
configurazione del forza 4 (schema 67), ed un colore che deve muovere, questo ritorna sempre la
mossa migliore per quel colore?
4.b E' semidecidibile il problema del punto 4.a?
Esercizio 3 (punti 8)
Si consideri la seguente –inutile!- funzione, definita mediante pseudocodice.
void useless (int n)
{for (i = 1, i <= n, i++) do aux(i)}
dove a sua volta la funzione aux(m) è definita nel modo seguente:
void
aux(int m)
{if(m == 1) return
else
if(odd (m))aux(m-1)
else aux (m/2)
}
Si valuti la complessità asintotica di useless mediante la notazione O,o, preferibilmente, mediante la
notazione .
Esercizio 4 (punti 6)
1.
Si definisca una struttura dati per rappresentare la rete stadale di una città. La rete stradale è
fatta di incroci, collegati da strade, che possono essere a senso unico o a doppio senso; una
strada si dice tratto di strada elementare se collega due incroci senza che tra essi ve ne siano
altri; è anche possibile che ci siano dei cavalcavia, ossia strade che intersecano i propri tragitti
senza per questo dare origine a un incrocio.
2.
Si progetti un algoritmo per la struttura dati definita al punto 1 che determini, dato un incrocio
della città, un percorso che ritorni al punto di partenza senza passare 2 volte da uno stesso
incrocio (ovviamente escluso il primo) o da una stessa strada. Il percorso trovato dovrebbe
essere quello di lunghezza minore tra quelli che soddisfano i vincoli, intendendo come
lunghezza il numero di tratti di strada elementari che lo compongono.
3.
Si valuti la complessità (asintotica) dell'algoritmo progettato.
Esercizio 5 (punti 3)
Si consideri il problema di stabilire se un numero naturale, codificato in binaro, sia pari o dispari. Si
dica, giustificando brevemente la risposta, con quale complessità spaziale e temporale possono
risolvere questo problema (ovviamente, lavorando al meglio delle proprie possibilità) le seguenti
macchine astratte:
1. Una macchina di Turing a k nastri
2. Una macchina di Turing a nastro singolo
3. Una RAM, con criterio di costo logaritmico.
Tracce delle Soluzioni
Esercizio 1
Definisco per convenienza il predicato substring:
ab (substring(a, b) cd cad = b)
Precondizioni
c (char( c )  (substring(c, x) substring(c, y) ) )
Postcondizioni
ESITO=1  ( substring(x,y) substring(y,x) ) 
ESITO=0 ESITO=1
Esercizio 2
1.
Decidibile: lo schema è finito.
2.
Decidibile (è comunque un problema di ricerca in uno spazio limitato).
3.
Decidibile, anzi deciso: essendoci un numero illimitato di posizioni, se un giocatore gioca in
modo “stupido” è sempre possibile che l’altro vinca.
4.a
Indecidibile:anche se la funzioneha un dominio finito, i possibili programmi sono infiniti:
sussistono quindi le ipotesi del teorema di Rice.
4.b
Semidecidibile: se un programma calcola la funzione in modo corretto, ciò può essere
stabilito eseguendo il programma poiché la funzione ha un dominio finito.
Esercizio 3
La funzione aux ha una complessità che è soluzione della seguente equazione alle ricorrenze:
T(1) = 1;
T(n) =
if odd(n) then 1 + T(n-1)
else
1 + T(n/2)
Consideriamo due casi estremi:
a) n = 2k: in tal caso, abbiamo
T(n) = 1+ T(n/2) = 1 + 1 + T(n/4) = 1+1+1 … 1+ T(1) = 1*k , quindi T(n) è O(log(n))
b) n è dispari, (n-1)/2 è pure dispari e così via finché la ricorsione si chiude: in tal caso:
T(n) = 1+ T(n-1) = 1 + 1 + T((n-1)/2) = 1+1+1+ T((n-3)/2) = 1 +1 +1+1+ T((n-3)/4) …
che è O(2.log(n)) = O(log(n)).
Quindi aux ha una complessità O(log(n)) (e anche (log(n))).
useless chiama n volte aux con parametro i che “va da 1 a n”; quindi
T(n) per useless è 
T(n) è anche 
che è O(n.log(n)).
, che è (n.log(n))
Quindi T(n) è (n.log(n)).
Esercizio 4
1.
La struttura è un tipico esempio di grafo orientato. Si noti anche che la presenza dei
cavalcavia non obbliga il grafo ad essere planare. Quindi esso può essere rappresentato in uno
dei classici modi della letteratura (matrice delle adiacenze, lista dei nodi adiacenti, …).
2.
Il problema è un classico problema di raggiungibilità: si può quindi usare uno dei tanti
algoritmi dedicati a questo problema con opportuni, semplici adattamenti; ad esempio
l’algoritmo BFS standard –descritto nel testo-potrebbe essere adattato al problema
semplicemente verificando se il nodo v coincide con s: non appena questo test dà esito
positivo, si è anche trovato il (un) percorso a distanza minima, grazie all’impostazione
greadth-first dell’algoritmo di visita. Si noti che è impossibile passare due volte per la stessa
strada, in un senso qualsiasi, senza anche passare due volte da uno stesso incrocio.
La complessità totale è quindi O(|V| + |E|) (però se si usa la matrice della adiacenze per
rappresentare il grafo il ciclo for della linea di codice 10 nell’algoritmo fornito dal testo richiede un
tempo O(|V|) e quindi la complessità diventa O(|V|2) indipendentemente da |E|.
Esercizio 5
Tutte le macchine non devono fare altro che verificare se l’ultimo bit sia 1 o 0:
1. La MT a k nastri deve solo spostare la testina fino all’ultimo bit:
Complessità spaziale O(1) e temporale O(k) dove k è la lunghezza della stringa binaria che
codifica il dato di ingresso n; ossia O(log(n)).
2. La MT a nastro singolo fa esattamente le stesse operazioni ma la sua complessità spaziale
include sempre l’input (si tratta però di una convenzione)
3. La RAM può:
a. leggere il dato di ingresso come intero con un’unica operazione; poi dividerlo per 2 e
rimoltiplicare il risultato per due: in tal caso complessità spaziale e temporale sono
entrambe O(log(n)).
b. leggere il dato di ingresso bit a bit e verificare solo il valore dell’ultimo. In tal caso la
complessità temporale è O(log(n)) e quella spaziale O(1) perché non deve
memorizare tutta la stringa di ingresso ma solo l’ultimo bit letto; inoltre ogni singola
operazione costa O(1) anche a criterio di costo logaritmico.
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere
25 Novembre 2013
Avvisi importanti
Il tempo a disposizione è di 1 ora e 30 minuti.
Se non verranno risolti in maniera soddisfacente gli esercizi 1, 2, 3 (ossia ottenendo almeno 2
punti in ognuno di essi) non si procederà alla correzione dell'esercizio 4.
Chi otterrà una valutazione inferiore a 6/15-esimi non potrà sostenere la seconda prova e
potrà iscriversi soltanto al secondo appello della sessione invernale.
Esercizio 1 (punti 3/15-esimi)
Dire se esiste un automa a stati finiti che riconosce il seguente linguaggio:
L = {anbncn | n > 2}  {a*b*c*}
Spiegare brevemente la risposta.
Esercizio 2 (punti 3/15-esimi)
Quale delle seguenti formule del prim’ordine definisce correttamente i numeri di Fibonacci?
(si ricorda che l’n-esimo numero di Fibonacci è la somma dell’(n-1)-esimo e dell’(n-2)-esimo, per n
> 1, mentre per n = 0 o 1 ha il valore convenzionale 0 e 1, rispettivamente.)
)  n((n=0  fib(n) = 0)  (n=1  fib(n) = 1)  (n > 1  fib(n) = fib(n-1) + fib(n-2)))
)  n((n=0  fib(n) = 0)  (n=1  fib(n) = 1)  (n > 1  fib(n) = fib(n-1) + fib(n-2)))
Spiegare brevemente la risposta, preferibilmente fornendo esempi opportuni di valori di n e fib(n)
che soddisfino o non soddisfino le formule ) e ): per esempio, se m è l’n-esimo numero di
Fibonacci e ) è la formula corretta, la coppia n, m deve soddisfare ) ma non l’altra formula e
viceversa.
Esercizio 3 (punti 3/15-esimi)
Si consideri il seguente (frammento di) programma:
while (x >= 0)
{x = x*x - 2*x;}
E' decidibile il problema di stabilire se la sua esecuzione termina qualsiasi sia il valore iniziale
della variabile x all'inizio del ciclo? Spiegare brevemente la risposta.
Esercizio 4 (punti 8/15-esimi)
Si consideri la seguente macchina astratta MA, descritta informalmente nel modo seguente:
 MA è dotata di un nastro di ingresso e uno di uscita;
 è dotata inoltre di un organo di controllo a stati finiti;
 e di una memoria ausiliaria consistente in una sequenza lineare di celle (come per altre
classiche macchine astratte, ogni cella può contenere un carattere di un alfabeto finito)
illimitata da ambo le parti; MA può accedere in lettura e scrittura solo ai due estremi della
memoria ausiliaria.
Una mossa di MA consiste nel:
 Leggere il simbolo in corrispondenza della testina del nastro di ingresso, oppure effettuare
una -mossa nella quale non viene letto nessun carattere;
 Leggere i due simboli alle estremità della memoria ausiliaria;
In base ai valori acquisiti e allo stato dell'organo di controllo, la MA può:
 Cambiare stato dell'organo di controllo;
 Scrivere, in sostituzione dei caratteri alle estremità della memoria ausiliaria, due rispettive
stringhe;
 Scrivere una stringa, eventualmente nulla, sul nastro di uscita;
 Spostare a destra di una posizione o lasciare ferma la testina del nastro di lettura, a seconda
che venga eseguita una mossa di lettura o una -mossa;
 Spostare a destra la testina del nastro di scrittura di un numero di posizioni corrispondente
alla lunghezza della stringa scritta.
1. Si formalizzi completamente la descrizione di MA, specificandone i suoi elementi, le sue
configurazioni e relative transizioni, il criterio di accettazione.
2. Si confronti la sua potenza con quella delle altre macchine astratte conosciute. Per
semplicità il confronto può essere limitato alla capacità di riconoscimento di linguaggi,
tralasciando la capacità di traduzione.
NB: la precedente descrizione informale, trascura volutamente di precisare alcuni dettagli (ad
esempio, il criterio di accettazione, possibili situazioni anomale o di errore): la formalizzazione
dovrà quindi risolvere eventuali ambiguità garantendo un funzionamento di MA utile a riconoscere
una classe significativa di linguaggi.
Tracce di soluzioni
Esercizio 1
Siccome {anbncn | n > 2} è contenuto in {a*b*c*}, il linguaggio è ovviamente regolare.
Esercizio 2
La formula corretta è la ), che è soddisfatta (solo) dalla serie {0, 1, 1, 2, 3, 5, 8, …}; la ) invece è
soddisfatta da qualsiasi coppia n, fib(n) perché qualsiasi valore di n falsifica almeno uno degli
antecedenti delle formule in disgiunzione, garantendo quindi che la formula complessiva sia sempre
vera.
Esercizio 3
Il problema è "chiuso" perché il programma cui ci si riferisce è fissato e si chiede di stabilirne la
terminazione per ogni valore iniziale della variabile x. E’ quindi necessariamente decidibile.
Inoltre è anche deciso: infatti si può verificare che per x = 0 il programma non termina, pertanto non
è vero che il programma termina qualsiasi sia il valore iniziale della variabile x all'inizio del ciclo.
Esercizio 4
1.
Una possibile formalizzazione della MA (in versione deterministica) è la seguente.
 Una MA è una tupla (Q, I, , O, q0, Z0, F, , ), dove i vari simboli hanno il tradizionale
significato della teoria degli automi –stati dell’organo di controllo, alfabeti, ecc.-. Le
funzioni ,  hanno rispettivamente i domini e codomini seguenti:
o : Q  (I  {})  2  Q  (*)2
/* dato lo stato dell’OC, il simbolo in lettura o eventuale -mossa, i due simboli alle
estremità della memoria ausiliaria, la macchina si porta in un nuovo stato e riscrive
alle due estremità della memoria le corrispondenti stringhe di caratteri in */.
Le usuali restrizioni sulla definizione di  vanno applicate per garantire il
determinismo.
o : Q  (I  {})  2  O*
/* in corrispondenza della mossa definita dalla  viene scritta la stringa in O* sul
nastro di uscita.*/
 Una configurazione di MA è una tupla c = <q, x, , z> , con q  Q, x,  I*,   *, z 
O*. La relazione di transizione tra configurazioni
c = <q, x, , z> |-- c’ = <q’, x’, ’, z’> è definita nel modo tradizionale, con il seguente
aspetto significativo:
o se x = i.y ,  = AB e (q, i, A, B) = (q’, , ), allora
x’ = y, ’ = ;
z’ è definita analogamente sulla base di .
o l’effetto di una -mossa è definito analogamente.


Una stringa x è accettata se <q0, x, Z0, > |--* <q, , , z>, con q  F. In tal caso z è
l’eventuale traduzione (x) definita dal trasduttore. (Si noti però che, anche in caso di MA
deterministica la traduzione da essa definita potrebbe essere multipla a causa di possibili mosse a scansione dell’input completata). Si noti che, a causa di quanto verrà precisato in
seguito a proposito della potenza della MA, non è decidibile se una tale MA per un generico
ingresso x termini o meno la computazione.
NB. la definizione precedente espone al rischio di conflitti nel caso || = 1, ossia  = A: in
tal caso si potrebbe verificare (q, i, A, A) = (q’, , ) con    (più precisamente,   R,
perché  viene memorizzato in modo simmetrico rispetto a , ossia in modo che il prossimo
carattere letto a sinistra sia il primo di  e il prossimo carattere letto a destra sia l’ultimo di
) e la mossa della macchina non potrebbe avvenire in modo coerente. Una possibile
soluzione consiste nel “bloccare” la MA qualora si verifichi la condizione suddetta;
l’alternativa di imporre  = R quando (q, i, A, A) = (q’, , ) sarebbe invece troppo
restrittiva perché limiterebbe il comportamento della MA anche in casi in cui  = AA.
Dovrebbe però fare eccezione il caso iniziale (q0, i (o ) , Z0, Z0) per permettere alla
macchina di eseguire la prima mossa senza bloccarsi subito; in alternativa si potrebbe
definire come configurazione iniziale <q0, x, Z0Z0, >.
2.
La MA può facilmente simulare sia un automa a doppia pila (tenendo un separatore Z0 tra la parte
sinistra e la parte destra della memoria in modo che esse possano simulare separatamente le due
pile) sia un automa a coda. In entrambi i casi è nota l’equipotenza di queste macchine con la
macchina di Turing.
Algoritmi e Principi dell'Informatica
Seconda Prova in Itinere
14 Febbraio 2014
Avvisi importanti
Il tempo a disposizione è di 1 ora e 30 minuti.
Se non verranno risolti in maniera soddisfacente gli esercizi 1, 2, (ossia ottenendo almeno 6
punti in totale tra i due) non si procederà alla correzione degli altri esercizi; l’esercizio
facoltativo 4, sarà valutato solo se si saranno ottenuti almeno 13 punti nei primi 3.
Esercizio 1 (punti 4/15-esimi)
Si consideri un albero binario in cui ogni nodo o sia una foglia o abbia entrambi i figli. Quali sono
l’altezza minima e massima di un tale albero con n nodi?
NB: si richiede il valore preciso della funzione di n, non basta l’ordine di grandezza!
Esercizio 2 (punti 3/15-esimi)
E’ noto che esistono linguaggi riconoscibili in tempo lineare da automi a pila deterministici e da
macchine di Turing a k nastri ma non da macchine di Turing a nastro singolo.
Esistono anche linguaggi regolari non riconoscibili in tempo lineare da macchine di Turing a nastro
singolo? Giustificare brevemente la risposta.
Esercizio 3 (punti 8/15-esimi)
Si descriva un algoritmo che, dato un BST (Binary Search Tree) stabilisca se esso possa essere
colorato in modo tale da diventare un albero rosso-nero (RB).
NB: non si chiede di costruire un algoritmo di colorazione, ma solo di stabilire se ciò sia possibile.
Si ricordi inoltre che per convenzione in un albero RB tutte le foglie sono NIL, T.NIL per la
precisione, e nere.
Si valuti la complessità temporale dell’algoritmo.
Esercizio 4, facoltativo (punti 3/15)
Si formalizzi la seguente definizione informale di complessità spaziale di una macchina di Turing a
nastro bidimensionale:
Il nastro della macchina è costituito dal primo quadrante di un piano cartesiano a coordinate
intere. La complessità spaziale è data dal numero di celle del nastro visitate dalla testina
della macchina durante il suo funzionamento; al solito, essa è espressa come funzione della
lunghezza della stringa (lineare) di ingresso.
Tracce di soluzioni
Esercizio 1
L’altezza massima si ha quando ogni nodo interno ha, ad esempio, un foglia come figlio sinistro,
tranne l’ultimo i cui figli sono entrambi foglia. In tal caso, detti h l’altezza dell’albero, (definita
come il cammino di lunghezza massima, intesa come il numero di archi del cammino, tra la radice e
le foglie) e n il numero di nodi, si ha
n = 2.h + 1; quindi
h=
n 1
2
L’altezza minima si ha invece quando l’albero è bilanciato e completo, ossia
=
- 1; quindi
.
Esercizio 2
NO: una MT a nastro singolo, una volta posizionata all’inizio delle stringa di ingresso può
comportarsi esattamente come un automa a stati finiti, usando il proprio organo di controllo.
Siccome un automa a stati finiti esegue sempre uno spostamento a destra della testina di lettura per
ogni mossa, la stessa cosa può fare la MT senza dover utilizzare altre porzioni del nastro.
Esercizio 3
Una condizione necessaria e sufficiente perché un BST possa essere colorato in modo da diventare
un albero rosso-nero è che, nell’intero albero e in ogni suo sottoalbero il rapporto tra le lunghezze
minime e massime dei cammini che dalla radice raggiungono le foglie non superi mai 2. Infatti in
tal caso sarà sempre possibile colorare i nodi in modo da evitare due nodi rossi consecutivi sullo
stesso cammino e l’altezza di ogni sottoalbero sarà comunque (log(n)).
Un semplice algoritmo ricorsivo potrebbe quindi visitare l’albero, ad esempio in preordine sinistro,
e calcolare, per ogni nodo, la lunghezza dei cammini minimo e massimo da esso alle foglie (min =
min(leftSon.min, rightSon.min) +1; max = max(leftSon.max, rightSon.max) +1; min e max dei nodi
foglia sono ovviamente 0). Non appena max/min >2 l’algoritmo ritorna FALSE; se giunge fino alla
radice con max/min <= 2, ritorna TRUE. Si noti però che, rispetto a un normale BST in un albero
rosso-nero le foglie sono tutte NIL (T.NIL per la precisione) e hanno convenzionalmente altezza
(nera) = 0; ogni nodo interno ha quindi entrambi i figli.
L’algoritmo ha evidentemente complessità (n).
Esercizio 4
Una possible definizione formale della complessità spaziale richiesta può essere fornita nel modo
seguente:
In primo luogo occorre formalizzare il concetto di configurazione:
c = <q, x, contenuto: N  N  A, <i,j>, h>
dove q rappresenta lo stato dell’organo di controllo, x la stringa in ingresso, contenuto indica il
simbolo contenuto in ogni cella del nastro (con l’usuale vincolo che solo un numero finito di celle
sia diverso da blank), <i,j> indica la posizione della testina del nastro di memoria e h quella del
nastro di ingresso. La transizione tra configurazioni è poi definita nel modo tradizionale.
La complessità spaziale di M è allora espressa dalla funzione:
SM(n) = max|x| = n| |{<i,j> | c <i,j>  c 
c0 = <q0, x, [contenuto(0, 0) = Z0, contenuto(i, j) = blank  <i,j>  <0,0>], <0,0>, 0] |---* c}|
Ossia la massima cardinalità, rispetto a tutte le stringhe di lunghezza n, dell’insieme delle
coordinate delle posizioni della testina di memoria raggiunte durante il funzionamento della
macchina a partire dalla configurazione iniziale.
Algoritmi e principi dell’Informatica
Recupero prima prova in itinere  24 Febbraio 2014
Avvisi importanti
La prova è riservata ai laureandi che non abbiano superato la prima prova in itinere
La durata della prova di recupero è di 1 ora
Esercizio 1 (punti 7/15-esimi)
Si dica, giustificando brevemente le risposte, se le seguenti affermazioni sono vere o false:
1. Dato un qualsiasi automa a pila A, sia deterministico che nondeterministico, esiste sempre
un automa a pila, sia deterministico che nondeterministico, che riconosce il complemento di
L(A).
2. Dato un qualsiasi automa a pila A, sia deterministico che nondeterministico, esiste sempre
una macchina di Turing, che riconosce il complemento di L(A).
Esercizio 2 (punti 8/15-esimi)
Si consideri l’alfabeto A = {a,b}.
Per una stringa s costruita su A* chiamiamo massima sequenza ciascuna sottostringa non nulla t di s
i cui caratteri siano tutti uguali e che non sia né seguita né preceduta da un ulteriore carattere uguale
ai precedenti o ai seguenti. Ad esempio, nella stringa abbaaaa le massime sequenze sono a, bb,
aaaa.
1) Si specifichi in logica del prim’ordine un predicato ternario same(s,c,n) che è vero se e solo
se la stringa s è di n caratteri, tutti uguali al carattere c. (Nota: c è rappresentato come una
stringa di un solo carattere.)
2) Si fornisca una specifica in logica del prim’ordine del predicato binario maxSeq(t,s) che è
vero se è solo se t è una massima sequenza per s. Nella specifica, si faccia ricorso al
predicato same definito al punto precedente.
Nota bene: nella scrittura delle formule si può fare ricorso esclusivamente alle seguenti funzioni,
predicati e costanti la cui definizione può essere data per scontata e quindi da non specificare
ulteriormente:
 s = t (predicato di uguaglianza: vero se e solo se s è uguale a t)
 st (funzione che indica la concatenazione delle stringhe s e t)
 len(s) (funzione “lunghezza” che indica la lunghezza della stringa s)
 0, 1, … (costanti che indicano i numeri naturali)
 a (costante che indica la stringa di un solo carattere “a”)
 b (costante che indica la stringa di un solo carattere “b”)
Tracce di soluzioni
Esercizio 1
1. NO: la classe dei linguaggi riconosciuti da APN non è chiusa rispetto al complemento,
essendo chiusa rispetto all’unione ma non rispetto all’intersezione.
2. SI: i linguaggi riconosciuti da APN sono ricorsivi, quindi lo sono anche i loro complementi.
Esercizio 2
Definizione di same:
s n c same(s,c,n) 
len(s) = n 
x y z (s=xyz  len(y)=1  y=c)
Definizione di maxSeq:
t s maxSeq(t,s)  xyzcn (
t= xyz 
(c = a  c = b) 
same(y,c,n) 
(v x = vc) 
(w z = cw)
)
Algoritmi e Principi dell’Informatica
Appello del 3 Marzo 2014
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4 e 5 in 1 ora e 15 minuti.
NB1: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
NB2: l’esercizio 5 verrà valutato solo se negli altri esercizi si sarà ottenuto un punteggio di almeno 11.
Esercizio 1 (punti 4)
Si consideri la seguente grammatica:
S  S a | a S | b B | b
S B  B B S S
B S  a b b a
Quale linguaggio genera? Qual è la classe di automi a potenza minima in grado di accettare lo
stesso linguaggio?
Esercizio 2 (punti 4 senza restrizione; punti 8 se si applica la restrizione)
Si specifichi in logica del prim’ordine il seguente linguaggio L:
L = {an b2n cn-1, con n>0}
Restrizione: nella scrittura delle formule si può fare ricorso esclusivamente alle seguenti funzioni,
predicati e costanti la cui definizione può essere data per scontata e quindi da non specificare
ulteriormente:
 x  L (predicato di appartenenza: vero se e solo se x appartiene a L)
 s = t (predicato di uguaglianza: vero se e solo se s è uguale a t)
 st (funzione che indica la concatenazione delle stringhe s e t)
 a (costante che indica la stringa di un solo carattere “a”)
 b (costante che indica la stringa di un solo carattere “b”)
 c (costante che indica la stringa di un solo carattere “c”)
Esercizio 3 (punti 7)
E’ decidibile il problema di stabilire se, dato un generico trasduttore a stati finiti T e una stringa y 
O*, esista una stringa x  I*, tale che y = (x), dove:



O è l’alfabeto di output di T
I è l’alfabeto di input di T
: I*  O* è la traduzione definita da T
?
Giustificare brevemente la risposta.
Esercizio 4 (punti 5)
Qual è il numero massimo di possibili ordinamenti topologici compatibili con un DAG di n nodi?
Esercizio 5 (punti 11)
Si scriva un algoritmo che ordini una coda di interi, supposta già in memoria, assumendo che essa
sia utilizzabile come una struttura astratta di cui sia nota solo l’interfaccia, a sua volta costituita
esclusivamente dalle primitive canoniche ENQUEUE e DEQUEUE (e non altre!). Si valuti la
complessità asintotica dell’algoritmo.
NB: sono preferite soluzioni che non implichino aumento della lunghezza della coda durante
l’esecuzione e usino il minor numero possibile di celle ausiliarie, in ogni caso in quantità
indipendente dal numero di elmenti in coda. Per semplicità si può assumere che la coda non
contenga elementi ripetuti; questa assunzione però diminuisce il valore della soluzione di 1 punto.
Tracce delle Soluzioni
Esercizio 1
Il linguaggio generato dalla grammatica è L(G) = a*ba*. Infatti le prime due regole generano
stringhe del tipo a*Sa*; quando si applica la regola S  b B, si ottiene una stringa del tipo
a*bBa* che non potrà derivare nessun’altra stringa perché per riscrivere B occorre che esso compaia
vicino a un S; quindi per poter generare una stringa terminale è necessario applicare la regola S 
b che impedisce ulteriori derivazioni.
L(G) è chiaramente regolare anche se G non lo è; di conseguenza esso è riconoscibile da un automa
a stati finiti.
Esercizio 2
Soluzione senza restrizione
Il linguaggio L può essere definito con una formula del prim’ordine nel modo seguente:
x (x  L  n (x = power(a, n)  power(b, 2n)  power(c, n-1)  n > 0))
dove, al solito, il predicato power(x,n) è definito dalla formula
x ( (power(x,0) = )  n (n > 0)  (power(x,n) = x  power(x,n-1)
Soluzione con restrizione
Se invece sono consentiti solo i costrutti indicati nel testo, conviene definire alcuni linguaggi di
supporto:
x (x  La  x = a  y (y  La  x = a  y)) (ossia La = a+)
x (x  Lb  x = b  y (y  Lb  x = b  y)) (ossia Lb = b+)
x (x  Lc  x = c  y (y  Lc  x = c  y)) (ossia Lc = c+)
x (x  L1  x = a  b  b  y (y  L1  x = a  y  b  b)) (ossia L1 = an b2n, n>0)
x (x  L2  x = a  y (y  L2  x = a  y  c)) (ossia L2 = an cn-1, n>0)
Infine definisco L:
x (x  L  x = a  b  b 
yzw (x = y  z  w  y  La  z  Lb  w  Lc  y  z  L1  y  w  L2))
Esercizio 3
Premessa: la lunga storia della teoria degli automi dimostra che molto raramente un problema
relativo agli automi a stati finiti è indecidibile; ciò grazie alle sue proprietà essenziali, riassunte nel
pumping lemma.
Il problema in oggetto non costituisce un’eccezione. Infatti, anche se in generale non è detto che |x|
 |(x)| a causa di eventuali mosse che non scrivono nulla in output, è possibile enumerare le
stringhe di input in modo tale da garantire che l’insieme traduzione di un numero finito di esse
contenga tutte le stringhe di output z tali che |z|  |y|. Precisamente si potrebbe procedere come
segue:
Si enumerino tutte le stringhe x  I* per lunghezza crescente e se ne calcolino le rispettive (x)
finché |(x)| > |y|. Se durante tale enumerazione si individua una sottostringa w di x tale che x = zws,
*(q0, z) = q, *(q, w) = q e *(q, w) = , w può essere eliminata dalla stringa x senza
evidentemente cambiare il risultato della traduzione. Rimangono quindi da prendere in esame solo
stringhe “a traduzione crescente” nel senso che per tali stringhe x
)
Enumerando quindi tutte le stringhe di I* ma escludendo quelle che contengono sottostringhe del
tipo w di cui sopra è possibile ottenere tutte le stringhe di lunghezza  |y| che siano traduzione di
qualche x. Se tra esse non figura la stringa y, ciò significa che non può essere ottenuta come
risultato della traduzione .
Esercizio 4
Se il grafo non ha archi qualsiasi permutazione dei nodi è un ordinamento topologico compatile con
esso; quindi se ne possono ottenere n!
Esercizio 5
L’impossibilità di usare memoria ausiliaria in quantità arbitraria e la necessità di accedere alla coda
solo mediante le primitive canoniche obbliga a far scorrere la coda diverse volte fino ad ottenerne
una trasformazione ordinata.
Un semplice algoritmo descritto a grandi linee è il seguente:


Una prima passata calcola il minimo valore in coda e il numero n di elementi presenti. Per
farlo senza aumentare la lunghezza della coda e senza escludere l’esistenza di elementi
ripetuti si può agire come segue:
o DEQUEUE (x); min = x; ENQUEUE (‘#’); n = 1;
o /* per semplicità si omette un test di coda vuota*/
o DEQUEUE (x);
o while x != ‘#’ do
 {
 if x < min { ENQUEUE(min); min = x} else ENQUEUE(x);
 DEQUEUE (x); n++;
 }
o ENQUEUE(min);
o /* alla fine di questa passata n contiene la lunghezza della coda il cui ultimo
elemento è il valore minimo della coda originaria; seguono n -1 passate:*/
for (i = n-1, i >= 1, i--) do
o DEQUEUE (x); min = x;
o for (k = 1, k < i, k++) do
 { DEQUEUE (x);
 if x < min { ENQUEUE(min); min = x} else ENQUEUE(x);
 };
o ENQUEUE(min);
o for (j = i, j < n, j++) do { DEQUEUE (x); ENQUEUE(x)}
o /* la parte già ordinata della coda viene ricopiata identica*/
Questo algoritmo non aumenta la lunghezza originaria della coda, usa le variabili ausiliarie min, x,
n, oltre ai contatori i, j, k (di cui uno potrebbe essere risparmiato, usando lo stesso k al posto di j) e
ha ovviamente complessità O(n2). Appare decisamente difficile, probabilmente impossibile,
ottenere complessità asintotiche migliori di O(n2).
Qui sotto viene riporata una versione eseguibile dello pseudocodice.
function queue_sort(Q) {
'use strict';
var x, min, n, i, j, k;
x = dequeue(Q);
min = x;
enqueue(Q, '#');
n = 1;
x = dequeue(Q);
while (x !== '#') {
if (x < min) {
enqueue(Q, min);
min = x;
} else {
enqueue(Q, x);
}
x = dequeue(Q);
n += 1;
}
enqueue(Q, min);
for (i = n - 1; i >= 1; i -= 1) {
min = dequeue(Q);
for (k = 1; k < i; k += 1) {
x = dequeue(Q);
if (x < min) {
enqueue(Q, min);
min = x;
} else {
enqueue(Q, x);
}
}
enqueue(Q, min);
for (j = i; j < n; j += 1) {
x = dequeue(Q);
enqueue(Q, x);
}
}
}
.
Algoritmi e Principi dell’Informatica
Appello del 7 Luglio 2014
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1a, 1b e 2 in 1 ora e
15 minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1a (punti 5)
Si consideri il linguaggio Lk, dove k è un parametro, costituito da stringhe sull’alfebto {a, b} tali
che ogni volta che si trovino k a consecutive ne segua immediatamente almeno una b.
Si costruisca una rete di Petri che accetti L3. NB: è preferible che la rete non contenga transizioni
che siano sia in ingresso che in uscita al medesimo posto.
Esercizio 1b (punti 5)
Si scriva una formula del prim’ordine che specifichi un generico linguaggio Lk per un dato valore
del parametro k (la formula deve quindi dipendere da k, variabile libera) dell’esercizio 1.a usando
variabili intere che indichino la posizione di un carattere nella stringa e i predicati a(i) e b(i) per
indicare che il carattere in posizione i-esima è a o b, rispettivamente.
Ad esempio la formula a(1)  b(2) indica che la stringa deve inziare con ab.
NB: qualora fosse utile si può fare uso del predicato  (indefinitio) per indicare l’assenza di
carattere in posizione i: per convenzione si può assumere che valga  (0) e che per una stringa lunga
n valga (a(n)  b(n))   (n+1).
Esercizio 2 (punti 7)
Una macchina di Turing Mi (che calcola la funzione fi) è detta riproducibile se esiste un'altra
macchina di Turing Mj (che calcola la funzione fj) tale per cui fi=fj.
Si consideri l’insieme delle MT definite sull’alfabeto di due caratteri {0, 1}. Al suo interno siano:
 F l’insieme delle funzioni calcolate da macchine di Turing riproducibili.
 G l'insieme delle funzioni calcolate da macchine di Turing riproducibili e con meno di 10
stati.
 H l'insieme delle funzioni calcolate da macchine di Turing riproducibili e con più di 10 stati.
Dire se i seguenti problemi sono decidibili:
1) Stabilire se una generica macchina di Turing calcoli una funzione in F.
2) Stabilire se una generica macchina di Turing calcoli una funzione in G.
3)
Stabilire
se
una
generica
macchina
di
Turing
calcoli
una
funzione
in
H.
Esercizio 3 (punti 7)
Si consideri la traduzione (x) = ak bh, dove x  {a,b}+, k è il numero di b in x e h il numero di a in
x.
Si descriva il funzionamento di un MT a nastro singolo che implementi usando esclusivamente le
celle di memoria contenenti x. Se ne valutino la complessità temporale e spaziale.
Esercizio 5 (punti 9)
Dati: un elenco di attività e di vincoli di precedenza fra esse
scrivere un algoritmo che rappresenta queste attività in un grafo di precedenze o fallisce se i vincoli di
precedenza sono incoerenti (as esempio, se A precede B e B precede A, sia direttamente che indirettamente,
i vincoli sono incoerenti).
Indicare la complessità dell’algoritmo
Ad esempio:
Date le 7 attività
A, B, C, D, E, F, G
con i seguenti vincoli di precedenza
A −> C, B −> C, C −> E, D −> F, B −> D, C −> F, D −> G
il grafo di precedenze risultante è
Tracce delle Soluzioni
Esercizio 1°
La rete di Petri seguente, dove è indicata la marcatura iniziale e ogni possibile marcatura seguente
viene riconosciuta come finale (un solo token può marcare un solo posto), riconosce il linguaggio
L3.

b
b
a
b
a
b
a
Esercizio 1.b
x i (((x  i < x+k)  a(i))b(x+k))
Esercizio 2
Il problema 1 è decidibile ed è anche deciso. Infatti, ogni macchina di Turing è riproducibile: come
è noto, data una funzione calcolabile, esistono infinite macchine di Turing che la calcolano. Quindi
F coincide con l’insieme universo di tutte le funzioni calcolabili.
Il problema 2 è indecidibile per il teorema di Rice. Infatti, l’insieme delle macchine di Turing con
meno di 10 stati e con alfabeto di due caratteri è finito (proprietà che abbiamo anche usato per
enumerare le macchine di Turing), pertanto sarà finito (e non vuoto) anche l’insieme di funzioni
calcolabili calcolate da dette macchine di Turing. Allora l’insieme G non è né l’insieme vuoto, né
l’insieme di tutte le funzioni computabili, da cui l’indecidibilità per il teorema i Rice.
Il problema posto nel quesito 3 è decidibile per il teorema di Rice. Infatti, ogni funzione calcolabile
è calcolabile (anche) mediante una macchina con più di 10 stati. Come scritto in precedenza, per
ogni funzione computabile esistono infinite macchine di Turing che la calcolano, mentre le
macchine di Turing con un numero di stati minore o uguale a 10 sono in numero finito, quindi ogni
funzione calcolabile dev’essere calcolata anche da macchine con più di 10 stati.
Pertanto H è l’insieme di tutte le funzioni computabili e il problema è allora decidibile per il
teorema di Rice.
Esercizio 3
1) la macchina fa una passata scambiando le a con le b e viceversa: complessità ((n))
2) la macchina fa una passata cercando coppie ba e scambiando la b con la a (scambio: costo
costante; costo della passata: (n))
3) se alla fine della passata non trova coppie ba, si ferma, altrimenti ripete il passo 2)
Al max si fanno n passate, quindi la complessità totale sarà (n2).
Esercizio 4
Come suggerito nel testo dell’esercizio, si costruisca un grafo che rappresenti le attività (nodi) e i
relativi vincoli di precedenza (archi): i vincoli sono incoerenti se e solo se il grafo contiene cicli.
Ciò può essere verificato mediante una opportuna modifica dell’algoritmo di visita Depth-first
(costituito da diverse visite ricorsive) che distingua tra i nodi scoperti in una precedente visita e
quelli scoperti nella visita corrente; se finisce su uno del primo tipo, la visita corrente termina, e se
ne lancia un’altra; nel secondo caso la visita termina restituendo false.
Se l’algoritmo ha successo, cioè non trova cicli, il grafo ottenuto è un DAG e ad esso può essre
applicato un topological sort.
FIND-LOOP(G)
/* ritorna flalse se I vincoli sono incoerenti, e quindi se il grafo contiene un ciclo*/
1 for each u ∊ G.V
2 u.color := 0
3 c := 0
4 for each u ∊ G.V
5 if u.color = 0
6
c := c+1
7
if FIND-LOOP-VISIT(u, c) = false
8
return false
9 return true
FIND-LOOP-VISIT(u, c)
1 u.color := c
2 for each v ∊ u.Adj
3 if v.color = c
4
return false
5 if v.color = 0
6
return FIND-LOOP-VISIT(v, c)
7 return true
L’algoritmo proposto è quindi O(|V| + |E|) e potrebbe essere incluso come parte integrante in un
algoritmo di topological sort senza alterarne la complessità.
Algoritmi e Principi dell’Informatica
Appello del 17 Luglio 2014
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2 e 3 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4 e 5 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 5)
Si considerino la grammatica e l’automa a pila seguenti, e i linguaggi L(G) e L(A) definiti da essi
sull’alfabeto {a,b}:
G:
S --->  | aSb
A:
b, C/
a, A/AA
b, A/
a, C/CA
b, A/
a, Z0/Z0C
b, C/
b, Z0/Z0B
a, A/B
aC/CB
a, B/BB
a, Z0/Z0B
b, Z0/Z0B
a, B/BB
b, B/BB
b, B/BB
Si costruiscano un automa o una grammatica a potenza minima che riconoscano/generino
rispettivamente L(G)  L(A) e L(G)  L(A).
Esercizio 2 (punti 6)
Si consideri la seguente formula F:
xyz m(x,y,z)  t m(x,y,t)
2.a
Come noto, una formula può essere intesa in senso puramente sintattico come una sequenza di
simboli. Si indichi la categoria sintattica (funzione, predicato, ecc.) di ciascun simbolo utilizzato in
F; se pertinente, indicare anche la arietà associata al simbolo.
Si dica anche se F è una formula chiusa.
2.b
Si consideri poi un’interpretazione in cui m(x,y,z) indica il fatto che la macchina di Turing con
indice y e ingresso x produce z in uscita.
E’ vera la formula F sotto l’interpretazione data?
Esercizio 3 (punti 6)
Il signor Giovanni sta cercando di procurarsi un compilatore “open source” o commerciale che
traduca codice C nell’assembler del suo hardware xyz. Egli sa che non tutto il SW open-source o
disponibile sul mercato è affidabile al 100% (eufemismo). Quindi, prima di procedere
all’acquisizione (che intende utilizzare per sviluppare applicazioni altamente critiche) intende anche
e preliminarmente acquisire sufficienti “garanzie” (intese in senso tecnico, non semplicemente
commerciale (in caso di danni previsione di adeguato risarcimento)). Quindi, prima ancora di
mettersi alla caccia del compilatore che faccia al caso suo si mette alla ricerca di uno strumento e/o
di un benchmark che gli possa verificare con certezza il corretto funzionamento del compilatore che
intende esaminare per l’eventuale acquisizione.
Può la ricerca del signor Giovanni (quella dello strumento o del benchmark, non quella successiva
del compilatore) avere successo? Si spieghi brevemente il motivo della risposta.
Parte opzionale
Che cosa consigliereste al signor Giovanni riguardo alla sua ricerca: è preferibile orientarsi verso un
opportuno benchmark oppure verso uno strumento che certifichi la correttezza del compilatore?
Esercizio 4 (punti 7)
Dato il seguente algoritmo che calcola la reverse di una coda di elementi
Reverse(P):
If queue P is not empty do:
Dequeue (P)  element
Reverse (P)
Enqueue (P, element)
Ricavare e risolvere in maniera precisa l’equazione alle ricorrenze
T(n) = ?
(si osservi che il tempo per fare il reverse di una coda di 1 elemento , T(1), è costante)
Esercizio 5 (punti 9)
Si considerino due alberi binari di ricerca (BST). Si definisca un algoritmo per costruire un BST
contenente i dati di entrambi gli alberi e che sia “ragionevolmente” bilanciato, ossia abbia
un’altezza dello stesso ordine di grandezza di quella di un albero perfettamente bilanciato. Se ne
valutino le complessità spaziale e temporale.
Tracce delle Soluzioni
Esercizio 1
L(G) è chiaramente il linguaggio {anbn | n  0}
A invece accetta tutte le stringhe non in L(G) oltre la stringa nulla.
Quindi L(G)  L(A) = {a, b}* e L(G)  L(A = {}, entrambi linguaggi regolari.
Esercizio 2
Parte 2.a:
 quantificatore universale
x variabile
 quantificatore universale
z variabile
 quantificatore esistenziale
y variabile
m predicato con arietà 3
( punteggiatura
x variabile
, punteggiatura
y variabile
, punteggiatura
z variabile
) punteggiatura
 connettivo logico (implicazione)
 quantificatore esistenziale
t variabile
m predicato con arietà 3
( punteggiatura
x variabile
, punteggiatura
y variabile
, punteggiatura
t variabile
) punteggiatura
La formula è chiusa in quanto tutte le variabili sono quantificate.
Parte 2.b
La formula F è vera nell’interpretazione data.
Se, data una coppia di valori <x,y>, esiste un valore z tale che <x,y,z> soddisfi m (ossia la funzione
calcolata dalla macchina di Turing con indice y per l’ingresso x è definita e restituisce z), tale tripla
può essere utilizzata per soddisfare anche la parte a destra dell’implicazione (basta scegliere un
valore di t uguale a z).
Se invece non esiste un valore di z tale che <x,y,z> soddisfi m (ossia la funzione calcolata dalla
macchina di Turing con indice y per l’ingresso x non è definita), l’implicazione è banalmente
soddisfatta poiché l’antecedente è falso.
Esercizio 3
Il problema della correttezza di un compilatore, come la correttezza di un qualsiasi programma è
formalizzabile come il problema di stabilire se un generico algoritmo calcola una funzione data;
quindi in tal caso è applicabile il teorema di Rice poiché la compilazione dal C a un linguaggio
assembler è formalizzabile come una specifica funzione computabile (diversa dall’insieme vuoto e
dall’insieme universo di tutte le funzioni computabili).
Nessun benchmark può quindi certificare la correttezza assoluta (assenza di errori) di un programma
(a meno di non ridurre il problema a un dominio finito e ipotizzare un testing esaustivo). Tuttavia
un benchmark ben congegnato ha buone possibilità, se il programma testato è scorretto, di
evidenziarne eventuali errori (semidecidibilità della Scorrettezza di un programma). E’ quindi
preferibile consigliare al signor Giovanni la ricerca di un buon benchmark piuttosto che quella di un
tool che per motivi teorici non potrà mai garantire la correttezza di un qualsiasi compilatore.
Tuttavia, ciò non esclude che il signor Giovanni possa trovare su Internet un compilatore corredato
di una specifica certificazione di correttezza che matematicamente DIMOSTRI tale correttezza
come risultato di un’adeguata analisi formale eseguita da esperti del settore (certificazione che a sua
volta Giovanni potrebbe controllare se fornito di adeguata competenza teorica o fare verificare da
un tool automatico per la verifica di correttezza di prove matematiche).
Esercizio 4
Condizione iniziale: il tempo per fare il reverse di una coda di un elemento è costante
T(1) = O(1) = 1
Relazione alle ricorrenze: il tempo per fare il reverse di una coda di N elementi è il tempo di fare il
reverse di una coda dì N-1 elementi più 2 operazioni (dequeue e enqueue).
T(N) = T(N-1) + 2
Sostituendo abbiamo
T(N-1) = T(N-2) + 2
T(N-2) = T(N-3) + 2
……
T(2) = T(1) + 2
T(1) = 1
sommiamo a sinistra e a destra:
T(N) + T(N-1) + T(N-2) + T(N-3) + …. T(3) + T(2) =
= T(N-1) + T(N-2) + T(N-3) + …. T(3) + T(2) + T(1) + 2*(N-1)
semplificando :
T(N) = T(1) + 2*(N-1) = 1 + 2*(N-1)
l’algoritmo è quindi O(N)
Esercizio 5
1) Si effettua visita "in ordine" dei due alberi T1 e T2, ottenendo due liste ordinate L1 e L2
(complessità (n1+n2), dove n1 = |L1|, n2 = |L2|).
2) Si fondono le due liste in un array ordinato ( (n1+n2)).
3) Si crea un BST partendo dall'elemento centrale dell'array, poi ricorrendo sui due sottoarray (
(n1+n2)).
Quindi le complessità risultanti sono entrambe lineari nel numero dei nodi presenti nei sottoalberi:
S(n) = T(n) = (n), dove n = n1+n2.
Algoritmi e Principi dell’Informatica
Appello del 2 Settembre 2014
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5 e 6 in 1 ora e 15
minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 6)
Si consideri il linguaggio L={ ambn | m  n, m, n > 0 }. Esempi di stringhe di L sono: aabbb e aaabb,
mentre ab, aabb, aba,  sono stringhe non appartenenti ad L.
1.
Si fornisca una grammatica, preferibilmente a potenza generativa minima tra le classi conosciute,
che generi L.
2.
Si fornisca un automa, preferibilmente a potenza riconoscitiva minima tra le classi conosciute, che
riconosca L.
Esercizio 2 (punti 6 senza la parte opzionale, 8, con la parte opzionale)
Una procedura P riceve in ingresso un numero naturale n > 1 e due array, in e out, entrambi contenenti 2n
numeri naturali (l’indice di entrambi gli array è compreso tra 1 e 2n inclusi).
Preliminarmente si specifichino i predicati odd(n) e even(n), facendo uso di formule del prim’ordine
contenenti esclusivamente variabili e costanti intere, il predicato di uguaglianza, i simboli delle operazioni
di somma e prodotto, in modo tale che i due predicati assumano il loro naturale significato, ossia odd(n)
risulti vero se e solo se n è un numero naturale dispari, e even(n) se e solo se n è un numero naturale pari.
Successivamente:
1) Si specifichino le precondizioni seguenti che devono quindi valere all’inizio dell’esecuzione di P.
a) Ogni elemento dell’array in è diverso da ogni altro elemento dello stesso array in.
b) Tutti gli elementi dell’array in in posizioni dispari sono dispari, e tutti quelli in posizione pari sono
pari.
La procedura copia tutti gli elementi dell’array in nell’array out, piazzando i numeri dispari nelle prime n
posizioni e quelli pari nelle n posizioni seguenti.
2) Si specifichino ora le seguenti postcondizioni per la procedura P.
a) Tutti gli elementi della parte inferiore (ossia quelli nelle posizioni 1 .. n) dell’array out sono uguali a
qualche elemento dispari di in.
b) Tutti gli elementi della parte superiore dell’array out sono uguali a qualche elemento pari di in.
3) Opzionalmente si aggiungano ulteriori post-condizioni, se ritenute necessarie, per rendere la specifica
della procedura perfettamente coerente con la sua definizione informale fornita qui sopra.
NB: la parte opzionale verrà valutata solo se i due punti precedenti saranno risolti in modo
soddisfacente.
Esercizio 3 (punti 3)
E’ decidibile il problema di stabilire se una qualsiasi procedura Q soddisfa la specifica fornita dalle pre- e
post-condizioni dell’esercizio precedente (incluse o escluse eventuali post-condizioni opzionali)? Si fornisca
una breve ma precisa spiegazione della risposta.
Esercizio 4 (punti 8)
a) Descrivere a grandi linee ma con precisione una MT che realizzi la procedura dell'esercizio 2 in
modo da ottenere la miglior complessità temporale (asintotica) possibile. (Si assuma che gli interi
contenuti nell'array siano limitati, in modo che la complessità dipenda solo da n.)
b) Descrivere anche una macchina RAM, il cui repertorio istruzioni sia esattamente quello del testo,
con lo stesso obiettivo.
Quale delle due complessità temporali (la seconda a criterio logaritmico) è migliore? Perché?
Esercizio 5 (punti 3)
Si risolva la seguente equazione alle ricorrenze:
T(n) = 5 T(n/2) + n2log(n)
Esercizio 6 (punti 5)
Si consideri come struttura dati un albero generale, in cui cioè ogni nodo può avere un numero arbitrario di
figli, anche maggiore di 2.
a) Dire come si può rappresentare un albero generale con una struttura a puntatori.
b) Si sviluppi un algoritmo per verificare, per ogni nodo x diverso dalla radice, se è soddisfatta la
proprietà che la chiave del padre di x è > della chiave di x stesso. Si dia la complessità
dell’algoritmo scritto.
Tracce delle soluzioni
Esercizio 1
1. S  aCb
C  aCb | A | B
A  aA | a
B  bB | b
2.
b, C/
a, A/AA
b, A/
a, C/CA
a, Z0/Z0C
b, A/
b, C/
b, Z0/Z0
b, Z0/Z0
Esercizio 2
x ( odd(x)  k ( x = 2k + 1 ) )
x ( even(x)  k ( x = 2k ) )
1) Precondizioni.
a) Ogni elemento dell’array in è diverso da ogni altro elemento dello stesso array in.
i (1  i  2n  j (1  j  2n  i  j  in[i] = in[j] ) )
b) Tutti gli elementi dell’array in in posizioni dispari sono dispari, e tutti quelli in posizione pari sono
pari.
i (1  i  2n  ( ( odd(i)  odd(in[i]) )  (even(i)  even(in[i]) ) )
2) Postcondizioni.
a) Tutti gli elementi della parte inferiore (ossia quelli nelle posizioni 1 .. n) dell’array out sono uguali a
qualche elemento dispari di in.
i (1  i  n  j (1  j  2n  odd(in[j])  out[i] = in[j] ) )
c) Tutti gli elementi della parte superiore dell’array out sono uguali a qualche elemento pari di in.
i (n+1  i  2n  j (1  j  2n  even(in[j])  out[i] = in[j] ) )
3) Parte opzionale.
L’array out deve contenere tutti gli elementi dell’array in.
i (1  i  2n  j (1  j  2n  out[i] = in[j] ) )
Esercizio 3
La domanda dell’esercizio è un tipico problema di correttezza: si chiede se un generico algoritmo
implementa una particolare funzione o famiglia di funzioni definita mediante le pre- e post-condizioni. In
questo caso, evidentemente le funzioni che soddisfano le pre- e post-condizioni, sia includendo che
escludendo la parte opzionale, non sono evidentemente né l’insieme vuoto (la specifica non è soddisfacibile)
né l’insieme universo (la specifica è soddisfatta da qualsiasi funzione computabile). Quindi per il teorema di
Rice il problema è indecidibile.
Esercizio 4
Essendo i numeri memorizzati nell’array limitati, ognuno di essi può essere memorizzato in un numero
finito e costante di celle della MT.
In una prima passata la MT copia nel nastro di uscita solo i numeri in posizione dispari; successivamente si
riporta all’inizio bel nastro di ingresso e copia a seguire i numeri in posizione pari. La complessità ottenuta è
chiaramente O(n).
La RAM invece non ha la possibilità di percorrere a ritroso il nastro di ingresso, né quello di output; essa
deve perciò memorizzare preliminarmente il contenuto del nastro di ingresso e procedere poi alla stessa
maniera della MT; ogni memorizzazione di un numero però, a criterio di costo logaritmico, costa O(log(n));
quindi la complessità asintotica della RAM è O(n.log(n)).
Esercizio 5
La ricorrenza si risolve semplicemente applicando il Master Theorem. In questo caso logb(a) = log2(5), che
ha valore un po’ maggiore di 2 (circa 2.3). n2.3 è polinomialmente maggiore di n2log(n), quindi la ricorrenza
ha soluzione Θ(nlog2(5)).
Esercizio 6
a) Un albero generale può essere rappresentato con una struttura a puntatori in cui ogni nodo x ha 4 attributi:
x.key è la chiave, x.p è il puntatore al padre, x.fst è il puntatore al figlio più a sinistra, e x.sibling è il
puntatore al fratello a destra.
b)
test_property(T)
x := T.root
return test(x)
test(x)
if x = NIL
return true
if (x.p = NIL OR x.p.key > x.key)
return test(x.fst) AND test(x.sibling)
else return false
La complessità dell’algoritmo scritto è semplicemente Θ(n), in quanto vengono analizzati tutti i nodi uno ad
uno.
Algoritmi e Principi dell’Informatica
Appello del 18 Settembre 2014
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1, 2, 3 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 4, 5 e 6 in 1 ora e 15
minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 5)
Si consideri il linguaggio L delle stringhe anbn, anbnanbn, ... dove anbn può essere ripetuto 1 o più
volte, con 0 < n < 4.
Esempi di stringhe in L sono: aabb, abab. Esempi di stringhe non in L sono invece: abb,
aabbab.
Si scrivano un automa e/o una grammatica a potenza minima per L e per L1 = L  {(ambm)+, m >
0}.
NB: è preferita una soluzione che presenti sia una grammatica che un automa ma è accettabile anche
uno solo dei due formalismi.
Esercizio 2 (punti 8)
Punto a.
Specificare in logica del prim’ordine il predicato binario substring(x,y) che indica che il primo
argomento x è una sottostringa del secondo argomento y, ossia una sequenza di caratteri consecutivi
che compare in y. NB: come caso particolare la stringa nulla è sottostringa di qualsiasi stringa.
Ad esempio
substring(ac,abcd) è falso
substring(bc,abcd) è vero
Per la specifica, oltre al predicato di uguaglianza, si può usare solo la funzione binaria concat
(concatenazione tra stringhe), che restituisce la concatenazione dei suoi argomenti.
Ad esempio: concat(ab,cd) restituisce abcd
Punto b.
Si specifichi poi il predicato substring2(x,y,i,j) che indica che x è uguale alla sottostringa di y che
va dal carattere in posizione i di y al carattere in posizione j  i di y (estremi inclusi). Si noti che per
una stringa di lunghezza n, le posizioni dei suoi caratteri vanno da 1 a n; si noti anche che questa
definizione implica che x non sia la stringa nulla.
Per la specifica, in aggiunta a quanto consentito al punto a, si possono usare le 4 operazioni
aritmetiche, le costanti intere e la funzione unaria len che restituisce la lunghezza di una stringa.
Ad esempio: len(abcd) restituisce 4
Si può evitare, in quanto sottinteso, l’uso di predicati string(x) e integer(i) per specificare che una
variabile rappresenta una stringa o un intero, rispettivamente; di conseguenza non è necessario
specificare esplicitamente domini e codomini delle funzioni utilizzate.
Punto c.
Infine, osservando le restrizioni imposte ai punti precedenti, ossia utilizzando esclusivamente
predicati e funzioni ivi definiti, si specifichi il predicato binario reverse(x,y) che indica che la
stringa x, letta da sinistra a destra, è uguale alla stringa y letta da destra a sinistra.
Ad esempio:
reverse(abcd,dcba) è vero
reverse(abcd,cba) è falso
Se utile, è possibile usare anche i predicati definiti ai punti precedenti.
Esercizio 3 (punti 3)
E’ decidibile il problema di stabilire se, date due qualunque stringhe ed eventualmente due interi,
essi soddisfino i predicati definiti nell’Esercizio 2?
Esercizio 4 (punti 4)
Qual è la complessità migliore ottenibile da MT a nastro singolo che riconoscano, rispettivamente, i
linguaggi L e L1 di cui all’esercizio 1? Giustificare brevemente la risposta.
Esercizio 5 (punti 4)
Si risolva la seguente equazione alle ricorrenze:
T(n) = T(n-1) + n2
Esercizio 6 (punti 7)
Scrivere lo pseudocodice di una funzione che, dato un albero binario che rappresenta una
espressione aritmetica ne calcoli il valore e lo restituisca in output.
Nota: la radice ed i nodi intermedi rappresentano gli operatori, le foglie dell'albero rappresentano gli
operandi e la loro chiave ne contiene il valore. Le parentesi non sono rappresentate.
Si assuma che l'espressione contenga solo gli operatori aritmetici binari: +, -, *, / e numeri interi.
Ad esempio l’espressione ((1+2)*5) è rappresentata dall’albero in figura
Tracce delle soluzioni
Esercizio 1
L è un linguaggio regolare perché n può assumere solo i valori 1, 2, 3 e poi può seguire un’altra stringa con
le stesse caratteristiche; non è quindi necessaria una capacità di conteggio illimitata. Una grammatica
regolare che genera L è la seguente, facilmente convertibile in un automa a stati finiti:
S -> a A1 | a B1 | a C1
A1 -> b A2 | b
A2 -> a A1
B1 -> a B2
B2 -> b B3
B3 -> b B4 | b
B4 -> a B1
C1 -> a C2
C2 -> a C3
C3 -> b C4
C4 -> b C5
C5 -> b C6 | b
C6 -> a C1
L1 coincide con L perché {(ambm)+, m > 0} evidentemente contiene L; quindi la stessa grammatica e lo
stesso automa definiscono L e L1.
Esercizio 2
Punto a.
x y substring(x,y)  p q r (r = concat(p,x)  y = concat(r,q))
Punto b.
x y i j, substring2(x,y,i,j) 
p q r (r = concat(p,x)  y = concat(r,q)  len(p) = i-1  len(x) = j-i+1)
Punto c.
x y reverse(x,y) 
(len(x) = len(y) = 0) /* x e y sono entrambe la stringa nulla*/ 
((c i substring2(c,x,i,i)  substring2(c,y,len(y)-i+1,len(y)-i+1) ) 
(c i substring2(c,y,i,i)  substring2(c,x,len(x)-i+1,len(x)-i+1) ))
Una formula alternativa ed equivalente è la seguente:
x y reverse(x,y) 
(len(x) = len(y) = 0) /* x e y sono entrambe la stringa nulla*/ 
len(y) = len(x) = 1  x = y

(z, w, r, q, (x = concat(z,w)  (y = concat(r,q)) 
(len(z) = len(q)  1 len(w) = len(r)  1) 
(reverse(z,q)  reverse(w,r)))
Esercizio 3
Evidentemente SI: è molto facile scrivere algoritmi che stabiliscano rispettivamente se due stringhe sono
una sottostringa dell’altra, se una stringa è la concatenazione di altre due, o calcolino la concatenazione tra
due stringhe, ecc.
Esercizio 4
Una MT a nastro singolo estende l’automa a stati finiti che costituisce il suo organo di controllo, quindi può
eseguire esattamente le mosse che esegue un automa a stati finiti. Essendo L1 = L un linguaggio regolare,
anche la complessità di un MT a nastro singolo che lo riconosca sarà O(n), per la precisione T M(n) = n+1.
Esercizio 5
E’ facile sviluppare T(n) in n2 + (n-1)2 + (n-2)2 + (n-3)2 ... + c
ossia
che è Θ(n3), infatti
e
Esercizio 6
calcola-valore (tree t)
{
 if t è una foglia return key (t)
 if key(t) = "+" return (calcola-valore (left(t)) +
calcola valore (right(t))) /*nodo intermedio: operatore +*/
 if key(t) = "- "return (calcola-valore (left(t)) calcola valore (right(t))) /*nodo intermedio: operatore - */
 if key(t) = "*" return (calcola-valore (left(t)) *
calcola valore (right(t))) /* nodo intermedio: operatore * */
 if e key(t) = "/ "return (calcola-valore (left(t)) /
calcola valore (right(t))) /*nodo intermedio: operatore /*/
else return errore “espressione mal formata"
}
.
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere
25 Novembre 2014
Il tempo a disposizione è di 1 ora e 45 minuti.
Esercizio 1 (punti 6/15 senza la parte facoltativa, 9 con la parte facoltativa)
Si ricordi che la stringa inversa di una generica stringa w, qui denotata wR, è ottenuta da w
scrivendo i suoi caratteri in ordine inverso, ad esempio abaabbR = bbaaba, aaabbbR = bbbaaa.
L’operazione di inversione viene estesa dalle stringhe ai linguaggi nel modo naturale:
LR = {wR | w L }
Si dica, con brevi spiegazioni, quali delle seguenti famiglie di linguaggi sono chiuse rispetto
all’operazione di inversione:
 Il linguaggi regolari
 I linguaggi non contestuali
 I linguaggi generati da grammatiche non ristrette
 (Parte facoltativa) I linguaggi non contestuali deterministici
NB: la parte facoltativa verrà valutata solo se nelle restanti parti si saranno ottenuti almeno 5 punti.
Esercizio 2 (punti 7/15)
Due macchine di Turing (MT) si dicono isomorfe se:
 hanno lo stesso numero di nastri;
 ad ogni mossa spostano le rispettive testine del nastro i-esimo alla stessa maniera (entrambe
a destra o entrambe a sinistra o lasciano entrambe ferme);
Si noti che di conseguenza due MT isomorfe usano esattamente le stesse celle di memoria.
E' decidibile il fatto che due qualsiasi MT isomorfe siano equivalenti, ossia calcolino la stessa
funzione o riconoscano lo stesso linguaggio? Giustificare brevemente la risposta
Esercizio 3 (punti 5/15)
Specificare in logica del prim’ordine il linguaggio L1 = { anbncn | n0 }. Nella specifica si possono
usare esclusivamente i seguenti predicati e funzioni:
 il predicato di appartenenza insiemistica: 
 il predicato di uguaglianza: =
 la funzione di concatenazione: 
 le costanti dei caratteri alfabetici a, b, c e la stringa vuota 
 il simbolo L1 per riferirsi al linguaggio da specificare (più eventuali altri simboli L2, L3, …
per eventuali linguaggi intermedi)
Non si può quindi utilizzare la funzione di elevamento a potenza.
Tracce di soluzioni
Esercizio 1




Data una grammatica G non-contestuale che genera il linguaggio L, la grammatica GR
ottenuta trasformando ogni produzione di G, A  , nella produzione A  R, genera
evidentemente LR.
In particolare, se G è anche regolare, ogni produzione del tipo A  Ba viene trasformata in
A  aB ottenendo quindi una grammatica che genera LR e soddisfa ancora la definizione di
grammatica regolare (è noto infatti che le grammatiche lineari a sinistra o lineari a destra
sono tra loro equivalenti e generano entrambe tutti e solo i linguaggi regolari).
Anche i linguaggi generati da grammatiche non ristrette sono chiusi rispetto all’inversione;
infatti queste grammatiche sono equivalenti alle macchine di Turing. Data quindi una MT
che riconosca L basta costruirne una che inverta la stringa di ingresso in un nastro ausiliario
e successivamente simuli il comportamento della MT originaria usando il nastro ausiliario al
posto del nastro di ingresso.
(Parte facoltativa)
I linguaggi non contestuali deterministici non sono invece chiusi rispetto all’inversione. Ciò
si può dedurre ricordando che L = {anbn}  {anb2n} è nondeterministico e osservando invece
che L1 = {1anbn}  {0anb2n} è deterministico (la lettrura del primo simbolo permette di
stabilire subito se si dovranno contare 2 b per ogni a oppure un solo b). L1R però non è
deterministico perché a inizio stringa non è possibile stabilire quale sarà il rapporto corretto
tra il numero di b e quello di a.
Esercizio 2
Il problema non è decidibile: ogni coppia di MT può essere trasformata in una coppia equivalente
che soddisfi la proprietà indicata: basta arricchire l’una con la memoria e il controllo dell’altra (che
poi non verranno utilizzati per la computazione “vera”): quindi, date due MT con k1 e k2 nastri
rispettivamente se ne costruiscono altre due, entrambe di k1 + k2 nastri, rispettivamente equivalenti
alle originarie. Perciò se fosse possibile decidere l'equivalenza delle due nuove MT sarebbe
decidibile anche l’equivalenza tra due MT generiche.
Precisazione
Occorrerebbe anche precisare che, in conseguenza della definizione data, due MT isomorfe o
terninano entrambe per lo stesso input o non terminano entrambe. Perciò, per valutare l’equivalenza
tra due MT generiche trasformandole in MT isomorfe, a rigore occorrerebbe cambiare anche la
regola che ne definisce l’accettazione di una stringa: la stringa è accettata se la MT raggiunge uno
stato di accettazione (o scrive un messaggio di accettazione sul nastro di uscita) anche in caso di
eventuale computazione che dopo aver raggiunto tale stato proceda all’infinito.
In questo modo Si possono ottenere due MT MT1’ e MT2’ isomorfe a MT1 e MT2 tali che MT1’
accetta tutte e sole le stringhe accettate da MT1 e similmente per MT2. Tuttavia se una tra MT1 e
MT2 non termina entrambe MT1’ e MT2’ non terminano ma segnalano in tempo finito l’eventuale
accettazione.
Si sottolinea che questo tipo di precisazine non è stato considerato parte necessaria della soluzione
che invece è ritenuta valida anche in sua assenza.
Esercizio 3
x( xL1  x =   yzw x = yzw  yz  L2  zw  L3  y  L4  z  L5  w  L6 )

x( xL2  x =   y x = ayb y  L2 )

x( xL3  x =   y x = byc y  L3 )

x( xL4  x =   y x = ay  y  L4 )

x( xL5  x =   y x = by  y  L5 )

x( xL6  x =   y x = cy  y  L6 )
Algoritmi e Principi dell'Informatica
Seconda Prova in Itinere
13 Febbraio 2015
Avvisi importanti
Il tempo a disposizione è di 1 ora e 45 minuti.
Esercizio 1 (punti 5/15-esimi)
Si calcoli la complessità del seguente frammento di codice che definisce l’“ossatura” di una
funzione f applicata a un array A:
f(A):
n := A.length
i := 1
altre eventuali inizializzazioni eseguite in tempo costante
while i < n
do_something_in_tempo_costante
i := i*2
f(A[1..n/3])
f(A[n/3+1..(2/3)*n])
j := 2
while j < n*n
do_something_in_tempo_costante
j := j*j
return result
Esercizio 2 (punti 7/15-esimi)
Si consideri un albero rosso-nero di altezza nera bh e costituito da soli nodi neri.
1. Quali sono, rispettivamente, il numero minimo e massimo di nodi contenuti nell’albero? (si
precisi se nel conto viene incluso il nodo T.NIL o no).
2. E’ possibile ottenere da esso un nuovo albero rosso-nero costituito da soli nodi neri
applicandovi esclusivamente operazioni di inserimento di nuovi nodi? In caso positivo in
che modo? (eventualmente illustrandolo mediante un semplice esempio).
3. Qual è il numero massimo di nuovi nodi che si possono inserire in esso senza effettuare
cancellazioni e senza alterare bh?
Si forniscano brevi ma chiare spiegazioni per le risposte date.
Esercizio 3 (punti 7/15-esimi)
Sia dato un grafo G e due sottoinsiemi dei suoi vertici, V1 e V2.
La distanza tra V1 e V2, d(V1, V2), è la distanza minima tra un nodo appartenente a V1 e un nodo
appartenente a V2. Se V1 e V2 non sono disgiunti allora la loro distanza è uguale 0.
Si specifichi un algoritmo che, a partire da un grafo G e da due suoi sottoinsiemi V1 e V2, calcoli la
distanza tra V1 e V2; se ne discuta quindi la complessità. La valutazione dell’algoritmo proposto
dipenderà ovviamente dalla sua complessità.
N.B.: Si può assumere che esista una funzione che in tempo costante determini l’appartenenza di un
vertice a uno dei due insiemi.
Tracce di soluzioni
Esercizio 1
Lo pseudocodice ricorsivo dell’esercizio ha una funzione di complessità definita da una ricorrenza
del tipo
T(n) = 2T(n/3) + log(n) + log(log(n))
che si risolve mediante il master theorem ottenendo una funzione
(nlog3(2)).
Esercizio 2
Risposte
1. Posto che l’altezza nera si calcola contando il numero di nodi neri tra la radice, esclusa, e la
foglia T.NIL, compresa e posto che ogni “cammino nero” dalla radice a T.NIL deve avere la
stessa lunghezza, un albero rosso-nero di soli nodi neri è necessariamente perfettamente
bh1
bilanciato; quindi il numero di nodi interni è
2
i
 2 bh  1 cui va aggiunto l’unico T.NIL e
i 0
il numero, sia minimo che massimo, di nodi totale è 2bh.
2. Ogni nodo nuovo viene inserito con colore rosso; successivamente la procedura di FIXUP
lascia in ogni caso almeno un nodo rosso. Quindi non è possibile ottenere alberi interamente
neri esclusivamente mediante inserimenti (a meno che l’albero non consista nella sola
radice).
3. Se l’albero è inizialmente costituito da soli nodi neri si possono inserire nuovi nodi senza
alterarne la bh, quindi necessariamente rossi, fino al massimo a raddoppiarne l’altezza: h =
2.bh. Ciò può essere ottenuto anche eseguendo solo inserimenti: ad esempio l’albero di
figura a può essere trasformato in quello di figura b eseguendo nell’ordine l’inserimento dei
nodi 3, 7, 12, 20, 1. 4. 6. 8, 11, 13, 16, 22.
10
10
5
5
15
T.NIL
3
1
4
…..
Figura a
15
7
6
20
12
8
T.NIL
11
…..
Figura b
13
16
22
Legenda: i nodi quadrati rappresentano nodi neri; quelli tondi nodi rossi.
Quindi il numero totale di nodi (compreso T.NIL) del nuovo albero di altezza 2.bh è 22bh e il
numero massimo di nodi inseribili è 22bh - 2bh .
Esercizio 3
È possibile effettuare una visita BFS a partire da ogni nodo in V1. |V1| = O(n); quindi si eseguono
O(n) visite, ognuna di costo O(m + n). Tale soluzione ha complessità O(n(m+ n)).
Una soluzione migliore consiste nel modificare la BFS in modo che tutti i nodi u in V1 siano inseriti
subito nella coda e la loro distanza, u.dist, sia posta a 0. L’algoritmo analizza quindi tutti i nodi
adiacenti ai nodi in V1 che non appartengono a V1, li inserisce nella coda e pone la loro distanza
uguale a 1. Se tra questi nodi è incluso un nodo di V2, l’algoritmo termina restituendo 1 (la distanza
calcolata). Altrimenti, si procede con l’estrazione dalla coda dei nodi a distanza 1 e con
l’inserimento di tutti i nodi a distanza 2 da V1. Vengono cosi progressivamente individuati tutti i
nodi a distanza crescente dai nodi in V1.
Per come è definita la BFS, il primo nodo in V2 che si incontra durante la visita avrà distanza
minima e tale distanza potrà essere restituita dall’algoritmo come valore di ritorno. Se la visita non
trova alcun nodo dell’insieme V2, allora V2 non è raggiungibile da V1; quindi l’algoritmo restituisce
un valore opportuno (per es., ∞).
Essendo basto su una visita BFS, l’algoritmo ha complessità O(m + n).
Algoritmi e principi dell’Informatica
Recupero prima prova in itinere - 13 Febbraio 2015
Avvisi importanti
La prova è riservata ai laureandi che non abbiano superato la prima prova in itinere.
Chi sostiene questa prova di recupero non potrà iscriversi al II appello di questa sessione.
La durata della prova di recupero è di 1 ora
Esercizio 1 (punti 6)
Si consideri il predicato binario estensionale segment(a,b), da non definirsi ulteriormente, che
indica la presenza di un segmento sulla retta reale, dal punto con coordinata a al punto con
coordinata b.
Si specifichi in logica del prim’ordine il predicato binario coalescedSegment(x,y) che
indica che ogni punto sulla retta compreso tra il punto di coordinata x e il punto di coordinata y
appartiene a un qualche segmento specificato tramite il predicato segment.
A titolo esemplificativo, la figura rappresenta il caso in cui valgano le formule seguenti:
segment(t1,t3)
segment(t2,t4)
segment(t4,t5)
segment(t6,t7).
Si può allora ad esempio evincere che valga anche la formula:
coalescedSegment(t1,t5).
Esercizio 2 /punti 5)
Si consideri il linguaggio definito sull’alfabeto {a, b, c}dalla formula seguente:
L = ({abb}+. (({baba}*- {bababa}+)  {c}*.{ab}+.c+)  {a}*.{b}*.{cabc}*)
Si dica, spiegando berevemente la risposta quale è il formalismo a potenza minima (generativa se
trattasi di grammatica, riconoscitiva se trattasi di automa o in generale macchina a stati) in grado di
definire il linguaggio L.
NB: non è richiesto di costruire la grammatica e/o l’automa che definisce L, bensì solo di indicare a
quale famiglia, a potenza minima, esso/a appartenga.
Si rammenti che i simboli utilizzati nella formula indicano rispettivamente:
*:
la chiusura riflessiva e transitiva (operatore “stella di Kleene”)
+:
la chiusura transitiva, non riflessiva
-:
la differenza insiemistica
:
l’unione insiemistica
:
l’intersezione insiemistica
.:
la concatenazione tra linguaggi
Esercizio 3 (punti 4)
Si consideri il linguaggio L definito nell’Esercizio 2: è decidibile il problema di stabilire se una
generica macchina di Turing riconosce L?
Spiegare brevemente la risposta.
Tracce delle soluzioni
Esercizio 1
xy coalescedSegment(x,y)  wz segment(w,z)  wx  zx  (zy
 coalescedSegment(z,y))
Esercizio 2
I linguaggi regolari sono chiusi rispetto a tutte le operazioni utilizzate nella formula che definisce L.
Siccome esse sono applicate a partire da singoli caratteri dell’alfabeto, che sono casi particolari di
linguaggi regolari, l’espressione complessiva definisce un linguaggio regolare, riconoscibile quindi
da un automa a stati finiti.
Esercizio 3
Il problema di stabilire se una generica MT riconosca L è evidentemente indecidibile, poiché il
riconoscimento di L può essere descritto come la funzione
fL(x) = 1 se x  L, 0 se x  L
Per il teorema di Rice non è quindi possibile stabilire se una generica MT calcola una funzione
fissata, o, equivalentemente, riconosce un linguaggio fissato.
Algoritmi e Principi dell’Informatica
Appello del 2 Marzo 2015
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 8)
Una macchina di Turing si dice n-generatrice se, quando riceve 0 in ingresso, termina entro n+1
passi scrivendo il numero n in uscita (n0).
Fissata una qualsiasi enumerazione algoritmica E delle macchine di Turing, il generatore minimo di
un numero n, indicato con gm(n), è il più piccolo indice, secondo E, di macchina di Turing ngeneratrice. Si risponda alle seguenti domande fornendo brevi ma chiare spiegazioni per le risposte
date:
a) La funzione gm è totale?
b) La funzione gm è computabile?
Esercizio 2 (punti 9)
Si consideri il seguente linguaggio:
L = {anb3n | n ≥ 0}  {an(bbbc)n | n ≥ 0}
Si forniscano:
a) Una grammatica, preferibilmente a potenza generativa minima, che generi L
b) Un automa, preferibilmente a potenza minima tra le famiglie tradizionali a stati finiti, a pila
(deterministici o no), macchine di Turing, che riconosca L
c) Una rete di Petri che riconosca L
Esercizio 3 (punti 9)
Si consideri il seguente linguaggio:
L={
| 1 ≤ k ≤ 100, ∀ 1 ≤ i ≤ k.(ni ≥ 1),  1 ≤ i < j ≤ k.(ni = nj)}
Si descrivano a grandi linee, ma in maniera sufficientemente precisa, una MT e una RAM che
riconoscano L e se ne valutino le complessità temporali, nel caso della RAM sia a criterio di costo
costante che a criterio logaritmico.
Sono ovviamente preferite soluzioni a minor complessità per entrambi i tipi di macchina.
Esercizio 4 (punti 8)
1.
Si scriva un algoritmo che, data in input una sequenza P contenente i dati anagrafici di diverse
persone, determina se nella sequenza ci sono 2 persone che compiono gli anni lo stesso giorno
dell’anno. Si assuma pure che i dati di ogni persona siano rappresentati da un oggetto che ha diversi
attributi, nome, indirizzo, codice_fiscale, data_nascita, e che la data di nascita a sua volta sia un
oggetto con 3 attributi, giorno, mese, anno (per cui se p è il riferimento ad una persona,
p.data_nascita è la sua data di nascita, e p.data_nascita.giorno è il giorno del mese in cui la persona
è nata).
Si dia la complessità temporale asintotica dell’algoritmo scritto nel caso pessimo.
2.
Come al punto 1: Come cambia, se cambia, la complessità dell’algoritmo se, sapendo che tutte le
persone della sequenza P sono nate nel XX secolo, occorre determinare se nella sequenza P ci sono
2 persone nate esattamente lo stesso giorno?
3.
Come cambia, se cambia, la complessità dell’algoritmo se, sapendo che tutte le persone della
sequenza P sono viventi, occorre determinare se nella sequenza P ci sono 2 persone nate
esattamente lo stesso giorno?
NB: Il punteggio dato sarà tanto maggiore quanto migliore è la complessità degli algoritmi scritti.
Tracce delle soluzioni
Esercizio 1
a) La funzione è certamente totale, in quanto, per qualunque numero n, si può facilmente
costruire una macchina di Turing n-generatrice. Basta, infatti, compiere un passo di stampa
per ogni cifra di n (per un totale di un passo se n=0 e di log2 n+1 passi se n>0, quindi
sempre entro n+1 passi). Tale macchina potrebbe non essere la n-generatrice con l’indice più
piccolo, ma la sua esistenza implica che la funzione gm è definita nel punto n.
b) Sì. Infatti, per quanto osservato al punto a), si può facilmente trovare un limite superiore al
valore di gm(n). A tale scopo, sia i l’indice della macchina esibita al punto a). Basta a questo
punto, mediante una macchina di Turing universale, testare, in successione, ciascuna delle
macchine di Turing con indice da 0 a i per n+1 passi a fronte dell’ingresso 0: il primo indice
per il quale la macchina termina e produce n in uscita è il valore gm(n) cercato.
Esercizio 2
Punto a.
S→X|Y|
X → aXbbb | abbb
Y → aYbbbc | abbbc
Punto b.
Un automa a pila deterministico A che riconosca L può essere costruito secondo le linee seguenti:
1. A impila gli n a (ponendo lo stato iniziale tra quelli finali, accetta anche la stringa vuota);
2. Al ricevimento del primo b ne conta altri due;
3. Dopo aver letto i primi 3 b, si sposta in due stati diversi a seconda che il carattere successivo
sia b o c (e ovviamente va in uno stato di errore se non siverifica nessuna delle circostanze
previste)
4. Da questo punto in poi verifica che per ogni a impilato si trovino 3 b oppure 3 b seguite da c
a seconda dello stato scelto al punto precedente.
Punto c.
La rete di Petri seguente (con la relativa marcatura iniziale) riconosce L quando viene a trovarsi con
tutti i posti vuoti.
Esercizio 3
Soluzione mediante MT
Grazie al fatto che il parametro k è limitato e ≤ 100 è possibile progettare diverse MT che riconoscano L con
complessità temporale O(n).
Un primo modo consiste nel costruire una MT con 100 nastri di memoria: ogni sequenza ani viene
memorizzata su un nastro diverso; successivamente tutte le testine vengono riposizionate sulla prima cella
dei rispettivi nastri e vengono spostate di una posizione a destra contemporaneamente: se due di essere
giungono alla fine della propria sottostringa contemporaneamente (ciò può essere verificato mediante la
funzione  della macchina che produce uno stato di accettazione se due testine leggono
contemporaneamente una marca di fine stringa) la stringa originaria viene accettata.
Una MT con meno nastri invece memorizza la stringa in ingresso in due nastri di memoria e, per ogni
frammento
di un nastro verifica se sull’altro nastro ne esiste un altro con lo stesso numero di a. Si noti
che per evitare di considerare il caso ni = nj quando i = j può essere opportuno marcare in qualche modo la
porzione di nastro sotto esame, e.g. sostituendo la b iniziale con un altro carattere. La MT prende in
considerazione il primo gruppo
dal primo nastro e scorre il secondo nastro per verificare se esiste un
altro gruppo con lo stesso numero di a (per fare questo deve fare k volte andata e ritorno nello scorrimento
di
impiegando un tempo 2.k.n1+ n; il processo viene ripetuto per tutti gli
volte; si ha quindi una complessità quadratica in k ma ancora lineare in O(n).
del primo nastro ossia k
Una MT più sofisticata potrebbe memorizzare soltanto i numeri ni codificandoli in binario e poi verificare
l’esistenza di coppie di valori uguali alla stessa maniera. La prima fase richiede un tempo O(n log(n)) =
(un’analisi più attenta però mostra che il tempo necessario è addirittura O(n)); essendo il
risultato della prima fase O(log(n)), la seconda può poi essere completata in tempo O(k2log(n)).
Soluzione mediante RAM
Una RAM può procedere con uno schema algoritmico uguale a quello utilizzato per la terza MT descritta
sopra. A criterio di costo costante ciò richiede O(n) per la prima fase e O(k 2) per la seconda; essendo k ≤
100, il costo totale è O(n).
A criterio di costo logaritmico invece la prima fase costa O(n.log(n)) ma la seconda O((k 2.log(n))) ossia
ancora O(log(n)), comunque dominata dalla fase precedente.
Esercizio 4
1.
In alternativa al confronto tra tutti gli elementi della sequenza (complessità Θ(n 2), n = lunghezza della
sequenza P) è possibile usare un vettore di appoggio di dimensione pari al numero di giorni dell’anno (365)
e conteggiare così la frequenza in P di ogni singolo giorno dell’anno. Questa soluzione avrebbe complessità
temporale Θ(n). L’uso del vettore di appoggio comporta un incremento costante, quindi trascurabile, della
complessità spaziale.
È possibile tuttavia considerare che, poiché al massimo ci sono 356 giorni in un anno (contando la
possibilità di anni bisestili), se l’array P è più lungo di 356 elementi di sicuro ci sono almeno 2 persone che
compiono gli anni lo stesso giorno. Se ce ne sono meno di 356, è accettabile anche eseguire un doppio ciclo
for, in quanto comunque il ciclo è ripetuto un numero limitato di volte.
stesso_compleanno (P)
1 if P.length > 356
2 return true
3 for i := 1 to P.length -1
4 for j := i+1 to P.length
5
if P[i].data_nascita.giorno = P[j].data_nascita.giorno and
P[i].data_nascita.mese = P[j].data_nascita.mese
6
return true
7 return false
Ognuno dei 2 cicli annidati 3-4 viene eseguito al più 356 volte, quindi la complessità dell’algoritmo è Θ(1).
2.
Anche in questo caso se P contiene più elementi di un certo numero K costante fissato di sicuro ci sono 2
persone che sono nate lo stesso giorno. In questo caso K = 356*100 (il valore è anche minore, in quanto non
tutti gli anni sono bisestili, ma non cambia niente dal punto di vista della complessità), quindi alla riga 1
occorre cambiare 356 in 35600, ma comunque la complessità rimane costante (e aggiungere il controllo
sull’anno alla riga 5).
3.
In questo caso, considerando che un uomo non vive fino a 130 anni, basta prendere K=356*130, ed il
ragionamento del punto 2 rimane invariato. (Si noti che non cambia nulla se, per stare larghi, si prende
K=356*200).
Algoritmi e Principi dell’Informatica
Appello del 6 Luglio 2015
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 9)
Punto a)
Si scriva una grammatica che generi il linguaggio L1 composto da stringhe sull’alfabeto  = {(, ),]}, tali che
le parentesi tonde siano bilanciate — ossia ben parentetizzate —, con la variante che la parentesi quadra può
bilanciare un numero arbitrario (non nullo) di parentesi tonde aperte. Ad esempio, le stringhe (()()), ((())),
((()(](()] appartengono al linguaggio, mentre le stringhe ((), ((((](, ]()() non vi appartengono. Si scriva una
grammatica, preferibilmente a potenza minima che produca il linguaggio L1.
In alternativa è possibile costruire un automa, sempre a potenza minima, che riconosca lo stesso linguaggio;
ciò però comporta una diminuzione del punteggio ottenibile di 2 punti.
Punto b)
E' vero che se un linguaggio L non è regolare allora neanche il suo complemento Lc è regolare? Perché?
Punto c)
E' vero che se un linguaggio L non è libero dal contesto allora neanche il suo complemento Lc è libero dal
contesto? Perché?
Esercizio 2 (punti 7)
Si consideri l’insieme S delle stringhe costituite da caratteri appartenenti a due alfabeti disgiunti, A1 e A2.
Si formalizzi, mediante una formula del prim’ordine, il predicato unario proprietà, che indica che il suo
argomento appartiene al sottoinsieme di S costituito da stringhe in cui non compaiano due caratteri
consecutivi appartenenti ad A1. Ad esempio, se i caratteri di A1 sono lettere maiuscole e quelli di A2 lettere
minuscole, le seguenti stringhe soddisfano la proprietà suddetta:
AbcDghm, cvHmUnI, , F, …
mentre le seguenti non la soddisfano:
AA, aGnnHH, …
NB: La formula deve far uso esclusivamente dei simboli seguenti:
 Quantificatori e connettivi logici proposizionali
 Il simbolo di appartenenza 
 Simboli di variabile i cui domini siano insiemi di stringhe o insiemi di caratteri
 I simboli di costante A1 e A2 rappresentanti i due alfabeti
 Il simbolo ‘’ che denota l’operazione di concatenazione, applicabile a stringhe e a caratteri.
Esercizio 3 (punti 6)
Si immagini di voler ordinare un array di n elementi mediante l’algoritmo Quicksort. Si immagini inoltre
che l’array in input sia tale per cui l’operazione di partizione sposti il pivot in posizione n – k, k essendo una
costante indipendente da n, e si assuma che lo stesso effetto si ripresenti nella successiva partizione della
porzione di array di lunghezza n – k -1; e così via finché la cardinalità della porzione considerata non
diventa <= k.
Sulla base delle suddette informazioni, è possibile determinare l’ordine di grandezza della complessità
temporale dell’esecuzione di Quicksort su un tale array? In caso positivo, quale sarebbe l’ordine di
grandezza?
Esercizio 4 (punti 11)
Sia L una lista semplice (cioè con puntatori solo all’elemento successivo) contenente n interi positivi
memorizzati in ordine strettamente crescente. Si consideri il problema di trovare due puntatori a due
elementi di L, i, e j, se esistono, tali che la somma degli elementi di L compresi tra i e j, estremi inclusi, sia
uguale a un valor dato X.
Si descriva un algoritmo, mediante opportuno pseudocodice, per risolvere il problema (ossia stabilire se tali
i, j esistono e nel caso produrli in uscita) e se ne valuti la complessità asintotica.
NB: la complessità dell’algoritmo, ovviamente, influenza la valutazione della qualità dell’algoritmo
prodotto.
Soluzioni schematiche
Esercizio 1
Punto a)
Una grammatica noncontestuale è necessaria e sufficiente per generare L1; ad esempio la seguente:
S → BS | N]S | 
B → BB | (B) | 
N → NN | (N | (B
Punto b)
Vero. Supponiamo per assurdo che Lc sia regolare. Allora grazie alla chiusura dei linguaggi regolari
rispetto alla complementazione, anche il complemento di Lc dev'essere regolare. Ma il complemento
di Lc è L, che per ipotesi non è regolare. Assurdo.
Punto c)
Falso. Un esempio di linguaggio non libero dal contesto è L={anbncn}, non riconoscibile da nessun
(ND)PDA. Il suo complemento è invece libero dal contesto. Si tratta infatti del linguaggio le cui
stringhe o sono del tipo anbmcl con n≠m o n≠l oppure non sono del tipo a*b*c*. Chiamiamo L1={
anbmcl | n≠m o n≠l } e L2=a*b*c* e sia L2c il complemento di L2. In sostanza, Lc è dato dall'unione
di L1 e L2c, che sono entrambi liberi dal contesto. Infatti, per riconoscere L1 basta un NDPDA,
mentre notiamo che L2 è un linguaggio regolare, e quindi anche il suo complemento L2c è regolare
(e quindi anche libero dal contesto).
Esercizio 2
x proprietà(x)  y, z, c1, c2(c1 A1  c2 A1  x = y  c1  c2  z)
Esercizio 3
L’equazione alle differenze in questo caso è la seguente
T(n) = T(k) + T(n-k) + Θ(n)
laddove T(k) = O(1), in quanto per ordinare un array di dimensione fissata k serve un tempo
costante, quindi la soluzione O(n2)
Esercizio 4
FIND_SUM(L,X)
1 j := L.head
2 i := L.head
3 sum := j.key
4 while i ≠ j.next and j ≠ NIL and sum ≠ X
5 if sum < X
6
j := j.next
7
sum := sum + j.key
8 else
9
sum := sum – i.key
10 i := i.next
11 if sum = X
12 return (i, j)
13 else
14 return false
La complessità asintotica dell’algoritmo è chiaramente O(n) poiché i e j scorrono la lista una
sola volta.
Algoritmi e Principi dell’Informatica
Appello del 16 Luglio 2015
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (punti 8)
Scrivere una grammatica a potenza minima che generi il linguaggio { anbmcl | n≠m o n≠l }
In alternativa è possibile costruire un automa, sempre a potenza minima, che riconosca lo stesso
linguaggio; ciò però comporta una diminuzione del punteggio ottenibile di 2 punti.
Esercizio 2 (punti 8)
Parte a
È decidibile stabilire se una macchina di Turing M entra più di una volta in un qualche stato
dell’organo di controllo quando riceve in input una stringa w?
In altre parole:
Indicata con <M> la codifica di una MT M e con <w> quella di una stringa sull’alfabeto di input di
M, si dica se è computabile la funzione
F(<M>, <w>) = 1, se quando M opera su w esistono due configurazioni di M
con lo stesso stato dell’organo di controllo
0 altrimenti
Parte b
È decidibile stabilire se una macchina di Turing M (con un unico stato iniziale dell’organo di
controllo) entra più di una volta nello stato iniziale dell'organo di controllo quando riceve in input
una stringa w?
In altre parole:
Indicata con <M> la codifica di una MT M, con <w> quella di una stringa sull'alfabeto di input di
M e con q0 lo stato iniziale dell'organo di controllo di M, si dica se è computabile la funzione
F(<M>, <w>) = 1, se quando M opera su w esistono due configurazioni di M
in cui lo stato dell’organo di controllo è q0
0 altrimenti
Giustificare brevemente le risposte date.
Esercizio 3 (punti 10)
Dato un albero binario di ricerca T, i cui nodi memorizzano una variabile che ne rappresenta il
colore, si vuole determinare se T è un albero Rosso-Nero. Si definisca un algoritmo che risolva
questo problema e se ne discuta la complessità.
Esercizio 4 (punti 5)
Parte a
Si consideri una tabella hash, con m = 10 posizioni, le cui chiavi sono interi non negativi. La tabella
è gestita mediante indirizzamento aperto.
Data la funzione hash:
h(k ,i) = (k +2×i) mod m
si discuta la bontà di h(k,i) rispetto alle sequenze di ispezione che essa genera nella tabella
considerata.
Parte b
Si consideri una generica tabella hash con m posizioni e fattore di carico  = 1/2.
Si considerino i due casi di tabella con liste concatenate e di tabella aperta: qual è, nel caso pessimo,
il tempo necessario (è sufficiente l’ordine di grandezza) per la ricerca e l’inserimento di un
elemento in tabella nei due casi? Giustificare brevemente la risposta.
Soluzioni schematiche
Esercizio 1
S -> A | B (A è il sottolinguaggio con n≠m, B quello con n≠l)
A -> A1 A2 C0 | A2 B1 C0 (sottolinguaggio con n≠m. due modi per farlo:
1) ho più a che b e quindi ho un prefisso non vuoto di a (A1) seguito da a e b bilanciate (A2), seguite da c
arbitrarie (C0)
2) ho meno a che b e quindi ho a e b bilanciate (A2) seguite da un prefisso non vuoto di b (B1) seguito da c
arbitrarie (C0))
A2 -> a A2 b | ε
B -> A1 B2 | B2 C1 (sottolinguaggio con n≠l. due modi per farlo:
1) ho più a che c e quindi ho un prefisso non vuoto di a (A1) seguito da a e c bilanciate con in mezzo delle b
arbitrarie (B2)
2) ho meno a che c e quindi ho a e c bilanciate con in mezzo delle b arbitrarie (B2) seguite da un prefisso non
vuoto di c (C1))
B2 -> aB2c | B0 (a e c bilanciate con in mezzo delle b arbitrarie (B0))
A1 -> a A1 | a
B1 -> b B1 | b
C1 -> c C1 | c
B0 -> B1 | ε
C0 -> C1 | ε
Esercizio 2
Parte a
Il problema è decidibile. Mentre le possibili configurazioni di una MT sono infinite, gli stati
dell'organo di controllo sono finiti (indichiamoli con QM). Basta infatti simulare al più |QM| + 1
passi dell'esecuzione di M su w e verificare se uno stato è visitato almeno due volte (NB:
l'esecuzione di M su w potrebbe non terminare, e potrebbe anche darsi che la testina di lettura di M
non legga alcun carattere di w).
Parte b
Il problema non è decidibile. Infatti si può ridurre ad esso il problema dell’arresto di una TM nel
modo seguente: data M,
 costruisco una la macchina M' ottenuta aggiungendo a M un nuovo stato iniziale q0’, e una
transizione iniziale che porta da q0’ a q0 senza fare nient’altro; aggiungo poi delle
transizioni che da ogni stato finale di M portano a q0’ e fermano la macchina; l'unico stato
finale di M' è q0’. Chiaramente M e M' riconoscono lo stesso linguaggio e M accetta una
stringa, ossia si ferma, se e solo se M’ raggiunge il suo stato iniziale più di una volta.
Esercizio 3
L’algoritmo seguente verifica che le proprietà degli alberi Rosso-Neri siano rispettate: verifica che
la radice sia nera, quindi richiama una funzione che ricorsivamente analizza i sottolaberi per
calcolarne l’altezza nera e controllare che i figli dei nodi rossi siano neri. La complessità è
proporzionale al numero di nodi dell’albero.
checkRB (Tree T) {
if (T.color=RED)
return FALSE
(bh, RB) <-- checkSubTree(T, 0); /*bh = altezza nera del
sottoalbero T; RB = valore di verità per
le proprietà RB */
return RB;
}
checkSubTree(Tree T, int bh) {
if (T=NIL)
return (bh, TRUE)
if ((T.color = RED) AND (T.left.color = RED OR T.right.color
= RED))
return (bh, FALSE)
if (T.color = BLACK)
bh = bh+1
(bh_left, RBleft) = checkSubTree(T.left, bh)
(bh_right, RBright) = checkSubTree(T.right, bh)
if not (RBleft AND RBright)
return (bh, FALSE)
if (bh_left != bh_right)
return (bh, FALSE)
return (bh_left, TRUE)
}
Esercizio 4
Parte a
Visto che m è pari, le sequenze di ispezione generate visitano solo le posizioni pari o solo quelle
dispari (dipende dalla prima posizione visitata). Se m fosse dispari, la funzione permetterebbe
invece di ispezionare tutti gli elementi della tabella.
Parte b
In entrambi i tipi di tabella il caso pessimo produce n/2 conflitti sulla stessa posizione determinando
quindi un tempo di ricerca O(n) in ambo i tipi di tabella; se si vogliono evitare occorrenze ripetute è
necessario comunque anche scandire l’intera lista sia nel caso di tabella aperta che di tabella con
liste concatenate. Quindi il tempo di ricerca e inserimento nel caso pessimo è comunque O(n).
Algoritmi e Principi dell’Informatica
Appello del 2 Settembre 2015
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1
(Punti 8)
Si considerino i linguaggi seguenti:
L1 = { z  {a,b,c}* |
x (y (z = x.y)  (#a(x)  #b(x)  #c(x))  (#a(x) - #b(x)  2) }
L2 = { z  {a,b,c}* |
x (y (z = x.y)  (#a(x)  #b(x)  #c(x))  (#b(x) - #c(x)  2) }
L3 = { z  {a,b,c}* |
x (y (z = x.y)  (#a(x)  #b(x)  #c(x))  (#a(x) - #c(x)  2) }
dove, per un carattere  e una stringa x, l’espressione #(x) denota il numero di volte in cui il
carattere  si ripete nella stringa x. Ad es. #a(ababaccc) = 3.
Si costruisca una macchina astratta che riconosca L = L1  L2  L3. Tra le diverse macchine astratte
che riconoscono L sono preferite macchine “a potenza minima” ossia appartenenti alla categoria di
automi a minor potenza riconoscitiva possibile.
Esercizio 2 (9 punti)
Sia d : N × N  N la biiezione tra N e N × N definita come segue:
d(x,y) = (x+y)(x+y+1)/2 + x
Si considerino i seguenti insiemi:

S1 = { d(x,y) | fx(y)   }

S2 = { x | fx(0)   }

S3(k) = { x | fk(x)   }, dove k è un parametro.
Per ciascuno dei predetti insiemi, si dica se esso è ricorsivo, motivando brevemente la risposta.
Esercizio 3 (8 punti)
Si definisca un algoritmo per determinare se due alberi binari di ricerca T1 e T2 sono uguali sia per
il valore delle chiavi sia per la struttura. Valutare la complessità dell’algoritmo definito.
Esercizio 4 (punti 8)
Si consideri il seguente insieme di numeri interi:
{5, 60, 18, 23, 10, 15}.
Si individui una sequenza di inserimenti (senza cancellazioni) di questi valori come chiavi di un
albero r-b (rosso-nero) inizialmente vuoto in modo che l’albero risultante abbia altezza complessiva
doppia dell’altezza nera. Si ricorda che per convenzione la radice di un sottoalbero non viene
computata nell’altezza (né nera né complessiva) mentre le foglie ( i nodi T-NIL, neri) vengono
computate.
Si mostri il risultato finale ottenuto dopo i vari inserimenti e almeno un risultato intermedio, ad
esempio dopo l’inserimento dalla prima metà dei dati.
Tracce delle soluzioni
Esercizio 1
Poiché la differenza tra il numero di a, b e c in ogni prefisso delle stringhe del linguaggio è limitata,
un automa a stati finiti è sufficiente per riconoscere il linguaggio:
a
#a = #b+1 =
#c+1
c
b
#a = #b = #c
#a = #b+2 =
#c+2
a
b
#a = #b = #c+1
a
c
c
#a = #b+1 =
#c+2
b
#a = #b = #c+2
q0 =
#a = #b = #c
F=Q
Esercizio 2
S1 non è ricorsivo. Infatti la funzione d stabilisce banalmente una biiezione tra N e NxN, e se si
potesse stabilire l’insieme delle coppie di numeri (x,y) tali per cui fx(y)   allora il problema
dell’arresto risulterebbe decidibile, il che è assurdo.
S2 non è ricorsivo. Sia F l’insieme di funzioni calcolabili definite nel punto 0; tale insieme non è né
l’insieme di tutte le funzioni computabili, né l’insieme vuoto. L’insieme S2 di indici delle macchine
di Turing che calcolino funzioni in F non è pertanto ricorsivo per il teorema di Rice.
La ricorsività di S3(k) dipende da k. Per alcuni valori di k si sa esattamente per quali valori di
ingresso x la funzione fk(x) è definita. Ad esempio, se fk(x) fosse la funzione x2, si saprebbe che è
definita sempre e quindi il problema sarebbe decidibile (e deciso). Per altri valori di k, invece, il
problema è indecidibile. Se, ad esempio, fk(x) fosse la funzione fx(0), tale funzione sarebbe
certamente calcolabile, ma, come ad esempio osservato al punto b), non se ne potrebbe stabilire
l’insieme di definizione.
Esercizio 3
È possibile definire un algoritmo ricorsivo che, dopo aver verificato che le radici degli alberi non
sono nulle e che le chiavi sono uguali, visita ricorsivamente il sottoalbero sinistro e quello destro e
restituisce valore false se una delle condizioni verificate è falsa. La complessità dell’algoritmo è
proporzionale al numero di nodi.
boolean compare(Tree T1, Tree T2){
if
(T1
return true;
==
null
&&
T2
==
null)
if
(T1
!=
null
&&
T2
!=
null)
return((T1.key == T2.key) && compare(T1.left, T2.left) &&
compare(T1.right, T2.right));
else return(false);
}
Esercizio 4
Se si inseriscono i dati in ordine crescente o decrescente (e.g. {60, 23, 18, 15,10, 5} si ottiene un
albero in cui ogni sottoalbero ha la proprietà che il cammino sinistro alterna nodi rossi e nodi neri
mentre il cammino destro ha solo nodi neri ed è quindi lungo la metà del sinistro. La figura seguente
mostra lo stato dell’albero dopo l’inserimento di, rispettivamente:
60
T.NIL
60
23
23
18
T.NIL
Inserimento di 60, 23, 18
60
T.NIL
23
x
23
18
60
15
y
x
18
23
60
15
T.NIL
T.NIL
Inserimento di 15
23
23
18
15
60
x
18
60
15
10
10
T.NIL
y
T.NIL
23
y
23
15
60
18
10
T.NIL
Inserimento di 10
23
15
60
18
10
5
T.NIL
Risultato finale.
Algoritmi e Principi dell’Informatica
Appello del 21 Settembre 2015
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1
(Punti 7)
Si consideri il linguaggio seguente:
L1 = {a,b,c}* - a*.b*
dove il – indica la differenza insiemistica.
Si costruiscano una macchina astratta che riconosca L1 e una grammatica che lo generi; è fortemente
raccomandato che entrambi i formalisimi siano a “potenza minima” ossia appartenenti alla categoria
di automi/grammatiche a minor potenza riconoscitiva/generativa possibile.
Esercizio 2
(Punti 8)
Si consideri, oltre al linguaggio L1 dell’esercizio 1, anche il linguaggio L2 seguente:
L2 = {a,b}* - {anbn | n > 0}
Si dica, motivando brevemente la risposta, quali dei seguenti problemi sono decidibili e quali no:
1.
2.
3.
4.
Stabilire se un generico automa a stati finiti riconosce L1
Stabilire se un generico automa a stati finiti riconosce L2
Stabilire se una generica macchina di Turing riconosce L1
Stabilire se una generica macchina di Turing riconosce L2
Esercizio 3
(Punti 7)
Si consideri il linguaggio L = {wcwcw | w  {a,b}+}. Si descriva una macchina RAM che riconosca
L, minimizzando la complessità spaziale sia a criterio di costo costante che logaritmico.
Esercizio 4 (Punti 8)
Sia dato un array A di n interi che assumono valori nell'intervallo [0, …, n+1]. L’array non contiene
valori duplicati; i valori in esso contenuti saranno quindi tutti quelli compresi nell’intervallo
considerato, tranne due. A non è ordinato.
Si specifichi un algoritmo che individui e produca in output i due valori mancanti in A e se ne
discuta la complessità. La valutazione dell’algoritmo proposto dipenderà dalla sua complessità.
Tracce di soluzioni
Esercizio 1
L1 è la differenza tra due linguaggi regolari (di cui il primo è il monoide libero sull’alfabeto {a,b,c}.
Siccome i linguaggi regolari sono chiusi rispetto alla differenza insiemistica, e in particolare rispetto al
complemento, L1 è pure regolare.
Un automa a stati finiti e una G regolare che riconosca e generi L1, rispettivamente sono i seguenti:
a
b
c
b
a, c
a, b, c
S  aS | bB | cC | c
B  bB | aC | a | cC | c
C  aC | bC | cC | a | b | c
Esercizio 2
1. Il problema è decidibile: in generale è decidibile l’equivalenza tra due automi a stati finiti (L(A 1) =
L(A2) se e solo se L(A1)  L(A2) e L(A2)  L(A1); L(A1)  L(A2) se e solo se
L(A1)  (L(A2)) = , dove L(A2) indica il complemento di L(A2)).
Quindi in particolare è decidibile se un generico A riconosce L1.
2. Il problema è non solo decidibile ma anche banalmente deciso sulla base del fatto che L2 è
(deterministico) non-contestuale ma non regolare; quindi nessun automa a stati finiti può
riconoscerlo.
3. Il problema non è decidibile in base al teorema di Rice; infatti l’insieme delle MT che riconoscono
L1 (risolvono il problema rappresentato da L1) palesemente non è né l’insieme vuoto né l’insieme
universo.
4. Lo stesso ragionamento vale per L2.
Osservazione a latere: essendo decidibile il problema dell’equivalenza tra automi a pila deterministici
(risultato relativamente recente e di molto complessa dimostrazione!) il problema di stabilire se un generico
automa a pila deterministico riconosca L1 o L2 è decidibile poiché entrambi i linguaggi sono deterministici
noncontestuali.
Esercizio 3
Basta vedere i fattori w come numeri binari, per comodità con le cifre meno significative a sinistra, dove ad
es a=0 e b=1. Si utilizza una cella di memoria per codificare w (es. M[1]), moltiplicando per 2 tutte le volte
che si legge una nuova cifra, e sommando 1 se essa è b. Alla lettura della prima c si codifica in maniera
analoga il secondo fattore w in M[2]. Alla seconda c si controlla che M[1] sia uguale ad M[2], poi si
procede a codificare il fattore w finale in M[1]; l’ultimo controllo M[1]=M[2] avviene a fine stringa.
La complessità spaziale risulta pari a (1) a criterio costante e (log(n)) a criterio logaritmico, con n
lunghezza della stringa in ingresso.
Esercizio 4
E’ possibile ispirarsi all’algoritmo del counting sort e utilizzare un array ausiliario B di n+2 valori booleani
(0 e 1), tale che B[i] = 1 se i è presente nell’array; altrimenti B[i] = 0. L’algoritmo risultante (riportato di
seguito) ha complessità Θ(n).
void mancanti(int A[], int n)
{
int i, trovati = 0;
int B[n+2];
for (i=0; i< n+2; i++)
B[i] = 0;
for (i=0; i < n; i++)
B[A[i]] = 1;
i=0;
while (i < n+2 && trovati < 2) {
if (B[i] == 0) {
print(i);
trovato++;
}
}
}
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere (modulo Informatica teorica)
23 Novembre 2015
Il tempo a disposizione è di 1 ora e 45 minuti.
Esercizio 1 (punti 7/15 senza la parte c, 8/15 con la parte c)
Parte a.
Si consideri il gioco della roulette. Un giocatore adotta la seguente strategia:
 inizialmente punta 1€ sul rosso;
 a ciascuna estrazione successiva punterà sempre sul rosso;
 in particolare, se esce il nero, il giocatore perde la posta e al prossimo turno raddoppierà la
puntata; altrimenti vince il doppio di quanto ha puntato e al prossimo turno punterà tutta la
vincita.
Modellare il comportamento del giocatore con un automa a potenza minima (tra le classi FSA,
DPDA, NDPDA e TM) che riceva in ingresso una stringa costruita sull’alfabeto {R,N} (dove R
indica che è uscito il rosso e N che è uscito il nero) e che la accetti se e solo se il giocatore che abbia
puntato secondo la strategia indicata nelle estrazioni corrispondenti ai simboli in ingresso è in attivo
(ossia le vincite superano gli importi complessivamente puntati).
Parte b.
Qual è il linguaggio accettato da tale automa?
Parte c.
Cambierebbe la classe dell’automa richiesto se la strategia fosse modificata in modo che, quando
esce il rosso, al turno successivo il giocatore punti solo 1€?
Esercizio 2 (Punti 5/15)
Il predicato binario succ indica che i suoi argomenti sono numeri naturali tali per cui il secondo è il
successore del primo. Ad esempio, succ(1,2) è vero mentre succ(2,6) è falso.
Si specifichi in logica del prim’ordine il predicato ternario somma, che indica che il terzo
argomento è la somma dei primi due. Ad esempio, somma(2,3,5) è vero mentre somma(3,6,2) è
falso.
Nella specifica del predicato somma non si può fare uso di predicati diversi da succ e dal predicato
di uguaglianza. Inoltre, non si possono usare funzioni aritmetiche (ad esempio il +…). E’ invece
consentito l’uso di costanti che indicano numeri naturali (0, 1, 2, …).
Esercizio 3 (punti 5/15)
Si consideri il seguente programma P codificato in uno pseudolinguaggio ispirato al C.
P:
{
int x, y, z;
read (x, y, z);
while (x != y) {
x = x - y;
z = z + y};
write z; }
Sia f(x, y, z) la funzione calcolata da P. Si dica, giustificando brevemente la risposta, se la seguente
funzione:
g(x, y, z) = 1 se f(x,y,z) ≠, 0 altrimenti
è calcolabile o no.
Tracce di soluzioni
Esercizio 1
Parte a.
La strategia delle puntate è fatta in modo tale che, se il giocatore vince, vince necessariamente
almeno 1€ in più di quanto può aver perso complessivamente in precedenza; se perde, perde
necessariamente almeno 1€ in più di quanto ha vinto in precedenza. E’ sufficiente pertanto un
semplice FSA per modellare questo comportamento.
Parte b.
Il linguaggio riconosciuto dall’automa è composto da tutte e sole le stringhe che terminano con una
R.
Parte c.
Sì, occorre un formalismo più potente. In questo caso non c’è più la garanzia di essere in perdita
dopo l’uscita del nero, in quanto ci possono essere state vincite precedenti che compensano
largamente la perdita. Occorrerebbe pertanto tenere conto sia di quanti euro sono stati puntati in
precedenza, sia dell’entità della puntata corrente, o comunque di poter ricostruire il bilancio attuale
del giocatore (negativo o positivo e arbitrariamente grande), il che eccede il potere espressivo di un
automa a stati finiti.
Esercizio 2
xyz (somma(x,y,z)  ((y=0  x=z)  (y’z’ succ (y’,y)  succ (z’,z)  somma(x,y’,z’))))
Esercizio 3
L'esecuzione di P termina se e solo se i dati forniti in ingresso sono tali che x e y siano dello stesso
segno, x sia ≥ y se entrambi positivi o viceversa se entrambi negativi, e sia, in modulo, un suo
multiplo; più precisamente:
g(x, y, z) = 1 se
x=y

((x > y > 0  x < y < 0)   k (k > 1  |x| = k.|y|))
0 altrimenti
ed è evidentemente calcolabile.
Algoritmi e Principi dell'Informatica
Prima Prova in Itinere (modulo Informatica teorica)
23 Novembre 2015
English version
Total available time: 1h 45'.
Exercise 1 (7/15 points without part c, 8/15 with it)
Part a.
Consider the roulette game. A player adopts the following strategy:
 She first bids 1€ on the red;
 All her following bids will be on the red;
 In particular, if black wins, the player loses all her bid money, and at the next step she will double her bid;
otherwise, she wins twice the value of her bid, and the next time she will bid all the money won.
Please model the player's behavior with an automaton having minimal accepting power (among the classes FSA, DPDA,
NDPDA, and TM).
Such automaton gets as input a string on the alphabet {R, B} (where R stands for Red and B for Black), and accepts if
and only if the player won more money than she bid.
Part b.
What is the language of the automaton?
Part c.
Consider a variant of the strategy where the player, when she wins with the red, at the following step will bid only 1€. In
this case, does the automaton class change? Please, explain your answer.
Exercise 2 (5/15 points)
A binary predicate succ denotes that its arguments are natural numbers such that the second is the successor of the first.
For instance, succ(1,2) is true, while succ(2,6) is not.
Please write a first-order logic formula that defines the ternary predicate sum, which holds if and only if its third
argument is the sum of the previous two arguments. E.g. sum(2,3,5) is true, while sum(3,6,2) is not.
In your formula, you cannot use other predicates from succ and =; moreover, you cannot use arithmetic functions such
as +, ... It is possible to use constants (e.g. 0, 1,...).
Exercise 3 (5/15 points)
Consider the following program P, written in a pseudo-C language:
P:
{
int x, y, z;
read (x, y, z);
while (x != y) {
x = x - y;
z = z + y};
write z; }
Let f(x, y, z) be the function computed by P. Is the following function g computable?
g(x, y, z) = 1 if f(x,y,z) ≠, 0 else
Please, explain your answer.
Algoritmi e Principi dell'Informatica
Seconda Prova in Itinere
3 Febbraio 2016
Avvisi importanti
Il tempo a disposizione è di 1 ora e 45 minuti.
Esercizio 1 (punti 6/15-esimi)
Si consideri il linguaggio L = {cm al1 b al2 b ... alm b ... alz b dn | n, m, li, z > 0, lm = n}.
Per esempio ccaaabaaaabababdddd L.
Si descrivano una macchina di Turing e una macchina RAM che accettano L, calcolandone le
complessità spaziali e temporali, sia a criterio di costo costante che logaritmico.
Esercizio 2 (punti 11/15-esimi)
Si consideri la gestione delle tabelle hash mediante indirizzamento aperto. E’ noto che in tal caso
per eliminare un elemento della sequenza di ispezione associata a una chiave k non basta
assegnargli il valore NIL, perché altrimenti si “romperebbe la catena”. Un rimedio normalmente
utilizzato in questi casi consiste nel marcare l’elemento come Deleted, in modo tale che la ricerca di
altri elementi lungo la sequenza non si debba interrompere.
In questo modo però, a lungo andare si genera una forma di “garbage” che ovviamente diminuisce
la memoria disponibile e peggiora anche le prestazioni temporali.
Si progetti un algoritmo di Compattamento il quale, per una data tabella T (per semplicità la si
consideri una variabile globale), ricevendo come argomento una chiave k, elimini dalla sequenza
associata alla chiave k tutti gli elementi marcati come Deleted ricompattando così la sequenza e
recuperando la memoria inutilizzata.
NB: se l’algoritmo elimina anche altri elementi Deleted oltre a quelli indicati, il risulato è
ugualmente accettabile (anzi, è addirittura preferibile); purché non interrompa alcuna sequenza.
Si rammenta che la notazione T[p], data una posizione p della tabella, restituisce NIL, Deleted, o k,
ossia la chiave contenuta nella posizione, se questa non è né Deleted né vuota. Si assuma inoltre che
la funzione h(k, i) sia del tipo h(k, i) = (f(k) + g(i)) mod m con g(0) = 0 (non si tratta quindi di
doppio hashing) con f e g funzioni calcolabili in tempo costante.
Si valuti la complessità asintotica dell’algoritmo.
Parte opzionale (ulteriori 2punti)
L’algoritmo prodotto è applicabile anche al caso in cui la funzione h sia una funzione di tipo doppio
hashing? Giustificare brevemente la risposta.
Tracce di soluzioni
Esercizio 1
Entrambe le macchine devono contare i c in ingresso, la MT in unario e la RAM in una cella es.
M[1].
Alla prima a, si contano i gruppi di a separati da b, fino all’arrivo dell’m-esimo.
Si può usare M[1] o il nastro della MT a questo punto per contare il numero di a.
Si ignorano i successivi a e b, controllando solo che la sequenza finisca con b; fino all’arrivo dei d,
che devono essere pari al numero memorizzato in M[1] o nel nastro.
Complessità:
RAM (costo costante): T(n) = (n), S(n) = (1)
RAM (costo logaritmico): T(n) = (n log n), S(n) = (1og n)
MT: T(n) = (n), S(n) = (n)
Esercizio 2
Descrizione informale dell’algoritmo.
L’approccio naturale al problema consiste nello scandire completamente la sequenza associata a una
chiave k, ossia fino alla marca NIL; quando si incontra una posizione marcata Deleted si mette al
suo posto la posizione corrente marcando questa a sua volta come Deleted; quando la posizione
corrente raggiunge il NIL le eventuali posizioni intercorrenti tra l’ultima posizione aggiornata,ormai
solo Deleted, e il NIL vengono tutte messe a NIL.
In questo modo però si rischia di imbattersi in posizioni occupate da altre sequenze: in tal caso
sarebbe un errore spostarne il contenuto; quindi conviene accontonare questi elementi in una lista
temporanea e marcarli come Deleted, per poi reinserirli ex-novo a compattamento ultimato.
Siccome però la funzione di hash costruisce la stessa sequenza per ogni chiave con ugual valore di
f(k), è possibile e opportuno eliminare tutti gli elementi delle sequenze che hanno la stessa origine.
Pseudocodice
compact(k)
/*compattamento della lista associata alla chiave
(variabile globale) cui l’algoritmo viene applicato.
k;
T
denota
la
tabella
Sia h(k,i) la funzione di hash; T[p] indica il contenuto di T nella posizione p,
ossia NIL, Deleted, oppure la chiave presente in p.
In realtà il presente algoritmo “ripulisce” tutte le posizioni Deleted di tutte
le sequenze che hanno la stessa origine in h(k,0) mediante un semplice test;
poiché tali sequenze coincidono non si rischia di interrompere impropriamente
altre sequenze.
Per semplicità si assume che la sequenza termini comunque in un elemento NIL,
assunzione garantita, ad esempio, segnalando un overflow se in fase di
inserimento si giunge a un punto in cui h(k, i) = h(k, 0).*/
{
i = 0; PosCorrente = h(k,i);
while (T[PosCorrente] != NIL && T[PosCorrente] != Deleted)
{i++; PosCorrente = h(k,i); }
if (T[PosCorrente] == NIL) return; //non ci sono elementi Deleted
else // T[PosCorrente] è Deleted
{j = i; ProxDeleted = PosCorrente;
while (T[PosCorrente] != NIL)
{
while (T[PosCorrente] != NIL)
if (T[PosCorrente] == Deleted) {j++; PosCorrente = h(k,j)};
else
if h(T[PosCorrente],0)!= h(k,0)
{inserisci T[PosCorrente] in una lista temporanea TempL;
T[PosCorrente] = Deleted;
/*in questo modo gli elementi che non fanno parte di una
delle sequenze che hanno origine in f(k) vengono
accontonati
j++; PosCorrente = h(k,j)
};
/* si giunge a fine sequenza o al primo elemento non NIL e non
Deleted di una sequenza che ha origine in h(k,0)*/
if (T[PosCorrente] != NIL)
/*cioè PosCorrente appartiene a una sequenza che ha
origine in f(k)*/
{T[ProxDeleted] = T[PosCorrente];
T[PosCorrente] = Deleted;
i++; ProxDeleted = h(k, i)
}
else //l’elemento Deleted era l’ultimo della sequenza
{T[ProxDeleted] = NIL;}
}
/* a questo punto tutti gli elementi tra i e j sono deleted e si
possono porre a NIL*/
while (i != j) {T[h(k, i)] = NIL; i++;}
}
/* a questo punto non resta che reinserire in tabella gli elementi
accantonati che appartenevano a sequenze non originanti in f(k)*/
Forall elements k in TempL Insert(T, k)
}
Si noti che entrambi gli indici, i, e j utilizzati nel programma percorrono tutta la sequenza che parte
da h(k, 0), includendo anche gli elementi che non sono stati inserti a partire dalla chiave k ma che si
trovano in posizione h(k, i) per qualche i. Quindi la complessità della prima parte dell’algoritmo,
fino al reinserimento in T degli elementi di TempL, è O(n), n essendo la lunghezza complessiva
della sequenza. La complessità di quest’ultima parte è O(p.m), dove p è la lunghezza di TempL e m
la lunghezza dell’intera tabella, poiché ogni inserimento, nel caso pessimo costa O(r), con 1 <= r <=
m. E’ però probabile che nel caso medio anche questa parte dell’algoritmo abbia una complessità
più vicina a O(p) che a O(p.m) perché i nuovi inserimenti avverranno probabilmente in posizioni
rese disponibili dalla passata precedente.
Quindi la complessità totale dell’algoritmo è O(n+ p.m). Come sempre nel caso delle tabelle hash
nel caso pessimo “teorico” p  n  m e quindi si ha una complessità O(m2), caso comunque
solitamente lontano dal caso medio: normalmente si può ipotizzare p < n << m.
Parte opzionale
L’algoritmo sfrutta l’ipotesi che, se h(k1, 0) = h(k2, 0) per qualche chiave k1, k2, la sequenza
generata a partire da h(k1, 0) coincide con quella generata a partire da h(k2, 0); quindi confrontando
semplicemente l’origine della sequenza originata da f(k) con quella originata da f(k’) dove k’ è la
chiave contenuta nella posizione corrente, è possibile decidere se eliminare o meno l’elemento
contenuto; si noti che in tal modo si eliminano in un colpo solo tutti gli elementi Deleted dell’unica
sequenza originata in f(k) per tutte le chiavi con lo stesso valore di f(k), nel caso di clustering
secondario.
Al contario, se si adotta un doppio hashing è possibile che esistano due chiavi k1, k2, e due indici i1,
i2, tali che h(k1, i1) = h(k2, i2), con h(k1, 0) = h(k2, 0) ma appartenenti a sequenze diverse e quindi
tali che si debba eliminare l’elemento appartenente all’una ma non all’altra.
Osservazione
Un algoritmo leggermente meno efficiente potrebbe più semplicemente accantonare in TempL tutti
gli elementi non Deleted e poi reinserirli. In questo caso il p della formula precedente sarebbe
maggiore e la passata di reinserimento in tabella rischierebbe di avvicinarsi maggiormente a una
complessità quadratica. Al solito, però si tatta di considerazioni di tipo “euristico”.
Soluzione alternativa
Lo pseudocodice seguente è sostanzialmente equivalente a quello precedente anche in termini di
complessità, ma fa uso di tre liste separate, ossia gli indici della sequenza, le chiavi delle sequenze
con origine in h(k,0), le chiavi delle sequenze non originanti in h(k,0).
compact_p(T, k):
i = 0
pos = hash(k, i, max)
while T[pos] != NIL && i < m
list_insert(indexes, pos)
if T[pos] != Deleted
currk = T[pos]
if hash(currk, 0) == hash(k, 0)
list_insert(keys, currk)
else
list_insert(others, currk)
T[pos] = NIL
i++
pos = hash(k, i, max)
curr = last(indexes)
i = 0
for x in keys
T[curr.value] = x
curr = curr.prev
for x in others
hash_insert(T, x)
Algoritmi e Principi dell'Informatica
Recupero della I Prova in Itinere (solo per Laureandi)
3 Febbraio 2016
Avvisi importanti
Il tempo a disposizione è di 1 ora.
Chi partecipa a questa prova, non potrà svolgere il successivo appello di Febbraio.
Esercizio 1 (punti 8/15-esimi)
Si consideri il linguaggio L = {cm al1 b al2 b ... alm b ... alz b dn | n, m, li, z > 0, lm = n}.
Per esempio ccaaabaaaabababdddd L.
Si definisca un automa (o grammatica, o rete di Petri) A a potenza minima tale che L(A) = L.
Esercizio 2 (punti 8/15-esimi)
Si dica, giustificando brevemente la risposta se le seguenti affermazioni sono vere o false:
1. E’ decidibile stabilire se una generica MT riconosce L (il linguaggio definito nell’esercizio
1)
2. E’ decidibile stabilire se il complemento di L è non contestuale.
3. E’ decidibile stabilire se, dati una rete di Petri PN 1-bounded -ossia tale che nelle marcature
raggiungibili da una marcatura iniziale non accada mai che un posto contenga più di un
token- e un automa a stati finiti A, essi siano equivalenti, ossia riconoscano lo stesso
linguaggio.
Tracce di soluzioni
Esercizio 1
Basta un automa a pila deterministico A.
A deve contare i c in ingresso, mettendo C sulla pila.
Alla prima a, si contano i gruppi di a separati da b, fino all’arrivo dell’m-esimo, eliminando una C
per ogni gruppo dalla pila.
A questo punto si impila A per ogni a trovato, fino alla prima b.
Si ignorano i successivi a e b, controllando solo che la sequenza finisca con b; all’arrivo dei c si
spilano le A, controllando che siano pari alle c.
Esercizio 2
1. NO (Teorema di Rice)
2. Sì (Problema chiuso e deciso (L riconosciuto da APD; ling. CF det. Chiusi rispetto al
complemento)
3. Sì: Le PN 1-bounded sono equivalenti agli automi a stati finiti e l’equivalenza tra ling.
Regolari è decidibile.
Algoritmi e Principi dell’Informatica
Appello del 25 Febbraio 2016
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1
(Punti 9)
1) Si definisca formalmente il seguente modello di automa, chiamato macchina di Turing monodirezionale
ad un nastro (MTM1).
Una MTM1 è un accettore nondeterministico (non effettua quindi traduzioni) dotato di un nastro di ingresso
e un nastro di memoria. Il funzionamento è analogo a quello di una MT tradizionale, a parte il movimento
delle due testine dei nastri: esso può essere solamente S (stop) o R (right).
2) Si confronti la capacità espressiva delle MTM1 con i modelli visti a lezione.
3) Si consideri una variante “a nastro singolo” e deterministica della MTM1 e se ne valuti l'eventuale
differenza di capacità espressiva.
Esercizio 2
(Punti 8)
Si consideri il seguente insieme.
S = { i | La macchina di Turing Mi termina la sua esecuzione in meno di 100 passi per qualche ingresso }
S è ricorsivamente enumerabile? S è ricorsivo? Giustificare brevemente le risposte.
Esercizio 3
(Punti 7)
Sia dato un insieme di n interi distinti. Si descriva un algoritmo che restituisce il k-esimo elemento più
piccolo e se ne valuti la complessità; ovviamente la valutazione della soluzione proposta terrà conto della
complessità ottenuta. Nella specifica della soluzione è possibile far riferimento ad algoritmi noti,
specificandone con precisione funzionalità e complessità.
Esercizio 4 (Punti 9)
Sia T un albero binario. Sia t un suo nodo e siano t.left e t.right il sottoalbero sinistro e destro di t.
Denotiamo con nodi(t) il numero di nodi del sottoalbero radicato in t.
Un albero binario si dice perfettamente bilanciato quando per ogni suo nodo t la differenza tra il numero
dei nodi dei due sottoalberi di t è in valore assoluto al più 1:
| nodi(t.left) - nodi(t.right)| ≤ 1.
Si definisca un algoritmo che, dato in input un nodo t, verifica se l’albero radicato in t è perfettamente
bilanciato. Si discuta la complessità dell’algoritmo definito.
Tracce di soluzioni
Esercizio 1
1)
A = <Q, , , q0, F, , Z0>, stato iniziale q0  Q, stati finali F  Q
Funzione di transizione : (Q – F)      (Q    {S, R}2)
Configurazione: per comodità usiamo come seconda componente la stringa in ingresso ancora da leggere
(cioè la parte destra della stringa, testina inclusa); per la terza componente, che rappresenta il nastro,
indichiamo la parte scritta e visitata dalla macchina (cioè la parte sinistra, testina inclusa).
<q, a.x, y.b> |-- <q’, a’.x, y.b’.c>, se (q’, b’, m1, m2)  (q,a,b) dove
a’ =  se m1 = R altrimenti a’ = a
c =  se m2 = S altrimenti c = _ (blank)
x  L(A) sse <q0, x, Z0> |-*- <qF, x’, y>, qF  F.
2) Una MTM1 accede solo ad una cella di memoria (quella corrente) e non può in alcun modo ritornare sulla
parte sinistra del nastro di memoria. Questa informazione è finita ( ) e può essere facilmente codificata
nello stato dell’organo di controllo. Per questo motivo le MTM1 definiscono tutti e soli i linguaggi Regolari.
3) L’uso di un unico nastro e del determinismo non cambia nulla.
Esercizio 2
S è ricorsivo (e quindi anche ricorsivamente enumerabile). Infatti basta verificare se la macchina si
arresta entro 99 passi per qualche stringa di lunghezza <100. Tali stringhe sono in numero finito,
quindi la verifica avviene in un numero finito di passi. Non occorre considerare stringhe più lunghe
perché, se anche ci fosse una stringa più lunga di 100 caratteri tale per cui la macchina si arresti in
meno di 100 mosse, e quindi avendo letto un prefisso di lunghezza minore di 100, necessariamente
vi sarebbe anche una stringa con lo stesso prefisso ma lunga meno di 100 che farebbe arrestare la
macchina nello stesso numero di mosse.
Si noti che in questo caso non è applicabile il teorema di Rice, in quanto la proprietà delle macchine
di Turing considerate per l’insieme S (terminare in meno di 100 passi per qualche ingresso) non è
una proprietà della funzione calcolata, bensì una proprietà strutturale della macchina.
Esercizio 3
Questo problema prevede diverse soluzioni. Ne riportiamo alcune:
- è possibile ordinare l’insieme usando uno degli algoritmi classici di ordinamento (O(n log n), non
potendo fare alcuna assunzione sui valori dell’insieme), quindi restituire i primi k elementi;
- è possibile far uso di una coda di priorità. Si invoca k volte la removeMin(). Si restituisce in
output il valore trovato con l’ultima chiamata. Se la coda di priorità è implementata tramite un minheap, allora la costruzione dello heap ha complessità O(n). Il costo delle k invocazioni di
removeMin() è O(k log n). Si ottiene quindi complessità totale in O(n + k log n).
- è possibile utilizzare algoritmi specifici per la selezione, come il quickselect deterministico
(BFPRT), la cui complessità è lineare nel numero di elementi dell’insieme (O(n)).
Esercizio 4
Ci sono diverse soluzioni con complessità Θ(n) (n essendo il numero di nodi nel sottoalbero considerato),
tutte basate sulla visita in post-ordine del sottoalbero. Riportiamo di seguito una soluzione “intuitiva”, che
ha complessità temporale Θ(n) e che: i) fa uso di memoria aggiuntiva per memorizzare in ogni nodo il
numero di nodi del suo albero; ii) visita l’albero due volte: una prima volta per calcolare il numero dei nodi
(funzione count(t)) e una seconda volta per verificare il bilanciamento. È possibile definire algoritmi più
“compatti”, che attraversano l’albero una sola volta, restituendo a ogni chiamata ricorsiva il conteggio dei
nodi del sottoalbero visitato e il risultato della verifica di bilanciamento per il sottoalbero. Per tale classe di
soluzioni è necessario fare attenzione al conteggio dei nodi nei vari sottoalberi, per evitare di considerare
più volte gli stessi nodi. Questo, infatti, comporterebbe un numero maggiore di chiamate ricorsive e il
conseguente incremento della complessità.
boolean checkBalance(TREE t) {
count(t);
return checkBalanceRic(t);
}
integer count(TREE t) {
if t = nil
return 0
t.count = count(t.left) + count(t.right) + 1
return t.count
}
boolean checkBalanceRic(TREE t) {
integer nodiL = 0, nodiR = 0
boolean balancedL = true, balancedR = true
if t.left != nil {
nodiL = t.left.count
balancedL = checkBalanceRic(t.left)
}
if t.right != nil {
nodiR = t.right.count
balancedR = checkBalanceRic(t.right)
}
return (balancedL AND balancedR AND (|nodiL – nodiR| <= 1)
}
Algoritmi e Principi dell’Informatica
Appello del 30 Giugno 2016
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1
(Punti 8)
Scriva una formula logica del prim’ordine che formalizzi la frase seguente:
Tutte le volte che mangio del salame entro 24 ore mi viene mal di pancia, a meno che, prima che
sopraggiunga il mal di pancia, non prenda una pillola gastroprotettrice.
Si supponga, per semplicità, che mangiare salame sia un evento isolato nel tempo e che non possa
ripetersi più di una volta nell’arco di 24 ore.
Suggerimento (non imposizione!)
Si consiglia di far uso, non necessariemtne esclusivo, dei seguenti predicati, tutti parametrici rispetto alla
variabile t:



Salame(t): mangio del salame al tempo t
MalPancia(t): mi viene mal di pancia
Pillola(t): assumo una pillola
La variabile t può essere interpretata indifferentemente in un dominio discreto o continuo.
Esercizio 2
(Punti 7)
Siano L1, L2, .. Lk, k > 1 linguaggi definiti su un alfabeto , tali che valgano le seguenti proprietà:
 i ≠ j, Li  Lj = ,
 L1  L2  …  Lk = *,
  i, Li è semidecidibile.
Si dica, giustificando brevemente la risposta se le seguenti affermazioni sono vere o false:



Tutti i linguaggi L1, L2, .. Lk sono ricorsivi
E’ possibile che alcuni di essi siano regolari
Tutti i linguaggi L1, L2, .. Lk sono necessariamente regolari
Esercizio 3
(Punti 7)
Si definisca una MT a k nastri che riconosca il linguaggio L = {www | w  {0,1}+} e se ne valutino
le complessità spaziale e temporale.
Esercizio 4 (Punti 8)
In un albero binario, il grado di sbilanciamento di un nodo può essere calcolato come valore
assoluto della differenza fra il numero di foglie presenti nei suoi due sottoalberi. A partire da tale
valore calcolato per ogni nodo, è possibile ricavare un grado di sbilanciamento di un albero come
il massimo tra i gradi di sbilanciamento calcolati per tutti i suoi nodi.
Per esempio, dato il seguente albero binario, per il quale si riportano anche i gradi di sbilanciamento
(gs) dei singoli nodi:
il grado di sbilanciamento per l’albero radicato in A è 2, poiché questa è la differenza massima del
numero di foglie nei due sottoalberi di A (quella cioè calcolata per il sottoalbero radicato in C).
Si definisca un algoritmo per il calcolo del grado di sbilanciamento di un albero binario; se ne
discuta quindi la complessità.
Tracce di soluzioni
Esercizio 1
Soluzione A
I seguenti predicati
salame(t), malPancia(t), pillola(t) sono usati con l’ovvio significato. La frase dell’esercizio è allora
formalizzata come segue:
 t (salame(t) 
 t1( t < t1 <= t +24   salame(t1)) 
(
( t1 ((pillola(t1)  ( t2 ( t < t2 < t1   malPancia(t2))) 
 t1( t <= t1 <= t +24   malPancia (t))

( t3 (t <= t3 <= t +24  (( t2 ( t < t2 < t3  pillola(t2))  malPancia(t3))
)
)
Soluzione B
t (salame(t) 
 t1( t < t1 <= t +24   salame(t1)) 
(
t1 (t ≤ t1 ≤ t +24  pillola(t1)  t2 ( t ≤ t2 ≤ t+24  malPancia(t2)))

t1 (t ≤ t1 ≤ t +24  malPancia(t1)  t2 ( t ≤ t2 ≤ t1  pillola(t2)))
)
)
Esercizio 2


Poiché i linguaggi sono tra loro disgiunti e la loro unione è l’intero *, enumerando tutte
stringhe di L1, L2, .. Lk nell’ordine 1, 2, …k, (ossia, una stringa di L1, una stringa di L2, …)
prima o poi una qualsiasi string x deve comparire in una e una sola delle sequenze Li, e
quindi si può decidere a quale linguaggio appartiene.
E’ certamente possibile che qualche o anche tutti gli Li, siano regolari, ma non necessario.
Esercizio 3
1) La MT fa una prima passata sulla stringa in ingresso (sia essa x) e sul nastro 1 memorizza un
simbolo X ogni 3 caratteri letti – in questo modo viene calcolata la lunghezza del fattore w
in unario.
2) Alla seconda passata la macchina copia il fattore w sul nastro 2, sfruttando il nastro 1 per
vedere quando esso termina. Continua poi la lettura, controllando che il secondo e il terzo
fattore w siano identici a quanto salvato nel nastro 2.
Complessità spaziale: vengono memorizzate 2 stringhe di lunghezza n/3, S(n) = (n), con n = |x|.
Complessità temporale: la macchina effettua 2 scansioni lineari di x, T(n) = (n).
Esercizio 4
È possibile definire una funzione ricorsiva che usa una visita in post-ordine per calcolare, per ogni
nodo dell’albero, il numero di foglie e il massimo grado di sbilanciamento del sottoalbero radicato
nel nodo. Facciamo uso di una struttura per memorizzare i due valori calcolati in ogni chiamata
ricorsiva; restituiamo la struttura come valore di ritorno della funzione ricorsiva.
typedef struct{
int leafs;
int maxUnbalance;
}Result;
Result unbalanceFactor(TREE T) {
Result Res, L, R;
if (T == nil) {
Res.leafs=0;
Res.maxUnbalance=0;
return Res;
}
if ((T.left == nil) and (T.right == nil )) {
Res.leafs = 1;
Res.maxUnbalance=0;
return Res;
}
L = unbalanceFactor(T.left);
R = unbalanceFactor(T.right);
Res.leafs = L.leafs + R.leafs;
Res.maxUnbalance = max(L.maxUnbalance, R.maxUnbalance,
abs(L.leafs − R.leafs));
return Res;
}
La complessità dell’algoritmo è la stessa di una visita di un albero, cioè O(n).
Algoritmi e Principi dell’Informatica
Appello del 1 Settembre 2016
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1
(9 punti)
1. Si costruisca un automa, preferibilmente a minima potenza riconoscitiva, che accetti il
linguaggio L1  {a,b}* costituito da tutte e sole le stringhe w tali che, se w contiene la
sottostringa aa, allora la sua lunghezza è dispari.
2. Si determini la famiglia di automi a potenza riconoscitiva minima -o minimale- tale che un suo
membro riconosca il linguaggio L2  {a,b,c}*, costituito da tutte e sole le stringhe w tali che w
includa la stringa canc (per qualche n > 0) e, successivamente, la stringa ba2nb (la stringa w può
contenere altre sottostringhe oltre alle suddette canc e ba2nb).
a. Si costruisca un automa in tale famiglia che riconosca L2;
b. Si costruisca una grammatica, preferibilmente a minima potenza generativa, che generi
L2.
Esercizio 2 (8 punti)
Per entrambi i punti seguenti si assuma che L sia un linguaggio infinito costruito su un alfabeto A.
1. Sia L un linguaggio ricorsivo.
Esiste necessariamente una enumerazione algoritmica E che enumera tutte le stringhe di L in
ordine lessicografico? Motivare brevemente la risposta.
2. Sia E una enumerazione algoritmica E che enumera tutte le stringhe di un linguaggio L in
ordine lessicografico.
L è necessariamente ricorsivo? Motivare brevemente la risposta.
Esercizio 3 (7 punti)
Si descriva una MT a k nastri che, dato in input un valore n naturale maggiore di 0 codificato in
unario, produce in output le prime n potenze di 4, cioè 40, 41, 42, ... 4n-1, ognuna codificata in
binario e seguita dal simbolo #.
Dare le complessità temporale e spaziale della MT ideata.
Esercizio 4 (8 punti)
E’ noto che il Quicksort ha un comportamento nel caso pessimo O(n2); ad esempio la versione
presentata nel corso (e fornita dal testo) ha complessità O(n2) quando l’array in input è già
totalmente ordinato.
1. Si modifichi il codice della versione suddetta, riportata qui sotto per comodità, in modo che
la complessità di esecuzione, se A è già ordinato, risulti O(n⋅log(n)).
NB: la nuova versione deve essere esclusivamente una modifica dell’algoritmo originario,
non includere altri (sotto)algoritmi più adatti al caso specifico.
2. Qual è la complessità asintotica della nuova versione nel caso pessimo? Descrivere come è
fatto il caso pessimo, illustrandolo con un esempio.
QUICKSORT(A, p, r)
1 if p < r
2
q := PARTITION(A, p, r)
3
QUICKSORT(A, p, q−1)
4
QUICKSORT(A, q+1, r)
PARTITION(A, p, r)
1 x := A[r]
2 i := p − 1
3 for j := p to r − 1
4
if A[j] ≤ x
5
i := i + 1
6
swap A[i] ↔ A[j]
7 swap A[i+1] ↔ A[r]
8 return i + 1
Tracce delle soluzioni
Esercizio 1
1. Il seguente automa a stati finite riconosce L1.
2. Un automa a stati finiti non è evidentemente in grado di riconoscere L2 a causa della necessità di
un conteggio illimitato. Neanche un automa a pila deterministico è in grado di operare il
riconoscimento perché una stringa del linguaggio può contenere diverse sottostringhe del tipo canc,
di cui solo una abbia una corrispondente sottostringa ba2nb come ad esempio nella stringa
acaaacbbcaccbaabc.
E’ anche possibile costruire una rete di Petri che riconosca L2; quindi, siccome PDA e reti di Petri
hanno potenza riconoscitiva incomparabile, vi sono almeno due famiglie di automi, tra quelle
classiche, a potenza riconoscitiva minimale, in grado di formalizzare L2.
a.
b. S → XDX
D → caEaab
E → aEaa | aXb
X → aX | bX | cX | 
Esercizio 2
1) L è ricorsivo, quindi esiste un “decisore” per L, cioè una macchina di Turing M che termina
sempre e scrive 1 in uscita se la stringa in ingresso appartiene a L, 0 altrimenti. L’enumerazione
algoritmica E richiesta si ottiene come segue: basta enumerare tutte le stringhe di A* in ordine
lessicografico (cosa sempre possibile) e, per ciascuna di esse, testarne l’appartenenza ad L tramite
M (che è disponibile per ipotesi), stampandola in uscita solo se appartiene a L.
2) L è enumerabile algoritmicamente mediante E in ordine lessicografico. Si può quindi costruire un
decider M per L come segue: quando riceve una stringa x in ingresso, M esegue l’enumerazione E e
legge la lista di tutte le stringhe di L in ordine lessicografico fino a che non compare una stringa che
lessicograficamente stia dopo x (tale stringa deve necessariamente esistere, perché L è infinito). Se
x è apparso nell’enumerazione, allora M stampa 1 in uscita, altrimenti stampa 0.
Esercizio 3
Per produrre i valori desiderati è sufficiente una MT a 1 nastro di memoria, che funziona nel
seguente modo:





Legge un simbolo dal nastro in ingresso.
Scrive 1 sul santro di output.
Copia tutti gli 0 (leggendoli da sinistra a destra) dal nastro di memoria al nastro di output, ed
aggiunge in fondo al nastro di output un #.
Mette due 0 sul nastro di memoria (la testina è ora in fondo al nastro di memoria).
Torna all’inizio del nastro di memoria, leggendo gli 0 da destra a sinistra, e poi ricomincia
da capo.
Per il calcolo della complessità spaziale conta solo il nastro di memoria, non il nastro di input, né
quello di output, quindi la complessità è Θ(n).
Per il calcolo della complessità temporale, il costo della i-esima iterazione del ciclo è Θ(2i), quindi
il costo totale è ∑i={1..n} 2i, che è Θ(n2).
Esercizio 4
1. Il comportamento dell’algoritmo è determinato dalla scelta del “pivot” che nel nostro caso è
l’ultimo elemento dell’array. Perciò se l’array è già ordinato la partizione è totalmente
sbilanciata. In questo caso perciò conviene scegliere come pivot l’elemento mediano, in
modo che la partizione lasci inalterato l’array e così via ricorsivamente ottenendo una
complessità O(n⋅log(n)). La modifica dell’algoritmo in tal senso può semplicemente
consistere nel premettere al codice di PARTITION l’istruzione
k = (r + p)/2
e usare A[k] come pivot, ossia scambiare A[k] con A[r]. Alla fine della partizione,
l’array tornerà nella permutazione originaria già ordinata e così via ricorsivamente.
2. Ovviamente anche la versione così modificata ha un comprtamento O(n2) nel caso pessimo
che si verifica quando l’array è tale che il pivot è sempre il massimo dell’array che rimane
da ordinare. Quindi, prendendo come esempio un array di lunghezza pari, l’elemento di
mezzo è il massimo, il secondo elemento più grande è l’ultimo, ecc. Un esempio di tale
array è [2, 4, 6, 8, 10, 5, 3, 7, 1, 9], che dà luogo alla seguente sequenza di chiamate (la parte
non in grassetto è l’array di sinistra in ogni successiva chiamata di Quicksort, la parte in
grassetto sono i pivot, e l’array di destra è sempre vuoto):
[2, 4, 6, 8, 10, 5, 3, 7, 1, 9]
[2, 4, 6, 8, 9, 5, 3, 7, 1, 10]
[2, 4, 6, 8, 1, 5, 3, 7, 9, 10]
[2, 4, 6, 7, 1, 5, 3, 8, 9, 10]
[2, 4, 6, 3, 1, 5, 7, 8, 9, 10]
[2, 4, 5, 3, 1, 6, 7, 8, 9, 10]
[2, 4, 1, 3, 5, 6, 7, 8, 9, 10]
[2, 3, 1, 4, 5, 6, 7, 8, 9, 10]
[2, 1, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Algoritmi e Principi dell’Informatica
Appello del 15 Settembre 2016
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (8 punti)
In matematica, si definiscono numeri primi gemelli due numeri primi che differiscano tra loro di 2.
La congettura dei numeri primi gemelli afferma che esistono infinite coppie di numeri primi
gemelli.
Specificare tale congettura mediante una formula di logica del prim’ordine. Nella specifica è
consentito utilizzare:
 come funzioni, le usuali quattro operazioni aritmetiche;
 come costanti, i numeri naturali 0, 1, 2, …;
 come predicati, il predicato di uguaglianza (=), i comparatori (<, >, , ) e un predicato
unario nat che indica che il suo argomento è un numero naturale.
È inoltre possibile, e consigliabile, specificare dei predicati ausiliari per render più agevole la
scrittura e la comprensione della formula; tuttavia la semantica di tali predicati dovrà essere
esplicitamente definita mediante opportune formule che facciano riferimento ai simboli base di cui
sopra.
Esercizio 2 (9 punti)
Punto a)
Ad oggi, la più grande coppia di numeri primi gemelli trovata è 3756801695685 · 2666669 ± 1. Si
tratta di numeri con ben 200700 cifre, ma non è ancora stato dimostrato l’enunciato della
congettura, che potrebbe quindi anche essere falsa.
Che cosa si può concludere in merito alla decidibilità dell’enunciato della congettura?
Punto b)
Sia f una funzione definita come segue:
f(x) = 1 se esiste una coppia di numeri primi gemelli maggiori di x;
f(x) = 0 altrimenti.
La funzione f è calcolabile?
Esercizio 3 (9 punti)
Si consideri il linguaggio Lq di figure definito sull’ alfabeto {a, b}, composto da tutte e sole le
figure quadrate fatte da righe di soli simboli 'a' alternate a righe di soli simboli 'b', partendo con le
'a'.
Es.
aaaa
bbbb
aaaa
bbbb
Si descrivano esaurientemente due macchine di Turing che accettino Lq, una a k-nastri e una a
nastro singolo, sapendo che la figura è fornita sul nastro in ingresso riga per riga e senza separatori,
e se ne studino le complessità spaziali e temporali.
Esercizio 4 (7 punti)
Sia dato un vettore di interi, A, ordinato in ordine non decrescente. Sia dato inoltre un valore intero
v. Si definisca un algoritmo che verifichi se A contiene due elementi ai e aj tali che ai – aj = v. Il
punteggio dell’esercizio sarà commisurato alla complessità temporale dell’algoritmo.
Tracce delle soluzioni
Esercizio 1
Definisco per comodità un predicato che cattura il concetto di numero primo:
x (primo(x)  nat(x)  ¬yz x = yz  nat(y)  nat(z)  y>1  z>1)
La congettura è quindi specificata come segue:
x (nat(x)  yz y>x  primo(y)  z=y+2  primo(z))
Esercizio 2
Punto a)
Si tratta di una questione certamente decidibile poiché la formula che la specifica è chiusa.
Punto b)
Se la congettura dei numeri primi gemelli è vera, allora la funzione f vale costantemente 1, ed è
pertanto calcolabile.
Se la congettura è falsa, allora esiste un numero k oltre il quale non è più vero che esistono due
numeri primi gemelli (e prima del quale esistono). Pertanto la funzione f sarà fatta a “scalino”, e
sarà pari a 1 per ingressi minori di k, e pari a 0 per ingressi maggiori o uguali a k. Anche in questo
caso la funzione è certamente calcolabile.
Esercizio 3
Macchina a k-nastri:
si legge la prima sequenza di ‘a’ copiandole su 2 nastri di memoria; poi il primo nastro viene
utilizzato per contare il numero di elementi di ogni riga, mentre il secondo serve per contare il
numero di righe.
Chiaramente basta una passata sulla stringa in ingresso. Siano m gli elementi di una riga, la stringa è
lunga n = m2, mentre la memoria occupata risulta 2m.
Quindi: S(n) = (
), T(n) = (n).
Macchina a nastro singolo:
l’idea è controllare la lunghezza di ogni riga, cambiando di volta in volta le ‘a’ in ‘A’ e le ‘b’ in ‘B’
riga per riga, da sinistra verso destra, a parte i primi elementi di ogni riga che verranno cambiati in
‘X’. In questo modo possiamo controllare che tutte le righe siano lunghe uguali, facendo (nm)
mosse.
Per controllare che il numero di righe sia corretto, la macchina può controllare che il numero delle
‘X’ sia uguale al numero di ‘A’ della prima riga + 1, facendo ulteriori (nm) mosse (ad esempio
cambiandoli uno alla volta in altri simboli).
Quindi: S(n) = (n), T(n) = (n
).
Esercizio 4
Una soluzione banale, ma poco efficiente, controlla tutte le coppie, A[i], A[j], con 1 ≤ i < j ≤
A.lenght, per verificare se A[j] - A[i] = v. La complessità di tale soluzione è O(n2).
È possibile poi definire una soluzione con complessità O(n log n). Per ognuno degli n elementi
dell’array, A[i], si applica una ricerca binaria agli elementi successivi per cercare un elemento pari
a v+A[i].
CercaCoppia-RicercaBinaria (A, v) {
for i = 1 to A.length
if (RicercaBinaria(A[i + 1 . . . A.length], v + A[i]))
return true;
return false;
}
È infine possibile ottenere una soluzione più efficiente, di complessità O(n), scandendo gli elementi
in modo lineare tramite un opportuno incremento di due indici, i e j:
CercaCoppia-Lineare (A, v) {
i = 1;
j = 2;
while (j ≤ A.length)
if ((A[j] − A[i]) < v)
j = j + 1;
else if ((A[j] − A[i]) > v)
i = i + 1;
else return true;
return false;
}
A ogni iterazione, si incrementa j oppure i A ogni iterazione j ≥ i; si eseguono quindi O(n) iterazioni.
oppure
si
esce
dalla
funzione.
Algoritmi e Principi dell’Informatica
Prova in itinere del 24 novembre 2016
Il tempo per completare la prova è 1 h e 45 minuti.
Esercizio 1 (punti 7/15)
Si consideri un semplice linguaggio di programmazione LP1 che tratta solo interi (NB: l’insieme
matematico degli interi, non quello limitato del C) e array (non limitati a compile-time) di interi, ed
è dotato delle normali istruzioni di assegnamento (variabile = espressione), dell’istruzione
condizionale if-then-else e del ciclo while. Si consideri poi un linguaggio LP2 che differisce da LP1
in quanto invece del ciclo while ha il costrutto for definito da questa sintassi:
for <variabile di tipo intero> = <costante intera1> to <costante intera2> do {<corpo del ciclo>}
in cui <costante intera2>  <costante intera1>
e la cui semantica consiste in:




Inizializzare la variabile intera, diciamo i, con il valore <costante intera1>,
eseguire il corpo del ciclo,
incrementare di un’unità i,
uscire dal ciclo quando i è maggiore di <costante intera2>
NB1: il corpo del ciclo non può contenere assegnamenti ad i.
E’ decidibile il problema di stabilire se, dato un generico programma scritto in LP1 ne esiste un
altro ad esso equivalente in LP2? Spiegare brevemente la risposta.
Esercizio 2 (punti 5/15)
Specificare in logica del prim’ordine un predicato unario pal che indica che il suo argomento è una
stringa palindroma (cioè che non cambia se letta da sinistra verso destra o da destra verso sinistra)
servendosi esclusivamente dei seguenti predicati, funzioni e costanti:
•
•
•
•
il predicato unario char che è vero se e solo se il suo argomento è una stringa di lunghezza
1;
il predicato (binario) = che rappresenta l’uguaglianza tra stringhe;
la funzione binaria • che rappresenta la concatenazione di stringhe;
la costante ε, che rappresenta la stringa vuota.
Esercizio 3 (punti 4/15 per le parti a) e b), + 2 per la parte c); NB: la parte c) verrà valutata
solo per chi abbia svolto correttamente le due parti precedenti).
Si consideri il linguaggio L delle stringhe palindrome costruite sull’alfabeto {a,b} (per la
definizione di “palindromo” si veda l’esercizio precedente).
a) Definire una grammatica, a potenza generativa minima, che generi L.
b) Costruire un automa, a potenza riconoscitiva minima, che riconosca L.
c) Definire una grammatica, a potenza generativa minima, che riconosca il complemento di L.
Soluzioni
Esercizio 1
E’ ben noto che i costrutti base di LP1 sono sufficienti per dare al linguaggio la potenza della MT (è
un facile esercizio codificare una qualsiasi MT in LP1). Al contrario LP2 non ha tutta la potenza
della MT (tra l’altro i suoi programmi terminano sempre). Quindi i problemi (in questo caso
funzioni definite su numeri interi) risolvibili da LP2 sono un sottoinsieme proprio non vuoto dei
problemi ricorsivamente enumerabili. Se fosse possibille decidere il problema suddetto sarebbe
perciò anche possibile decidere se una generica MT risolve un problema della famiglia dei problemi
risolvibili con LP2, violando il teorema di Rice.
Esercizio 2
∀x (pal(x) ↔ x=ε ∨ char(x) ∨ ∃y∃z char(y) ∧ (y • z) • y = x ∧ pal(z))
Esercizio 3
a) S  aSa | bSb | a | b | ε
b) E’ sufficiente un NDPDA che, nondeterministicamente, individua il punto di mezzo del
palindromo (di un carattere, se la stringa è di lunghezza dispari, o di zero caratteri se la
stringa è di lunghezza pari). Non è possibile individuare tale punto deterministicamente
prima di aver letto interamente la stringa, quando è ormai troppo tardi per determinare se si
tratti di un palindromo.
a,A/AA
a,B/AB
a,Z0/AZ0
a,A/ε
b,B/ε
b,A/BA
b,B/BB
b,Z0/BZ0
q0
a,A/A
a,B/B
a,Z0/Z0
b,A/A
b,B/B
b,Z0/Z0
ε ,A/A
ε ,B/B
ε ,Z0/Z0
c)
S  aSa | bSb | aTb | bTa
T  Ta | Tb | a | b | ε
ε ,Z0/Z0
q1
q2
Algoritmi e Principi dell’Informatica
Midterm test, November 24th 2016
English version
The available time is 1 h and 45 minutes
Exercise 1 (score 7/15)
Consider a simple programming language LP1 that manages only the Integer data type (unlike languages
such as C, Integer is the infinite mathematical set of integers) and (unbounded) arrays of integers. LP1
contains exclusively:



Assignment statements (variable = expression)
Conditional statements (if-then-else)
while loops
Then, consider another language LP2 that differs from LP1 in that instead of while loops offers only for
loops defined as
for <integer variable> = <integer constant1> to <integer constant2> do {<body of the loop>}
where < integer constant2>  <integer constant1>
The execution of the for loop is specified as follows:




The integer variable, say i, is initialized with the value <integer constant1>
The body is executed
The variable i is incremented by 1
The loop is exited when i becomes greater than <integer constant2>
NB: the loop body cannot contain any assignment to the variable i.
Consider the problem of stating whether, given a generic program P1 coded by means of LP1, there exists
another program P2 in LP2 equivalent to P1. Is such a problem decidable? Explain briefly your answer.
Exercise 2 (score 5/15)
Give a first-order formula that specifies a unary predicat pal(x); pal(x) must be true if and only if x is a
palindrome, i.e. a string that is the same whether it is read left-to-right or right-to-left. Your formula can
make use exclusively of the following predicates, functions and constants, besides pal:




The unary predicate char, which is true if and only if its argument is a string of length 1;
The binary predicate ‘=’, which denotes string equality;
The binary function •, which denotes string concatenation;
The constant ε, which denotes the empty string.
Exercise 3 (score 4/15 for parts a) and b), + 2 extra points for part c). Notice however that
part c) will be evaluated only if the previous parts are correct.)
Let L be the language of palindromes (see previous exercise 2) over the alphabet {a,b}.
a) Write a grammar, belonging to the class of minimum possible generating power, that generates L.
b) Write an automaton, belonging to the class of minimum possible recognizing power, that recognizes L.
c) Write a grammar, belonging to the class of minimum possible generating power, that generates the
complement of L.
Algoritmi e Principi dell'Informatica
Seconda Prova in Itinere
31 Gennaio 2017
Avvisi importanti
Il tempo a disposizione è di 1 ora e 45 minuti.
Esercizio 1 (punti 7/15-esimi)
Si consideri un tipo di macchina di Turing (MT) con nastro di memoria bidimensionale consistente
nel primo quadrante del piano cartesiano intero (N  N) e nastro di ingresso monodimensionale.
Una mossa della MT può gestire il nastro di input come una normale MT a k nastri e spostare la
testina del nastro bidimensionale di una posizione in orizzontale o in verticale.
Si descriva, con sufficiente precisione, come una RAM possa simulare una tale MT e se ne valuti la
complessità temporale (al solito maggiorandone l’ordine di grandezza) in funzione della
complessità TM(n) della MT, ossia TR(n) O(f(TM(n))), usando sia il criterio di costo costante sia
quello logaritmico.
Esercizio 2 (punti 7/15-esimi)
Sia dato un vettore di n numeri reali non nulli. Si progetti un algoritmo che modifichi il vettore
spostando tutti gli elementi negativi prima di quelli positivi (senza introdurre alcun ordinamento
particolare tra i valori negativi e quelli positivi e senza necessariamente preservare l’ordinamento
originariamente presente nella sequenza di input). Si specifichi chiaramente l’algoritmo,
preferibilmente mediante pseudocodice, e se ne discuta la complessità. La valutazione terrà conto
della complessità computazionale della soluzione proposta.
Esercizio 3 (punti 4/15-esimi)
1.
Si consideri una variante della ricerca binaria, detta "ricerca ternaria", che divide la sequenza di input di n elementi
in 3 partizioni di dimensione n/3 (al solito a meno di arrotondamenti). Si determini e si risolva l’equazione alle
ricorrenze che esprime la complessità dell’algoritmo ricerca ternaria.
2.
Si consideri un’altra variante che divide la sequenza di input in due partizioni di dimensione n/3 e 2n/3. Si
determini e si risolva l’equazione alle ricorrenze per questa seconda variante.
NB: al solito la soluzione dell’equazione alle ricorrenze va fornita in termini di ordine di grandezza,
preferibilmente mediante la notazione .
Tracce di soluzioni
Esercizio 1
Una prima soluzione potrebbe consistere nel memorizzare il contenuto del nastro bidimensionale
“per righe” o “per colonne” come avviene nella memoria di un normale calcolatore per gli array.
Tuttavia, come accade quando un linguaggio di programmazione permette di variare le dimensioni
dell’array a run-time, ogni volta che la MT “entra in nuova riga o colonna” occorre spostare una
quantità di celle della memoria della RAMche è dell’ordine di grandezza dell’intera memoria al
momento in uso, con evidente aumento complessivo della complessità temporale.
Una soluzione più efficiente consiste invece nello sfruttare una corrispondenza biunivoca N  N
 N di tipo diagonale, ad esempio la classica
d ( x, y ) 
( x  y )( x  y  1)
x
2
In questo modo la RAM memorizza solo il contenuto delle celle effettivamente utilizzate dalla MT.
Più precisamente:
 Vengono allocate due celle x e y per memorizzare il valore corrente delle coordinate del
nastro di memoria della MT e n celle per copiare l’input della MT nella memoria della RAM
(richiede O(n)).
 La posizione della cella della RAM corrispondente a quella di coordinate <x, y> della MT è
quella calcolata dalla funzione d di cui sopra (sommato alle (O(n) celle allocate
inizialmente).
 Ogni mossa della MT è simulata dalla RAM nel modo seguente:
o Calcola m = d(x.y) (+ l’offset di cui sopra), in tempo costante o O(log(x) + log(y)) 
O(log(TM(n))) a seconda del criterio di costo adottato; a sua volta m è O(TM(n)).
o Sulla base del contenuto di m e dello stato della MT, simula la sua mossa
aggiornando il contenuto di m, dello stato e di x e y (in tempo costante o O(log(m)),
ossia O(log(TM(n))) a seconda del criterio di costo).
In conclusione la complessità temporale della RAM è O((TM(n)) a criterio di costo costante e
O(TM(n).log(TM(n))) a criterio logaritmico.
Esercizio 2
È possibile prendere spunto dalla procedura perno (o partition) di Quicksort considerando lo 0
come valore in base al quale individuare le due partizioni di valori negativi e positivi. Lo 0 è un
valore opportuno, visto che la sequenza iniziale non contiene valori nulli.
Così come previsto dalla funzione perno, è necessario scandire il vettore iniziale con due indici:
neg, che cresce dalle posizioni più basse a quelle più alte, e pos che decresce nel verso contrario.
Quando neg punta a un elemento positivo e pos a uno negativo si effettua uno scambio. Si prosegue
fino a quando i due indici non si incrociano (neg > pos), il che indica che il vettore è stato
interamente esaminato.
La complessità dell’algoritmo è la stessa della funzione perno (O(n)).
E’ possibile considerare anche un’altra soluzione di complessità O(n), ispirata al Counting sort.
Tale soluzione ricopia gli elementi in un secondo vettore, B, secondo il seguente criterio: gli
elementi negativi sono ricopiati in posizioni scandite dall’indice neg (che parte da sinistra ed è
incrementato ogni volta che un numero negativo è ricopiato in B); gli elementi positivi sono
ricopiati in posizioni scandite dall’indice pos (che parte da destra ed è decrementato ogni volta che
un numero positivo viene ricopiato in B).
Non è necessario utilizzare un terzo vettore, in quanto non abbiamo necessità di mantenere
l’ordinamento dei valori presente nella sequenza di input.
Ovviamente, si potrebbe utilizzare un algoritmo di ordinamento qualsiasi; questo tuttavia
implicherebbe una complessità Ω(n log (n)) per produrre un ordinamento totale dei valori che non è
invece richiesto.
Esercizio 3
Ricordiamo che la ricorrenza per la ricerca binaria può essere espressa come T(n) = T(n/2)+1. Questa equazione tiene
conto del costo per il confronto con l’elemento in posizione centrale, più il costo per la chiamata ricorsiva della funzione
su una delle due partizioni che tale elemento determina.
1.
L’algoritmo "ricerca ternaria" esegue due confronti con gli elementi in base ai quali si partiziona la sequenza in
tre sotto-sequenze di n/3 elementi. Quindi, si richiama ricorsivamente la funzione su una partizione.
Analogamente all’equazione della ricerca binaria, per la variante dell’algoritmo avremo T(n) = T(n/3) + 2. Tale
equazione può essere risolta con il Teorema dell’Esperto (secondo caso) e ha soluzione (log n).
2.
La seconda variante esegue un solo confronto per individuare le due partizioni di dimensione n/3 e 2n/3.
Il caso pessimo si verifica quando la chiamata ricorsiva opera sulla partizione più grande (2n/3 elementi). In
questo caso, la ricorrenza è T(n) = T (2n/3) + 1 e si risolve applicando il secondo caso del Teorema
dell’Esperto. Quindi, nel caso pessimo T(n) è (log n). Nel caso ottimo (l’ordine di) complessità è lo stesso;
quindi è possibile dire che la complessità dell’algoritmo è comunque (log n).
Algoritmi e Principi dell'Informatica
Second Test
January 31, 2017
The time to complete the test is 1 hour and 45 minutes.
Exercise 1 (7/15 points)
Consider a Turing machine (TM) equipped with a bi-dimensional memory tape, consisting of the first
quarter of the integer Cartesian plane (N  N) plus the input tape, which is mono-dimensional. A
transition of the TM manages the input tape as the usual k-tape machine and moves the memory head
by one position either vertically or horizontally.
Describe, with sufficient precision, how a RAM can simulate such a TM and evaluate the (order of
magnitude of the) complexity of the RAM as a function of the TM complexity, i.e., TR(n) O(f(TM(n)));
use both the constant and the logarithmic cost criteria.
Exercise 2 (7/15 points)
It is given an array of n real numbers other than 0. Design an algorithm that modifies the array by
moving all negative numbers before the positive ones. It is not necessary to sort the numbers nor is it
requested that the original ordering among them is preserved. The algorithm must be specified in a
clear enough way, preferably by including a pseudocode thereof, in such a way that its complexity
can be clearly evaluated. As usual, the lower the (asymptotic) algorithm complexity, the better is the
solution.
Exercise 3 (4/15 points)
1. Consider a variation of the classical (recursive) binary search algorithm, named “ternary
search”: the algorithm divides the sorted sequence in 3 partitions of size n/3 (as usual, up to
rounding.) Write the recurrence equation defining the algorithm complexity and solve it (in
terms of the order of magnitude, preferably through the  notation).
2. Then, consider another variation of the same algorithm that divides the original sequence in two
parts of size n/3 and 2n/3, respectively, and give the equation and its solution for this version
too.
Algoritmi e Principi dell’Informatica
Appello del 20 febbraio 2017
Chi deve sostenere l’esame integrato (API) deve svolgere tutti gli esercizi in 2 ore e 30 minuti.
Chi deve sostenere solo il modulo di Informatica teorica deve svolgere gli Esercizi 1 e 2 in 1 ora e 15
minuti.
Chi deve sostenere solo il modulo di Informatica 3 deve svolgere gli Esercizi 3 e 4 in 1 ora e 15 minuti.
NB: i punti attribuiti ai singoli esercizi hanno senso solo con riferimento all’esame integrato e hanno
valore puramente indicativo.
Esercizio 1 (9 punti)
Si consideri l’insieme S definito nel modo seguente:
S = { i | i è l’indice di una macchina di Turing che accetta almeno una stringa }
Si risponda alle seguenti domande, motivando opportunamente le risposte:
a) S è ricorsivo?
b) S è ricorsivamente enumerabile?
c) Il complemento di S è ricorsivamente enumerabile?
Si considerino ora gli insiemi seguenti:



S1 = { i | i è un numero naturale e non è l’indice di una macchina di Turing che accetta
almeno una stringa }
S2 = { i | i è l’indice di una macchina di Turing che non accetta alcuna stringa }
S3 = { i | i è l’indice di una macchina di Turing in cui almeno una stringa non è accettata }
d) Per ognuno degli insiemi S1, S2 e S3, dire se rappresenta il complemento di S.
Esercizio 2 (8 punti)
Si consideri la grammatica G seguente (con le usuali convenzioni alfabetiche):
S  aaAbc
A  aAb | c
Sia L il linguaggio generato da G: si fornisca una specifica logica di L.
NB: nello scrivere la formula che specifica L si può fare uso esclusivamente dei seguenti elementi,
oltre agli usuali connettivi logici proposizionali, quantificatori e punteggiatura:
 Lettere di “variabili stringhe” x, y, z, … che assumono valori in {a,b,c}*
 Lettere di “variabili linguaggio” L, L1, L2, … (Il simbolo è L è “riservato” per L(G))
 Le costanti a, b, c
 Il simbolo di concatenazione tra stringhe ‘.’ (usato con notazione infissa; si può darne per
scontata l’associatività, se ne può anche omettere la scrittura quando ciò non generi dubbi
interpretativi: ad esempio, ab abbrevia a.b)
 Il simbolo di appartenza ‘’ (di una stringa a un linguaggio)
 Il simbolo di uguaglianza ‘=’.
Esercizio 3 (8 punti se non si sceglie la parte opzionale; 11 punti se si sviluppa correttamente
ed esaurintemente la parte opzionale)
Siano dati due alberi BST (Binary search tree) bilanciati, ossia tali che le lunghezze dei vari
cammini dalla radice alle foglie differiscano al massimo di 1. Si scriva un’algoritmo che determini
se i due alberi abbiano intersezione non nulla. Ovviamente la qualità della soluzione dipenderà
primariamente dalla sua complessità asintotica.
Parte opzionale (da svolgere in alternativa, non in aggiunta alla precedente ma esclusivamente
se si è sicuri di poterla portare a termine con sufficiente chiarezza e a complessità non
superiore alla soluzione non vincolata.)
Si costruisca un algoritmo per risolvere lo stesso problema in modo da non dover utilizzare
memoria aggiuntiva, dove per memoria aggiuntiva rispetto ai dati in ingresso si intende memoria di
dimensionni dipendenti dai dati, ossia non O(k).
NB: un algoritmo che non faccia uso di memoria aggiutiva ma abbia complessità superiore a quello
che invece ne fa uso viene considerato di qualità inferiore ad esso.
Esercizio 4 (7 punti)
Si considerino due insiemi di interi S = {s1, s2, ..., sm} e T = {t1, t2, ..., tn}, m ≤ n.
a. Si specifichi un algoritmo che faccia uso di una tabella hash di dimensione m, gestita con il metodo
del concatenamento, per verificare se S è un sottoinsieme di T. Se ne discuta la complessità,
utilizzando l’analisi del caso medio. N.B. Non è necessario definire la funzione H per l’accesso alla
tabella; si supponga che questa sia già definita e che distribuisca le chiavi in tabella in modo
abbastanza uniforme, ciò che giustifica l’uso dell’analisi del caso medio.
b. Si discuta se l’utilizzo della tabella hash introduce vantaggi in termini di complessità rispetto ad
altre possibili soluzioni.
Soluzioni
Esercizio 1
a) Ricadiamo chiaramente nelle ipotesi di applicazione del teorema di Rice: l’insieme di
funzioni considerate non è né l’insieme vuoto (c’è almeno una macchina di Turing che
accetta almeno una stringa), né l’insieme di tutte le funzioni computabili (non tutte le
macchine di Turing accettano almeno una stringa), pertanto l’insieme S non è ricorsivo.
b) Per stabilire che S è ricorsivamente enumerabile si può, ad esempio, mostrare che S è
l’insieme di definizione di una funzione f (parziale e) computabile. Tale funzione f è
implementata da una macchina di Turing che procede come segue. Per un dato indice i,
simula il comportamento di della i-esima macchina di Turing Mi; partendo da n=0 e m=1,
verifica, per ogni stringa x di lunghezza n, se in m passi Mi accetta x, e procede enumerando
(n,m) con la solita tecnica diagonale (0,1), (1,1), (0,2), (2,1), (1,2), (0,3), … fino a che non
trova una stringa accettata da Mi, se esiste. Si noti che, fissato n, è sempre possibile
enumerare tutte le stringhe di lunghezza n in tempo finito. Pertanto, se esiste una stringa di
lunghezza n’ accettata da Mi in un numero di passi m’, questa viene prima o poi enumerata
con il procedimento sopra illustrato; se non esiste, tale procedimento non termina.
c) Il complemento di S non può essere ricorsivamente enumerabile. Se lo fosse, sia S sia il suo
complemento sarebbero ricorsivamente enumerabili (vedi punto precedente), pertanto si
potrebbe concludere che S è ricorsivo, ma al punto a) abbiamo mostrato che non lo è.
d) L’insieme S1 è esplicitamente definito come il complemento
ℕ - S di S, cioè l’insieme degli
indici che non stanno in S. L’insieme S2 è definito come l’insieme degli indici che godono
della proprietà opposta (l’opposto di accettare almeno una stringa è non accettare alcuna
stringa) di quella goduta dagli indici che stanno in S, e quindi è ancora una volta il
complemento di S. L’insieme S3 invece non è il complemento di S, infatti una stessa
macchina di Turing può accettare una stringa (e quindi avere l’indice in S) e non accettarne
un’altra (e quindi avere l’indice anche in S3).
Esercizio 2
L(G) è chiaramente il linguaggio {aa.ancbnbc | n  0}. L’appartenenza di x a L(G) può essere quindi
espressa dalla formula seguente:
x  L  ((x = aacbc)   y, z, w (y = aazcwbc  y  L  x = aaazcwbbc)))
Esercizio 3
Una soluzione banale consiste nel visitare tutti i nodi dell’albero A1, ad esempio mediante una
visita in post-ordine e per ognuno di essi fare una ricerca del suo valore su A2. Essendo entrambi gli
alberi bilanciati ogni ricerca costa log(n) e quindi la complessità totale è O(n.log(n)), dove n è il
masssimo tra le cardinalità dei due alberi; se la differenza tra esse fosse notevole, converrebbe
applicare la visita esaustiva all’albero di cardinalità minore.
Una soluzione più efficiente, che però richiede l’allocazione di memoria extra consiste nello
sviuppare entrambi gli alberi in array ordinati; questo può essere fatto con una visita in-ordine
(figlio di sinistra, radice, figlio di destra) e complessità O(n); indi scandire “in parallelo” i due array
confrontandoli mediante due rispettivi indici: se si trova una coppia A1[i] = A2[j] la ricerca ha
successo altrimenti se A1[i] < A2[j] si incrementa i e viceversa se A1[i] > A2[j], ottenendo così una
complessità O(n).
Un algoritmo più sofisticato che opera direttamente sugli alberi senza “travasarli” in array è invece
descritto a grandi linee nel modo seguente:
Esso trae ispirazione dall’algoritmo precedente ma semplicemente esegue la scansione ordinata
direttamente sui due alberi:
1. Determino i minimi dei due alberi (le foglie più a sinistra) , con complessità O(log(n));
2. Proseguo eseguendo gli stessi confronti del precedente algoritmo semplicemente sostituendo
l’incremento degli indice degli array con il calcolo del successore.
Per valutare la complessità dell’algoritmo, con riferimento alla figura sottostante, si osservi che:
1. Il successore delle foglie che sono figli di sinistra, che sono ≤ n/2, è il loro padre, a distanza 1 =
20 da esse.
2. Il successore successore delle foglie che sono figli di destra, che sono ≤ n/2, è il padre del loro
primo antenato che è figlio di sinistra, che per metà di esse si trova a distanza 2, per 1/4 di esse
si trova distanza 3, , per 1/8 a distanza 4, …
3. Il successore di un nodo interno si trova a una distanza ≤ dell’altezza del sottoalbero di cui esso
è radice.
In entambi i casi 2 e 3 il costo complessivo delle varie chiamate alla procedura Successore è
maggiorato dalla formula
log(n )

h 0
n
2 h1
.O(h)  O(n)
come mostrato ad esempio nello sviluppo dell’algoritmo heap-sort.
Quindi il numero di chiamate al Successore è O(n) e così pure la complessità dell’intero algoritmo.
0
2
1
2
22
3
2
4
2
Esercizio 4
Punto a. H è la tabella hash di dimensione m.
Sottoinsieme_Hash (T, S, n, m)
per ogni ti in T
inserisci(H, ti) //inserimento in testa alla lista
per ogni sj in S
trovato = ricerca(H, sj)
if (!trovato)
return False
return True
Inserire tutti gli elementi di T nella tabella H con il metodo del concatenamento richiede una
complessità nΘ(1) = Θ(n)
Se S è un sottoinsieme di T, l’algoritmo eseguirà al più m ricerche con successo; quindi la
complessità del secondo ciclo for sarà m(1+alfa) = O (m + n)
Se S non è un sottoinsieme di T, allora nel caso pessimo tutti gli elementi, tranne l’ultimo in S, sono
in T. Saranno quindi eseguite m-1 ricerche con successo e una senza successo. La complessità del
ciclo di ricerca è comunque O(m + n).
La complessità dell’algoritmo è quindi O(n).
Punto b. Una soluzione alternativa, diversa da quella ovvia (ma inefficiente) che confronta ogni
elemento di S con gli elementi di T, potrebbe ordinare gli elementi di T e poi usare la ricerca binaria
per cercare le occorrenze degli elementi di S in T:
Sottoinsieme_RicercaBinaria(T,S,n,m)
Ordina (T)
per ogni sj in S
trovato = RicercaBinaria(T, sj)
if (!trovato)
return False
return True
Tale soluzione avrebbe complessità O(n.log(n) + m.log(n)) che è meno vantaggiosa rispetto alla
complessità ottenuta con l’uso della tabella Hash.
NB: in tal caso si tratterebbe di complessità nel caso pessimo, apparentemente non ben
confrontabile con il caso medio utilizzato per l’uso della tabella Hash; tuttavia in gran parte dei casi
normali la complessità di algoritmi di sorting a caso pessimo O(n.log(n)) è O(n.log(n)) anche nel
caso medio.
Algoritmi e Principi dell’Informatica
English version
February 20, 2017
Total time available is 2h 30'.
If you are registered for the first module only (Informatica Teorica), you must solve Exercises
1 and 2 in 1h 15’.
If you are registered for the second module only (Informatica 3), you must solve Exercises 3
and 4 in 1h 15’.
Exercise 1 (Points 9)
Let S be a set of natural numbers defined as:
S = { i | i is the index of a Turing machine that accepts at least one word}
Answer the following questions and briefly motivate your answers:
a) Is S recursive?
b) Is S recursively enumerable?
c) Is S’s complement recursively enumerable?
Then consider the following sets of natural numbers:



S1 = { i | i is not the index of a Turing machine that accepts at least one word }
S2 = { i | i is the index of a Turing machine that does not accept any word }
S3 = { i | i is the index of a Turing machine that does not accept at least one word }
Exercise 2 (Points 8)
Consider the following grammar G (with the usual alphabetic conventions):
S  aaAbc
A  aAb | c
Let L be the language generated by G: build a logic formula specifying L.
NB: in writing your formula you can use exclusively the following symbols, besides the usual
propositional operators, quantifiers, and punctuation markers:
 Letters denoting “string variables” x, y, z, … which take value in {a,b,c}*
 Letters denoting “language variables” L, L1, L2, … (Symbol L is “reserved” for L(G))
 Constants a, b, c
 The concatenation symbol ‘.’ (used through the standard infix notation; you can give for
granted its associativity and can omit it if no ambiguity may arise e.g., abc is an abbreviation
for (a.b).c
 The symbol ‘’ (for a string belonging to a language)
 The equality symbol ‘=’.
Exercise 3 (Points 8 for the standard version, 11 points for the optional version)
Two balanced BST (Binary search trees) are given (remember that in a balanced BST the maximun
difference among the length of paths from the root to the leaves is 1). Write an algorithm that states
whether the two trees have empty intersection or not. Of course, the lower the complexity of your
algorithm, the better your solution.
Optional version, to be developed instead of the unconsrained one above, only if you are
confident to be able to carry it over to competion in such a way that its complexity is not
higher than that of the previous version.
Solve the saame problem without using auxiliry memory, possibly excluding few extra variables
whose global size is O(k).
NB: An algorithm that does not use auxiliary memory but has a higher complexity than one that
does it, is evaluated as of lower quality than the other one.
Exercise 4 (Points 7)
Consider two sets of integers S = {s1, s2, ..., sm} and T = {t1, t2, ..., tn}, m ≤ n.
a. Build an algorithm that uses an hash table of size m, managed through the linked list
method, that checks whether S is a subset of T or not. Discuss algrithm’s complexity in the
average case. NB: It is not necessary to define the H function to access the table: just assume
that it maps the set of keys into the m positions of the table with a reasonably uniform
distribution (which is a good hypothesis to apply the average case analysis).
b. Is the use of a hash table preferable, in terms of complexity, w.r.t. other pssible solutions?
Briefly motivate your answer.