En previsión del comienzo del curso "Algoritmos para desarrolladores", prepararon otra traducción de un artículo interesante.
Problema : Dada una gráfica y un vértice inicial src en una gráfica, es necesario encontrar las rutas más cortas desde src a todos los vértices en una gráfica dada. El gráfico puede contener aristas con pesos negativos.
Ya hemos discutido el algoritmo de Dijkstra como una forma de resolver este problema. El algoritmo de Dijkstra es un algoritmo codicioso, y su complejidad es O (VLogV) (usando el montón de Fibonacci). Sin embargo, Dijkstra no funciona para gráficos con pesos de borde negativos, mientras que Bellman-Ford lo es por completo. El algoritmo de Bellman-Ford es aún más simple que el algoritmo de Dijkstra y es muy adecuado para sistemas distribuidos. Al mismo tiempo, su complejidad es
O (VE) , que es más que el indicador del algoritmo de Dijkstra.
Recomendación : antes de pasar a ver la solución, intente
practicar usted mismo.
Algoritmo
Los siguientes son pasos detallados.
Entrada : Gráfico y vértice inicial
src
.
Salida : La distancia más corta a todos los vértices desde src. Si se produce un ciclo de peso negativo, no se calculan las distancias más cortas, se muestra un mensaje que indica la presencia de dicho ciclo.
- En este paso, las distancias desde el vértice inicial a todos los demás vértices se inicializan como infinitas, y se supone que la distancia a src es 0. Una matriz
dist[]
tamaño |V|
con todos los valores iguales al infinito, con la excepción del elemento dist[src]
, donde src
es el vértice original. - El segundo paso calcula las distancias más cortas. Se deben realizar los siguientes pasos
|V|
-1 veces, donde |V|
- el número de vértices en este gráfico.
- Realice la siguiente acción para cada borde uv :
Si dist[v] > dist[u] + uv
, entonces actualice dist[v]
dist [v] = dist [u] + uv
- En este paso, se informa si hay un ciclo de peso negativo en el gráfico. Para cada borde uv , haga lo siguiente:
- Si
dist[v] > dist[u] + uv
, entonces el gráfico contiene un ciclo de peso negativo.
La idea del paso 3 es que el paso 2 garantiza la distancia más corta si el gráfico no contiene un ciclo de peso negativo. Si volvemos a recorrer todos los bordes y obtenemos un camino más corto para cualquiera de los vértices, esto será una señal de la presencia de un ciclo de peso negativo.
Como funciona Como en otras tareas de programación dinámica, el algoritmo calcula las rutas más cortas de abajo hacia arriba. Primero, calcula las distancias más cortas, es decir, caminos con una longitud de no más de un borde. Luego calcula las rutas más cortas con una longitud de no más de dos aristas, y así sucesivamente. Después de la iteración i-ésima del bucle externo, se calculan las rutas más cortas con una longitud de no más de
i aristas. En cualquier ruta simple, puede haber un máximo de
| V | -1 aristas, por lo que el bucle externo se ejecuta exactamente
| V | -1 veces. La idea es que si calculamos la ruta más corta con no más de
i bordes, iterar sobre todos los bordes garantiza obtener la ruta más corta con no más de
i + 1 bordes (la prueba es bastante simple, puede consultar
esta conferencia o
video del MIT )
Ejemplo
Veamos el algoritmo en el siguiente ejemplo de gráfico. Imágenes tomadas
desde aquí .
Deje que el vértice inicial sea 0. Tome todas las distancias como infinitas, excepto la distancia para
src
. El número total de vértices en el gráfico es 5, por lo que todos los bordes deben ir 4 veces.

Deje que las costillas se trabajen en el siguiente orden: (B, E), (D, B), (B, D), (A, B), (A, C), (D, C), (B, C), ( E, D). Obtenemos las siguientes distancias cuando el pasaje a lo largo de las costillas se completó por primera vez. La primera línea muestra las distancias iniciales, la segunda línea muestra las distancias cuando se procesan los bordes (B, E), (D, B), (B, D) y (A, B). La tercera línea muestra la distancia de procesamiento (A, C). La cuarta línea muestra lo que sucede cuando se procesan (D, C), (B, C) y (E, D).

La primera iteración asegura que todas las rutas más cortas no sean más largas que la ruta de 1 arista. Obtenemos las siguientes distancias cuando se completa la segunda pasada en todos los bordes (la última línea muestra los valores finales).

La segunda iteración asegura que todas las rutas más cortas tengan una longitud de como máximo 2 aristas. El algoritmo se ejecuta a lo largo de todos los bordes 2 veces más. Las distancias se minimizan después de la segunda iteración, por lo que la tercera y la cuarta iteraciones no actualizan los valores de distancia.
Implementación
Valores de salida:
Notas:- Los pesos negativos se encuentran en varias aplicaciones de gráficos. Por ejemplo, en lugar de aumentar el costo de una ruta, podemos beneficiarnos siguiendo una ruta específica.
- El algoritmo Bellman-Ford funciona mejor para sistemas distribuidos (mejor que el algoritmo de Dijkstra). A diferencia de Dijkstra, donde necesitamos encontrar el valor mínimo de todos los vértices, en Bellman Ford, los bordes se consideran uno a la vez.
Ejercicios:- El algoritmo estándar de Bellman-Ford informa los caminos más cortos solo si no tiene ciclos de peso negativo. Modifíquelo para que informe las rutas más cortas incluso si existe tal ciclo.
- ¿Podemos usar el algoritmo de Dijkstra para encontrar las rutas más cortas en un gráfico con pesos negativos? Existe una idea así: calcule el valor de peso mínimo, agregue un valor positivo (igual al valor absoluto del valor de peso mínimo) a todos los pesos y ejecute el algoritmo Dijkstra para el gráfico modificado. ¿Funcionará tal algoritmo?
Implementación simple del algoritmo Bellman-FordFuentes:www.youtube.com/watch?v=Ttezuzs39nken.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithmwww.cs.arizona.edu/classes/cs445/spring07/ShortestPath2.prn.pdf