Алгоритм Флойда — различия между версиями
Kirelagin (обсуждение | вклад) м |
AVasilyev (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | '''Алгоритм Флойда (алгоритм Флойда–Уоршелла)''' | + | '''Алгоритм Флойда (алгоритм Флойда–Уоршелла)''' {{---}} алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Работает корректно, если в графе нет циклов отрицательной величины, а в случае, когда такой цикл есть, позволяет найти хотя бы один такой цикл. Этот алгоритм работает в течение времени <tex> \Theta(n^3) </tex> и использует <tex> \Theta(n^2) </tex> памяти. Разработан в 1962 году. |
== Алгоритм == | == Алгоритм == | ||
[[Файл:Floyd.png|right|thumb|Текущий (синий) путь и потенциально более короткий (красный)]] | [[Файл:Floyd.png|right|thumb|Текущий (синий) путь и потенциально более короткий (красный)]] | ||
− | + | ||
+ | === Постановка задачи === | ||
+ | |||
+ | Дан взвешенный ориентированный граф <tex> G(V, E) </tex>; <tex>\omega_{uv} = | ||
\begin{cases} | \begin{cases} | ||
\text{weight of }uv ,& \text{if } uv \in E \\ | \text{weight of }uv ,& \text{if } uv \in E \\ | ||
+\infty ,& \text{if } uv \notin E | +\infty ,& \text{if } uv \notin E | ||
− | \end{cases}</tex> | + | \end{cases}</tex>, в котором вершины пронумерованы от <tex>1</tex> до <tex>n</tex>. Требуется найти матрицу кратчайших расстояний <tex> d </tex>, в которой элемент <tex> d_{ij} </tex> либо равен длине кратчайшего пути из <tex> i </tex> в <tex> j </tex>, либо равен <tex> +\infty </tex>, если вершина <tex> j </tex> не достижима из <tex> i </tex>. |
+ | |||
+ | === Описание === | ||
− | Обозначим длину кратчайшего пути между вершинами <tex>u</tex> и <tex>v</tex>, содержащего, помимо | + | Обозначим длину кратчайшего пути между вершинами <tex> u </tex> и <tex> v </tex>, содержащего, помимо <tex>u</tex> и <tex>v</tex>, только вершины из множества <tex> \{ 1 .. i \} </tex> как <tex>d_{uv}^{(i)}</tex>, <tex>d_{uv}^{(0)} = \omega_{uv}</tex>. |
− | |||
− | На каждом шаге алгоритма, мы будем брать очередную вершину (пусть | + | На каждом шаге алгоритма, мы будем брать очередную вершину (пусть её номер {{---}} <tex> i </tex>) и для всех пар вершин <tex>u</tex> и <tex>v</tex> вычислять <tex> d_{uv}^{(i)} = min(d_{uv}^{(i-1)}, d_{ui}^{(i-1)} + d_{iv}^{(i-1)}) </tex>. То есть, если кратчайший путь из <tex>u</tex> в <tex>v</tex>, содержащий только вершины из множества <tex> \{ 1 .. i \} </tex>, проходит через вершину <tex>i</tex>, то кратчайшим путем из <tex> u </tex> в <tex> v </tex> является кратчайший путь из <tex> u </tex> в <tex> i </tex>, объединенный с кратчайшим путем из <tex> i </tex> в <tex> v </tex>. В противном случае, когда этот путь не содержит вершины <tex> i </tex>, кратчайший путь из <tex>u</tex> в <tex>v</tex>, содержащий только вершины из множества <tex> \{ 1 .. i \} </tex> является кратчайшим путем из <tex>u</tex> в <tex>v</tex>, содержащим только вершины из множества <tex> \{ 1 .. i-1 \} </tex>. |
=== Код (в первом приближении) === | === Код (в первом приближении) === | ||
# Инициализация | # Инициализация | ||
− | d | + | <tex dpi = "105"> d^{(0)} = w </tex> |
# Основная часть | # Основная часть | ||
for i in {1..n}: | for i in {1..n}: | ||
for u in {1..n}: | for u in {1..n}: | ||
for v in {1..n}: | for v in {1..n}: | ||
− | d | + | <tex dpi = "105" > d^{(i)}_{uv} = min(d^{(i - 1)}_{uv}, d^{(i - 1)}_{ui} + d^{(i - 1)}_{iv}) </tex> |
+ | |||
+ | В итоге получаем, что матрица <tex> d^{(n)} </tex> и является искомой матрицей кратчайших путей, поскольку содержит в себе длины кратчайших путей между всеми парами вершин, имеющих в качестве промежуточных вершин вершины из множества <tex> \{ 1..n \} </tex>, что есть попросту все вершины графа. Такая реализация работает за <tex> \Theta(n^3) </tex> времени и использует <tex> \Theta(n^3) </tex> памяти. | ||
=== Код (окончательный) === | === Код (окончательный) === | ||
− | + | Утверждается, что можно избавиться от одной размерности в массиве <tex> d </tex>, т.е. использовать двумерный массив <tex>d_{uv}</tex>. В процессе работы алгоритма поддерживается инвариант <tex>\rho(u, v) \le d_{uv} \le d_{uv}^i</tex>, а значит <tex>d_{uv}</tex> тоже в итоге сойдутся к решению. | |
# Инициализация | # Инициализация |
Версия 03:45, 1 ноября 2011
Алгоритм Флойда (алгоритм Флойда–Уоршелла) — алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Работает корректно, если в графе нет циклов отрицательной величины, а в случае, когда такой цикл есть, позволяет найти хотя бы один такой цикл. Этот алгоритм работает в течение времени
и использует памяти. Разработан в 1962 году.Содержание
Алгоритм
Постановка задачи
Дан взвешенный ориентированный граф
; , в котором вершины пронумерованы от до . Требуется найти матрицу кратчайших расстояний , в которой элемент либо равен длине кратчайшего пути из в , либо равен , если вершина не достижима из .Описание
Обозначим длину кратчайшего пути между вершинами
и , содержащего, помимо и , только вершины из множества как , .На каждом шаге алгоритма, мы будем брать очередную вершину (пусть её номер —
) и для всех пар вершин и вычислять . То есть, если кратчайший путь из в , содержащий только вершины из множества , проходит через вершину , то кратчайшим путем из в является кратчайший путь из в , объединенный с кратчайшим путем из в . В противном случае, когда этот путь не содержит вершины , кратчайший путь из в , содержащий только вершины из множества является кратчайшим путем из в , содержащим только вершины из множества .Код (в первом приближении)
# Инициализация# Основная часть for i in {1..n}: for u in {1..n}: for v in {1..n}:
В итоге получаем, что матрица
и является искомой матрицей кратчайших путей, поскольку содержит в себе длины кратчайших путей между всеми парами вершин, имеющих в качестве промежуточных вершин вершины из множества , что есть попросту все вершины графа. Такая реализация работает за времени и использует памяти.Код (окончательный)
Утверждается, что можно избавиться от одной размерности в массиве
, т.е. использовать двумерный массив . В процессе работы алгоритма поддерживается инвариант , а значит тоже в итоге сойдутся к решению.# Инициализация d = w # Основная часть for i in {1..n}: for u in {1..n}: for v in {1..n}: d[u][v] = min(d[u][v], d[u][i] + d[i][v])
Алгоритм всегда завершит работу за
— как несложно видеть, три вложенных цикла выполняются по раз каждый.Пример работы
Вывод кратчайшего пути
Алгоритм Флойда легко модифицировать таким образом, чтобы он возвращал не только длину кратчайшего пути, но и сам путь. Для этого достаточно завести дополнительный массив
, в котором будет храниться номер вершины, в которую надо пойти следующей, чтобы дойти из в по кратчайшему пути.Модифицированный алгоритм
# Инициализация d = w t[u][v] = v если есть ребро uv # Основная часть for i in {1..n}: for u in {1..n}: for v in {1..n}: if (d[u][i] + d[i][v]) < d[u][v]: d[u][v] = d[u][i] + d[i][v] t[u][v] = t[u][i]
# Вывод кратчайшего пути def get_shortest_path(u, v): if d[u][v] == inf: raise NoPath # Из u в v пути нет c = u while c != v: yield c c = t[c][v] yield v
Литература
- Кормен, Томас Х., Лейзерсон, Чарльз И., Ривест, Рональд Л., Штайн Клиффорд Алгоритмы: построение и анализ, 2-е издание. Пер. с англ. — М.:Издательский дом "Вильямс", 2010. — 1296 с.: ил. — Парал. тит. англ. — ISBN 978-5-8459-0857-5 (рус.)