Алгоритм Беллмана-Форда
Описание
Алгоритм Беллмана-Форда (Bellman-Ford algorithm) - это алгоритм поиска кратчайших путей от одной вершины графа до всех остальных во взвешенном графе. В отличие от алгоритма Дейкстры, данный алгоритм допускает ребра с отрицательным весом.
Алгоритм маршрутизации RIP (алгоритм Беллмана-Форда) был впервые разработан в 1969 году, как основной для сети ARPANET.

Задача
Дан ориентированный или неориентированный граф G
со взвешенными ребрами. Длиной пути назовем сумму весов ребер, входящих в этот путь. Требуется найти кратчайшие пути от выделенной вершины s
до всех вершин графа.
Заметим, что кратчайших путей может не существовать. Так, в графе, содержащем цикл с отрицательным суммарным весом, существует сколь угодно короткий путь от одной вершины этого цикла до другой (каждый обход цикла уменьшает длину пути). Цикл, сумма весов ребер которого отрицательна, называется отрицательным циклом.
Решение задачи будет зависеть от того, содержит ли граф отрицательные циклы.
Сложность
- худшая временная -
O(V x E)
, гдеV
- множество вершин, аE
- множество ребер - лучшая временная -
O(E)
- худшая пространственная -
O(V)
Реализация
// algorithms/graphs/bellman-ford.js
// Функция принимает граф и начальную вершину
export default function bellmanFord(graph, startNode) {
// Расстояния
const distances = {}
// Предыдущие вершины
const previous = {}
// Расстояние до начальной вершины равняется 0
distances[startNode.getKey()] = 0
// Все остальные расстояния равняются бесконечности
graph.getAllNodes().forEach((node) => {
if (node.getKey() !== startNode.getKey()) {
distances[node.getKey()] = Infinity
}
previous[node.getKey()] = null
})
// Нам требуется `V - 1` итераций, где `V` - множество вершин
for (let i = 0; i < graph.getAllNodes().length - 1; i++) {
// Перебираем все вершины на каждой итерации
Object.keys(distances).forEach((key) => {
const node = graph.getNodeByKey(key)
// Перебираем все ребра
graph.getNeighbors(node).forEach((neighbor) => {
const edge = graph.findEdge(node, neighbor)
// Проверяем, является ли расстояние до соседа
// на этой итерации меньше, чем на предыдущей
const distanceToNeighbor = distances[node.getKey()] + edge.weight
if (distanceToNeighbor < distances[neighbor.getKey()]) {
distances[neighbor.getKey()] = distanceToNeighbor
previous[neighbor.getKey()] = node
}
})
})
}
return {
distances,
previous,
}
}
Тесты
Запускаем тесты:
npm run test ./algorithms/graphs/__tests__/bellman-ford
