Алгоритм Флойда
Алгоритм Флойда (алгоритм Флойда–Уоршелла) — алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Работает корректно, если в графе нет циклов отрицательной величины, а в случае, когда такой цикл есть, позволяет найти хотя бы один такой цикл. Этот алгоритм работает в течение времени
и использует памяти. Разработан в 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 (рус.)