Русская Википедия:Алгоритм Джонсона

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Алгоритм Джонсона — позволяет найти кратчайшие пути между всеми парами вершин взвешенного ориентированного графа. Данный алгоритм работает, если в графе содержатся рёбра с положительным или отрицательным весом, но отсутствуют циклы с отрицательным весом. Назван в честь Шаблон:Нп5, опубликовавшего алгоритм в 1977 году.

Алгоритм

Дан граф <math>G = (V,E)</math> с весовой функцией <math>\omega\colon E \to R</math>. Если веса всех рёбер <math>\omega</math> в графе неотрицательные, можно найти кратчайшие пути между всеми парами вершин, запустив алгоритм Дейкстры один раз для каждой вершины. Если в графе содержатся рёбра с отрицательным весом, но отсутствуют циклы с отрицательным весом, можно вычислить новое множество рёбер с неотрицательными весами, позволяющее воспользоваться предыдущим методом. Новое множество, состоящее из весов рёбер <math>\hat{\omega}</math>, должно удовлетворять следующим свойствам.

  • Для всех рёбер <math>(u,\;v)</math> новый вес <math>\hat{\omega}(u,\;v)>0</math>.
  • Для всех пар вершин <math>u,\;v \in V</math> путь <math>p</math> является кратчайшим путём из вершины <math>u</math> в вершину <math>v</math> с использованием весовой функции <math>\omega</math> тогда и только тогда, когда <math>p</math> — также кратчайший путь из вершины <math>u</math> в вершину <math>v</math> с весовой функцией <math>\hat{\omega}</math>.

Сохранение кратчайших путей

Лемма (Изменение весов сохраняет кратчайшие пути). Пусть дан взвешенный ориентированный граф <math>G = (V,\;E)</math> с весовой функцией <math>\omega\colon E \to R</math>, и пусть <math>h\colon V \to R</math> — произвольная функция, отображающая вершины на действительные числа. Для каждого ребра <math>(u,\;v) \in E</math> определим

<math>\hat{\omega}(u,\;v) = \omega(u,\;v) + h(u) - h(v).</math>

Пусть <math>p = \langle v_0,\;v_1,\;\ldots,\;v_k \rangle</math> — произвольный путь из вершины <math>v_0</math> в вершину <math>v_k</math>. <math>p</math> является кратчайшим путём с весовой функцией <math>\omega</math> тогда и только тогда, когда он является кратчайшим путём с весовой функцией <math>\hat{\omega}</math>, то есть равенство <math>\omega(p) = \delta(v_0,\;v_k)</math> равносильно равенству <math>\hat{\omega}(p) = \hat{\delta}(v_0,\;v_k)</math>. Кроме того, граф <math>G</math> содержит цикл с отрицательным весом с использованием весовой функции <math>\omega</math> тогда и только тогда, когда он содержит цикл с отрицательным весом с использованием весовой функции <math>\hat{\omega}</math>.

Изменение веса

  1. Для данного графа создадим новый граф <math>G' = (V',\;E')</math>, где <math>V' = V \cup \{s\}</math>, для некоторой новой вершины <math>s \not\in V</math>, а <math>E' = E \cup \{(s,\;v): v \in V\}</math>.
  2. Расширим весовую функцию <math>\omega</math> таким образом, чтобы для всех вершин <math>v \in V</math> выполнялось равенство <math>\omega(s,\;v) = 0</math>.
  3. Далее определим для всех вершин <math>v \in V'</math> величину <math>h(v) = \delta(s,\;v)</math> и новые веса для всех рёбер <math>\hat{\omega}(u,\;v) = \omega(u,\;v) + h(u) - h(v) \geqslant 0</math>.

Основная процедура

В алгоритме Джонсона используется алгоритм Беллмана — Форда и алгоритм Дейкстры, реализованные в виде подпрограмм. Рёбра хранятся в виде списков смежных вершин. Алгоритм возвращает обычную матрицу <math>D = d_{ij}</math> размером <math>|V|\times |V|</math>, где <math>d_{ij} = \delta(i,\;j)</math>, или выдает сообщение о том, что входной граф содержит цикл с отрицательным весом.

Алгоритм Джонсона
Строится граф <math>G'</math>
if Bellman_Ford<math>(G',\;\omega,\;s)</math> = FALSE
   then do print «Входной граф содержит цикл с отрицательным весом»
           return ø
for для каждой <math>v \in V'</math>
   do присвоить величине <math>h(v)</math> значение <math>\delta(s,\;v)</math>,
      вычисленное алгоритмом Беллмана — Форда
   for для каждого ребра <math>(u,\;v) \in E'</math>
      do <math>\hat{\omega}(u,\;v) \leftarrow \omega(u,\;v) + h(u) - h(v)</math>
   for для каждой вершины <math>u \in V</math>
      do вычисление с помощью алгоритма Дейкстры
         <math>(G,\;\hat{\omega},\;u)</math> величин <math>\hat{\delta}(u,\;v)</math>
         для всех вершин <math>v \in V</math>
      for для каждой вершины <math>v \in V</math>
         do <math>d_{uv} \leftarrow \hat{\delta}(u,\;v) + h(v) - h(u)</math>
return D

Сложность

Если в алгоритме Дейкстры неубывающая очередь с приоритетами реализована в виде фибоначчиевой кучи, то время работы алгоритма Джонсона равно <math>O(V^2\log V + V E)</math>. При более простой реализации неубывающей очереди с приоритетами время работы становится равным <math>O(V E\log V)</math>, но для разреженных графов эта величина в асимптотическом пределе ведёт себя лучше, чем время работы алгоритма Флойда — Уоршелла.

См. также

Ссылки

Литература

Шаблон:Алгоритмы поиска на графах