Алгоритм Форда-Беллмана — различия между версиями
м |
|||
| Строка 19: | Строка 19: | ||
'''for''' k = 0 '''to''' n - 2 | '''for''' k = 0 '''to''' n - 2 | ||
'''for''' <tex>v \in V</tex> | '''for''' <tex>v \in V</tex> | ||
| − | '''for''' <tex>u | + | '''for''' <tex> (u, v) \in E </tex> |
d[k + 1][u] = min(d[k + 1][u], d[k][v] + <tex>\omega(u, v)</tex>) <font color="green">// <tex>\omega(u, v)</tex> - вес ребра uv</font> | d[k + 1][u] = min(d[k + 1][u], d[k][v] + <tex>\omega(u, v)</tex>) <font color="green">// <tex>\omega(u, v)</tex> - вес ребра uv</font> | ||
| Строка 57: | Строка 57: | ||
==Реализация алгоритма и ее корректность== | ==Реализация алгоритма и ее корректность== | ||
| − | ''' | + | '''bool''' bellman_ford(s)''':''' |
'''for''' <tex>v \in V</tex> | '''for''' <tex>v \in V</tex> | ||
d[v] = <tex>\mathcal {1}</tex> | d[v] = <tex>\mathcal {1}</tex> | ||
| Строка 79: | Строка 79: | ||
|statement=Пусть <tex>G = (V, E) </tex> {{---}} взвешенный ориентированный граф, <tex> s </tex> {{---}} стартовая вершина. Тогда после завершения <tex> |V| - 1 </tex> итераций цикла для всех вершин, достижимых из <tex>s</tex>, выполняется равенство <tex> d[v] = \delta (s, v) </tex>. | |statement=Пусть <tex>G = (V, E) </tex> {{---}} взвешенный ориентированный граф, <tex> s </tex> {{---}} стартовая вершина. Тогда после завершения <tex> |V| - 1 </tex> итераций цикла для всех вершин, достижимых из <tex>s</tex>, выполняется равенство <tex> d[v] = \delta (s, v) </tex>. | ||
|proof=Рассмотрим произвольную вершину <tex>v</tex>, достижимую из <tex>s</tex>. | |proof=Рассмотрим произвольную вершину <tex>v</tex>, достижимую из <tex>s</tex>. | ||
| − | Пусть <tex>p = \langle v_0,..., v_{k} \rangle </tex>, где <tex>v_0 = s</tex>, <tex>v_{k} = v</tex> {{---}} кратчайший ациклический путь из <tex> s </tex> в <tex> v </tex>. Путь <tex> p </tex> содержит не более <tex> |V| - 1 </tex> ребер. Поэтому <tex>k \ | + | Пусть <tex>p = \langle v_0,..., v_{k} \rangle </tex>, где <tex>v_0 = s</tex>, <tex>v_{k} = v</tex> {{---}} кратчайший ациклический путь из <tex> s </tex> в <tex> v </tex>. Путь <tex> p </tex> содержит не более <tex> |V| - 1 </tex> ребер. Поэтому <tex>k \leqslant |V| - 1</tex>. |
Докажем следующее утверждение: | Докажем следующее утверждение: | ||
| − | :После <tex>n : (n \ | + | :После <tex>n : (n \leqslant k)</tex> итераций первого цикла алгоритма, <tex>d[v_n] = \delta(s, v_n) </tex> |
Воспользуемся индукцией по <tex>n</tex>: | Воспользуемся индукцией по <tex>n</tex>: | ||
| Строка 89: | Строка 89: | ||
'''Индукционный переход''' | '''Индукционный переход''' | ||
:Пусть после <tex>n : (n < k)</tex> итераций, верно что <tex>d[v_n] = \delta(s, v_n)</tex>. Так как <tex>(v_n, v_{n + 1})</tex> принадлежит кратчайшему пути от <tex>s</tex> до <tex>v</tex>, то <tex>\delta(s, v_{n+1}) = \delta(s, v_n) + \omega(v_n, v_{n + 1})</tex>. Во время <tex>l + 1</tex> итерации релаксируется ребро <tex>(v_n,v_{n+1})</tex>, следовательно по завершению итерации будет выполнено | :Пусть после <tex>n : (n < k)</tex> итераций, верно что <tex>d[v_n] = \delta(s, v_n)</tex>. Так как <tex>(v_n, v_{n + 1})</tex> принадлежит кратчайшему пути от <tex>s</tex> до <tex>v</tex>, то <tex>\delta(s, v_{n+1}) = \delta(s, v_n) + \omega(v_n, v_{n + 1})</tex>. Во время <tex>l + 1</tex> итерации релаксируется ребро <tex>(v_n,v_{n+1})</tex>, следовательно по завершению итерации будет выполнено | ||
| − | ::<tex>d[v_{n+1}] \ | + | ::<tex>d[v_{n+1}] \leqslant d[v_n] + \omega(v_n, v_{n+1}) = \delta(s, v_n) + \omega(v_n, v_{n+1}) = \delta(s, v_{n+1})</tex>. |
| − | :Ясно, что <tex>d[v_{n+1}] \ | + | :Ясно, что <tex>d[v_{n+1}] \geqslant \delta(s, v_{n+1}) </tex>, поэтому верно что после <tex>l + 1</tex> итерации <tex>d[v_{n+1}] = \delta(s, v_{n + 1})</tex>. |
:Индукционный переход доказан. | :Индукционный переход доказан. | ||
| Строка 114: | Строка 114: | ||
Из того, что <tex> v_0 = v_{k} </tex> следует, что <tex> \sum\limits^{k}_{i=1} {d[v_{i}]} = \sum \limits_{i=1}^{k} {d[v_{i - 1}]} </tex>. | Из того, что <tex> v_0 = v_{k} </tex> следует, что <tex> \sum\limits^{k}_{i=1} {d[v_{i}]} = \sum \limits_{i=1}^{k} {d[v_{i - 1}]} </tex>. | ||
| − | Получили, что <tex> \sum \limits_{i=1}^{k} {\omega (v_{i-1}, v_{i})} \ | + | Получили, что <tex> \sum \limits_{i=1}^{k} {\omega (v_{i-1}, v_{i})} \geqslant 0 </tex>, что противоречит отрицательности цикла <tex> c </tex>. |
}} | }} | ||
| Строка 127: | Строка 127: | ||
Зная, что вершина <tex> u </tex> лежит на цикле отрицательного веса, можно восстанавливать путь по сохраненным вершинам до тех пор, пока не встретится та же вершина <tex> u </tex>. Это обязательно произойдет, так как в цикле отрицательного веса релаксации происходят по кругу. | Зная, что вершина <tex> u </tex> лежит на цикле отрицательного веса, можно восстанавливать путь по сохраненным вершинам до тех пор, пока не встретится та же вершина <tex> u </tex>. Это обязательно произойдет, так как в цикле отрицательного веса релаксации происходят по кругу. | ||
| − | + | '''int[]''' neg_cycle(s)''':''' | |
| − | + | '''for''' <tex>v \in V</tex> | |
| − | + | d[v] = <tex>\mathcal {1}</tex> | |
| − | + | p[v] = -1 | |
| − | + | d[s] = 0 | |
| − | + | '''for''' i = 0 '''to''' <tex>|V| - 1</tex> | |
| − | + | '''for''' <tex> (u, v) \in E </tex> | |
| − | + | '''if''' d[v] > d[u] + <tex>\omega(u, v)</tex> | |
| − | + | d[v] = d[u] + <tex>\omega(u, v)</tex> | |
| − | + | p[v] = u | |
| − | + | '''for''' <tex> (u, v) \in E </tex> | |
| − | + | '''if''' d[v] > d[u] + <tex>\omega(u, v)</tex> | |
| − | + | '''for''' i = 0 '''to''' <tex>|V| - 1</tex> | |
| − | + | v = p[v] | |
| − | + | u = v | |
| − | + | '''while''' u != p[v] | |
| − | + | ans.add(v) | |
| − | + | v = p[v] | |
| − | + | reverse(ans) | |
| − | + | '''break''' | |
| − | + | '''return''' ans | |
== Источники == | == Источники == | ||
Версия 02:40, 19 декабря 2015
| Задача: |
| Для заданного взвешенного графа найти кратчайшие пути из заданной вершины до всех остальных вершин. В случае, когда в графе содержатся отрицательные циклы, достижимые из , сообщить, что кратчайших путей не существует. |
Содержание
Введение
Сначала стоит вспомнить формулу для количества путей длины . Теперь перепишем ее для пути кратчайшей длины. — стартовая вершина. , при этом , а
| Лемма: |
Если существует кратчайший путь от до , то |
| Доказательство: |
| Пусть кратчайший путь состоит из ребер, тогда корректность формулы следует из динамики, приведенной ниже. |
Псевдокод
Используя приведенные формулы, алгоритм можно реализовать методом динамического программирования.
for k = 0 to n - 2
for
for
d[k + 1][u] = min(d[k + 1][u], d[k][v] + ) // - вес ребра uv
Также релаксацию можно свести к одномерному случаю (одномерный массив будем обозначать ):
Корректность
| Лемма: |
Пусть — взвешенный ориентированный граф, — стартовая вершина.
Тогда после завершения итераций цикла выполняется неравенство . |
| Доказательство: |
|
Воспользуемся индукцией по : База индукции
Индукционный переход
|
Реализация алгоритма и ее корректность
bool bellman_ford(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[] neg_cycle(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. — с.672 — 676. — ISBN 978-5-8459-0857-5.
- Алгоритм Форда-Беллмана