Cammini minimi con una
sorgente
Problema dei cammini minimi
Varianti e archi negativi
Sottostruttura ottima di un cammino minimo
Algoritmo di Dijkstra
Complessità dell’algoritmo
Rappresentazione dei cammini minimi
Problema dei cammini minimi
Input: un grafo G=(V,E) orientato e pesato, con una
funzione peso w: E → R, che associa ad ogni arco in E
un peso a valore nei reali.
1
9
8
1
2
1
3
1
1
3
1
1
6
4
4
-3
5
6
1
1
4
-1
1
3
3
6
2
1
5
1
Problema dei cammini minimi
Il peso di un cammino p= <v1, v2, …,vk> è la somma
dei pesi degli archi che lo costituiscono.
k
w(p)   w(v i 1 , v i )
i2
15 min + 50 min = 65 min
50
MC
20
p1= <PO, FI, SI> =
PT
LU
20
35
25
20
PO
PI
FI
LI
35
50
65
SI
70
GR
p2 = <PO, FI, AR, SI> =
15
60
40
AR
15 min + 35 min + 40 min =
= 90 min
p3 = <PO, FI, PI, LI, GR,
SI> = 160 min
Problema dei cammini minimi
Il peso di un cammino minimo dal vertice u al vertice
v è definito da:


p
min w(p) : u 

v se esiste un cammino da u a v
δ(u, v)  

altrimenti

Un cammino minimo dal vertice u al vertice v è definito
come un qualunque cammino p con peso w(p) = δ(u,v).
Può non essere unico!
δ(6,1) = 7
9
8
1
2
1
3
3
3
3
3
4
-2
5
6
-1
p1 = <6, 2, 3, 1 >
w(p1) = 7
p2 = <6, 1>
w(p2) = 9
p3 = <6, 5, 6, 2, 3, 1 >
w(p3) = 9
p4 = <6, 5, 4, 3, 1 >
w(p4) = 7
Vari problemi
• Problema di cammini minimi con sorgente singola: si
vuole trovare un cammino minimo da un dato vertice
sorgente s ad ogni vertice v in V.
• Problema di cammini minimi con destinazione
singola: si vuole trovare da ogni vertice v in V un
cammino minimo ad un dato vertice destinazione t.
• Problema di cammini minimi tra una coppia: si vuole
trovare un cammino minimo da u a v.
• Problema di cammini minimi tra tutte le coppie:
determinazione di un cammino minimo per ogni coppia di
vertici u e v.
Archi con pesi negativi
Un possibile problema può essere rappresentato dalla
presenza di pesi negativi sugli archi e di cicli che
contengano archi con pesi negativi.
Se il peso di un ciclo è negativo, allora tutti i nodi
raggiungibile dal ciclo hanno un cammino minimo
infinitamente negativo (-∞).
Ciclo <6,5> negativo.
9
8
1
1
3
Ogni volta che compio un giro
diminuisco il peso del cammino
che passa per il ciclo.
2
3
3
3
3
4
-2
5
6
-7
δ(6,1) = -∞
Sottostruttura ottima di un cammino
minimo
Sottocammini di cammini minimi sono cammini minimi
Dato un grafo G=(V,E) con funzione peso w:E→ R, sia
p= <v1, v2, …,vk> un cammino minimo da v1 a vk. Per ogni
i e j tali che 1 ≤ i ≤ j ≤ k, ha che il sottocammino
pij= <vi, vi+1, …,vj> è un cammino minimo.
w(pij)=δ(i,j)
1
i
j
k
p’ij
Dato un altro sottocammino da i a j p’ij, necessariamente
w(pij ) ≤ w(p’ij), altrimenti il cammino minimo passa per p’ij.
Sottostruttura ottima di un cammino
minimo
Di conseguenza:
Si supponga che un cammino minimo p da una sorgente
ad un vertice v passi per l’arco (u,v) con peso w(u,v). Il peso
del cammino minino da s a v è δ(s,v) = δ(s,u) + w(u,v).
δ(s,u)
i
cammino minimo tra u e v
u
w(u,v)
v
δ(s,v) = δ(s,u) + w(u,v).
Più in generale, se esiste un arco (u,v), allora si ha:
δ(s,v) ≤ δ(s,u) + w(u,v).
Algoritmo di Dijkstra
L’algoritmo di Dijkstra risolve il problema dei cammini
minimi con sorgente singola su un grafo orientato e
pesato G=(V,E) nel caso in cui tutti i pesi degli archi siano
non negativi.
Ci sono due insiemi:
• S: dove d[v] = δ(s,v), quindi un cammino minimo tra s e v
è stato determinato.
• Q = V-S: una coda a priorità dove d[v] ha il valore del
cammino con peso minore finora scoperto.
All’inizio, S contiene solo s, d[s]=0, mentre Q=V-{s} con
d[v]=∞.
Algoritmo di Dijkstra
DIJKSTRA(G,w,s)
1.
for ogni vertice u in V[G]
// inizializzazione di ogni vertice
2.
do d[u] ← ∞
3.
p[u] ← NIL
4.
d[s] ← 0
// si comincia dal vertice s
5.
Q ← V[G]
// coda a priorità
6.
S←Ø
// insiemi dei cammini minimi trovati
7.
while Q≠Ø
// termina quando la coda Q è vuota
8.
do u ← EXTRACT-MIN(Q)
// prendi il cammino in Q più
piccolo
9.
S ← S U {u}
// inserisci u in S
10.
for ogni vertice v in Adj[u] // aggiorna cammini minimi in Q
con v adiacente a u
11.
do if d[v] > d[u] + w(u,v)
12.
then d[v] ← d[u] + w[u,w]
13.
p[v] ← u
Esempio
u
10
3
s
0
∞
2
v
1
∞
3
s
9
u
10
4 6
0
10
2
v
1
∞
x
5
5
y
x
(a)
3
s
0
v
1
8
2
5
x
3
s
4 6
(d)
5
5
y
u
10
13
9
2
2
9
4 6
x
0
2
y
5
5
9
3
s
9
4 6
x
2
(e)
y
u
10
0
v
1
8
2
9
9
4 6
7
7
7
7
2
(c)
v
1
8
14
7
∞
2
7
5
1
8
(b)
u
10
0
v
7
∞
2
3
s
4 6
7
5
∞
9
u
10
7
y
5
5
x
2
(f)
7
y
Correttezza algoritmo
Se si esegue un l’algoritmo di Dijkstra su un grafo orientato
e pesato G=(V,E) nel caso in cui tutti i pesi degli archi siano
non negativi, allora al termine vale d[v] = δ(s,v) per ogni v
in V.
Dimostrazione
Supponiamo per assurdo che u sia il primo vertice ad
entrare in S tale che d[u] ≠ δ(s,u). Prendiamo un cammino
minimo da s a u, che può essere decomposto in
s→x→y→u, con x in S, y in Q e (x,y) arco di G.
s
S
p1
x
Può essere
y
p2
u
s=xoy=u
Correttezza algoritmo
s
S
p1
d[x] = δ(s,x)
x
y
p2
u
x è entrato prima
di u in S.
Si ha anche d[y] = δ(s,y) = δ(s,y) + w(x,y), perché
sottocamino di un cammino minimo.
Inoltre d[y] = δ(s,y) ≤ δ(s,u) ≤ d[u].
Nell’algoritmo u viene scelto prima di y (EXTRACT-MIN(Q)), quindi
deve valere l’uguaglianza:
d[y] = δ(s,y) = δ(s,u) = d[u].
ASSURDO! δ(s,u) ≠ d[u].
Complessità
Analisi del tempo di esecuzione:
• Si consideri che la coda con priorità Q come un array
lineare.
• EXTRACT-MIN(Q): ricerca del minimo in Q. Bisogna
vedere tutti i valori in Q, richiede tempo O(|V|)
• EXTRACT-MIN(Q) viene eseguito per ogni vertice quindi il
tempo totale è O(|V|x|V|) = O(|V|2)
• Come in BFS vengono, si esamina la lista di adiacenza
di ogni vertice v, che entra solo una volta in S.
• La somma di tutte liste di adiacenze è |E|.
• Il tempo totale dell’algoritmo di Dijkstra è O(|E|+|V|2).
Rappresentazione dei cammini
minimi
Come nella visita in ampiezza (BFS), l’algoritmo Dijkstra
definisce un sottografo dei predecessori Tp=(Vp,Ep).
L’albero che ne segue contiene i cammini minimi individuati
da s ad ogni vertice raggiungibile v.
Nota: questo vale solo al termine dell’algoritmo.
u
10
3
s
0
1
8
2
u
v
9
3
s
9
4 6
v
1
8
9
Tp=(Vp,Ep)
0
7
5
5
x
2
7
y
5
5
x
2
7
y
Scarica

ppt