Algoritmi Complementi
Algoritmi Complementi
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
Enumerazione e backtracking
06.02 Esercitazioni
E06
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
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)
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)
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
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]
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)
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
wij
dij(k) =
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)}