<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=78.155.172.60&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=78.155.172.60&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/78.155.172.60"/>
		<updated>2026-05-11T11:17:26Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A4%D0%BB%D0%BE%D0%B9%D0%B4%D0%B0&amp;diff=55355</id>
		<title>Алгоритм Флойда</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A4%D0%BB%D0%BE%D0%B9%D0%B4%D0%B0&amp;diff=55355"/>
				<updated>2016-06-20T14:06:25Z</updated>
		
		<summary type="html">&lt;p&gt;78.155.172.60: Восстановление правильного кода&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Флойда (алгоритм Флойда–Уоршелла)''' {{---}} алгоритм нахождения длин кратчайших путей между всеми парами вершин во взвешенном ориентированном графе. Работает корректно, если в графе нет циклов отрицательной величины, а в случае, когда такой цикл есть, позволяет найти хотя бы один такой цикл. Алгоритм работает за &amp;lt;tex&amp;gt; \Theta(n^3) &amp;lt;/tex&amp;gt; времени и использует &amp;lt;tex&amp;gt; \Theta(n^2) &amp;lt;/tex&amp;gt; памяти. Разработан в 1962 году.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм ==&lt;br /&gt;
&lt;br /&gt;
=== Постановка задачи ===&lt;br /&gt;
[[Файл:Floyd_first.png|right|thumb|180px|Текущий (синий) путь и потенциально более короткий (красный)]]&lt;br /&gt;
&lt;br /&gt;
Дан взвешенный ориентированный [[Основные определения: граф, ребро, вершина, степень, петля, путь, цикл|граф]] &amp;lt;tex&amp;gt; G(V, E) &amp;lt;/tex&amp;gt;, в котором вершины пронумерованы от &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;\omega_{uv} =&lt;br /&gt;
\begin{cases}&lt;br /&gt;
\text{weight of }uv ,&amp;amp; \text{if } uv \in E \\&lt;br /&gt;
+\infty ,&amp;amp; \text{if } uv \notin E&lt;br /&gt;
\end{cases}&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;Требуется найти матрицу кратчайших расстояний &amp;lt;tex&amp;gt; d &amp;lt;/tex&amp;gt;, в которой элемент &amp;lt;tex&amp;gt; d_{ij} &amp;lt;/tex&amp;gt; либо равен длине кратчайшего пути из &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt;, либо равен &amp;lt;tex&amp;gt; +\infty &amp;lt;/tex&amp;gt;, если вершина &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt; не достижима из &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Описание ===&lt;br /&gt;
&lt;br /&gt;
Обозначим длину кратчайшего пути между вершинами &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;, содержащего, помимо &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, только вершины из множества &amp;lt;tex&amp;gt; \{ 1 .. i \} &amp;lt;/tex&amp;gt; как &amp;lt;tex&amp;gt;d_{uv}^{(i)}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;d_{uv}^{(0)} = \omega_{uv}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
На каждом шаге алгоритма, мы будем брать очередную вершину (пусть её номер {{---}} &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;) и для всех пар вершин &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; вычислять &amp;lt;tex&amp;gt; d_{uv}^{(i)} = \min(d_{uv}^{(i-1)}, d_{ui}^{(i-1)} + d_{iv}^{(i-1)}) &amp;lt;/tex&amp;gt;. То есть, если кратчайший путь из &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, содержащий только вершины из множества &amp;lt;tex&amp;gt; \{ 1 .. i \} &amp;lt;/tex&amp;gt;, проходит через вершину &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, то кратчайшим путем из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt; является кратчайший путь из &amp;lt;tex&amp;gt; u &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;, объединенный с кратчайшим путем из &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt; v &amp;lt;/tex&amp;gt;. В противном случае, когда этот путь не содержит вершины &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;, кратчайший путь из &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, содержащий только вершины из множества &amp;lt;tex&amp;gt; \{ 1 .. i \} &amp;lt;/tex&amp;gt; является кратчайшим путем из &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, содержащим только вершины из множества &amp;lt;tex&amp;gt; \{ 1 .. i-1 \} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Код (в первом приближении) ===&lt;br /&gt;
 &amp;lt;tex&amp;gt;d^{(0)}_{uv} = w&amp;lt;/tex&amp;gt;&lt;br /&gt;
 '''for''' &amp;lt;tex&amp;gt;i \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;u \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
             &amp;lt;tex&amp;gt; d^{(i)}_{uv} = \min(d^{(i - 1)}_{uv}, d^{(i - 1)}_{ui} + d^{(i - 1)}_{iv}) &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В итоге получаем, что матрица &amp;lt;tex&amp;gt; d^{(n)} &amp;lt;/tex&amp;gt; и является искомой матрицей кратчайших путей, поскольку содержит в себе длины кратчайших путей между всеми парами вершин, имеющих в качестве промежуточных вершин вершины из множества &amp;lt;tex&amp;gt; \{ 1..n \} &amp;lt;/tex&amp;gt;, что есть попросту все вершины графа. Такая реализация работает за &amp;lt;tex&amp;gt; \Theta(n^3) &amp;lt;/tex&amp;gt; времени и использует &amp;lt;tex&amp;gt; \Theta(n^3) &amp;lt;/tex&amp;gt; памяти.&lt;br /&gt;
&lt;br /&gt;
=== Код (окончательный) ===&lt;br /&gt;
Утверждается, что можно избавиться от одной размерности в массиве &amp;lt;tex&amp;gt; d &amp;lt;/tex&amp;gt;, т.е. использовать двумерный массив &amp;lt;tex&amp;gt;d_{uv}&amp;lt;/tex&amp;gt;. В процессе работы алгоритма поддерживается инвариант &amp;lt;tex&amp;gt;\rho(u, v) \leqslant d_{uv} \leqslant d_{uv}^{(i)}&amp;lt;/tex&amp;gt;, а, поскольку, после выполнения работы алгоритма &amp;lt;tex&amp;gt; \rho(u, v) = d_{uv}^{(i)} &amp;lt;/tex&amp;gt;, то тогда будет выполняться и &amp;lt;tex&amp;gt; \rho(u, v) = d_{uv} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
В течение работы алгоритма Флойда выполняются неравенства: &amp;lt;tex&amp;gt;\rho(u, v) \leqslant d_{uv} \leqslant d_{uv}^{(i)}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
&lt;br /&gt;
После инициализации все неравенства, очевидно, выполняются. Далее, массив &amp;lt;tex&amp;gt; d &amp;lt;/tex&amp;gt; может измениться только в строчке 5. &lt;br /&gt;
&lt;br /&gt;
'''Докажем второе неравенство индукцией по итерациям алгоритма.'''&lt;br /&gt;
&lt;br /&gt;
Пусть также &amp;lt;tex&amp;gt;d'_{uv}&amp;lt;/tex&amp;gt; {{---}} значение &amp;lt;tex&amp;gt;d_{uv}&amp;lt;/tex&amp;gt; сразу после &amp;lt;tex&amp;gt;i - 1&amp;lt;/tex&amp;gt; итерации.&lt;br /&gt;
&lt;br /&gt;
Покажем, что &amp;lt;tex&amp;gt; d_{uv} \leqslant d_{uv}^{(i)} &amp;lt;/tex&amp;gt;, зная, что &amp;lt;tex&amp;gt; d'_{uv} \leqslant d_{uv}^{(i - 1)} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим два случая:&lt;br /&gt;
* Значение &amp;lt;tex&amp;gt; d_{uv}^{(i)} &amp;lt;/tex&amp;gt; стало меньше, чем &amp;lt;tex&amp;gt; d_{uv}^{(i - 1)} &amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt; d_{uv}^{(i)} = d_{ui}^{(i-1)} + d_{iv}^{(i-1)} \geqslant &amp;lt;/tex&amp;gt; (выполняется на шаге &amp;lt;tex&amp;gt; i - 1 &amp;lt;/tex&amp;gt;, по индукционному  предположению) &amp;lt;tex&amp;gt; \geqslant d'_{ui}  + d'_{iv} \ge&amp;lt;/tex&amp;gt; (в силу выполнения 7-ой строчки алгоритма на &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой итерации и невозрастания элементов массива &amp;lt;tex&amp;gt; d &amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;\geqslant d_{uv}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* В ином случае всё очевидно: &amp;lt;tex&amp;gt; d_{uv}^{(i)} = d_{uv}^{(i - 1)} \geqslant d'_{uv} \geqslant d_{uv} &amp;lt;/tex&amp;gt;, и неравенство тривиально.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Докажем первое неравенство от противного.'''&lt;br /&gt;
&lt;br /&gt;
Пусть неравенство было нарушено, рассмотрим момент, когда оно было нарушено впервые. Пусть это была &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ая итерация и в этот момент изменилось значение &amp;lt;tex&amp;gt;d_{uv}&amp;lt;/tex&amp;gt; и выполнилось  &amp;lt;tex&amp;gt;\rho(u,v) &amp;gt; d_{uv}&amp;lt;/tex&amp;gt;. Так как &amp;lt;tex&amp;gt;d_{uv}&amp;lt;/tex&amp;gt; изменилось, то &amp;lt;tex&amp;gt;d_{uv} = d_{ui} + d_{iv} \ge&amp;lt;/tex&amp;gt; (так как ранее &amp;lt;tex&amp;gt;\forall u, v \in V: \rho(u,v) \leqslant d_{uv}&amp;lt;/tex&amp;gt;) &amp;lt;tex&amp;gt;\geqslant \rho(u, i) + \rho(i, v) \ge&amp;lt;/tex&amp;gt; (по неравенству треугольника) &amp;lt;tex&amp;gt;\geqslant \rho(u, v)&amp;lt;/tex&amp;gt;. &lt;br /&gt;
Итак &amp;lt;tex&amp;gt;d_{uv} \geqslant \rho(u,v)&amp;lt;/tex&amp;gt; {{---}} противоречие.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
 '''func''' floyd(w)''':'''&lt;br /&gt;
     d = &amp;lt;tex&amp;gt;\omega&amp;lt;/tex&amp;gt;                &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// изначально &amp;lt;tex&amp;gt;d = \omega&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;i \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;u \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''for''' &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
                 d[u][v] = min(d[u][v], d[u][i] + d[i][v])&lt;br /&gt;
&lt;br /&gt;
Данная реализация работает за время &amp;lt;tex&amp;gt; \Theta(n^3) &amp;lt;/tex&amp;gt;, но требует уже &amp;lt;tex&amp;gt; \Theta(n^2) &amp;lt;/tex&amp;gt; памяти. В целом, алгоритм Флойда очень прост, и, поскольку в нем используются только простые операции, константа, скрытая в определении &amp;lt;tex&amp;gt; \Theta &amp;lt;/tex&amp;gt; весьма мала.&lt;br /&gt;
&lt;br /&gt;
=== Пример работы ===&lt;br /&gt;
{|class = &amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center;&amp;quot;&lt;br /&gt;
| &amp;lt;tex&amp;gt;i = 0&amp;lt;/tex&amp;gt; ||  &amp;lt;tex&amp;gt;i = 1&amp;lt;/tex&amp;gt; ||  &amp;lt;tex&amp;gt;i = 2&amp;lt;/tex&amp;gt; ||  &amp;lt;tex&amp;gt;i = 3 &amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;i = 4&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|width = &amp;quot;180px&amp;quot;| [[Файл:0.png|170px]] ||width = &amp;quot;180px&amp;quot;|[[Файл:Floyd_1.png|170px]] ||width = &amp;quot;180px&amp;quot;|[[Файл:Floyd_2.png|170px]] ||width = &amp;quot;180px&amp;quot;|[[Файл:Floyd_algo_3.png|170px]] ||width = &amp;quot;180px&amp;quot;|[[Файл:Floyd_4.png|170px]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tex&amp;gt;\begin{pmatrix}&lt;br /&gt;
\times &amp;amp; 1 &amp;amp; 6 &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \times &amp;amp; 4 &amp;amp; 1 \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; \times &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; 1 &amp;amp; \times \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 || &amp;lt;tex&amp;gt;\begin{pmatrix}&lt;br /&gt;
\times &amp;amp; 1 &amp;amp; 6 &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \times &amp;amp; 4 &amp;amp; 1 \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; \times &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; 1 &amp;amp; \times \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 || &amp;lt;tex&amp;gt;\begin{pmatrix}&lt;br /&gt;
\times &amp;amp; 1 &amp;amp; \bf{5} &amp;amp; \bf{2} \\&lt;br /&gt;
\infty &amp;amp; \times &amp;amp; 4 &amp;amp; 1 \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; \times &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; 1 &amp;amp; \times \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 || &amp;lt;tex&amp;gt;\begin{pmatrix}&lt;br /&gt;
\times &amp;amp; 1 &amp;amp; 5 &amp;amp; 2 \\&lt;br /&gt;
\infty &amp;amp; \times &amp;amp; 4 &amp;amp; 1 \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; \times &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; 1 &amp;amp; \times \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/tex&amp;gt;&lt;br /&gt;
 || &amp;lt;tex&amp;gt;\begin{pmatrix}&lt;br /&gt;
\times &amp;amp; 1 &amp;amp; \bf{3} &amp;amp; 2 \\&lt;br /&gt;
\infty &amp;amp; \times &amp;amp; \bf{2} &amp;amp; 1 \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; \times &amp;amp; \infty \\&lt;br /&gt;
\infty &amp;amp; \infty &amp;amp; 1 &amp;amp; \times \\&lt;br /&gt;
\end{pmatrix}&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Вывод кратчайшего пути ==&lt;br /&gt;
Алгоритм Флойда легко модифицировать таким образом, чтобы он возвращал не только длину кратчайшего пути, но и сам путь. Для этого достаточно завести дополнительный массив &amp;lt;tex&amp;gt;next&amp;lt;/tex&amp;gt;, в котором будет храниться номер вершины, в которую надо пойти следующей, чтобы дойти из &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; по кратчайшему пути.&lt;br /&gt;
&lt;br /&gt;
=== Модифицированный алгоритм ===&lt;br /&gt;
 '''func''' floyd(w)''':'''&lt;br /&gt;
     d = &amp;lt;tex&amp;gt;\omega&amp;lt;/tex&amp;gt;               &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// изначально &amp;lt;tex&amp;gt;d = \omega&amp;lt;/tex&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''for''' &amp;lt;tex&amp;gt;i \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''for''' &amp;lt;tex&amp;gt;u \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
             '''for''' &amp;lt;tex&amp;gt;v \in V&amp;lt;/tex&amp;gt;&lt;br /&gt;
                 '''if''' d[u][i] + d[i][v] &amp;lt; d[u][v]&lt;br /&gt;
                     d[u][v] = d[u][i] + d[i][v]&lt;br /&gt;
                     next[u][v] = next[u][i]&lt;br /&gt;
&lt;br /&gt;
 '''func''' getShortestPath(u, v)''':'''&lt;br /&gt;
     '''if''' d[u][v] == &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''print''' &amp;quot;No path found&amp;quot;                 &amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;// между вершинами u и v нет пути&amp;lt;/font&amp;gt;&lt;br /&gt;
     c = u&lt;br /&gt;
     '''while''' c != v&lt;br /&gt;
         '''print''' c&lt;br /&gt;
         c = next[c][v]&lt;br /&gt;
     '''print''' v&lt;br /&gt;
&lt;br /&gt;
== Нахождение отрицательного цикла ==&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
При наличии цикла отрицательного веса в матрице &amp;lt;tex&amp;gt; D &amp;lt;/tex&amp;gt; появятся отрицательные числа на главной диагонали.&lt;br /&gt;
|proof=&lt;br /&gt;
Так как алгоритм Флойда последовательно релаксирует расстояния между всеми парами вершин &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;, в том числе и теми, у которых &amp;lt;tex&amp;gt;i = j&amp;lt;/tex&amp;gt;, а начальное расстояние между парой вершин &amp;lt;tex&amp;gt;(i, i)&amp;lt;/tex&amp;gt; равно нулю, то релаксация может произойти только при наличии вершины &amp;lt;tex&amp;gt; k &amp;lt;/tex&amp;gt; такой, что &amp;lt;tex&amp;gt; d[i][k] + d[k][i] &amp;lt; 0 &amp;lt;/tex&amp;gt;, что эквивалентно наличию отрицательного цикла, проходящего через вершину &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
Из доказательства следует, что для поиска цикла отрицательного веса необходимо, после завершения работы алгоритма, найти вершину &amp;lt;tex&amp;gt; i &amp;lt;/tex&amp;gt;, для которой &amp;lt;tex&amp;gt; d[i][i] &amp;lt; 0 &amp;lt;/tex&amp;gt;, и вывести кратчайший путь между парой вершин &amp;lt;tex&amp;gt; (i, i) &amp;lt;/tex&amp;gt;. При этом стоит учитывать, что при наличии отрицательного цикла расстояния могут уменьшаться экспоненциально. Для предотвращения переполнения все вычисления стоит ограничивать снизу величиной &amp;lt;tex&amp;gt;-\infty&amp;lt;/tex&amp;gt;, либо проверять наличие отрицательных чисел на главной диагонали во время подсчета.&lt;br /&gt;
&lt;br /&gt;
== Построение транзитивного замыкания ==&lt;br /&gt;
Сформулируем нашу задачу в терминах графов: рассмотрим граф &amp;lt;tex&amp;gt;G=(V,\; E),\; |V| = n&amp;lt;/tex&amp;gt;, соответствующий отношению &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;. Тогда необходимо найти все пары вершин &amp;lt;tex&amp;gt;(x, y) &amp;lt;/tex&amp;gt;, соединенных некоторым путем.&lt;br /&gt;
Иными словами, требуется построить новое отношение &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt;, которое будет состоять из всех пар &amp;lt;tex&amp;gt;(x, y) &amp;lt;/tex&amp;gt; таких, что найдется последовательность &amp;lt;tex&amp;gt;x = x_0, x_1, \dots, x_k = y &amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; (x_{i-1}, x_i) \in R, i = 1, 2, \dots, k &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
Изначально матрица &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt; заполняется соответственно отношению &amp;lt;tex&amp;gt;R&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;W[i][j] = [(i, j) \in R] &amp;lt;/tex&amp;gt;. Затем внешним циклом перебираются все элементы &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; множества &amp;lt;tex&amp;gt;X&amp;lt;/tex&amp;gt; и для каждого из них, если он может использоваться, как промежуточный для соединения двух элементов &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, отношение &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; расширяется добавлением в него пары &amp;lt;tex&amp;gt;(i, j)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''for''' k = 1 '''to''' n&lt;br /&gt;
     '''for''' i = 1 '''to''' n&lt;br /&gt;
         '''for''' j = 1 '''to''' n&lt;br /&gt;
             W[i][j] = W[i][j] '''or''' (W[i][k] '''and''' W[k][j])&lt;br /&gt;
=== Доказательство ===  &lt;br /&gt;
&amp;lt;wikitex&amp;gt;Назовем ''промежуточной'' вершину некоторого пути $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 \}$, то между ними будет ребро.&lt;br /&gt;
&lt;br /&gt;
* База индукции. Если у нас нет промежуточных вершин, что соответствует начальной матрице смежности, то утверждение выполнено: либо есть ребро (путь не содержит промежуточных вершин), либо его нет.&lt;br /&gt;
* Индуктивный переход. Пусть предположение выполнено для $i = k - 1$. Докажем, что оно верно и для $i = k$ Рассмотрим случаи (далее под вершиной будем понимать ее номер для простоты изложения):&lt;br /&gt;
** $k$ не является промежуточной вершиной пути $p$. Тогда все его промежуточные пути принадлежат множеству вершин с номерами $\left \{ 1, 2, \dots, k-1 \right \} \subset \left \{ 1, 2, \dots, k \right \}$, то есть существует путь с промежуточными вершинами в исходном множестве. Это значит $W[i][j]$ будет истиной. В противном случае $W[i][j]$ будет ложью и на k-ом шаге ею и останется.&lt;br /&gt;
** $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]$ после итерации будет ложью.&lt;br /&gt;
&lt;br /&gt;
Таким образом, после завершения внешнего цикла у нас будет $W[i][j] = true$, если между этими вершинами есть путь, содержащий в качестве промежуточных вершин из множества всех остальных вершин графа, что и есть транзитивное замыкание.&lt;br /&gt;
&amp;lt;/wikitex&amp;gt;&lt;br /&gt;
=== Оптимизация с помощью битовых масок ===&lt;br /&gt;
Строки матрицы &amp;lt;tex&amp;gt;W&amp;lt;/tex&amp;gt; можно хранить с помощью массива битовых масок длиной &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Тогда последний цикл будет выполняться в &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; раз быстрее и сложность алгоритма снижается до &amp;lt;tex&amp;gt;O\Big(\dfrac{n^3}{k}\Big)&amp;lt;/tex&amp;gt;. &amp;lt;br&amp;gt;&lt;br /&gt;
Пример реализации оптимизации с помощью битмасок:&lt;br /&gt;
 &lt;br /&gt;
 '''unsigned int''' W[N][N / 32 + 1]           &lt;br /&gt;
 &lt;br /&gt;
 '''func''' transitiveClosure(W)''':'''&lt;br /&gt;
     '''for''' k = 1 '''to''' n&lt;br /&gt;
         '''for''' i = 1 '''to''' n&lt;br /&gt;
             '''if''' бит с номером ''(k % 32)'' в маске ''a[i][k / 32]'' единичный&lt;br /&gt;
                 '''for''' j = 1 '''to''' n / 32 + 1&lt;br /&gt;
                     W[i][j] = W[i][j] '''or''' W[k][j]&lt;br /&gt;
&lt;br /&gt;
В данной реализации длина битовой маски &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; равна &amp;lt;tex&amp;gt;32&amp;lt;/tex&amp;gt; битам. Последний цикл делает в &amp;lt;tex&amp;gt;32&amp;lt;/tex&amp;gt; раза меньше операций {{---}} сложность алгоритма &amp;lt;tex&amp;gt;O\Big(\dfrac{n^3}{32}\Big)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* Томас Х. Кормен, Чарльз И. Лейзерсон, Рональд Л. Ривест, Клиффорд Штайн Алгоритмы: построение и анализ — 2-е изд — М.: Издательский дом «Вильямс», 2009. — ISBN 978-5-8459-0857-5.&lt;br /&gt;
* Романовский И. В. Дискретный анализ: Учебное пособие для студентов, специализирующихся по прикладной математике и информатике. Изд. 3-е. — СПб.: Невский диалект, 2003. — 320 с. — ISBN 5-7940-0114-3.&lt;br /&gt;
* [https://ru.wikipedia.org/wiki/Алгоритм_Флойда_—_Уоршелла Википедия - Алгоритм Флойда — Уоршелла]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm Wikipedia - Floyd–Warshall algorithm]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Кратчайшие пути в графах ]]&lt;/div&gt;</summary>
		<author><name>78.155.172.60</name></author>	</entry>

	</feed>