Алгоритм Форда-Беллмана
| Задача: |
| Для заданного взвешенного графа найти кратчайшие пути из заданной вершины до всех остальных вершин. В случае, когда в графе содержатся отрицательные циклы, достижимые из , сообщить, что кратчайших путей не существует. |
Введение
Количество путей длины рёбер можно найти с помощью метода динамического программирования.
Пусть — количество путей длины рёбер, заканчивающихся в вершине . Тогда .
Аналогично посчитаем пути кратчайшей длины. Пусть — стартовая вершина. Тогда , при этом , а
| Лемма: |
Если существует кратчайший путь от до , то |
| Доказательство: |
| Пусть кратчайший путь состоит из ребер, тогда корректность формулы следует из динамики, приведенной ниже. |
Псевдокод
Используя приведенные формулы, алгоритм можно реализовать методом динамического программирования.
for k = 1 to // вершины нумеруются с единицы for for d[k + 1][u] = min(d[k + 1][u], d[k][v] + ) // — вес ребра uv
Также релаксацию можно свести к одномерному случаю, если не хранить длину пути в рёбрах. Одномерный массив будем обозначать , тогда
Корректность
| Лемма: |
Пусть — взвешенный ориентированный граф, — стартовая вершина.
Тогда после завершения итераций цикла выполняется неравенство . |
| Доказательство: |
|
Воспользуемся индукцией по : База индукции
Индукционный переход
|
Реализация алгоритма и ее корректность
bool fordBellman(s):
for
d[v] =
d[s] = 0
for i = 0 to
for
if d[v] > d[u] + // — вес ребра uv
d[v] = d[u] +
for
if d[v] > d[u] +
return false
return true
В этом алгоритме используется релаксация, в результате которой уменьшается до тех пор, пока не станет равным .
— оценка веса кратчайшего пути из вершины в каждую вершину .
— фактический вес кратчайшего пути из в вершину .
| Лемма: |
Пусть — взвешенный ориентированный граф, — стартовая вершина. Тогда после завершения итераций цикла для всех вершин, достижимых из , выполняется равенство . |
| Доказательство: |
|
Рассмотрим произвольную вершину , достижимую из . Пусть , где , — кратчайший ациклический путь из в . Путь содержит не более ребер. Поэтому . Докажем следующее утверждение:
Воспользуемся индукцией по : База индукции
Индукционный переход
|
| Теорема: |
Пусть — взвешенный ориентированный граф, — стартовая вершина. Если граф не содержит отрицательных циклов, достижимых из вершины , то алгоритм возвращает и для всех . Если граф содержит отрицательные циклы, достижимые из вершины , то алгоритм возвращает . |
| Доказательство: |
|
Пусть граф не содержит отрицательных циклов, достижимых из вершины . Тогда если вершина достижима из , то по лемме . Если вершина не достижима из , то из несуществования пути. Теперь докажем, что алгоритм вернет значение . После выполнения алгоритма верно, что для всех , значит ни одна из проверок не вернет значения . Пусть граф содержит отрицательный цикл , где , достижимый из вершины . Тогда . Предположим, что алгоритм возвращает , тогда для выполняется . Просуммируем эти неравенства по всему циклу: . Из того, что следует, что . Получили, что , что противоречит отрицательности цикла . |
Сложность
Инициализация занимает времени, каждый из проходов требует времени, обход по всем ребрам для проверки наличия отрицательного цикла занимает времени. Значит алгоритм Беллмана-Форда работает за времени.
Нахождение отрицательного цикла
Приведенная выше реализация позволяет определить наличие в графе цикла отрицательного веса. Чтобы найти сам цикл, достаточно хранить вершины, из которых производится релаксация.
Если после итерации найдется вершина , расстояние до которой можно уменьшить, то эта вершина либо лежит на каком-нибудь цикле отрицательного веса, либо достижима из него. Чтобы найти вершину, которая лежит на цикле, можно раз пройти назад по предкам из вершины . Так как наибольшая длина пути в графе из вершин равна , то полученная вершина будет гарантированно лежать на отрицательном цикле.
Зная, что вершина лежит на цикле отрицательного веса, можно восстанавливать путь по сохраненным вершинам до тех пор, пока не встретится та же вершина . Это обязательно произойдет, так как в цикле отрицательного веса релаксации происходят по кругу.
int[] negativeCycle(s):
for
d[v] =
p[v] = -1
d[s] = 0
for i = 0 to
for
if d[v] > d[u] +
d[v] = d[u] +
p[v] = u
for
if d[v] > d[u] +
for i = 0 to
v = p[v]
u = v
while u != p[v]
ans.add(v) // добавим вершину к ответу
v = p[v]
reverse(ans)
break
return ans
Источники информации
- Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд — М.: Издательский дом «Вильямс», 2009. — ISBN 978-5-8459-0857-5.
- MAXimal :: algo :: Алгоритм Форда-Беллмана