Алгоритм Флойда — различия между версиями
Melnik (обсуждение | вклад) м (→Нахождение отрицательного цикла) |
Melnik (обсуждение | вклад) (Картинки) |
||
| Строка 4: | Строка 4: | ||
=== Постановка задачи === | === Постановка задачи === | ||
| − | [[Файл: | + | [[Файл:Floyd_first.png|right|thumb|180px|Текущий (синий) путь и потенциально более короткий (красный)]] |
Дан взвешенный ориентированный граф <tex> G(V, E) </tex>; <tex>\omega_{uv} = | Дан взвешенный ориентированный граф <tex> G(V, E) </tex>; <tex>\omega_{uv} = | ||
| Строка 70: | Строка 70: | ||
| <tex>i = 0</tex> || <tex>i = 1</tex> || <tex>i = 2</tex> || <tex>i = 3 </tex> || <tex>i = 4</tex> | | <tex>i = 0</tex> || <tex>i = 1</tex> || <tex>i = 2</tex> || <tex>i = 3 </tex> || <tex>i = 4</tex> | ||
|- | |- | ||
| − | |width = "180px"| [[Файл: | + | |width = "180px"| [[Файл:0.png|170px]] ||width = "180px"|[[Файл:Floyd_1.png|170px]] ||width = "180px"|[[Файл:Floyd_2.png|170px]] ||width = "180px"|[[Файл:Floyd_algo_3.png|170px]] ||width = "180px"|[[Файл:Floyd_4.png|170px]] |
|- | |- | ||
| <tex>\begin{pmatrix} | | <tex>\begin{pmatrix} | ||
Версия 21:56, 12 января 2013
Алгоритм Флойда (алгоритм Флойда–Уоршелла) — алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Работает корректно, если в графе нет циклов отрицательной величины, а в случае, когда такой цикл есть, позволяет найти хотя бы один такой цикл. Алгоритм работает за времени и использует памяти. Разработан в 1962 году.
Содержание
Алгоритм
Постановка задачи
Дан взвешенный ориентированный граф ; , в котором вершины пронумерованы от до . Требуется найти матрицу кратчайших расстояний , в которой элемент либо равен длине кратчайшего пути из в , либо равен , если вершина не достижима из .
Описание
Обозначим длину кратчайшего пути между вершинами и , содержащего, помимо и , только вершины из множества как , .
На каждом шаге алгоритма, мы будем брать очередную вершину (пусть её номер — ) и для всех пар вершин и вычислять . То есть, если кратчайший путь из в , содержащий только вершины из множества , проходит через вершину , то кратчайшим путем из в является кратчайший путь из в , объединенный с кратчайшим путем из в . В противном случае, когда этот путь не содержит вершины , кратчайший путь из в , содержащий только вершины из множества является кратчайшим путем из в , содержащим только вершины из множества .
Код (в первом приближении)
# Инициализация # Основная часть for i in {1..n}: for u in {1..n}: for v in {1..n}:
В итоге получаем, что матрица и является искомой матрицей кратчайших путей, поскольку содержит в себе длины кратчайших путей между всеми парами вершин, имеющих в качестве промежуточных вершин вершины из множества , что есть попросту все вершины графа. Такая реализация работает за времени и использует памяти.
Код (окончательный)
Утверждается, что можно избавиться от одной размерности в массиве , т.е. использовать двумерный массив . В процессе работы алгоритма поддерживается инвариант , а, поскольку, после выполнения работы алгоритма , то тогда будет выполняться и .
| Утверждение: |
В течение работы алгоритма Флойда выполняются неравенства: . |
|
После инициализации все неравенства, очевидно, выполняются. Далее, массив может измениться только в строчке 5. Докажем второе неравенство индукцией по итерациям алгоритма. Пусть также — значение сразу после итерации. Покажем, что , зная, что . Рассмотрим два случая:
Пусть неравенство было нарушено, рассмотрим момент, когда оно было нарушено впервые. Пусть это была -ая итерация и в этот момент изменилось значение и выполнилось . Так как изменилось, то (так как ранее ) (по неравенству треугольника) . Итак — противоречие. |
# Инициализация # Основная часть for i in {1..n}: for u in {1..n}: for v in {1..n}:
Данная реализация работает за время , но требует уже памяти. В целом, алгоритм Флойда очень прост, и, поскольку в нем используются только простые операции, константа, скрытая в определении весьма мала.
Пример работы
| |
||||
Вывод кратчайшего пути
Алгоритм Флойда легко модифицировать таким образом, чтобы он возвращал не только длину кратчайшего пути, но и сам путь. Для этого достаточно завести дополнительный массив , в котором будет храниться номер вершины, в которую надо пойти следующей, чтобы дойти из в по кратчайшему пути.
Модифицированный алгоритм
# Инициализация
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]
next[u][v] = i
# Вывод кратчайшего пути
def get_shortest_path(u, v):
if d[u][v] == inf:
raise NoPath # Из u в v пути нет
c = u
while c != v:
print c
c = next[c][v]
print v
Нахождение отрицательного цикла
| Утверждение: |
При наличии цикла отрицательного веса в матрице появятся отрицательные числа на главной диагонали. |
| Так как алгоритм Флойда последовательно релаксирует расстояния между всеми парами вершин , в том числе и теми, у которых , а начальное расстояние между парой вершин равно нулю, то релаксация может произойти только при наличии вершины такой, что , что эквивалентно наличию отрицательного цикла, проходящего через вершину . |
Из доказательства следует, что для поиска цикла отрицательного веса необходимо, после завершения работы алгоритма, найти вершину , для которой , и вывести кратчайший путь между парой вершин . При этом стоит учитывать, что при наличии отрицательного цикла расстояния могут уменьшаться экспоненциально. Для предотвращения переполнения все вычисления стоит ограничивать снизу величиной , либо проверять наличие отрицательных чисел на главной диагонали во время подсчета.
Литература
- Кормен, Томас Х., Лейзерсон, Чарльз И., Ривест, Рональд Л., Штайн Клиффорд Алгоритмы: построение и анализ, 2-е издание. Пер. с англ. — М.:Издательский дом "Вильямс", 2010. — 1296 с.: ил. — Парал. тит. англ. — ISBN 978-5-8459-0857-5 (рус.)