Изменения

Перейти к: навигация, поиск

Алгоритм Флойда

8187 байт добавлено, 17:06, 20 июня 2016
Восстановление правильного кода
[[Файл:Floyd_first.png|right|thumb|180px|Текущий (синий) путь и потенциально более короткий (красный)]]
Дан взвешенный ориентированный [[Основные определения: граф , ребро, вершина, степень, петля, путь, цикл|граф]] <tex> G(V, E) </tex>; , в котором вершины пронумерованы от <tex>1</tex> до <tex>n</tex>. <tex>\omega_{uv} =
\begin{cases}
\text{weight of }uv ,& \text{if } uv \in E \\
+\infty ,& \text{if } uv \notin E
\end{cases}</tex>, в котором вершины пронумерованы от <texbr>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>d^{(0)}_{uv} = w</tex>
'''for''' <tex>i = 1 '''to''' n\in V</tex> '''for''' <tex>u = 1 '''to''' n\in V</tex> '''for''' <tex>v = 1 '''to''' n\in V</tex>
<tex> d^{(i)}_{uv} = \min(d^{(i - 1)}_{uv}, d^{(i - 1)}_{ui} + d^{(i - 1)}_{iv}) </tex>
'''func''' floyd(w)''':'''
d = w<tex>\omega</tex> <font color="green">// изначально <tex>d = \omega</tex></font> '''for''' <tex>i = 1 '''to''' n\in V</tex> '''for''' <tex>u = 1 '''to''' n\in V</tex> '''for''' <tex>v = 1 '''to''' n\in V</tex>
d[u][v] = min(d[u][v], d[u][i] + d[i][v])
=== Модифицированный алгоритм ===
'''func''' floyd(w)''':'''
d = w<tex>\omega</tex> <font color="green">// изначально <tex>d = \omega</tex></font> '''for''' <tex>i = 1 '''to''' n\in V</tex> '''for''' <tex>u = 1 '''to''' n\in V</tex> '''for''' <tex>v = 1 '''to''' n\in V</tex>
'''if''' d[u][i] + d[i][v] < d[u][v]
d[u][v] = d[u][i] + d[i][v]
next[u][v] = next[u][i]
'''func''' get_shortest_pathgetShortestPath(u, v)''':'''
'''if''' d[u][v] == <tex>\infty</tex>
'''print''' "No path found" <font color="green">// между вершинами u и v нет пути</font>
}}
Из доказательства следует, что для поиска цикла отрицательного веса необходимо, после завершения работы алгоритма, найти вершину <tex> i </tex>, для которой <tex> d[i][i] < 0 </tex>, и вывести кратчайший путь между парой вершин <tex> (i, i) </tex>. При этом стоит учитывать, что при наличии отрицательного цикла расстояния могут уменьшаться экспоненциально. Для предотвращения переполнения все вычисления стоит ограничивать снизу величиной <tex>-\infty</tex>, либо проверять наличие отрицательных чисел на главной диагонали во время подсчета.
 == Литература Построение транзитивного замыкания ==Сформулируем нашу задачу в терминах графов: рассмотрим граф <tex>G=(V,\; E),\; |V| = n</tex>, соответствующий отношению <tex>R</tex>. Тогда необходимо найти все пары вершин <tex>(x, y) </tex>, соединенных некоторым путем.Иными словами, требуется построить новое отношение <tex>T</tex>, которое будет состоять из всех пар <tex>(x, y) </tex> таких, что найдется последовательность <tex>x = x_0, x_1, \dots, x_k = y </tex>, где <tex> (x_{i-1}, x_i) \in R, i = 1, 2, \dots, k </tex>. === Псевдокод ===Изначально матрица <tex>W</tex> заполняется соответственно отношению <tex>R</tex>, то есть <tex>W[i][j] = [(i, j) \in R] </tex>. Затем внешним циклом перебираются все элементы <tex>k</tex> множества <tex>X</tex> и для каждого из них, если он может использоваться, как промежуточный для соединения двух элементов <tex>i</tex> и <tex>j</tex>, отношение <tex>T</tex> расширяется добавлением в него пары <tex>(i, j)</tex>.  '''for''' k = 1 '''to''' n '''for''' i = 1 '''to''' n '''for''' j = 1 '''to''' n W[i][j] = W[i][j] '''or''' (W[i][k] '''and''' W[k][j])=== Доказательство === <wikitex>Назовем ''промежуточной'' вершину некоторого пути $p = \left \langle v_0, v_1, \dots, v_k \right \rangle$, принадлежащую множеству вершин этого пути и отличающуюся от начальной и конечной вершин, то есть принадлежащую $\left \{ v_1, v_2, \dots, v_{k-1} \right \}$. Рассмотрим произвольную пару вершин $i, j \in V$ и все пути между ними, промежуточные вершины которых принадлежат множеству вершин с номерами $\left \{ 1, 2, \dots, k \right \}$. Пусть $p$ {{---}} некоторый из этих путей. Докажем по индукции (по числу промежуточных вершин в пути), что после $i$-ой итерации внешнего цикла будет верно утверждение {{---}} если в построенном графе между выбранной парой вершин есть путь, содержащий в качестве промежуточных только вершины из множества вершин с номерами $\left \{ v_1, v_2, \dots, v_{i} \right \}$, то между ними будет ребро. * База индукции. Если у нас нет промежуточных вершин, что соответствует начальной матрице смежности, то утверждение выполнено: либо есть ребро (путь не содержит промежуточных вершин), либо его нет.* Индуктивный переход. Пусть предположение выполнено для $i = k - 1$. Докажем, что оно верно и для $i = k$ Рассмотрим случаи (далее под вершиной будем понимать ее номер для простоты изложения):** $k$ не является промежуточной вершиной пути $p$. Тогда все его промежуточные пути принадлежат множеству вершин с номерами $\left \{ 1, 2, \dots, k-1 \right \} \subset \left \{ 1, 2, \dots, k \right \}$, то есть существует путь с промежуточными вершинами в исходном множестве. Это значит $W[i][j]$ будет истиной. В противном случае $W[i][j]$ будет ложью и на k-ом шаге ею и останется.** $k$ является промежуточной вершиной предполагаемого пути $p$. Тогда этот путь можно разбить на два пути: $i \xrightarrow{p_1} k \xrightarrow{p_2} j$. Пусть как $p_1$, так и $p_2$ существуют. Тогда они содержат в качестве промежуточных вершины из множества $\left \{ 1, 2, \dots, k-1 \right \} \subset \left \{ 1, 2, \dots, k \right \}$ (так как вершина $k$ {{---}} либо конечная, либо начальная, то она не может быть в множестве по нашему определению). Тогда $W[i][k]$ и $W[k][j]$ истинны и по индуктивному предположению посчитаны верно. Тогда и $W[i][j]$ тоже истина. Пусть какого-то пути не существует. Тогда пути $p$ тоже не может существовать, так как добраться, например, от вершины $i$ до $k$ по вершинам из множества $\left \{ 1, 2, \dots, k \right \}$ невозможно по индуктивному предположению. Тогда вся конъюнкция будет ложной, то есть такого пути нет, откуда $W[i][j]$ после итерации будет ложью. Таким образом, после завершения внешнего цикла у нас будет $W[i][j] = true$, если между этими вершинами есть путь, содержащий в качестве промежуточных вершин из множества всех остальных вершин графа, что и есть транзитивное замыкание.</wikitex>=== Оптимизация с помощью битовых масок ===Строки матрицы <tex>W</tex> можно хранить с помощью массива битовых масок длиной <tex>k</tex>. Тогда последний цикл будет выполняться в <tex>k</tex> раз быстрее и сложность алгоритма снижается до <tex>O\Big(\dfrac{n^3}{k}\Big)</tex>. <br>Пример реализации оптимизации с помощью битмасок: '''unsigned int''' W[N][N / 32 + 1] '''func''' transitiveClosure(W)''':''' '''for''' k = 1 '''to''' n '''for''' i = 1 '''to''' n '''if''' бит с номером ''(k % 32)'' в маске ''a[i][k / 32]'' единичный '''for''' j = 1 '''to''' n / 32 + 1 W[i][j] = W[i][j] '''or''' W[k][j] В данной реализации длина битовой маски <tex>k</tex> равна <tex>32</tex> битам. Последний цикл делает в <tex>32</tex> раза меньше операций {{---}} сложность алгоритма <tex>O\Big(\dfrac{n^3}{32}\Big)</tex>. == Источники информации ==
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд — М.: Издательский дом «Вильямс», 2009. — ISBN 978-5-8459-0857-5.
* Романовский И. В. Дискретный анализ: Учебное пособие для студентов, специализирующихся по прикладной математике и информатике. Изд. 3-е. — СПб.: Невский диалект, 2003. — 320 с. — ISBN 5-7940-0114-3.
* [https://ru.wikipedia.org/wiki/Алгоритм_Флойда_—_Уоршелла Википедия - Алгоритм Флойда — Уоршелла]
* [https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm Wikipedia - Floyd–Warshall algorithm]
Анонимный участник

Навигация