Si existen múltiples rutas más cortas entre 2 nodos en un gráfico no dirigido, ¿es posible imprimirlas todas utilizando el algoritmo de Dijkstra?

Sí, pero con algunos ajustes al algoritmo.

El algoritmo de Dijkstra encuentra el camino más corto desde el punto inicial hasta el punto final. Para simplificar, digamos que el gráfico es una red de [matemática] M [/ matemática] por [matemática] N [/ matemática] nodos, con bordes ponderados no negativos entre nodos adyacentes, y el objetivo es encontrar el más corto ruta entre el punto [matemática] (0,0) [/ matemática] y [matemática] (M, N) [/ matemática] atravesando los bordes.

Permítanme citar primero el algoritmo de Dijkstra [1]

  1. Asigne a cada nodo un valor de distancia tentativo: ajústelo a cero para nuestro nodo inicial y al infinito para todos los demás nodos.
  2. Marque todos los nodos sin visitar. Establecer el nodo inicial como actual. Cree un conjunto de nodos no visitados llamado conjunto no visitado que consta de todos los nodos excepto el nodo inicial.
  3. Para el nodo actual, considere todos sus vecinos no visitados y calcule sus distancias tentativas . Por ejemplo, si el nodo actual A está marcado con una distancia tentativa de 6, y el borde que lo conecta con un vecino B tiene una longitud 2, entonces la distancia a B (a través de A) será 6 + 2 = 8. Si esta distancia es menor que la distancia tentativa previamente registrada de B, sobrescriba esa distancia. Aunque un vecino ha sido examinado, no está marcado como “visitado” en este momento, y permanece en el conjunto no visitado .
  4. Cuando hayamos terminado de considerar a todos los vecinos del nodo actual, marque el nodo actual como visitado y elimínelo del conjunto no visitado .
  5. Si el nodo de destino se ha marcado como visitado (cuando se planifica una ruta entre dos nodos específicos) o si la distancia tentativa más pequeña entre los nodos en el conjunto no visitado es infinito (cuando se planifica un recorrido completo), deténgase. El algoritmo ha terminado.
  6. Establezca el nodo no visitado marcado con la distancia tentativa más pequeña como el próximo “nodo actual” y vuelva al paso 3.

Supongamos que almacenamos el costo de la ruta más corta a cada nodo en una matriz [math] s [i] [j] [/ math]. Es decir, queremos encontrar el valor de [math] s [M] [N] [/ math]. En el algoritmo original de Dijkstra, este valor de la ruta más corta a cada punto [matemática] (i, j) [/ matemática] es independiente de la dirección de donde vino. Para imprimir la ruta más corta entre el punto inicial y el final, necesitamos almacenar la información sobre la dirección de donde vino.

Es decir, necesitamos agregar una nueva dimensión a la matriz [math] s [i] [j] [/ math], y convertirla en [math] s [i] [j] [k] [/ math]. En este caso, dado que cada nodo tiene 4 vecinos, [math] k [/ math] tiene 4 valores distintos, por ejemplo, [math] {0,1,2,3} [/ math]. Por lo tanto, almacenamos no solo el costo más bajo de llegar a ese nodo [matemática] (i, j) [/ matemática], sino también la dirección de donde vino. (Por ejemplo, k = 0 significa desde arriba, k = 1 significa desde la derecha, k = 2 significa desde la izquierda, k = 3 significa desde abajo). Es decir, en el paso 3, cuando encuentre la distancia tentativa a cada vecino, necesitaremos almacenarlo en la k adecuada para cada uno de sus vecinos.

Luego, cuando finaliza el algoritmo original de Dijkstra, es cuando recuperamos la información de la ruta. Tendremos que retroceder desde el punto [math] (M, N) [/ math] de forma recursiva, observando dónde está la dirección que dio el menor costo para llegar a ese nodo. Podemos hacer una primera búsqueda de amplitud o una primera búsqueda de profundidad para lograr esto. Una vez que presionamos [math] (0,0) [/ math] en la búsqueda, sabemos que tenemos una ruta que da la ruta más corta, y podemos imprimirla. Continuamos haciendo esto hasta que todos los caminos más cortos posibles hayan sido rastreados.

Hay algunos puntos a tener en cuenta al codificar este algoritmo:

  1. La comparación de costos en el paso 4 del algoritmo de Dijkstra es más complicada. En lugar de mirar [math] s [i] [j] [/ math] para nodos no visitados, necesitamos mirar el mínimo para todas las k en [math] s [i] [j] [k] [/ math ] en nodos no visitados.
  2. Si, al explorar los costos tentativos de llegar a los nodos adyacentes del nodo actual, encontramos otra manera de llegar a un nodo visitado en particular, con el mismo costo que el que ya tiene, entonces la matriz de costos [matemática] s [i] [j ] [k] [/ math] tiene que cambiarse para reflejar eso. Es decir, tenemos que hacer cambios en las direcciones donde podemos llegar a un nodo en particular, incluso si ya está visitado.
  3. Al final del algoritmo original de Dijkstra, se debe tener cuidado de no terminar antes de asegurarse de que no haya más rutas que produzcan el mismo costo que la ruta más corta al nodo [matemáticas] (M, N) [/ matemáticas]. Es decir, [matemática] s [i] [j] [k] [/ matemática] para todos los nodos no visitados debe ser mayor que el mínimo (para todas las k) para todos los nodos visitados.

Este algoritmo se puede generalizar fácilmente a un gráfico arbitrario. Supongamos que ahora hay nodos P en todo el gráfico. En este caso, podría ser más fácil hacer una matriz [math] s [p] [q] [/ math], donde p se refiere al nodo en el gráfico y q se refiere al nodo de donde proviene la ruta más corta, y p y q van de 0 a P-1. El algoritmo entonces procederá de manera similar a la descrita anteriormente.

[1] Algoritmo de Dijkstra

La solución de Chong realmente funciona, pero me gustaría ofrecer un método más simple. Usando el algoritmo de Dijkstra, construyó la distancia a todos los vértices. Luego, para cada borde de un gráfico, asigne una dirección desde el vértice con una distancia menor al vértice con una distancia mayor. Esto daría como resultado un gráfico acíclico dirigido.

Finalmente, desde el objetivo, realice esta recurrencia.

Si dist (s) + peso (s, t) = dist (t), para todos los bordes entrantes a t, imprima

(Caminos a s) -st

El bucle invariante del algoritmo de Dijkstra:

[matemáticas] d (u, v) = arg min_ {w} \ {d (u, w) + e (w, v) \} [/ matemáticas]

Una posible implementación de los Algoritmos de Dijkstra depende de una cola prioritaria para consultar los bordes con pesos mínimos primero en tiempo logarítmico.

Luego se mantiene un puntero al nodo padre w que se usa para llegar a v desde u con la ruta más corta. Creo que si mantiene una lista de muchos padres para cada nodo v, puede reconstruir fácilmente las rutas más cortas de una sola fuente.

Un criterio para empujar a los padres a dicha lista sería evaluar si dos o más nodos dan el mismo valor para el mínimo w. Luego, simplemente apunte los punteros a ambos en la lista de padres.

More Interesting

¿Cuál es la técnica de búsqueda que sigue Google?

¿Qué tipo de datos debo usar en C para almacenar datos como a1b2c3? ¿Podría usar una matriz de caracteres para almacenar esto como una cadena?

¿Debería usar la función de clasificación () incorporada de C ++ para problemas en la programación competitiva, o debería implementar el algoritmo por mi cuenta?

Cómo resolver este problema DP (http://codeforces.com/gym/101061/problem/F)

¿Cómo funciona el algoritmo CryptoNight?

¿Cuál es el máximo común divisor de 55 y 75 usando el algoritmo euclidiano?

Si f (n) es O (g (n)) yf (n) es O (h (n)), entonces cuál de las siguientes afirmaciones debe ser verdadera: f (n) + g (n) es O (h (n)), g (n) + h (n) es O (f (n)), f (n) es O (g (n) + h (n)), o ninguno de los anteriores?

¿Qué hace exactamente node = node-> next en una lista vinculada?

Cómo comenzar a crear un modelo / pronóstico de ventas con dos años y medio de datos de ventas anteriores

Cómo hacer que el software de mi sitio web lea un correo electrónico, capture la ID en el asunto y actúe en función de esa ID

Como estudiante universitario, ¿debería centrarme más en aprender estructuras de datos y algoritmos o aprender tecnologías como aplicaciones, web, desarrollo de iOS, etc.?

¿Cuál es la mejor manera de detectar conjuntos similares de flotadores de 0 a 1?

Cómo implementar este algoritmo usando Matlab

¿Cuál es la diferencia entre las estructuras de datos de std :: vector y std :: deque?

Cómo calcular el orden de crecimiento para un fragmento de código dado