Document

Transcripción

Document
Problema del camino
mínimo con costos negativos
Dra. Laura Cruz Reyes
Instituto Tecnológico de Ciudad Madero
México
Fundamento
„
El algoritmo de Dijkstra requiere que los
costos de las aristas sean no negativas.
„
Un algoritmo alternativa es necesario para
aristas negativas.
Fundamento
Una vez que un vértice V ha sido procesado, puede existir un camino
de vuelta a V desde un vértice U no procesado con costo bastante
negativo. En tal caso el camino que va desde O hasta V pasando por U
es mejor que ir de O a V sin pasar por U. Si esto ultimo ocurriera se
tendría que visitar de nuevo V porque los vértices alcanzables desde
V podrían también ser afectados.
2
-4
4
2
V
a
2
-10
O
2
5
5
U
8
b
6
Fundamento
El camino de V3 a V4 tiene costo 2. Sin embargo, existe
un camino mas corto siguiendo el ciclo V3, V4, V1, V3, V4,
que tiene coste -3. Y este camino no es aun el mas corto,
ya que podríamos dar un numero arbitrario de vueltas al
ciclo. Por lo que el camino mas corto entre estos dos
puntos está indefinido.
2
V0
-10
4
1
2
V2
V1
3
V4 2 -3
4
8
5
2
V3
6
V5
V6
1
Ciclo de costo negativo
Fundamento
„
Una combinación de los algoritmos con
peso y sin peso resolverá el problema,
pero a costa de un drástico incremento
potencial en el tiempo de ejecución.
„
Cuando se modifica Dw debemos
(re)visitar este vértice en algún momento
del futuro. Se utiliza una cola como en los
algoritmos sin peso, pero usando Dv+cv,w
como medida de la distancia
Fundamento
„
Para la detección de ciclos se lleva un control del
número de veces que se ha pasado por un nodo.
„
En el peor de los casos hay una liga de todos los
demás nodos al nodo en cuestión, y por lo tanto se
puede detectar un ciclo de costo negativo cuando
se ha llegado a él más de |V| veces.
„
Para acelerar el algoritmo, el mismo control de
pasadas puede indicar si el nodo no está en la cola
(extra ==0), en tal caso se inserta y se incrementa el
control. Si el nodo se encuentra en la cola
(extra==1) se hace una inserción y borrado lógico,
incrementando el control en dos unidades.
Algoritmo
Algoritmo costoNegativo (nodoOrig, tabla)
tabla es un grafo de adyacencia
v, w son nodos
cvw es el costo de ir de v a w
q es una cola de nodos
tabla[].extra =0 //número inicial de visitas al nodo
tabla[].dist = ∞ //costo inicial de todos los nodos
tabla[nodoOrig].dist=0 //costo del nodo origen
q.insertar(nodoOrig) //costo del nodo origen
//el nodo se hace impar para indicar que no está en cola
tabla[nodoOrig].extra = ++
while !q.estaVacia ()
v = q.eliminar( );
//si pasó |V| veces por el nodo entonces existe un ciclo
if (tabla[v].extra++ > 2 * numVertices)
return false;
for p=tabla[v].adj; p.estaDentro(); p.avanzar ()
(w, cvw) = p.retrieve(); //recupera destino y costo
//si el nodo adyacente disminuye su costo pasando por v
if (tabla[w].dist > tabla[v].dist + cvw)
tabla[w].dist = tabla[v].dist + cvw;
tabla[w].prev = v;
//si extra es par, el nodo no está en la cola
//el nodo se inserta y extra se incrementa
if (tabla[w].extra % 2 == 0)
q.insertar(w);
table [w].extra++
else //se cuenta la entrada y salida
table [w].extra+=2;
return true;
virtual a la cola
Complejidad
„
Cuando visitamos el vértice v por i-esima
vez, el valor de Dv es la longitud del camino
más corto formado por, a lo sumo i aristas.
„
Si no hay ciclos negativos un vértice puede
salir de la cola como mucho |V| veces y el
algoritmo consume un tiempo de O(|E| |V|).
Si un vértice sale de la cola más de |V|
veces, habremos detectado un ciclo de
coste negativo.
0
Ejemplo 1 0
19
19
A
19
B
12
0
19
A
19
B
8
D
12
C
A
8
C
17
0
19
A
12
D
‐2
29
D
17
12
‐2
C
17
19
B
8
19
B
29
‐2
17
29
12
D
19
‐2
8
C
19
B
‐2
8
D
A
0
C
El nodo estaba en cola
y se sacó para visitar
sólo a sus adyacentes
que obtienen un camino
de
menor
longitud
pasando por él.
0
Ejemplo 2 0
19
19
19
A
B
A
8
19
B
‐23
0
19
A
‐23
8
19
B
‐23
8
8
12
D
0
19
A
16
B
8
‐4
12
0
A
C
16
B
8
‐7
12
C
C
19
A
13
B
‐23
8
D
0
‐4
12
D
C
19
‐23
8
D
12
D
C
‐4
8
‐23
5
‐7
D
12
C
Ejemplo 2
0
19
A
10
B
8
‐23
2
‐10
D
12
C
El algoritmo se detiene
porque el nodo B ha sido
visitado |V | veces
Ejercicio
„
Encuentre los caminos mínimos del origen a
todos los demás vértices
0
A
E
‐43
‐11
19
D
‐23
B
87
10
C
Implementación del
algoritmo
Código
Este algoritmo permite aristas con coste negativo
Devuelve false si se detecta ciclos negativos
private boolean negative (int startNode)
{
int v, w;
Queue q = new QueueAr ();
int cvw;
clearData ();
table [startNode].dist = 0;
q.enqueue (new Integer (startNode));
table [startNode].scratch++;
try
{
while (!q.isEmpty ())
{
v = ((Integer) q.dequeue ()).intValue ();
v, W son las direcicones a los nodos
se crea la referencia a nodos a la cola.
inicializa los valores de dist, ant ,nombre
etc.
Inicializa costo del nodo origen
inserta el nodo origen
incrementa scretch(extra) cuando el
v vertice entra.
checa si existen elementos en la cola
quita el el primer elemnto de la cola
y verifica si el valor obtenido en su
posicion extra es mayor que el numero
de vertices*2 si es asi quiere
if (table [v].scratch++ > 2 * numVertices) decir que ese elemento ya estuvo en la
return false;
cola y que existe un ciclo negativo.
ListItr p = new LinkedListItr (table [v].adj);
for (; p.isInList () ; p.advance ())
{
w = ((Edge) p.retrieve ()).dest;
cvw = ((Edge) p.retrieve ()).cost
if (table [w].dist > table [v].dist + cvw)
{
table [w].dist = table [v].dist + cvw;
table [w].prev = v;
if (table [w].scratch++ % 2 ==
0)
q.enqueue (new Integer (w));
else
table [w].scratch++;
}
}
}
}
catch (Underflow e)
{
}
return true;
}
Crea el apuntador p, para los elementos adyacentes
Procesa vertices adaycentes
Recupera el valor del coste
Actualiza los valores si el coste actual es menor que el anterior.
Verifica si el elemento a agregar ya a entrado y salido de
la cola, si no ha entrado se inserta , de lo contrario
incremnta extra.
Retorna false
si existen ciclos negativos
Ejercicio
12
B
A
-11
87
19
23
E
D
C
10
43
0
tabla[nodoOriginal].dist = 0
q.Insertar( );
NODO ORIGEN
Nom
bre
dist
ant
extra
ady
0
A
0
∞
-1
1
0
BD
1
B
∞
-1
0
E
2
C
∞
-1
0
A
3
D
∞
-1
0
BC
E
∞
-1
0
D
4
0
0
Nodo Coste
tabla[nodoOrig].extra++;
if (tabla[0].extra++ > 2*numVertices)
If (1 > 2*5)
!q.esVacia( );
NO HAY CICLO
1
0
…
If (tabla[1].dist > tabla[0].dist+Cvw)
12
0
V=0
q
pÆB
W=1
Nodo Coste
(∞ > 0+12) SI
Cvw=12
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
BD
1
B
12 -1
∞
0
2
1
01
2
C
∞
-1
0
A
3
D
∞
-1
0
BC
4
E
∞
-1
0
D
{ tabla[1].dist=tabla[0].dist+Cvw;
∞=0+12
tabla[1].ant=v;
-1=0
If (tabla[1].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (1.12)
E
If (tabla[3].dist > tabla[0].dist+Cvw)
(∞ > 0+87) SI
{ tabla[3].dist=tabla[0].dist+Cvw;
∞=0+87
3
87
1
12
V=0
pÆD
W=3
Nodo Coste
Cvw=87
tabla[3].ant=v;
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
B 12
C ∞
0
1
E
-1
0
A
-1
0
1
0
BC
-1
0
D
-1=0
If (tabla[3].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (3.87)
2
3
4
D 87
∞
E ∞
if (tabla[1].extra++ > 2*numVertices)
If (1 > 2*5)
NO HAY CICLO
…
If (tabla[4].dist > tabla[1].dist+Cvw)
4
1
3
87
!q.esVacia( );
1
12
q
V=1
0
pÆE
pÆNULL
W=4
Nodo Coste
(∞ > 12+(-11)) SI
Cvw=-11
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
0
2
1
E
2
B 12
C ∞
-1
0
A
3
D 87
E
1
10
BC
4
0
-1
1
{ tabla[4].dist=tabla[1].dist+Cvw;
∞=12-11
tabla[4].ant=v;
-1=1
If (tabla[4].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (4.1)
1
∞
D
if (tabla[3].extra++ > 2*numVertices)
2
If (1 > 2*5)
NO HAY CICLO
…
If (tabla[2].dist
(tabla[1].dist > tabla[3].dist+Cvw)
-1=3
If (tabla[2].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (2.97)
1
3
87
!q.esVacia( );
V V= =3 1
q
pÆC
pÆB
pÆNULL
WW=1
=2
Cvw=23
Cvw
= 10
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
B 12
C 97
∞
{ tabla[2].dist=tabla[3].dist+Cvw;
tabla[2].ant=v;
4
Nodo Coste
(12 > 87+23) NO
(∞ > 87+10) Si
∞=87+10
97
3
0
-13
D 87 0
2 E
10 A
2 BC
1
4
E
1
2
1
1
D
if (tabla[4].extra++ > 2*numVertices)
If (1 > 2*5)
NO HAY CICLO
…
3
44
2
97
4
!q.esVacia( );
q
1
3
V= 4
pÆNULL
pÆD
w= 3
If (tabla[3].dist > tabla[4].dist+Cvw)
(87 > 1+43) SI
Nodo Coste
Cvw= 43
{ tabla[3].dist=tabla[4].dist+Cvw;
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
B 12
C 97
0
2
E
1
A
3
3
D 44
87 40
3
2
BC
4
E
12
D
87=1+43
tabla[3].ant=v;
0=4
If (tabla[3].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (3,44)
2
1
1
if (tabla[2].extra++ > 2*numVertices)
if (tabla[3].extra++ > 2*numVertices)
If (1 > 2*5)
If (3 > 2*5)
NO HAY CICLO
NO HAY CICLO
…
…
If (tabla[0].dist > tabla[2].dist+Cvw)
If (tabla[1].dist > tabla[3].dist+Cvw)
(0 > 97+19)
NO
If (tabla[2].dist
> tabla[3].dist+Cvw)
(12 > 44+23) NO
(97 > 44+10) SI
!q.esVacia( );
3
22 97
54
If (tabla[2].extra++ % 2 == 0)
(0==0) SI
{ q.insertar(); // (2,54)
V= 2
4
3
pÆNULL
pÆA
pÆB
pÆC
0
w= 2
1
19
Cvw= 10
23
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
0
2
B 12
C 54
97
3
D 44
2 E
1
2
3 A
4
3 BC
4
E
97=44+10
3=3
q
Nodo Coste
{ tabla[2].dist=tabla[3].dist+Cvw;
tabla[2].ant=v;
q
!q.esVacia(
);
44
1
3
4
1
2
D
if (tabla[2].extra++ > 2*numVertices)
If (2 > 2*5)
NO HAY CICLO
!q.esVacia( );
…
2
q
54
V= 2
3
pÆA
pÆNULL
pÆNULL
If (tabla[0].dist > tabla[2].dist+Cvw)
(0 > 54+19) NO
w= 0
Nodo Coste
Cvw= 19
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
0
3
D 44
2
43
4
E
2
B 12
C 54
BC
4
E
2
D
1
3
4
1
A
No
mb
re
dist
ant
extr
a
ady
0
A
0
-1
2
BD
1
0
3
A
3
D 44
4
E
4
1
2
4
4
E
2
B 12
C 54
2
D
1
BC

Documentos relacionados