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