Sei sulla pagina 1di 63

Algoritmi

Complementi
AA 2008-2009
Programma del corso..........................pag 2
Appunti . .pag 3
Riassunto Ricorsioni e Procedure
viste a lezione . pag 51
Domande di teoria in preparazione
allesame. pag 58

13.01 Ripasso/Esercitazioni
L01

Introduzione al corso

Mutua ricorsione

Count&Sort

Problemi di decisione, di ricerca e di ottimizzazione


E01

Crescita delle funzioni (cap. 3)

Richiami sulla ricorsione: calcolo del fattoriale

Ricerca dicotomica, calcolo altezza di un albero


binario (appendice B.5)
E02

Ricorrenze e tempi di calcolo di algoritmi ricorsivi


(capp. 4.1, 4.2 e 4.3)

Il metodo divide et impera: algoritmo Merge-sort


(cap. 2.3)
16.01 Introduzione alla programmazione dinamica
L02

Enumerazione e backtracking

Esempio numeri di Fibonacci, albero di ricorsione,


tabulazione (slides)
L03

Distanza di edit, importanza, ricorrenza, calcolo


(slides)
20.01 Programmazione dinamica 1
L04

Programmazione delle catene di montaggio (cap.


15.1)
L05

Prodotto righe per colonne di matrici: algoritmo base


(cap. 28.1)

Algoritmo di Strassen (cap. 28.2)


E03

Esecuzione di procedure ricorsive: stack e record di


attivazione
23.01 Programmazione dinamica 2
L06

Catena di moltiplicazioni di matrici (cap. 15.2)

Determinazione della ricorrenza di programmazione


dinamica

Calcolo tabulare di m(i,j): programma, esecuzione


manuale
L07

Gli elementi della programmazione dinamica (cap.


15.3)

Programmazione ricorsiva con memorizzazione

Iterazione vs. ricorsione


27.01 Programmazione dinamica 3 - Grafi
L08

Il problema della LCS (cap. 15.4)


L09

Nomenclatura su grafi (appendice B.4)

Rappresentazione di grafi in memoria (cap. 22.1)


L10

Visita in ampiezza (cap. 22.2): Schema generale


dellalgoritmo
30.01 Algoritmi di visita di grafi 1
L11

Correttezza di BFS (cap. 22.2)

BFS e cammini minimi (cap. 22.2)


L12

Visita in profondit (cap. 22.3): Schema generale


dellalgoritmo
03.02 Esercitazioni
E04

Calcolo della LCS crescente


E05

Calcolo della LCS crescente

06.02 Esercitazioni
E06

Calcolo della sottosequenza comune pi pesante


(HCS) e confronto con LCS
E07

Componenti connesse pari; SUBSETSUM


03.03 Algoritmi di visita di grafi 2 - Problemi di cammino
minimo
L13

Classificazione degli archi in DFS (cap. 22.3)

Propriet del DFS (cap. 22.3)


L14

Applicazioni di DFS: Ordinamento topologico (cap.


22.4)

Ricerca delle componenti fortemente connesse in un


grafo orientato (cap. 22.5)
L15

Introduzione ai problemi di cammino minimo (capp.


24.1 e 25.1)
06.03 Problemi di cammino minimo
L16

Algoritmo di rilassamento e propriet


L17

Algoritmo di Dijkstra (cap. 24.4)


10.03 Esercitazioni
E8

Cammino minimo con almeno un arco rosso 1


E9

Cammino minimo con almeno un arco rosso 2


13.03 Problemi di cammino minimo
L18

Algoritmo di Bellman-Ford (cap. 24.3)


L19

Algoritmo di Floyd-Warshall (cap. 25.3)


17.03 Esercitazioni
E10

Esercizi ricapitolativi sulla visita di un grafo


E11

Esercizi ricapitolativi su cammini minimi


E12

Esercizi ricapitolativi su cammini minimi


24.03 Reti di flusso - NP completezza
L20

Introduzione alle reti di flusso (cap. 26.1)


L21

Algoritmo di Ford-Fulkerson (cap. 26.2)


L22

Tempo polinomiale (cap. 34.2)

Verifica in tempo polinomiale (cap. 34.3)


27.03 NP completezza
L23

NP completezza e riducibilit (cap. 34.4)

Dimostrazione della NP completezza (cap. 34.5)


L24

Problemi NP completi (cap. 34.6)


N.B. Le date delle lezioni e la suddivisione degli argomenti tra
le lezioni sono indicative; potranno verificarsi piccoli
cambiamenti dovuti ad eventuali indisposizioni del docente,
scioperi, e altri eventi imprevedibili.

LCS
Significato parametri coefficienti delle ricorrenze
- X,Y sequenze di lunghezza |X|=n, |Y|=m
- Xi sottosequenza da 1 a i, Yj sottosequenza da 1
aj
- i in {1,...,n}, j in {1,...,m}
- C[i,j] lunghezza dellottimo relativo a Xi e Yj
(C[i,j]=|lcs(Xi,Yj)|)
Caso base
Se xiyj non esiste LCS tra Xi e Yj che termina sia
con xi e yj,
quindi C[i,j]=0.
Equazioni delle ricorrenze
c(i,j)={ se i=0,j=0
{ se ai=bj, con i,j>0 c(i,j)=c(i-1,j-1)+1
{ altrimenti c(i,j)=max { c(i-1,j), c(i,j-1)}
Tempo di calcolo TETA(nm)
LCS LUNGHEZZA>=K
INPUT: 2stringhe X e Y e k>=0
OUTPUT: C[i,j,z]:{0,1} se esiste una sottoseq
comune a X e Y >=z terminante con xi=yj
Z {0,.k}
X=<x1,..xn> Y=<y1,..ym>
Equazioni delle ricorrenze
{ se (i=0 V,j=0) and z=0  1
{ se (i=0 V,j=0) and z0  0
c(i,j,k) = { se i,j>=1 and z=0 and xi=yj  1
{ se xi=yj,e z>=1 con i,j>0  c(i-1,j-1,z-1)
{ se xiyj,e z>=1 con i,j>0  c(i-1,j,z) V
c(i,j-1,z)
Soluzione
C[m,n,k]={1  esiste / 0  non esiste}
Tempo di calcolo TETA(nm)
HCS seq comune + pesante
Caratterizzazione HCS
Z=<z1,.zk> = HCS(X,Y)
Se Xm=Yn  Zk=Xm=Yn
Zk-1=HCS(Xm-1,Yn-1)
Equazione ricorrenze
Indico con c[i,j] il peso di una HCS tra Xi e Yj
{0 se i=0 V j=0
C[i,j] = {w(xi) + c[i-1,j-1] se xi=yj
{MAX (c[i-1,j], c[i,j-1]) se xiyj
Tempo di calcolo TETA(nm)
LECS LCS crescente
INPUT: 2stringhe X e Y
X=<x1,..xm> Y=<y1,..yn>
c[i,j] = lunghezza LECS tra Xi e Yj con xi=yj
Ricorrenze
{0 se xiyj
C[i,j] = {1+ MAX (c[s,t] con 1sI 1tj xsxi)
se xi=yj
2
Tempo di calcolo O((nm) )
CONCATENAZIONE OTTIMA MATRICI
Significato parametri coefficienti delle ricorrenze
- A1..An Matrici : p1 p2 pn
p0[A1] * p1[A2] *...pn-1[An]
- i,j indici indicanti le matrici 1<=i<=j<=n

- M[i,j] num minimo di prodotti scalari per la


concatenazione
Equazioni delle ricorrenze
M(i,j)={ se i=j M(i,j)= 0
{ min(i<=k<=j){M(i,k)+M(k+1,j)+pi-1*pk*pj}
Caso base
Se non ho matrici da moltiplicare M(i,j)= 0
ZAINO
Input: n oggetti, ad ogni ogetto i {1,2,.n}
associato un peso wi>0 e un valore vi>0
Contenitore capacit W
Output: Riempire lo zaino max il val totale degli
oggetti selezionati
Def variabile
M[i,q]=valore max oggetti compresi tra {1,i} che
possono entrare in un box grande q
Con i:1.n
q:0..W
Eq ricorrenza
{se i=0 V q=0  0
M[i,q]= { se wi>q M[i-1,q] //nn c spazio non lo
metto
{ se wiq MAX(M[i-1,q-wi]+vi, M[i-1,q])
Algoritmo
For i=1 to m
For q=1 to W
If wi>q then M[i,q]=M[i-1,q]
Else M[i,q]= MAX(M[i-1,q-wi]+vi, M[i-1,q])
VARIANTE dello zaino
Esiste un sottoinsiem di {x1,xn} i cui elementi
danno somma k
Def variabile
E[i,k]={0,1} se esiste o no un sottoins..
Eq ricorrenza
{se per ogni i=0 e k=0  1
{se i=0 e per ogni k>0  0
M[i,q]= { se xi>k E[i-1,k]
{ se xik OR(E[i-1,k-xi], E[i-1,k])
1)Cammini minimi tra tutte le coppie di vertici
in G pesato.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- i,j nodi del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j) costo cammino minimo i,j con vertici
nell'intervallo 1...k
Ricorrenza
D(k)(i,j)={ se k non cammino minimo D(k)(i,j)
=D(k)(i,j)
{ se k D(k)(i,j) =D(k-1)(i,t)+D(k-1)(t,j)
D(k)(i,j)=min{D(k-1)(i,j), D(k-1)(i,k)+D(k1)(k,j) se k>=1
Caso base
D(0)(i,j)={w[i,j] per ogni(i,j) E
{ infinito altrimenti
D(0)(i,j)={w[i,j] per ogni(i,j) E
{ infinito altrimenti
D(0)(i,j)={infinito

Soluzione D(n)(i,j)
2)Cammini minimi tra tutte le coppie di vertici
in G pesato
t.c. contengano esattamente 2 archi rossi.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,col> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- col: E ->{R,N} funzione che associa un colore ad
un arco
- i,j vertici (nodi) del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,r) costo cammino minimo i,j con vertici
nell'intervallo,
con esattamente r archi rossi
Ricorrenza
D(k)(i,j,r)={ se k non D(k)(i,j,r) =D(k-1)(i,j,r)
{ se k D(k)
(i,j,r) =min(r1+r2=r){D(k-1)(i,k,r1)+D(k-1)(k,j,r2)}
D(k)(i,j,r)=min{D(k-1)(i,j,r) ,
min(r1+r2=r){D(k-1)(i,k,r1)+D(k-1)(k,j,r2)}}
Caso base
D(0)(i,j,0)={w[i,j] per ogni(i,j) E and col (i,j)=N
{ infinito altrimenti
D(0)(i,j,1)={w[i,j] per ogni(i,j) E and col (i,j)=R
{ infinito altrimenti
D(0)(i,j,2)={infinito
Soluzione D(n)(i,j,2)
3)Cammini minimi tra tutte le coppie di vertici
in G pesato
t.c. contengano al pi 2 archi rossi
//cambio condizione e copio quello sopra
Soluzione min{D(n)(i,j,r) | r <=2}
4)Cammini minimi tra tutte le coppie di vertici
in G pesato
t.c. contengano almeno 2 archi rossi.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,col> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- col: E ->{R,N} funzione che associa un colore ad
un arco
- i,j vertici (nodi) del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,r) costo cammino minimo i,j con vertici
nell'intervallo,
con almeno r archi rossi
Ricorrenza
D(k)(i,j,r)={ se k non D(k)(i,j,r) =D(k-1)(i,j,r)
{ se k D(k)(i,j,r) =min(*){D(k-1)(i,t,r1)+D(k1)(t,j,r2)}
* r1+r2>=r and 0<=r1<=k+1 and 0<=r2<=k+1
D(k)(i,j,r)=min{D(k-1)(i,j,r) , min(*){D(k1)(i,t,r1)+D(k-1)(t,j,r2)}}
Caso base
D(0)(i,j,0)={w[i,j] per ogni(i,j) E and col (i,j)=N
{ inf altrimenti
D(0)(i,j,1)={w[i,j] per ogni(i,j) E and col (i,j)=R
{ inf altrimenti

D(0)(i,j,2)={inf
Soluzione D(n)(i,j,2)
5)Cammini minimi tra tutte le copie di vertici in
G pesato
t.c. contengano esattamente 2 vertici rossi,
estremi esclusi.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,col> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- col: V ->{R,N} funzione che associa un colore ad
un vertice
- i,j vertici (nodi) del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,r) costo cammino minimo i,j con vertici
nell'intervallo,
con esattamente r vertici rossi
Ricorrenza
D(k)(i,j,r)={ se k non D(k)(i,j,r) =D(k-1)(i,j,r)
{ se k min 1{ se col(t)=N D(k)(i,j,r) =
min(r1+r2=r){D(k-1)(i,t,r1)+D(k-1)(t,j,r2)}
2{ se col(t)=R e r0 D(k)(i,j,r) =
min(r1+r2=r){D(k-1)(i,t,r1)+D(k-1)(t,j,r2)}
3{ se col(t)=R e r=0 D(k)(i,j,r) =infinito
D(k)(i,j,r)=min{D(k-1)(i,j,r) , min {1,2,3}}
Caso base
D(0)(i,j,0)={w[i,j] per ogni(i,j) E and col (i)=N and
col (j)=N
{ infinito altrimenti
D(0)(i,j,1)={w[i,j] per ogni(i,j) E and col (i)=R and
col (j)=R
{ infinito altrimenti
D(0)(i,j,2)={infinito
Soluzione D(n)(i,j,2)
6)Cammini minimi senza archi rossi
consecutivi.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,col> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- col: E ->{R,N} funzione che associa un colore ad
un arco
- a colore del primo arco nel cammino tra i,j
- b colore dell'ultimo arco nel cammino tra i,j
- i,j nodi del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,a,b) costo cammino minimo i,j con vertici
nell'intervallo,
con colore arco a diverso dal colore arco b
Ricorrenza
D(k)(i,j,a,b)={ se k non D(k)(i,j,a,b) =D(k1)(i,j,a,b)
{ se k D(k)(i,j,a,b) =
min(cd){D(k-1)(i,t,a,c)+D(k-1)(t,j,d,b)}
D(k)(i,j,a,b)=min{D(k-1)(i,j,a,b) ,
min(cd){D(k-1)(i,t,a,c)+D(k-1)(t,j,d,b)}}
Caso base
D(0)(i,j,a,b)={w[i,j] per ogni(i,j) E and w[i,j]=a=b
{ infinito altrimenti

Soluzione
min{D(k)(i,j,R,R),D(k)(i,j,R,N),D(k)(i,j,N,R),D(k)(i,j,
N,N)
7)Stabilire se esiste un cammino minimo
senza archi consecutivi dello stesso colore.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,col> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- col: E ->{R,N} funzione che associa un colore ad
un arco
- a colore del primo arco nel cammino tra i,j
- b colore dell'ultimo arco nel cammino tra i,j
- i,j nodi del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,a,b) true se esiste un cammino minimo i,j
con vertici
nell'intervallo e con colore arco a diverso dal
colore arco b
Ricorrenza
D(k)(i,j,a,b)={ se k non D(k)(i,j,a,b) =D(k1)(i,j,a,b)
{ se k D(k)(i,j,a,b) =
or(cd){D(k-1)(i,t,a,c)and D(k-1)(t,j,d,b)}
D(k)(i,j,a,b)=OR{D(k-1)(i,j,a,b) ,
or(cd){D(k-1)(i,t,a,c)and D(k-1)(t,j,d,b)}}
Caso base
D(0)(i,j,a,b)={true se (i,j) E and w[i,j]=a=b
{ false altrimenti
Soluzione
OR{D(k)(i,j,R,R),D(k)(i,j,R,N),D(k)(i,j,N,R),D(k)(i,j,
N,N)
8)Stabilire se esiste un cammino minimo
senza archi rossi consecutivi.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,a,b> V insieme vertici, E insieme
archi
- w[i,j] funzione peso dell'arco tra i,j
- col: E ->{R,N} funzione che associa un colore ad
un arco
- a colore del primo arco nel cammino tra i,j
- b colore dell'ultimo arco nel cammino tra i,j
- i,j nodi del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,a,b) true se esiste un cammino minimo i,j
con vertici
nell'intervallo e con colore arco a diverso dal
colore arco b
Ricorrenza
D(k)(i,j,a,b)={ se k non D(k)(i,j,a,b) =D(k1)(i,j,a,b)
{ se k D(k)(i,j,a,b) =
or(cd){D(k-1)(i,t,a,c)and D(k-1)(t,j,d,b)}
D(k)(i,j,a,b)=OR{D(k-1)(i,j,a,b) ,
or(cd){D(k-1)(i,t,a,c)and D(k-1)(t,j,d,b)}}
Caso base
D(0)(i,j,a,b)={true se (i,j) E and w[i,j]=a=b

{ false altrimenti
Soluzione
OR{D(k)(i,j,R,R),D(k)(i,j,R,N),D(k)(i,j,N,R),D(k)(i,j,
N,N)}
9)Stabilire se esiste per ogni coppia di vertici
un cammino di costo minore o uguale di K>0.
Significato parametri coefficienti delle
ricorrenze
- G=<V,E,w,> V insieme vertici, E insieme archi
- w[i,j] funzione peso dell'arco tra i,j
- i,j nodi del grafo;
- 1...k intervallo dei vertici intermedi tra i,j
-D(k)(i,j,h)=true se esiste un cammino minimo i,j
con vertici
nell'intervallo di costo <= h
Ricorrenza
D(k)(i,j,h)={ se k non D(k)(i,j,h) =D(k-1)(i,j,h)
{ se k D(k)(i,j,h) =
or(h1+h2<=h){D(k-1)(i,t,h1)and D(k-1)(t,j,h2)}
D(k)(i,j,a,b)=OR{D(k-1)(i,j,h) ,
or(h1+h2<=h){D(k-1)(i,t,h1)and D(k-1)(t,j,h2)}}
Caso base
D(0)(i,j,0)= false
D(0)(i,j,h)={true se (i,j) E and w[i,j]<=K
{ false altrimenti
con 1<=h<=K
Soluzione D(n)(i,j,K)

LCS (X, Y)
n = length(X);
m = length(Y);
for i = 0 to n
C[i,0] = 0
End for
for j = 0 to m
C[0,j] = 0
End for
for i = 1 to n
for j = 1 to m
if ai = bj then
C[i,j]=C[i-1,j-1]+1;
D[i,j]= freccia diag;
else if C[i-1,j] >= C[i,j-1] then
C[i,j]=C[i-1,j];
D[i,j]=;
else
C[i,j]=C[i,j-1];
D[i,j]=;
End for
End for
procedura stampa_lcs(D, X, Y, i, j)
if i = 0 OR j = 0 then return
else if D[i,j] = then
stampa_lcs(D, X, Y, i-1, j-1)
print X[i];
else if D[i,j] = then
stampa_lcs(D, X, Y, i-1, j)
else stampa_lcs(D, X, Y, i, j-1)

Lcs_crescente(X as Array, Y as Array)


m = length(X);
n = length(Y);
C as Matrix[m,n];
for i = 0 to n /* riempio la prima colonna di 0 */
C[i,0] = 0
End for
for j = 0 to m /* riempio la prima riga di 0 */
C[0,j] = 0
End for
for i = 1 to m
for j = 1 to n
if xi != yj then C[i,j] = 0
else
max = 0
for s = 1 to i-1
for t = 1 to j-1
if C[s,t] > max AND xs < xi
max = C[s,t]
end for
end for
C[i,j]=1 + max;
Return C
Procedura BFS(G, s)
For ogni vertice u V {s}
Color[u] = white;
d[u] = infinity;
p[u] = nil;
End for
Color[s] = grey;
d[s] = 0;
p[s] = nil;
Q = {s}
while Q
u = Head(Q)
for ogni vertice v Adj[u]
if color[v] = white then
p[v] = u
color[v] = grey
d[v] = d[v] + 1
Enqueue(Q, v)
End for
Dequeue(Q)
color[u] = black
end while
BFS_scopre_vertici_distanza_k_da_s(G,s)
For ogni vertice u V {s}
Color[u] = white;
d[u] = infinity;
p[u] = nil;
End for
Color[s] = grey;
d[s] = 0;
p[s] = nil;
Q = {s}
while Q
u = Head(Q)
for ogni vertice v Adj[u]
if color[v] = white then
p[v] = u

d[v] = d[v] + 1
if d[v]<k then
color[v] = grey
Enqueue(Q, v)
Else color[v]=black
End for
Dequeue(Q, u) //tolgo u dalla coda
color[u] = black
end while
Procedura BFS_conta_raggiungibili_da_s(G, s)

//scrivere il codice della BFS e dopo aggiungere


N=0
For ogni vertice u V {s}
If d[u] infinito then n=n+1
End for
Return n
Procedura
BFS_stampa_vertici_distanza_pari_da_s(G, s)
//scrivere il codice della BFS e dopo aggiungere
For ogni vertice u V {s}
If d[u] infinito and d[u] mod 2=0 then print u
End for
BFS_se_grafo_nn_orientato__connesso(G)
//non ho la s,scelgo a random un vertice
s=RANDOM(V)
eseguo BFS(G,s)
for ogni u V {s}
if d[u]=infinito return false
end for
return true
BFS_se_GnonOrientato__albero(G,s)
Def di albero: grafo non orientato,connesso e
aciclico
Connesso lo controllo con la procedura sopra e
per aciclico sfrutto il teorema: Se G non
orientato  G un albero = G connesso AND
|E|=|V|-1 = G aciclico AND |E|=|V|-1
Ricordo che se G non orientato ogni arco viene
scoperto 2volte quindi pongo |E|=uV|Adj[u]|
Connesso=
BFS_se_grafo_nn_orientato__connesso(G)
If(connesso=true) and (|E|=|V|-1) return true
Else return false

BFS_GnonOrientato_albero_binario_completo
_radiceS_altezzaK
G albero=G connesso AND |E|=|V|-1 (con
|E|=uV|Adj[u]|)
G binario e completo:
sorgente ha 2 archi incidenti: se d[u]=0 
|Adj[u]|=2
nodo intermedio ha 3 archi incidenti: se 0<d[u]<k
 |Adj[u]|=3
foglia ha 1 arco incidente se d[u]=k  |Adj[u]|=1
livello
e anche che 2
n (n=numero vertici su un
livello)
altezza k: scopro solo i vertici che distano K da s
For ogni vertice u V {s}
Color[u] = white;
d[u] = infinity;
p[u] = nil;
End for
Color[s] = grey;
d[s] = 0;
p[s] = nil;
liv=1
n=0
Q = {s}
while Q
u = Head(Q)
a=|Adj[u]|
if(d[u]=0 AND a 2) OR (0<d[u]<k AND a 3)
return false
for ogni vertice v Adj[u]
if color[v] = white then
p[v] = u
d[v] = d[v] + 1
if d[v]=liv then n=n+1
livello
else if n2
return false
liv=liv+1
n=1
if d[v]<k then
color[v]=gray
Enqueue(Q)
Else color[u]=black
End for
Dequeue(Q)
color[u] = black
end while
livello
if 2
n return false
for ogni vertice u V {s}
if color[u]=white return false
if (d[u]=k AND a1) return false
end for
if |E|=|V|-1 return true
else return false
DFS(G)
for ogni vertice u V
color[u] = white;
p[u] = null;
end for
time = 0;
for ognivertice u V
if color[u] = white then DFS_visit(u)

end for
DFS_visit(u)
color[u] = grey;
time = time + 1;
d[u] = time;
for ogni vertice v Adj[u]
if color[v] = white then
p[v] = u;
DFS_visit(v);
end for
time = time + 1;
f[u] = time;
color[u] = black;
1)DFS_VISIT(u) stampa tutti gli archi
classificandoli (G orientato)
//aggiungere DFS senza modifiche
color[u] = grey;
time = time + 1;
d[u] = time;
for ogni vertice v Adj[u] \ {p[u]}
if color[v] = white
print (u,v) arco dellalbero
p[v] = u;
DFS_visit(v);
Else if colour[v]=gray print (u,v) arco
allindietro
Else if d[u]<d[v] print (u,v) arco in avanti
Else print (u,v) arco di attraversamento
end for
time = time + 1;
f[u] = time;
color[u] = black;
2)DFS stampa tutti gli archi classificandoli
(G non orientato)
Dal teorema so che G non orientato ha solo archi
allindietro o archi dellalbero
In questo G larco (u,v) e (v,u) sono lo stesso
arco. Se allo stesso arco possono essere attribuiti
2 tipi diversi,la priorit verr data a quello che
compare per primo. Per dire che (u,v) arco
allindietro devo controllare che V non padre di
u. se v grigio e v padre di u (u,v) arco
dellalbero (e non arco allindietro)
//aggiungo DFS(G) senza modifiche
DFS_visit(u)
color[u] = grey;
time = time + 1;
d[u] = time;
for ogni vertice v Adj[u] \ {p[u]}
if color[v] = white
print (u,v) arco dellalbero
p[v] = u;
DFS_visit(v);
Else print (u,v) arco allindietro
end for
time = time + 1;
f[u] = time;
color[u] = black;

3)DFS_conta_compConness(G)
for ogni vertice u V
color[u] = white;
p[u] = null;
end for
time = 0;
cont = 0;
for ogni vertice u V
If color[u] = white
cont++;
DFS_visit(u);
end for
return n

color[u] = grey;
time = time + 1;
d[u] = time;
for ogni vertice v Adj[u] \ {p[u]}
if color[v] = white
p[v] = u;
DFS_visit(v);
else if color[v]=gray and aciclico =true
aciclico =false;
end for
time = time + 1;
f[u] = time;
color[u] = black;

4)DFS_compConnes=k(G)
for ogni vertice u V
color[u] = white;
p[u] = null;
end for
time = 0;
cont = 0;
for ogni vertice u V
If color[u] = white
cont++;
DFS_visit(u);
end for
if(cont==k) then return true
else return false

7)DFS - verifica se un grafo non orientato


formato da K alberi
Bisogna controllare se G aciciclico e se ha k
componenti connesse
boolean procedura DFS(G)
boolean aciclico =true;
int count = 0;
for each u V
color[u] = white;
p[u] = null;
end for
for each u V
if color[u] = white then
DFS_visit(u)
count++;
end for
if (aciclico=true)AND(count ==k) return true
else return false;

5)boolean DFS_aciclio(G orientato)


Dal teorema dellordinamento topologico di un
DAG affermo che: un grafo orientato aciclico se
e solo se la DFS su G non produce archi
allindietro
boolean aciclico = true;
for ogni vertice u V
color[u] = white;
p[u] = null;
end for
time = 0;
for ogni vertice u V
If color[u] = white DFS_visit(u);
end for
return aciclico

DFS_VISIT(u)
color[u] = grey;
for ogni vertice v Adj[u] \ {p[u]}
if color[v] = white
p[v] = u;
DFS_visit(v);
else if color[v]=gray and aciclico =true
aciclico =false;
end for
color[u] = black;
8)DFSconta_compConnes_con_num_nodi_pari

DFS_visit(u)
color[u] = grey;
time = time + 1;
d[u] = time;
for ogni vertice v Adj[u]
if color[v] = white then
p[v] = u;
DFS_visit(v);
else if color[v]=gray and aciclico =true
aciclico =false;
end for
time = time + 1;
f[u] = time;
color[u] = black;
6)DFS_Visit(u) G non orientato aciclico(G)
//aggiungere anche la DFS con var aciclico

Cc=0
for ogni vertice u V
color[u] = white;
p[u] = null;
end for
time = 0;
cont = 0;
for ogni vertice u V
If color[u] = white
If DFS_VISIT(u) mod 2=0 cc=cc+1
cont++;
end for
return cc
DFS_visit(u)
c[u] = grey;
cont = 0;
for ogni vertice v Adj[u]

if color[v] = white then


p[v] = u;
cont += DFS_visit(v);
end for
c[u] = black;
return cont + 1;
Dijkstra(G,s)
For ogni v V
p(v) = nil;
d(v) = infinity;
End for
d(s) = 0;
S = ;
Q=V
while Q
u = ExtractMin(Q);
S = S + {u};
for ogni v Adj[u]
Relax(u, v, w);
end for
End while
Relax(u, v, w)
if(d[v] > d[u] + w(u,v)) then
d[v] = d[u] + w(u,v);
p[v] = u;

DOMANDE TEORICHE IN PREPARAZIONE ALLESAME


Algoritmi Complementi
1. Siano X=< x1, , xm> e Y=< y1, , yn> due sequenze e sia Z=< z1, , zk> una LCS di X e Y.
Scrivere la proprieta di sottostruttura ottima di Z.
Pi precisamente data una sequenza X=< x1, , xm> diciamo che Xi il prefisso i-esimo della sequenza
X se e solo se Xi =<x1,x2,x3..xi> con i=1.m. Per esempio se X=<A,B,C,B,D,A,B> allora
X4=<A,B,C,B> e X0 la sequenza vuota.
Il problema della LCS soddisfa la propriet della sottostruttura ottima come dimostrato dal teorema.
TEOREMA Sottostrutta ottima di una LCS
Siano X=< x1, , xm> e Y=< y1, , yn> due sequenze e sia Z=< z1, , zk> una LCS di X e Y.
1). Se xm = yn allora zk=xm=yn e Zk-1 una LCS di Xm-1 e Yn-1
2) Se xm yn e zk xm allora Z una LCS di Xm-1 e Y
3) Se xm yn e zk yn allora Z una LCS di X e Yn-1
Questo teorema dimostra che una LCS di due sequenze contiene al suo interno una LCS dei prefissi
delle due sequenze. Quindi il problema della LCS soddisfa la propiet della sottostruttra ottima
N.B. Questo teorema implica che se devo trovare una LCS tra X e Y devo considerare uno o due
sottoproblemi: Infatti se xm = yn per trovare una LCS tra X e Y basta trovare una LCS tra Xm-1 e Yn-1
e concatenarci lelemento xm = yn. Nel caso in cui xm yn devo risolvere due sottopb: bisogna trovare
una LCS di Xm-1 e Y e una LCS di X e Yn-1. La pi grande di queste due LCS una LCS tra X e Y.
Quindi la sottostruttra ottima del pb dellLCS permette di derivare la formula ricorsiva richiesta nella
domanda 2

2. Scrivere le equazioni di ricorrenza per risolvere il problema della LCS di due sequenze,
specificando bene il significato delle variabili coinvolte.

c[i,j] =

0
c[i-1,j-1] +1
max(c[i-1,j],c[i,j-1])

se (i=0 o j=0)
se i,j >0 e xi=yj
se i,j >0 e xiyj

DEFINIZIONE VARIABILI
c[i,j] la lunghezza di una LCS delle sequenze xi e yi
xi lelemento i-esimo del prefisso Xi con Xi =<x1,x2,x3..xi> con i=1.m
yj lelemento j-esimo del prefisso Yj con Yj =<y1,y2,y3..yj> con j=1.n

3. Scrivere lalgoritmo che determina la lunghezza della LCS di due sequenze specificando il suo
tempo di calcolo.

matrice C: contiene i valori della lunghezza della LCS per ogni coppia di indici i e j
matrice B: contiene le indicazioni su come ricomporre la LCS.
Tempo di calcolo procedura: TETA(nm)
1 for -> 0<i<m
2 for -> 0<j<n
Quindi ho (n+1)(m+1) chiamate ricorsive distinte -> TETA(nm) sottopb distinti

procedura calcola_lungh_it(X, Y)
n = length(X);
m = length(Y);
for i = 0 to n /* riempio la prima colonna di 0 */
C[i,0] = 0
End for
for j = 0 to m /* riempio la prima riga di 0 */
C[0,j] = 0
End for
for i = 1 to n
for j = 1 to m
if xi = yj then
C[i,j]=C[i-1,j-1]+1;
B[i,j]=
;
else if C[i-1,j] >= C[i,j-1] then
C[i,j]=C[i-1,j];
B[i,j]=;
else
C[i,j]=C[i,j-1];
B[i,j]=;
End for
End for

4. Definire qual e il sottografo dei predecessori (o albero BFS) prodotto dalla visita BFS di un
grafo G=<V,E>, specificando bene da quali vertici e quali archi e composto.
La vistita BFS(G,s) produce un albero BFS che ha s come radice e che contiene tutti i vertici V
raggiungibili da s. Lalbero BFS rappresentato dal sottografo dei predecessori di G, cio dal campo
di ogni vertice. Allinzio della visita lalbero contiene solo s. Durante la scansione della lista di
adiacenza di un vertice u gi scoperto (grigio), se trovo un vertice v non ancora scoperto (bianco),
aggiungo allalbero il vertice v e larco (u,v). In questo caso dir che u il predecessore di v nellalbero
BFS. Per ogni vertice v raggiungibile da s, il cammino nellalbero BFS da s a v corrisponde ad un
cammino minimo da s a v in G
5. Scrivere qual e il tempo di calcolo dellalgoritmo BFS motivando la risposta.
La complessit algoritmo BFS O(V+E) cio un tempo lineare
Operazioni inserimento e eleminazione da Q per ogni vertice: ognuna ha tempo costante O(1), su un
grafo con V vertici O(V) (perch il test if colour[v]=WHITE assicura venga inserito in Q e quindi
eliminato da Q- al max una volta)
Scansione lista adiacenza di ogni vertice: scandisco la lista di adiacenza di ogni vertice una sola volta
(perch lo faccio quando tolgo il vertice da Q) quindi:
Tempo scansione della lista di v: O(1)
Tempo scansione di tutte le liste di adiacenza: TETA(E) (devo sommare tutte le lunghezze delle liste di
adiacenza - la lunghezza dipende dal numero di archi E)
Quindi: tempo massimo scansione di tutte le liste: O(1*E)=O(E)

Tempo dedicato alla fase di inizializzazione (colorare tutti i vertici a bianco)=O(V)


Quindi complessit algoritmo = O(V+E)
6. Spiegare il significato dei colori assegnati ai vertici dallalgoritmo BFS. Alla fine dellesecuzione
dellalgoritmo BFS su un grafo G=<V,E>, quali colori assumono i vertici?
Allinizio della visita BFS tutti i vertici vengono colorati di bianco prech non sono stati ancora
scoperti. Appena un vertice viene scoperto viene colorato di grigio e viene quindi esaminata la sua lista
di adiacenza. Quando sono stati scoperti tutti i vertici adiacenti ad un vertice grigio questo diventa nero.
N.B: I vertici grigi rappresentano la frontiera tra i vertici scoperti e non.
7. Definire qual e il sottografo dei predecessori (o foresta DFS) prodotto dalla visita DFS di un
grafo G=<V,E>, specificando bene da quali vertici e quali archi e composto.
La visti DFS produce una foresta composta da alberi DFS
La procedura DFS(G,s) si occupa di fare una visita in profondit su ogni vertice u non ancora scoperto,
quindi ogni volta che invocher la sottoprocedura DFS_VISIT(u) questa costruir un albero di radice u.
In ogni albero di radice u viene eseguita la scansione della sua lista di adiacenza: se trovo un vertice v
non ancora scoperto (bianco) aggiungo allalbero il vertice v e larco (u,v). In questo caso dir che u il
predecessore di v nellalbero DFS
8. Descrivere la classificazione degli archi che la visita in profondita produce a partire da un
grafo G=<V,E>. Come si classifica un generico arco (u,v) del grafo?
La DFS produce 4 tipi di archi:
Archi dellalbero: sono gli archi della foresta DFS: un arco (u,v) un arco dellalbero se v
stato scoperto esplorando larco (u,v)
Archi allindietro: sono archi (u,v) che connettono u ad un suo antenato v in un albero DFS. (i
cappi vengono considerati alberi allindietro).
Archi in avanti: sono archi che NON sono dellalbero e che connettono un vertice u ad un suo
discente v in un albero
Archi di attraversamento: Sono tutti gli altri:
o possono connettere vertici dello stesso albero DFS purch un vertice non sia antenato
dellaltro
o possono connettere vertici in alberi DFS distinti

9. Scrivere qual e il tempo di calcolo dellalgoritmo DFS motivando la risposta.


Complessit algoritmo: TETA(V+E) tempo lineare
Complessit DFS(G,s) = TETA(V) : i 2for vengono svolti V volte
Complessit DFS_VISIT(u) = TETA(E) : la DFS_VISIT viene chiamata esattamente una volta per ogni
vertice v in V (infatti prima o poi metto tutti i vertici a grigio). Allinterno della procedura il for viene
eseguito |Adj(v)| volte, quindi il costo totale dato dalla somma di tutte le |Adj(v)| cio TETA(E).
10. Esporre, motivando la risposta, quale la relazione tra il numero di componenti connesse di
un grafo G non orientato ed il numero di volte che la procedura DFSVisit viene invocata
allinterno della procedura DFS(G) eseguita su G.
Ogni volta che viene invocata la DFS_VISIT(u) viene costruita una nuova componente connessa di G
partendo da u. Quindi il numero di invocazioni corrisponde al numero di componenti connesse di G

11. Dare la definizione di ordinamento topologico, specificando bene a che tipo di grafo si applica.
Descrivere come si ottiene lordinamento topologico sfruttando lalgoritmo DFS.
Posso usare la DFS per effettuare un ordinamento topologico di GRAFI ORIENTATI ACICLICI
chiamati DAG.
Un ordinamento topologico di un DAG=(V,E) un ordinamento lineare di tutti i suoi vertici tale che se
G contiene un arco (u,v) allora u compare prima di v nellordinamento (se G non fosse aciclico un
ordinamento di questo tipo sarebbe impossibile).
Immagino questo ordinamento come un ordinamento di tutti i vertici di G lungo una linea orizzontale in
modo tale che gli archi orientati vadano da sx verso dx (questo lo faccio ordinando il tempo f[u]
(ottenuto dalla DFS) per ogni vertice v in modo decrescente)
12. Descrivere la caratterizzazione della struttura di un cammino minimo p=< v1, ,vl> utilizzata
dallalgoritmo di Floyd-Warshall.

k
i

Contiene tutti i vertici intermedi nellinsieme {1,2,k-1}


Contiene tutti i vertici intermedi nellinsieme {1,2,k-1}
Cammino minimo p: contiene tutti i vertici intermedi in {1,2.k-1}
Lalgoritmo di Floyd_warshall sfrutta una relazione tra il cammino minimo p e i cammini minimi da i a
j aventi vertici intermedi nellinsieme {1,2..k-1}
Questa relazione cambia a seconda se K un vertice intermedio di p oppure no.
Se K appartiene a P il costo del cammino minimo da i a j con vertici intermedi in {1.k} uguale alla
somma del cammino minimo da i a k con vertici intermedi in {1,2..k-1} e del cammino minimo da k a
j con vertici interme in {1,2,.k-1}.
Se K non appartiene a P il costo del cammino minimo da i a j con vertici intermedi in {1.k} uguale
al costo del cammino minimo da i a j con vertici intermedi in {1.k-1}
A priori non so se k un vertice intermedio a p oppure no, quindi per trovare il cammino minimo
considero entrambi i costi ottenuti dai due casi sopra e poi scelgo il minimo.
13. Illustrare e motivare le equazioni di ricorrenza su cui si basa lalgoritmo di Floyd-Warshall,
specificando bene il significato delle variabili coinvolte.
Le equazioni di ricorrenza su cui si basa lalgoritmo di Floyd Warshall derivano dal ragionamento
fatto nella domanda 12.
Definizione variabili:

dij(k) = il costo del cammino minimo da i a j con vertici intermedi in {1.k}


wij = peso dellarco (i,j)
eq. Ricorrenza:

wij

dij(k) =

se k=0 (non ho vertici intermedi)

min (dij(k-1) , dik(k-1) + dkj(k-1))

se k>=1

14. Illustrare un metodo per costruire i cammini minimi nellalgoritmo di Floyd- Warshall.

15. Che cose la chiusura transitiva di un grafo orientato? Descrivere un modo per calcolarla.
La chiusura transitiva di un grafo G un grafo G* che ha lo stesso insieme di vertici e un insieme di
archi E* >= E
E* un ampliamento dellinsieme di archi E
E* = {(i,j) : esiste un cammino da i a j in G}
2

V={1,2,3,4}
E= {(1,2), (2,3), (3,4)}
Applicando la chiusura transitiva ottengo

3
4

V*=V
E*={(1,2), (1,3), (1,4), (2,3), (2,4), (3,4)}

E transitiva perch se c la relazione 1R2 e 2R3 esiste anche la relazione 1R3


Aggiungo larco (1,4) solo se esiste un cammino minimo da 1 a 4 tramite vertici intermedi
I grafi G e G* li rappresento con la matrice di adiacenza e la variabile t rappresenta le celle della matrice
su G*

La soluzione sta in tij (n)

16. Descrivere come modificare le equazioni di ricorrenza dellalgoritmo di Floyd-Warshall per


calcolare la chiusura transitiva di un grafo orientato.
La procedura scritta nella risposta 15 la ricorrenza che risolve lalgoritmo di Floyd-Warshall con
queste sostituzioni:
Min -> OR
+ -> AND